├── .gitignore ├── .luacheckrc ├── Makefile ├── README.md ├── check.sh ├── etc ├── check.cfg ├── test.cfg └── testd.cfg ├── examples ├── check.lua └── test.lua ├── luaclib ├── cjson.so ├── codec.so ├── packet.so ├── protobuf.so ├── random.so └── webclient.so ├── lualib-src ├── lua-aes.c ├── lua-packet.c ├── lua-random.c └── lua-webclient.c ├── lualib ├── bw │ ├── auth │ │ ├── sha256.lua │ │ ├── sign.lua │ │ └── wx.lua │ ├── bash.lua │ ├── bewater.lua │ ├── class.lua │ ├── cms │ │ ├── api │ │ │ └── cms │ │ │ │ ├── debug │ │ │ │ └── inject.lua │ │ │ │ ├── skynet │ │ │ │ ├── all_service.lua │ │ │ │ └── node_info.lua │ │ │ │ ├── sys │ │ │ │ └── main.lua │ │ │ │ ├── user │ │ │ │ ├── gm.lua │ │ │ │ └── login.lua │ │ │ │ └── view │ │ │ │ ├── gm.lua │ │ │ │ ├── inject.lua │ │ │ │ ├── main.lua │ │ │ │ └── menu.lua │ │ ├── handler.lua │ │ ├── layui.lua │ │ ├── server.lua │ │ └── webconsole.lua │ ├── const.lua │ ├── db │ │ ├── mongo_helper.lua │ │ ├── mysql_helper.lua │ │ └── redis_helper.lua │ ├── gm.lua │ ├── hash_array.lua │ ├── hotfix.lua │ ├── ip │ │ ├── blacklist.lua │ │ ├── ip_country.lua │ │ └── whitelist.lua │ ├── lock.lua │ ├── log.lua │ ├── payment │ │ ├── alipay.lua │ │ ├── applepay.lua │ │ └── wxpay.lua │ ├── prop.lua │ ├── proto │ │ └── code.lua │ ├── protobuf.lua │ ├── random.lua │ ├── schedule.lua │ ├── share │ │ ├── autoid.lua │ │ ├── init.lua │ │ ├── operate.lua │ │ └── passport.lua │ ├── sname.lua │ ├── sock │ │ ├── network_t.lua │ │ ├── packet.lua │ │ └── robot_t.lua │ ├── timer.lua │ ├── util.lua │ ├── util │ │ ├── activity_helper.lua │ │ ├── clusterinfo.lua │ │ ├── date_helper.lua │ │ └── wrapper_helper.lua │ ├── uuid.lua │ ├── web │ │ ├── html.lua │ │ └── http_helper.lua │ ├── ws │ │ ├── bnf.lua │ │ ├── client.lua │ │ ├── network_t.lua │ │ ├── packet.lua │ │ ├── proto.lua │ │ ├── robot_t.lua │ │ ├── server.lua │ │ ├── socket_help.lua │ │ └── url.lua │ └── xml │ │ ├── XmlParser.lua │ │ ├── dom.lua │ │ ├── lua2xml.lua │ │ ├── print.lua │ │ ├── tree.lua │ │ └── xml2lua.lua ├── def.lua └── def │ ├── errcode.lua │ ├── errcode_helper.lua │ ├── opcode.lua │ └── opcode_helper.lua ├── script ├── check │ ├── cms.lua │ ├── date_helper.lua │ ├── inject.lua │ ├── ip_country.lua │ ├── logger.lua │ └── schedule.lua ├── conf.lua └── test │ └── stdout.lua ├── service ├── alert.lua ├── autoid.lua ├── battle │ ├── agent.lua │ ├── match.lua │ ├── matchcenter.lua │ └── watchdog.lua ├── db │ ├── mongod.lua │ ├── mysqld.lua │ └── redisd.lua ├── gm.lua ├── logger.lua ├── operate.lua ├── passport.lua ├── proto_env.lua ├── publish.lua ├── report.lua ├── sock │ ├── agent.lua │ └── watchdog.lua ├── stdout.lua ├── web │ ├── webclient.lua │ └── webserver.lua └── ws │ ├── agent.lua │ └── watchdog.lua ├── shell ├── etc.sh ├── kill.sh ├── log.sh ├── proto.sh └── run.sh └── tools ├── install_lua_luarocks.sh ├── protoc3 └── workspace.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .tags 2 | .cscope.out 3 | log/ 4 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | codes = true 2 | color = true 3 | 4 | std = "max" 5 | 6 | include_files = { 7 | "lualib/*", 8 | "service/*", 9 | } 10 | 11 | exclude_files = { 12 | "lualib/xml/*", 13 | "lualib/ws/*", 14 | "lualib/bash.lua", 15 | "lualib/schedule.lua", 16 | "lualib/ip/ip_country.lua", 17 | } 18 | 19 | ignore = { 20 | "i", 21 | "k", 22 | "v", 23 | "bash", 24 | "SERVICE_NAME", 25 | "self", 26 | } 27 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SRC_DIR = ./lualib-src 2 | LIB_DIR = ./luaclib 3 | 4 | SRC = ${wildcard ${SRC_DIR}/*.c} 5 | LIB = ${patsubst lua-%.c, ${LIB_DIR}/%.so, ${notdir ${SRC}}} 6 | 7 | 8 | all:${LIB} 9 | 10 | ${LIB_DIR}/%.so:${SRC_DIR}/lua-%.c 11 | cc -g -O2 -Wall -Iskynet/3rd/lua -fPIC --shared $< -o $@ -lcurl 12 | 13 | .PHONY:clean 14 | clean: 15 | rm ${LIB} 16 | -------------------------------------------------------------------------------- /check.sh: -------------------------------------------------------------------------------- 1 | luacheck --config .luacheckrc ./ 2 | -------------------------------------------------------------------------------- /etc/check.cfg: -------------------------------------------------------------------------------- 1 | workspace = "../bewater/" 2 | thread = 8 3 | logpath = "." 4 | harbor = 0 5 | start = "check" 6 | bootstrap = "snlua bootstrap" 7 | lualoader = "lualib/loader.lua" 8 | snax = workspace.."service/?.lua" 9 | luaservice = workspace.."examples/?.lua;"..workspace.."service/?.lua;"..workspace.."service/?.lua;".."./service/?.lua;".."./liblua/?.lua;" 10 | cpath = workspace.."luaclib/?.so;"..workspace.."luaclib/?.so;".."./cservice/?.so;./luaclib/?.so" 11 | lua_path = workspace.."script/?.lua;"..workspace.."lualib/?.lua;"..workspace.."lualib/?.lua;".."./lualib/?.lua;" 12 | lua_cpath = workspace.."luaclib/?.so;"..workspace.."luaclib/?.so;".."./luaclib/?.so;" 13 | logger = "logger" 14 | logservice = "snlua" 15 | clustername = "check" 16 | -------------------------------------------------------------------------------- /etc/test.cfg: -------------------------------------------------------------------------------- 1 | workspace = "../bewater/" 2 | thread = 8 3 | logpath = "." 4 | harbor = 0 5 | start = "test" 6 | bootstrap = "snlua bootstrap" 7 | lualoader = "lualib/loader.lua" 8 | snax = workspace.."service/?.lua" 9 | luaservice = workspace.."examples/?.lua;"..workspace.."service/?.lua;"..workspace.."service/?.lua;".."./service/?.lua;".."./liblua/?.lua;" 10 | cpath = workspace.."luaclib/?.so;"..workspace.."luaclib/?.so;".."./cservice/?.so;./luaclib/?.so" 11 | lua_path = workspace.."script/?.lua;"..workspace.."lualib/?.lua;"..workspace.."lualib/?.lua;".."./lualib/?.lua;" 12 | lua_cpath = workspace.."luaclib/?.so;"..workspace.."luaclib/?.so;".."./luaclib/?.so;" 13 | logger = "logger" 14 | logservice = "snlua" 15 | clustername = "test" 16 | -------------------------------------------------------------------------------- /etc/testd.cfg: -------------------------------------------------------------------------------- 1 | workspace = "../bewater/" 2 | thread = 8 3 | logpath = "." 4 | harbor = 0 5 | start = "test" 6 | bootstrap = "snlua bootstrap" 7 | lualoader = "lualib/loader.lua" 8 | snax = workspace.."service/?.lua" 9 | luaservice = workspace.."examples/?.lua;"..workspace.."service/?.lua;"..workspace.."service/?.lua;".."./service/?.lua;".."./liblua/?.lua;" 10 | cpath = workspace.."luaclib/?.so;"..workspace.."luaclib/?.so;".."./cservice/?.so;./luaclib/?.so" 11 | lua_path = workspace.."script/?.lua;"..workspace.."lualib/?.lua;"..workspace.."lualib/?.lua;".."./lualib/?.lua;" 12 | lua_cpath = workspace.."luaclib/?.so;"..workspace.."luaclib/?.so;".."./luaclib/?.so;" 13 | logger = "logger" 14 | logservice = "snlua" 15 | clustername = "test" 16 | daemon = workspace.."/log/pid/testd.pid" 17 | -------------------------------------------------------------------------------- /examples/check.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local bewater = require "bw.bewater" 3 | 4 | require "bw.ip.ip_country" 5 | require "bw.schedule" 6 | 7 | local check_list = { 8 | "ip_country", 9 | "schedule", 10 | "cms", 11 | "date_helper", 12 | -- "inject", 13 | "logger", 14 | } 15 | 16 | 17 | skynet.start(function() 18 | skynet.register "check" 19 | bewater.reg_code(_G) 20 | 21 | local count = 0 22 | for i, v in ipairs(check_list) do 23 | local ret = require("check."..v) 24 | if type(ret) == "function" then 25 | ret = ret() 26 | end 27 | skynet.error(string.format("check %s %s", v, ret and "ok" or "fail")) 28 | if ret then 29 | count = count + 1 30 | else 31 | break 32 | end 33 | end 34 | skynet.error(string.format("check %d files, %d ok, %d fail", 35 | #check_list, count, #check_list - count)) 36 | 37 | skynet.newservice("autoid") 38 | end) 39 | -------------------------------------------------------------------------------- /examples/test.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local http = require "bw.web.http_helper" 3 | local wc = require "bw.cms.webconsole" 4 | local sname = require "bw.sname" 5 | local json = require "cjson.safe" 6 | 7 | local function test(filename) 8 | require("test."..filename)() 9 | end 10 | 11 | skynet.start(function() 12 | wc.init({ 13 | port = "9999", 14 | users = { 15 | {account = "root", password = "123"} 16 | } 17 | }) 18 | 19 | skynet.error("Be water my friend.") 20 | 21 | --test "stdout" 22 | end) 23 | -------------------------------------------------------------------------------- /luaclib/cjson.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiyajunjun/bewater/a9ff302c8304f9d798f70c03a5755d22affb90a5/luaclib/cjson.so -------------------------------------------------------------------------------- /luaclib/codec.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiyajunjun/bewater/a9ff302c8304f9d798f70c03a5755d22affb90a5/luaclib/codec.so -------------------------------------------------------------------------------- /luaclib/packet.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiyajunjun/bewater/a9ff302c8304f9d798f70c03a5755d22affb90a5/luaclib/packet.so -------------------------------------------------------------------------------- /luaclib/protobuf.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiyajunjun/bewater/a9ff302c8304f9d798f70c03a5755d22affb90a5/luaclib/protobuf.so -------------------------------------------------------------------------------- /luaclib/random.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiyajunjun/bewater/a9ff302c8304f9d798f70c03a5755d22affb90a5/luaclib/random.so -------------------------------------------------------------------------------- /luaclib/webclient.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiyajunjun/bewater/a9ff302c8304f9d798f70c03a5755d22affb90a5/luaclib/webclient.so -------------------------------------------------------------------------------- /lualib-src/lua-aes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | static int l_init(lua_State *L); 13 | static int l_cleanup(lua_State *L); 14 | static int l_encrypt(lua_State *L); 15 | static int l_decrypt(lua_State *L); 16 | static void init(); 17 | static void cleanup(); 18 | static int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,unsigned char *iv, unsigned char *ciphertext); 19 | static int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,unsigned char *iv, unsigned char *plaintext); 20 | 21 | static const struct luaL_Reg luaaes [] = { 22 | {"init", l_init}, 23 | {"cleanup", l_cleanup}, 24 | {"encrypt", l_encrypt}, 25 | {"decrypt", l_decrypt}, 26 | {NULL, NULL} 27 | }; 28 | 29 | LUALIB_API int luaopen_aes_core(lua_State *L) 30 | { 31 | luaL_Reg libs[] = { 32 | {"init", l_init}, 33 | {"cleanup", l_cleanup}, 34 | {"encrypt", l_encrypt}, 35 | {"decrypt", l_decrypt}, 36 | {NULL, NULL} 37 | }; 38 | luaL_newlib(L, libs); 39 | return 1; 40 | } 41 | 42 | 43 | void init(void) 44 | { 45 | 46 | /* Initialise the library */ 47 | ERR_load_crypto_strings(); 48 | OpenSSL_add_all_algorithms(); 49 | OPENSSL_config(NULL); 50 | 51 | } 52 | 53 | void cleanup(void) 54 | { 55 | 56 | /* Clean up */ 57 | EVP_cleanup(); 58 | ERR_free_strings(); 59 | 60 | } 61 | 62 | int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, 63 | unsigned char *iv, unsigned char *ciphertext) 64 | { 65 | EVP_CIPHER_CTX *ctx; 66 | 67 | int len; 68 | 69 | int ciphertext_len; 70 | 71 | /* Create and initialise the context */ 72 | if(!(ctx = EVP_CIPHER_CTX_new())) return -1; 73 | 74 | if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)) 75 | return -1; 76 | 77 | if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) 78 | return -1; 79 | ciphertext_len = len; 80 | 81 | if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) 82 | return -1; 83 | 84 | ciphertext_len += len; 85 | 86 | /* Clean up */ 87 | EVP_CIPHER_CTX_free(ctx); 88 | 89 | return ciphertext_len; 90 | } 91 | 92 | int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, 93 | unsigned char *iv, unsigned char *plaintext) 94 | { 95 | EVP_CIPHER_CTX *ctx; 96 | 97 | int len; 98 | 99 | int plaintext_len; 100 | /* Create and initialise the context */ 101 | if(!(ctx = EVP_CIPHER_CTX_new())) 102 | return -1; 103 | 104 | if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv)) 105 | return -1; 106 | 107 | if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) 108 | return -1; 109 | plaintext_len = len; 110 | 111 | if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) 112 | return -1; 113 | plaintext_len += len; 114 | 115 | EVP_CIPHER_CTX_free(ctx); 116 | 117 | return plaintext_len; 118 | } 119 | 120 | static int l_init(lua_State *L) 121 | { 122 | 123 | init(); 124 | return 0; 125 | } 126 | 127 | static int l_cleanup(lua_State *L) 128 | { 129 | cleanup(); 130 | return 0; 131 | } 132 | 133 | static int l_encrypt(lua_State *L) 134 | { 135 | size_t pt_len=0; 136 | unsigned char* pt= (unsigned char*)lua_tolstring(L, 1,&pt_len); 137 | int ct_len=((pt_len&0xfffffffff80)+0x80); 138 | unsigned char* ct=(unsigned char*)malloc(ct_len); 139 | 140 | unsigned char* key= (unsigned char*)lua_tostring(L, 2); 141 | unsigned char* iv= (unsigned char*)lua_tostring(L, 3); 142 | ct_len=encrypt(pt,pt_len,key,iv,ct); 143 | if(ct_len>=0) 144 | { 145 | lua_pushnumber(L,0); 146 | lua_pushlstring(L,(const char*)ct,ct_len); 147 | free(ct); 148 | return 2; 149 | } 150 | else 151 | { 152 | free(ct); 153 | lua_pushnumber(L,-1); 154 | 155 | unsigned long l; 156 | char buf[256]; 157 | l=ERR_get_error(); 158 | ERR_error_string_n(l, buf, sizeof buf); 159 | lua_pushstring(L,buf); 160 | return 2; 161 | } 162 | } 163 | 164 | static int l_decrypt(lua_State *L) 165 | { 166 | size_t ct_len=0; 167 | unsigned char* ct= (unsigned char*)lua_tolstring(L, 1,&ct_len); 168 | int pt_len=ct_len; 169 | unsigned char* pt=(unsigned char*)malloc(pt_len); 170 | 171 | 172 | unsigned char* key= (unsigned char*)lua_tostring(L, 2); 173 | unsigned char* iv= (unsigned char*)lua_tostring(L, 3); 174 | 175 | pt_len=decrypt(ct,ct_len,key,iv,pt); 176 | if(pt_len>=0) 177 | { 178 | lua_pushnumber(L,0); 179 | lua_pushlstring(L,(const char*)pt,pt_len); 180 | free(pt); 181 | return 2; 182 | } 183 | else 184 | { 185 | free(pt); 186 | lua_pushnumber(L,-1); 187 | 188 | unsigned long l; 189 | char buf[256]; 190 | l=ERR_get_error(); 191 | ERR_error_string_n(l, buf, sizeof buf); 192 | lua_pushstring(L,buf); 193 | return 2; 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /lualib-src/lua-random.c: -------------------------------------------------------------------------------- 1 | // 2 | // $id: random.c O $ 3 | // 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define BASKET_SIZE 1000 16 | #define PER_BASKET 8 17 | 18 | static uint8_t arr[BASKET_SIZE][128] = {{0}}; // 128 x 8 = 1024bit 19 | 20 | static int rand_value() 21 | { 22 | return (int)fmax(0, fmin(BASKET_SIZE - 1, (double)rand() / RAND_MAX * BASKET_SIZE)); 23 | } 24 | 25 | static void shuffle(int slot) 26 | { 27 | int mask_count = 0; 28 | 29 | int bit = 0; 30 | for (bit = 0; bit < BASKET_SIZE; bit++) { 31 | int ai = bit / PER_BASKET; 32 | int aj = bit % PER_BASKET; 33 | int random_count = rand_value(); 34 | int bi = random_count / PER_BASKET; 35 | int bj = random_count % PER_BASKET; 36 | uint8_t a = arr[slot][ai] >> aj & 0x1; 37 | uint8_t b = arr[slot][bi] >> bj & 0x1; 38 | 39 | arr[slot][ai] &= ~(1 << aj); 40 | arr[slot][ai] |= b << aj; 41 | 42 | arr[slot][bi] &= ~(1 << bj); 43 | arr[slot][bi] |= a << bj; 44 | } 45 | 46 | for (bit = 0; bit < BASKET_SIZE; bit++) { 47 | int i = bit / PER_BASKET; 48 | int j = bit % PER_BASKET; 49 | if ((arr[slot][i] >> j & 0x1) == 1) 50 | mask_count++; 51 | } 52 | 53 | assert(mask_count == slot + 1); 54 | } 55 | 56 | static void init_prob() 57 | { 58 | static int init = 0; 59 | int slot; 60 | int bit; 61 | 62 | if (!init) 63 | { 64 | init = 1; 65 | srand((unsigned int)time(NULL)); 66 | 67 | for (slot = 0; slot < BASKET_SIZE; slot++) { 68 | for (bit = 0; bit < slot + 1; bit++) { 69 | int i = bit / PER_BASKET; 70 | int j = bit % PER_BASKET; 71 | arr[slot][i] |= 1 << j; 72 | } 73 | shuffle(slot); 74 | } 75 | } 76 | } 77 | 78 | static int random_prob(lua_State *L) 79 | { 80 | int prob = (int)fmax(1, fmin(BASKET_SIZE, (int)luaL_checknumber(L, 1))) - 1; 81 | int count = rand_value(); 82 | int i = count / PER_BASKET; 83 | int j = count % PER_BASKET; 84 | 85 | assert(prob >= 0 && prob < BASKET_SIZE); 86 | 87 | lua_pushboolean(L, (arr[prob][i] >> j & 0x1) == 1); 88 | 89 | return 1; 90 | } 91 | 92 | static int range_prob_cmp(const void *a, const void *b) 93 | { 94 | return (*(uint32_t *)b & 0xFFFF) - (*(uint32_t *)a & 0xFFFF); 95 | } 96 | 97 | static int random_range_prob(lua_State *L) 98 | { 99 | lua_settop(L, 1); 100 | luaL_checktype(L, 1, LUA_TTABLE); 101 | lua_pushvalue(L, lua_upvalueindex(1)); 102 | lua_pushvalue(L, lua_upvalueindex(2)); 103 | 104 | int length = lua_rawlen(L, 1); 105 | int total = 0; 106 | int idx = 0; 107 | 108 | if (length > BASKET_SIZE) 109 | { 110 | lua_pushfstring(L, "length too larger, expect less than '%d', got '%d'", BASKET_SIZE, length); 111 | lua_error(L); 112 | } 113 | 114 | uint16_t *indexes = (uint16_t *)lua_touserdata(L, 2); 115 | uint32_t *probs = (uint32_t *)lua_touserdata(L, 3); 116 | 117 | int i = 0; 118 | int j = 0; 119 | for (i = 0; i < length; i++) 120 | { 121 | lua_rawgeti(L, 1, i + 1); 122 | probs[i] = (uint16_t)luaL_checknumber(L, -1) | (i + 1) << 16; 123 | total += (probs[i] & 0xFFFF); 124 | lua_pop(L, 1); 125 | } 126 | 127 | if (total == 0) 128 | { 129 | lua_pushstring(L, "all prob is zero!!!!"); 130 | lua_error(L); 131 | } 132 | 133 | qsort(probs, length, sizeof(uint32_t), range_prob_cmp); 134 | 135 | for (i = 0; i < length; i++) 136 | { 137 | int prob = probs[i] & 0xFFFF; 138 | int index = probs[i] >> 16; 139 | int num = (int)((double) prob / total * BASKET_SIZE); 140 | for (j = 0; j < num; j++) 141 | { 142 | indexes[idx++] = index; 143 | } 144 | } 145 | 146 | for (i = 0; idx < BASKET_SIZE; i++) 147 | { 148 | if ((probs[i] & 0xFFFF) > 0) 149 | { 150 | indexes[idx++] = probs[i % length] >> 16; 151 | } 152 | } 153 | 154 | for (i = 0; i < BASKET_SIZE; i += 2) 155 | { 156 | int j = rand_value(); 157 | uint16_t a = indexes[i]; 158 | uint16_t b = indexes[j]; 159 | indexes[i] = b; 160 | indexes[j] = a; 161 | } 162 | 163 | lua_pushinteger(L, indexes[rand_value()]); 164 | 165 | return 1; 166 | } 167 | 168 | LUALIB_API int luaopen_random_core(lua_State *L) 169 | { 170 | lua_newtable(L); 171 | 172 | lua_pushcfunction(L, random_prob); 173 | lua_setfield(L, -2, "prob"); 174 | 175 | lua_newuserdata(L, sizeof(uint16_t) * BASKET_SIZE); // for prob index 176 | lua_newuserdata(L, sizeof(uint32_t) * BASKET_SIZE); // for prob value 177 | lua_pushcclosure(L, random_range_prob, 2); 178 | lua_setfield(L, -2, "range_prob"); 179 | 180 | init_prob(); 181 | 182 | return 1; 183 | } 184 | -------------------------------------------------------------------------------- /lualib/bw/auth/sign.lua: -------------------------------------------------------------------------------- 1 | local md5 = require "md5" 2 | local codec = require "codec" 3 | 4 | local string_format = string.format 5 | local string_upper = string.upper 6 | local table_sort = table.sort 7 | local table_concat = table.concat 8 | 9 | local function encode_uri(s) 10 | s = string.gsub(s, "([^A-Za-z0-9])", function(c) 11 | return string.format("%%%02X", string.byte(c)) 12 | end) 13 | return s 14 | end 15 | 16 | local M = {} 17 | -- mark 参数是否加引号 18 | function M.concat_args(args, mark) 19 | local list = {} 20 | for k, v in pairs(args) do 21 | if v ~= '' then 22 | list[#list+1] = string_format(mark and '%s="%s"' or '%s=%s', k, v) 23 | end 24 | end 25 | assert(#list > 0, "need one arg at least") 26 | table_sort(list, function(a, b) 27 | return a < b 28 | end) 29 | return table_concat(list, "&") 30 | end 31 | 32 | function M.md5_args(args, key, mark) 33 | local str = M.concat_args(args, mark) 34 | if key then 35 | str = str .. "&key=" .. key 36 | end 37 | return string_upper(md5.sumhexa(str)) 38 | end 39 | 40 | function M.rsa_private_sign(args, private_key, mark) 41 | local str = M.concat_args(args, mark) 42 | local bs = codec.rsa_private_sign(str, private_key) 43 | return encode_uri(codec.base64_encode(bs)) 44 | end 45 | --[[ 46 | function M.rsa_public_verify(args, public_key, mark) 47 | local str = M.concat_args(args, mark) 48 | return codec.rsa_public_verify(str, public_key) 49 | end 50 | ]] 51 | return M 52 | -------------------------------------------------------------------------------- /lualib/bw/auth/wx.lua: -------------------------------------------------------------------------------- 1 | -- 微信验证 2 | -- 每个需要用到的服务都需要在启动的时候调wx.init 3 | -- 4 | 5 | local http = require "bw.web.http_helper" 6 | local sha256 = require "bw.auth.sha256" 7 | local json = require "cjson.safe" 8 | 9 | local map = {} -- appid -> access 10 | 11 | local function request_access_token(appid, secret) 12 | assert(appid and secret) 13 | local ret, resp = http.get("https://api.weixin.qq.com/cgi-bin/token", { 14 | grant_type = "client_credential", 15 | appid = appid, 16 | secret = secret, 17 | }) 18 | if ret then 19 | resp = json.decode(resp) 20 | local access = {} 21 | access.token = resp.access_token 22 | access.exires_in = resp.expires_in 23 | access.time = os.time() 24 | map[appid] = access 25 | else 26 | error(resp) 27 | end 28 | end 29 | 30 | local M = {} 31 | function M.get_access_token(appid, secret) 32 | assert(appid and secret) 33 | local access = map[appid] 34 | if not access or os.time() - access.time > access.exires_in then 35 | request_access_token(appid, secret) 36 | return map[appid] 37 | end 38 | return access.token 39 | end 40 | 41 | function M.check_code(appid, secret, js_code) 42 | assert(appid and secret and js_code) 43 | local ret, resp = http.get("https://api.weixin.qq.com/sns/jscode2session",{ 44 | js_code = js_code, 45 | grant_type = "authorization_code", 46 | appid = appid, 47 | secret = secret, 48 | }) 49 | if ret then 50 | return json.decode(resp) 51 | else 52 | error(resp) 53 | end 54 | end 55 | 56 | -- data {score = 100, gold = 300} 57 | function M:set_user_storage(appid, secret, openid, session_key, data) 58 | local kv_list = {} 59 | for k, v in pairs(data) do 60 | table.insert(kv_list, {key = k, value = v}) 61 | end 62 | local post = json.encode({kv_list = kv_list}) 63 | local url = "https://api.weixin.qq.com/wxa/set_user_storage?"..http.url_encoding({ 64 | access_token = M.get_access_token(appid, secret), 65 | openid = openid, 66 | appid = appid, 67 | signature = sha256.hmac_sha256(post, session_key), 68 | sig_method = "hmac_sha256", 69 | }) 70 | local ret, resp = http.post(url, post) 71 | if ret then 72 | return json.decode(resp) 73 | else 74 | error(resp) 75 | end 76 | end 77 | 78 | -- key_list {"score", "gold"} 79 | function M:remove_user_storage(appid, secret, openid, session_key, key_list) 80 | local post = json.encode({key = key_list}) 81 | local url = "https://api.weixin.qq.com/wxa/remove_user_storage?"..http.url_encoding({ 82 | access_token = M.get_access_token(appid, secret), 83 | openid = openid, 84 | appid = appid, 85 | signature = sha256.hmac_sha256(post, session_key), 86 | sig_method = "hmac_sha256", 87 | }) 88 | local ret, resp = http.post(url, post) 89 | if ret then 90 | return json.decode(resp) 91 | else 92 | error(resp) 93 | end 94 | end 95 | 96 | return M 97 | -------------------------------------------------------------------------------- /lualib/bw/bash.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | package.path = "?.lua;" .. package.path 3 | 4 | local _ENV = setmetatable({}, {__index = _ENV}) 5 | 6 | local function io_popen(cmd, mode) 7 | local file = io.popen(cmd) 8 | local ret = file:read(mode or "*a") 9 | file:close() 10 | return ret 11 | end 12 | 13 | function add_lua_search_path(path) 14 | if not string.find(package.path, path, 1, true) then 15 | print("add search path: " .. path) 16 | package.path = path .. "/?.lua;" .. package.path 17 | end 18 | end 19 | 20 | function command(cmd, ...) 21 | local data = io_popen(string.format(cmd, ...)) 22 | return string.match(data, "(.*)[\n\r]+$") or data 23 | end 24 | 25 | function cat(path) 26 | local file = io.open(path) 27 | assert(file, "file not found: " .. path) 28 | local data = file:read("*a") 29 | file:close() 30 | return data 31 | end 32 | 33 | function exist(path) 34 | local file = io.open(path) 35 | if file then 36 | file:close() 37 | end 38 | return file ~= nil 39 | end 40 | 41 | function wcat(path) 42 | return io_popen("lynx -source " .. path) 43 | end 44 | 45 | function echo(path, content) 46 | local file = io.open(path, "w") 47 | file:write(content) 48 | file:flush() 49 | file:close() 50 | end 51 | 52 | local function lookup_local(level, key) 53 | assert(key and #key > 0, key) 54 | for i = 1, 256 do 55 | local k, v = debug.getlocal(level, i) 56 | if k == key then 57 | return v 58 | elseif not k then 59 | break 60 | end 61 | end 62 | 63 | local info1 = debug.getinfo(level, 'S') 64 | local info2 = debug.getinfo(level + 1, 'S') 65 | if info1.source == info2.source or 66 | info1.short_src == info2.short_src then 67 | return lookup_local(level + 1, key) 68 | end 69 | end 70 | 71 | function bash(expr, ...) 72 | if select('#', ...) > 0 then 73 | expr = string.format(expr, ...) 74 | end 75 | local function eval(expr) 76 | return string.gsub(expr, "(${?[%w_]+}?)", function (str) 77 | local key = string.match(str, "[%w_]+") 78 | local value = lookup_local(6, key) or _G[key] 79 | if value == nil then 80 | error("value not found for " .. key) 81 | else 82 | return tostring(value) 83 | end 84 | end) 85 | end 86 | local cmd = eval(expr) 87 | skynet.error(cmd) 88 | local ret = io_popen(cmd) 89 | if ret ~= "" then 90 | ret = string.match(ret, "(.+)\n$") -- 去掉最后一个换行符 91 | --skynet.error(ret) 92 | end 93 | return ret 94 | end 95 | 96 | function remote_bash(user, host, expr, ...) 97 | local cmd = string.format(expr, ...) 98 | if host == "localhost" or host == "127.0.0.1" then 99 | return bash(cmd) 100 | end 101 | return bash('ssh %s@%s "%s"', user, host, cmd) 102 | end 103 | 104 | return _ENV 105 | -------------------------------------------------------------------------------- /lualib/bw/bewater.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | 3 | local M = {} 4 | M.NORET = "NORET" 5 | function M.ret(noret, ...) 6 | if noret ~= M.NORET then 7 | skynet.retpack(noret, ...) 8 | end 9 | end 10 | 11 | local function __TRACEBACK__(errmsg) 12 | local track_text = debug.traceback(tostring(errmsg), 2) 13 | skynet.error("---------------------------------------- TRACKBACK ----------------------------------------") 14 | skynet.error(track_text, "LUA ERROR") 15 | skynet.error("---------------------------------------- TRACKBACK ----------------------------------------") 16 | return false 17 | end 18 | 19 | -- 尝试调一个function, 如果被调用的函数有异常,返回false, 20 | function M.try(func, ...) 21 | return xpcall(func, __TRACEBACK__, ...) 22 | end 23 | 24 | function M.reg_code(env) 25 | local code = require "bw.proto.code" 26 | code.REG(env) 27 | end 28 | 29 | -- 给一个服务注入一段代码 30 | -- return ok, output 31 | function M.inject(addr, source, filename) 32 | return skynet.call(addr, "debug", "RUN", source) 33 | --return skynet.call(addr, "code", source) 34 | --return skynet.call(addr, "debug", "INJECTCODE", source, filename) 35 | --local injectcode = require "skynet.injectcode" 36 | --return injectcode(source) 37 | end 38 | 39 | function M.timeout_call(ti, ...) 40 | local co = coroutine.running() 41 | local ret 42 | 43 | skynet.fork(function(...) 44 | ret = table.pack(pcall(skynet.call, ...)) 45 | if co then 46 | skynet.wakeup(co) 47 | co = nil 48 | end 49 | end, ...) 50 | 51 | skynet.sleep(ti/10) 52 | 53 | if co then 54 | co = nil 55 | skynet.error("call timeout:", ...) 56 | return false 57 | else 58 | if ret[1] then 59 | return table.unpack(ret, 1, ret.n) 60 | else 61 | error(ret[2]) 62 | end 63 | end 64 | end 65 | 66 | function M.locals(f) 67 | f = f or 2 68 | local variables = {} 69 | local idx = 1 70 | while true do 71 | local ln, lv = debug.getlocal(f, idx) 72 | if ln ~= nil then 73 | variables[ln] = lv 74 | else 75 | break 76 | end 77 | idx = 1 + idx 78 | end 79 | return variables 80 | end 81 | 82 | function M.traceback(start_level, max_level) 83 | start_level = start_level or 2 84 | max_level = max_level or 20 85 | 86 | for level = start_level, max_level do 87 | 88 | local info = debug.getinfo( level, "nSl") 89 | if info == nil then break end 90 | print( string.format("[ line : %-4d] %-20s :: %s", 91 | info.currentline, info.name or "", info.source or "" ) ) 92 | 93 | local index = 1 94 | while true do 95 | local name, value = debug.getlocal(level, index) 96 | if name == nil then break end 97 | print( string.format( "\t%s = %s", name, value ) ) 98 | index = index + 1 99 | end 100 | end 101 | end 102 | return M 103 | 104 | -------------------------------------------------------------------------------- /lualib/bw/class.lua: -------------------------------------------------------------------------------- 1 | -- 2 | -- $id: class.lua O $ 3 | -- 4 | 5 | local type = type 6 | local setmetatable = setmetatable 7 | 8 | local trace_count = 0 9 | local tracebacks = setmetatable({}, {__mode = "k"}) 10 | 11 | local function class(classname, super) 12 | local cls = {} 13 | 14 | cls.classname = classname 15 | cls.class = cls 16 | cls.__index = cls 17 | 18 | if super then 19 | -- copy super method 20 | for key, value in pairs(super) do 21 | if type(value) == "function" and key ~= "ctor" then 22 | cls[key] = value 23 | end 24 | end 25 | 26 | cls.super = super 27 | end 28 | 29 | function cls.new(...) 30 | local self = setmetatable({}, cls) 31 | local function create(_cls, ...) 32 | if _cls.super then 33 | create(_cls.super, ...) 34 | end 35 | if _cls.ctor then 36 | _cls.ctor(self, ...) 37 | end 38 | end 39 | create(cls, ...) 40 | 41 | -- debug 42 | trace_count = trace_count + 1 43 | tracebacks[self] = trace_count 44 | 45 | return self 46 | end 47 | 48 | return cls 49 | end 50 | 51 | return class 52 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/debug/inject.lua: -------------------------------------------------------------------------------- 1 | local bewater = require "bw.bewater" 2 | local layui = require "bw.cms.layui" 3 | local util = require "bw.util" 4 | return function(_, data) 5 | print("debug inject!", data.addr, data.code) 6 | local ok, output = bewater.inject(data.addr, data.code) 7 | return {output = output} 8 | end 9 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/skynet/all_service.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local util = require "bw.util" 3 | 4 | local function debug_call(addr, cmd, ...) 5 | return skynet.call(addr, "debug", cmd, ...) 6 | end 7 | return function() 8 | local head = {"地址", "描述", "内存", "任务", "消息队列"} 9 | local list = {} 10 | local all = skynet.call(".launcher", "lua", "LIST") 11 | for addr, desc in pairs(all) do 12 | addr = string.gsub(addr, ':', "0x") 13 | local mem = debug_call(addr, "MEM") 14 | --[[if mem < 1024 then 15 | mem = math.floor(mem).." Kb" 16 | else 17 | mem = math.floor(mem/1024).." Mb" 18 | end]] 19 | local stat = debug_call(addr, "STAT") 20 | --v.address = skynet.address(addr) 21 | table.insert(list, { 22 | addr = addr, 23 | desc = desc, 24 | mem = mem//1, 25 | task = stat.task, 26 | mqlen = stat.mqlen, 27 | }) 28 | end 29 | 30 | return { 31 | list = list 32 | } 33 | end 34 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/skynet/node_info.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local conf = require "conf" 3 | 4 | return function() 5 | local info = require "bw.util.clusterinfo" 6 | local profile = info.profile 7 | return { 8 | list = { 9 | {k="项目", v=conf.desc or "未知"}, 10 | {k="节点", v=conf.clustername or "未知"}, 11 | {k="外网ip", v=info.pnet_addr or "未知"}, 12 | {k="内网ip", v=info.inet_addr or "未知"}, 13 | {k="进程号", v=info.pid or "未知"}, 14 | {k="性能", v=profile and string.format("CPU:%sMEM:%.fM", profile.cpu, profile.mem/1024) or "未知"}, 15 | {k="监听端口", v=conf.gate and string.format("%s:%s", conf.gate.host, conf.gate.port) or "未知"}, 16 | {k="后台地址", v=conf.webconsole and string.format("%s:%s", conf.webconsole.host, conf.webconsole.port) or "未知"}, 17 | {k="mongo", v=conf.mongo and string.format("%s:%s[%s]", conf.mongo.host, conf.mongo.port, conf.mongo.name) or "未知"}, 18 | {k="redis", v= conf.redis and string.format("%s:%s", conf.redis.host, conf.redis.port) or "未知"}, 19 | {k="mysql", v=conf.mysql and string.format("%s:%s[%s]", conf.mysql.host, conf.mysql.port, conf.mysql.name) or "未知"}, 20 | {k="警报", v=(conf.alert and conf.alert.enable) and "已开启" or "未开启"}, 21 | } 22 | } 23 | end 24 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/sys/main.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local date_helper = require "bw.util.date_helper" 3 | local conf = require "conf" 4 | 5 | return function() 6 | local info = require "bw.util.clusterinfo" 7 | local profile = info.profile 8 | return { 9 | online = 0, 10 | run_time = date_helper.format_now(), 11 | list = { 12 | {k="项目", v=conf.desc or "未知"}, 13 | {k="节点", v=conf.clustername or "未知"}, 14 | {k="外网ip", v=info.pnet_addr or "未知"}, 15 | {k="内网ip", v=info.inet_addr or "未知"}, 16 | {k="进程号", v=info.pid or "未知"}, 17 | {k="性能", v=profile and string.format("CPU:%sMEM:%.fM", profile.cpu, profile.mem/1024) or "未知"}, 18 | {k="监听端口", v=conf.gate and string.format("%s:%s", conf.gate.host, conf.gate.port) or "未知"}, 19 | {k="后台地址", v=conf.webconsole and string.format("%s:%s", conf.webconsole.host, conf.webconsole.port) or "未知"}, 20 | {k="mongo", v=conf.mongo and string.format("%s:%s[%s]", conf.mongo.host, conf.mongo.port, conf.mongo.name) or "未知"}, 21 | {k="redis", v= conf.redis and string.format("%s:%s", conf.redis.host, conf.redis.port) or "未知"}, 22 | {k="mysql", v=conf.mysql and string.format("%s:%s[%s]", conf.mysql.host, conf.mysql.port, conf.mysql.name) or "未知"}, 23 | {k="警报", v=(conf.alert and conf.alert.enable) and "已开启" or "未开启"}, 24 | }, 25 | } 26 | end 27 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/user/gm.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local gm = require "bw.gm" 3 | local function ret(output) 4 | local time_str = string.format("[%s] ", os.date("%Y-%m-%d %H:%M:%S")) 5 | return { 6 | output = time_str .. output 7 | } 8 | end 9 | return function(_, data) 10 | local args = {} 11 | for arg in string.gmatch(data.gm, "[^ ]+") do 12 | table.insert(args, arg) 13 | end 14 | local modname = args[1] 15 | local cmd = args[2] 16 | if not modname or not cmd then 17 | return ret("格式错误") 18 | end 19 | table.remove(args, 1) 20 | table.remove(args, 1) 21 | return ret(gm.run(modname, cmd, table.unpack(args))) 22 | end 23 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/user/login.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local util = require "bw.util" 3 | return function(args, data) 4 | return skynet.call("cms", "lua", "req_login", data.account, data.password) 5 | end 6 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/view/gm.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local layui = require "bw.cms.layui" 3 | 4 | local action = layui.action 5 | 6 | return function() 7 | local item_list = { 8 | layui.label("指令", 'layui-form-label')..layui.div(layui.input("", "layui-input", {id = "gm", autocomplete = "on"}), 'layui-input-block'), 9 | layui.label("输出", 'layui-form-label')..layui.div(layui.textarea("", "layui-textarea", {id = "output", style = "height:600px"}), 'layui-input-block'), 10 | layui.div(layui.button("立即运行", nil, {id = "run"})..layui.button("重置", "layui-btn-primary", {id = "reset"}), 'layui-input-block'), 11 | } 12 | local run_action = {action.CLICK, "run", {action.POST, "/cms/user/gm", { 13 | {action.GET_VAL, "gm"}, 14 | }}} 15 | local reset_action = {action.CLICK, "reset", { 16 | {action.SET_VAL, "output", ""}, 17 | }} 18 | return { 19 | content = layui.div(layui.form(item_list), 'layui-col-xs12 layui-col-sm12 layui-col-md11'), 20 | actions = { 21 | run_action, 22 | reset_action, 23 | }, 24 | } 25 | end 26 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/view/inject.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local layui = require "bw.cms.layui" 3 | 4 | local action = layui.action 5 | 6 | return function() 7 | local item_list = { 8 | layui.label("地址", 'layui-form-label')..layui.div(layui.input("", "layui-input", {id = "addr"}), 'layui-input-block'), 9 | layui.label("代码", 'layui-form-label')..layui.div(layui.textarea("", "layui-textarea", {id = "code"}), 'layui-input-block'), 10 | layui.label("输出", 'layui-form-label')..layui.div(layui.textarea("", "layui-textarea", {id = "output"}), 'layui-input-block'), 11 | layui.div(layui.button("立即运行", nil, {id = "run"})..layui.button("重置", nil, {id = "reset"}), 'layui-input-block'), 12 | } 13 | local run_action = {action.CLICK, "run", {action.POST, "/cms/debug/inject", { 14 | {action.GET_VAL, "addr"}, 15 | {action.GET_VAL, "code"}, 16 | }}} 17 | local reset_action = {"reset", action.CLICK, { 18 | {action.SET_VAL, "code", ""}, 19 | {action.SET_VAL, "output", ""}, 20 | }} 21 | return { 22 | content = layui.div(layui.form(item_list), 'layui-col-xs12 layui-col-sm6 layui-col-md6'), 23 | actions = { 24 | run_action, 25 | reset_action, 26 | }, 27 | } 28 | end 29 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/view/main.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local layui = require "bw.cms.layui" 3 | local date_helper = require "bw.util.date_helper" 4 | local node_info = require "bw.cms.api.cms.view.node_info" 5 | 6 | local action = layui.action 7 | 8 | return function() 9 | local html = layui.blockquote("节点信息") 10 | html = html .. node_info().content 11 | 12 | local online = 0 13 | local run_time = date_helper.format_now() 14 | return { 15 | content = html, 16 | actions = { 17 | {action.SET_TEXT, "online", online}, 18 | {action.SET_TEXT, "online", run_time}, 19 | } 20 | } 21 | end 22 | -------------------------------------------------------------------------------- /lualib/bw/cms/api/cms/view/menu.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | 3 | return function () 4 | local menu = skynet.call("cms", "lua", "req_menu") 5 | local top = {} 6 | local navs = {} 7 | for _, v in pairs(menu) do 8 | table.insert(top, v) 9 | navs[v.name] = v.children 10 | end 11 | return { 12 | top = top, 13 | navs = navs, 14 | } 15 | end 16 | -------------------------------------------------------------------------------- /lualib/bw/cms/handler.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local json = require "cjson.safe" 3 | package.path = "../bewater/lualib/bw/cms/api/?.lua;" .. package.path 4 | 5 | local M = { 6 | api = { 7 | ['/cms/user/login'] = {data = {account = "str", password = "str"}, auth = false}, 8 | ['/cms/user/gm'] = {data = {gm = "str"}, auth = true}, 9 | ['/cms/debug/inject'] = {auth = true}, 10 | ['/cms/skynet/node_info'] = {auth = true}, 11 | ['/cms/skynet/all_service'] = {auth = true}, 12 | ['/cms/sys/main'] = {auth = true}, 13 | ['/cms/view/menu'] = {auth = true}, 14 | }, 15 | } 16 | 17 | function M.pack(data) 18 | return json.encode(data) 19 | end 20 | 21 | function M.unpack(data) 22 | return json.decode(data) 23 | end 24 | 25 | function M.auth(authorization) 26 | return skynet.call("cms", "lua", "get_account", authorization) 27 | end 28 | 29 | return M 30 | -------------------------------------------------------------------------------- /lualib/bw/cms/layui.lua: -------------------------------------------------------------------------------- 1 | local const = require "bw.const" 2 | 3 | local layui = {} 4 | layui.action = const { 5 | POST = "POST", -- POST请求:api, ... 6 | ALERT = "ALERT", -- 弹窗:str 7 | CLICK = "CLICK", -- 点击:... 8 | GET_VAL = "GET_VAL", -- 获取值:... 9 | SET_VAL = "SET_VAL", -- 设置值:... 10 | APPEND_VAL = "APPEND_VAL", -- 追加值:... 11 | GET_TEXT = "GET_TEXT", -- 获取值:... 12 | SET_TEXT = "SET_TEXT", -- 获取值:... 13 | OPEN = "OPEN", 14 | } 15 | 16 | local function parse(param) 17 | local str = "" 18 | for k, v in pairs(param or {}) do 19 | if k == "filter" then 20 | k = "lay-filter" 21 | elseif k == "event" then 22 | k = "lay-event" 23 | end 24 | str = str .. k .. '="' .. v .. '"' 25 | end 26 | return str 27 | end 28 | 29 | function layui.div(ctx, class) 30 | return string.format('
%s
', class or "", ctx or "") 31 | end 32 | 33 | function layui.row(ctx, class) 34 | return string.format('
%s
', class or "", ctx or "") 35 | end 36 | 37 | function layui.form(item_list, class, param) 38 | local ctx = "" 39 | for _, item in pairs(item_list) do 40 | ctx = ctx .. '
' .. item .. '
' 41 | end 42 | return string.format('
%s
', class or "", parse(param), ctx or "") 43 | end 44 | 45 | function layui.button(ctx, class, param, submit) 46 | return string.format('', 47 | class or "", parse(param), submit and "lay-submit" or "", ctx or "") 48 | end 49 | 50 | function layui.form_label(ctx, class) 51 | return string.format('', class or "", ctx or "") 52 | end 53 | 54 | function layui.input_block(ctx, class) 55 | return string.format('
%s
', class or "", ctx or "") 56 | end 57 | 58 | function layui.input(ctx, class, param) 59 | return string.format('%s', 60 | class or "", parse(param), ctx or "") 61 | end 62 | 63 | function layui.label(ctx, class, param) 64 | return string.format('', 65 | class or "", parse(param), ctx or "") 66 | end 67 | 68 | function layui.textarea(ctx, class, param) 69 | return string.format('', 70 | class or "", parse(param), ctx or "") 71 | end 72 | 73 | function layui.table(head, tbl, class, colgroup) 74 | local str = "" 75 | if head then 76 | str = str .. "" 77 | for _, v in ipairs(head) do 78 | str = str .. string.format("%s", v) 79 | end 80 | str = str .. "" 81 | end 82 | if colgroup then 83 | str = str .. '' 84 | for _, col in ipairs(colgroup) do 85 | str = str .. '' 86 | end 87 | str = str .. '' 88 | end 89 | str = str .. '' 90 | for _, tr in ipairs(tbl) do 91 | str = str .. "" 92 | for _, td in ipairs(tr) do 93 | str = str .. ""..td.."" 94 | end 95 | str = str .. "" 96 | end 97 | str = str .. '' 98 | return string.format('%s
', class or "mag0", str) 99 | end 100 | 101 | function layui.table_method(id, filter) 102 | return string.format('
', id, filter) 103 | end 104 | 105 | function layui.blockquote(ctx, class, param) 106 | return string.format('
%s
', 107 | class or "title", parse(param), ctx or "") 108 | end 109 | 110 | function layui.a(ctx, class, param) 111 | return string.format('%s', 112 | class or "", parse(param), ctx or "") 113 | end 114 | 115 | function layui.fieldset(ctx, class, param) 116 | return string.format('
%s
', 117 | class or "", parse(param), ctx or "") 118 | end 119 | 120 | return layui 121 | -------------------------------------------------------------------------------- /lualib/bw/cms/server.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local errcode = require "def.errcode" 3 | local uuid = require "bw.uuid" 4 | local log = require "bw.log" 5 | local util = require "bw.util" 6 | 7 | local trace = log.trace("cms") 8 | 9 | local M = {} 10 | local menu = {} 11 | local acc2info = {} 12 | local auth2acc = {} 13 | function M.start(users) 14 | for _, v in pairs(users) do 15 | acc2info[v.account] = v 16 | end 17 | 18 | skynet.register "cms" 19 | end 20 | 21 | function M.set_menu(data) 22 | menu = data 23 | end 24 | 25 | function M.get_account(auth) 26 | return auth2acc[auth] 27 | end 28 | 29 | function M.create_auth(account) 30 | local auth = string.gsub(uuid(), '-', '') 31 | if auth2acc[auth] then 32 | return M.create_auth(account) 33 | end 34 | auth2acc[auth] = account 35 | return auth 36 | end 37 | 38 | function M.req_login(account, password) 39 | trace("req_login, account:%s, password:%s", account, password) 40 | local info = acc2info[account] 41 | if not info then 42 | return errcode.ACC_NOT_EXIST 43 | end 44 | if password ~= info.password then 45 | return errcode.PASSWD_ERROR 46 | end 47 | return { 48 | authorization = M.create_auth(account) 49 | } 50 | end 51 | 52 | function M.req_menu() 53 | return menu 54 | end 55 | return M 56 | -------------------------------------------------------------------------------- /lualib/bw/cms/webconsole.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | 3 | local web 4 | 5 | local M = {} 6 | function M.init(args) 7 | local port = assert(args.port) 8 | local users = assert(args.users) 9 | web = skynet.newservice("web/webserver", "gate", args.server or "bw.cms.server", 10 | args.handler or "bw.cms.handler", port, 10) 11 | skynet.call(web, "lua", "start", users) 12 | 13 | skynet.call(web, "lua", "set_menu", args.menu or { 14 | {name = "skynet", title = "Skynet", icon = "", children = { 15 | {title = "节点信息", icon = "", href = "page/skynet/node_info.html"}, 16 | {title = "所有服务", icon = "", href = "page/skynet/all_service.html"}, 17 | {title = "注入调试", icon = "", href = "page/skynet/inject.html"}, 18 | {title = "GM", icon = "", href = "page/skynet/gm.html"}, 19 | }}, 20 | {name = "user", title = "用户管理", icon = "", children = { 21 | {title = "数据统计", icon = "", href = "page/stat.html", icon = ""}, 22 | {title = "GM", icon = "", href = "page/skynet/gm.html"}, 23 | }}, 24 | {name = "update", title = "更新", icon = "", children = { 25 | {title = "客户端更新", icon = "", href = "page/client_update"}, 26 | {title = "服务端热更", icon = "", href = "page/server_update"}, 27 | }}, 28 | }) 29 | end 30 | 31 | return M 32 | -------------------------------------------------------------------------------- /lualib/bw/const.lua: -------------------------------------------------------------------------------- 1 | local meta = { 2 | __newindex = function(_, k) 3 | error(string.format("readonly:%s", k), 2) 4 | end 5 | } 6 | 7 | local function const(t) 8 | setmetatable(t, meta) 9 | for _, v in pairs(t) do 10 | if type(v) == "table" then 11 | const(v) 12 | end 13 | end 14 | return t 15 | end 16 | return const 17 | -------------------------------------------------------------------------------- /lualib/bw/db/mongo_helper.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local sname = require "bw.sname" 3 | local M = {} 4 | setmetatable(M, {__index = function(t, k) 5 | local v = rawget(t, k) 6 | if v then 7 | return v 8 | else 9 | return function(...) 10 | return skynet.call(sname.MONGO, "lua", k, ...) 11 | end 12 | end 13 | end}) 14 | return M 15 | -------------------------------------------------------------------------------- /lualib/bw/db/mysql_helper.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local sname = require "bw.sname" 3 | local M = {} 4 | setmetatable(M, {__index = function(t, k) 5 | local v = rawget(t, k) 6 | if v then 7 | return v 8 | else 9 | return function(...) 10 | return skynet.call(sname.MYSQL, "lua", k, ...) 11 | end 12 | end 13 | end}) 14 | return M 15 | -------------------------------------------------------------------------------- /lualib/bw/db/redis_helper.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local sname = require "bw.sname" 3 | 4 | local M = {} 5 | setmetatable(M, { 6 | __index = function(t, k) 7 | local v = rawget(t, k) 8 | if v then 9 | return v 10 | else 11 | return function(...) 12 | return skynet.call(sname.REDIS, "lua", k, ...) 13 | end 14 | end 15 | end 16 | }) 17 | 18 | function M.auto_id() 19 | local auto_id = M.get("auto_id") or "10000" 20 | auto_id = tonumber(auto_id)//1 + 1 21 | M.set("auto_id", auto_id) 22 | return auto_id 23 | end 24 | 25 | return M 26 | -------------------------------------------------------------------------------- /lualib/bw/gm.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local sname = require "bw.sname" 3 | 4 | local M = {} 5 | function M.add_gmcmd(modname, gmcmd_path) 6 | skynet.call(sname.GM, "lua", "add_gmcmd", modname, gmcmd_path) 7 | end 8 | 9 | function M.run(...) 10 | return skynet.call(sname.GM, "lua", "run", ...) 11 | end 12 | return M 13 | -------------------------------------------------------------------------------- /lualib/bw/hash_array.lua: -------------------------------------------------------------------------------- 1 | local mt = {} 2 | mt.__index = mt 3 | 4 | function mt:add(obj) 5 | if self._hash[obj] then 6 | return 7 | end 8 | self._array[#self._array + 1] = obj 9 | self._hash[obj] = #self._array 10 | end 11 | 12 | function mt:remove(obj) 13 | local idx = self._hash[obj] 14 | if not idx then 15 | return idx 16 | end 17 | local tail_obj = self._array[#self._array] 18 | self._array[idx] = tail_obj 19 | self._array[#self._array] = nil 20 | self._hash[obj] = nil 21 | self._hash[tail_obj] = idx 22 | end 23 | 24 | function mt:has(obj) 25 | return self._hash[obj] ~= nil 26 | end 27 | 28 | function mt:random_one() 29 | return self._array[math.random(1, #self._array)] 30 | end 31 | 32 | function mt:random_index() 33 | return math.random(1, #self._array) 34 | end 35 | 36 | function mt:index(idx) 37 | return self._array[idx] 38 | end 39 | 40 | function mt:len() 41 | return #self._array 42 | end 43 | 44 | function mt:clear() 45 | self._array = {} 46 | self._hash = {} 47 | end 48 | 49 | local M = {} 50 | function M.new() 51 | local obj = { 52 | _array = {}, 53 | _hash = {}, 54 | } 55 | return setmetatable(obj, mt) 56 | end 57 | return M 58 | -------------------------------------------------------------------------------- /lualib/bw/hotfix.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local sname = require "bw.sname" 3 | 4 | local M = {} 5 | local function new_module(modname) 6 | skynet.cache.clear() 7 | local module = package.loaded[modname] 8 | if module then 9 | package.loaded[modname] = nil 10 | end 11 | local new_mod = require(modname) 12 | package.loaded[modname] = module 13 | return new_mod 14 | end 15 | 16 | local class_prop = { 17 | classname = true, 18 | class = true, 19 | Get = true, 20 | Set = true, 21 | super = true, 22 | __newindex = true, 23 | __index = true, 24 | new = true, 25 | } 26 | 27 | function M.class(modname) 28 | local old_class = require(modname) 29 | local new_class = new_module(modname) 30 | 31 | if old_class.classname and old_class.class then 32 | for k, v in pairs(new_class.class) do 33 | if not class_prop[k] then 34 | old_class[k] = v 35 | end 36 | end 37 | else 38 | for k, v in pairs(new_class) do 39 | old_class[k] = v 40 | end 41 | end 42 | end 43 | 44 | function M.module(modname) 45 | if not package.loaded[modname] then 46 | return require(modname) 47 | end 48 | local old_mod = require(modname) 49 | local new_mod = new_module(modname) 50 | 51 | for k,v in pairs(new_mod) do 52 | if type(v) == "function" then 53 | old_mod[k] = v 54 | end 55 | end 56 | return old_mod 57 | end 58 | 59 | -- 注册热更,由GM服务托管,需要处理hotfix这个消息 60 | function M.reg() 61 | skynet.send(sname.GM, "lua", "reg_hotfix", skynet.self()) 62 | end 63 | 64 | function M.unreg() 65 | skynet.send(sname.GM, "lua", "unreg_hotfix", skynet.self()) 66 | end 67 | 68 | return M 69 | -------------------------------------------------------------------------------- /lualib/bw/ip/blacklist.lua: -------------------------------------------------------------------------------- 1 | local redis = require "bw.db.redis_helper" 2 | 3 | local M = {} 4 | function M.add(ip) 5 | redis.sadd("blacklist", ip) 6 | end 7 | 8 | function M.remove(ip) 9 | redis.srem("blacklist", ip) 10 | end 11 | 12 | function M.check(ip) 13 | return redis.sismember("blacklist", string.match(ip, "([^:]+)")) 14 | end 15 | 16 | function M.list() 17 | return redis.smembers("blacklist") 18 | end 19 | 20 | function M.import(filepath) 21 | local file = io.open(filepath, "r") 22 | while true do 23 | local ip = file:read() 24 | if not ip then 25 | break 26 | end 27 | M.add(ip) 28 | end 29 | file:close() 30 | end 31 | 32 | function M.export(filepath) 33 | local list = M.list() 34 | local file = io.open(filepath, "w+") 35 | for _, ip in ipairs(list) do 36 | file:write(ip.."\n") 37 | end 38 | file:close() 39 | end 40 | 41 | function M.clear() 42 | return redis.del "blacklist" 43 | end 44 | 45 | return M 46 | -------------------------------------------------------------------------------- /lualib/bw/ip/ip_country.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local service = require "skynet.service" 3 | 4 | local addr 5 | skynet.init(function() 6 | addr = service.new("ip_country", function() 7 | local skynet = require "skynet" 8 | local util = require "bw.util" 9 | local http = require "bw.web.http_helper" 10 | local mongo = require "bw.db.mongo_helper" 11 | 12 | local CMD = {} 13 | local ips = {} 14 | local function load_all() 15 | -- todo 改用指针 16 | --[[local cur = mongo.find("ipinfo", {}, {_id = false}) 17 | while cur:hasNext() do 18 | local ret = cur:next() 19 | ips[ret.ip] = ret.country 20 | end 21 | ]] 22 | ips = { 23 | ['127.0.0.1'] = "local", 24 | ['localhost'] = "local", 25 | } 26 | local data = mongo.find("ipinfo", {}, {_id = false}) 27 | for _, v in pairs(data) do 28 | ips[v.ip] = v.country 29 | end 30 | end 31 | 32 | -- 同步调用,有一两秒的延时 33 | function CMD.get_country(ip) 34 | assert(ip) 35 | if ips[ip] then 36 | return ips[ip] 37 | end 38 | local user_agent = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36' 39 | local referer = 'http://www.ip.cn/index.php?ip=http%3A%2F%2F203.179.55.190' 40 | local headers = { 41 | ['User-Agent'] = user_agent, 42 | ['Referer'] = referer 43 | } 44 | local url = string.format('http://www.ip.cn/index.php?ip=%s', ip) 45 | local ret, resp = http.get(url, nil, headers) 46 | if not ret then 47 | skynet.error(string.format("request www.ip.cn error ip:%s", ip)) 48 | end 49 | local str = string.match(resp, "GeoIP:(.+)

") 50 | local country = string.match(str or "", " ([^,]+)$") or "unknown" 51 | if country == "unknown" then 52 | skynet.error("request ip country error, resp:", resp) 53 | end 54 | ips[ip] = country 55 | mongo.insert("ipinfo", {ip = ip, country = country}) 56 | return country 57 | end 58 | 59 | skynet.start(function() 60 | load_all() 61 | skynet.dispatch("lua", function(_, _, cmd, ...) 62 | local f = assert(CMD[cmd], cmd) 63 | util.ret(f(...)) 64 | end) 65 | end) 66 | end) 67 | end) 68 | 69 | local M = {} 70 | function M.is_china(ip) 71 | local country = M.get_country(ip) 72 | return country == "China" or country == "local" 73 | end 74 | function M.get_country(ip) 75 | return skynet.call(addr, "lua", "get_country", ip) 76 | end 77 | return M 78 | -------------------------------------------------------------------------------- /lualib/bw/ip/whitelist.lua: -------------------------------------------------------------------------------- 1 | local redis = require "bw.db.redis_helper" 2 | 3 | local M = {} 4 | function M.add(ip) 5 | redis.sadd("whitelist", ip) 6 | end 7 | 8 | function M.remove(ip) 9 | redis.srem("whitelist", ip) 10 | end 11 | 12 | function M.check(ip) 13 | return redis.sismember("whitelist", string.match(ip, "([^:]+)")) 14 | end 15 | 16 | function M.list() 17 | return redis.smembers("whitelist") 18 | end 19 | 20 | function M.import(filepath) 21 | local file = io.open(filepath, "r") 22 | while true do 23 | local ip = file:read() 24 | if not ip then 25 | break 26 | end 27 | M.add(ip) 28 | end 29 | file:close() 30 | end 31 | 32 | function M.export(filepath) 33 | local list = M.list() 34 | local file = io.open(filepath, "w+") 35 | for _, ip in ipairs(list) do 36 | file:write(ip.."\n") 37 | end 38 | file:close() 39 | end 40 | 41 | function M.clear() 42 | return redis.del "whitelist" 43 | end 44 | 45 | return M 46 | -------------------------------------------------------------------------------- /lualib/bw/lock.lua: -------------------------------------------------------------------------------- 1 | -- 协程锁,在协程挂起时,防止重入 2 | local skynet = require "skynet" 3 | 4 | local mt = {} 5 | mt.__index = mt 6 | 7 | function mt:_lock(co) 8 | assert(self.locked == false) 9 | self.locked = co 10 | self.lock_count = 1 11 | end 12 | 13 | function mt:lock() 14 | local co = coroutine.running() 15 | if self.locked == co then 16 | self.lock_count = self.lock_count + 1 17 | return 18 | end 19 | 20 | if not self.locked then 21 | self:_lock(co) 22 | return 23 | end 24 | table.insert(self.lock_waiter, co) 25 | skynet.wait() 26 | assert(self.locked == co) 27 | end 28 | 29 | function mt:unlock() 30 | local co = coroutine.running() 31 | assert(self.locked == co) 32 | self.lock_count = self.lock_count - 1 33 | if self.lock_count > 0 then 34 | return 35 | end 36 | self.locked = false 37 | self.lock_count = nil 38 | 39 | co = table.remove(self.lock_waiter, 1) 40 | if co then 41 | self:_lock(co) 42 | skynet.wakeup(co) 43 | end 44 | end 45 | 46 | function mt:lock_func(func, ...) 47 | self:lock() 48 | local ret = { xpcall(func, debug.traceback, ...) } 49 | self:unlock() 50 | assert(ret[1], "in lock:" .. tostring(ret[2])) 51 | return table.unpack(ret, 2) 52 | end 53 | 54 | local M = {} 55 | 56 | function M.new() 57 | local obj = { 58 | locked = false, 59 | lock_count = nil, 60 | lock_waiter = {} 61 | } 62 | return setmetatable(obj, mt) 63 | end 64 | 65 | return M 66 | 67 | -------------------------------------------------------------------------------- /lualib/bw/log.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | 3 | local tostring = tostring 4 | local select = select 5 | 6 | local M = {} 7 | function M.trace(sys) 8 | return function(fmt, ...) 9 | skynet.send(".logger", "lua", "trace", skynet.self(), sys, string.format(fmt, ...)) 10 | end 11 | end 12 | 13 | function M.print(sys) 14 | return function(...) 15 | local args = {} 16 | for i = 1, select('#', ...) do 17 | args[i] = tostring(select(i, ...)) 18 | end 19 | local str = table.concat(args, " ") 20 | skynet.send(".logger", "lua", "trace", skynet.self(), sys, str) 21 | end 22 | end 23 | 24 | 25 | function M.player(uid) 26 | return function(fmt, ...) 27 | skynet.send(".logger", "lua", "player", skynet.self(), uid, string.format(fmt, ...)) 28 | end 29 | end 30 | 31 | function M.error(fmt, ...) 32 | skynet.send(".logger", "lua", "error", skynet.self(), string.format(fmt, ...)) 33 | end 34 | 35 | function M.sighup() 36 | skynet.send(".logger", "lua", "register_sighup", skynet.self()) 37 | end 38 | 39 | return M 40 | -------------------------------------------------------------------------------- /lualib/bw/payment/alipay.lua: -------------------------------------------------------------------------------- 1 | local conf = require "conf" 2 | local codec = require "codec" 3 | local sign = require "bw.auth.sign" 4 | 5 | local M = {} 6 | function M.create_order(param) 7 | local order_no = assert(param.order_no) 8 | local private_key = assert(param.private_key) 9 | local item_desc = assert(param.item_desc) 10 | local pay_price = assert(param.pay_price) 11 | local partner = assert(param.partner) 12 | assert(param.uid) 13 | assert(param.item_sn) 14 | assert(param.pay_channel) 15 | assert(param.pay_method) 16 | 17 | local args = { 18 | partner = partner, 19 | seller_id = partner, 20 | out_trade_no = order_no..'-'..os.time(), 21 | subject = item_desc, 22 | body = item_desc, 23 | total_fee = pay_price, 24 | notify_url = string.format("%s/api/payment/alipay_notify", conf.pay.host), 25 | service = "mobile.securitypay.pay", 26 | payment_type = '1', 27 | anti_phishing_key = '', 28 | exter_invoke_ip = '', 29 | _input_charset = 'utf-8', 30 | it_b_pay = '30m', 31 | return_url = 'm.alipay.com', 32 | } 33 | args.sign = sign.rsa_private_sign(args, private_key, true) 34 | args.sign_type = "RSA" 35 | return { 36 | order_no = order_no, 37 | order = sign.concat_args(args, true), 38 | } 39 | end 40 | 41 | function M.notify(public_key, param) 42 | if param.trade_status ~= "TRADE_SUCCESS" then 43 | return 44 | end 45 | local args = {} 46 | for k, v in pairs(param) do 47 | if k ~= "sign" and k ~= "sign_type" then 48 | args[k] = v 49 | end 50 | end 51 | 52 | local src = sign.concat_args(args) 53 | local bs = codec.base64_decode(param.sign) 54 | local pem = public_key 55 | return codec.rsa_public_verify(src, bs, pem, 2) 56 | end 57 | 58 | return M 59 | -------------------------------------------------------------------------------- /lualib/bw/payment/applepay.lua: -------------------------------------------------------------------------------- 1 | local json = require "cjson.safe" 2 | local http = require "bw.web.http_helper" 3 | local log = require "bw.log" 4 | 5 | local trace = log.trace("applepay") 6 | 7 | local M = {} 8 | function M.verify_receipt(receipt, product_id) 9 | local ret, resp_str = http.post("https://buy.itunes.apple.com/verifyReceipt", receipt) 10 | local resp = json.decode(resp_str) 11 | if not ret then 12 | log.error("verify_receipt error, post:buy, product_id:%s, receipt:%s", 13 | product_id, receipt) 14 | return 15 | end 16 | if resp.status ~= 0 then 17 | trace("try sandbox") 18 | ret, resp_str = http.post("https://sandbox.itunes.apple.com/verifyReceipt", receipt) 19 | resp = json.decode(resp_str) 20 | end 21 | if not ret or not resp or resp.status ~= 0 then 22 | log.error("verify_receipt error, ret:%s, resp:%s", ret, resp_str) 23 | return 24 | end 25 | if not product_id then 26 | return resp.receipt.in_app[1].original_transaction_id 27 | end 28 | for i, v in pairs(resp.receipt.in_app) do 29 | if v.product_id == product_id then 30 | return v.original_transaction_id 31 | end 32 | end 33 | log.error("verify_receipt error, product_id is wrong, product_id:%s, ret:%s, resp_str:%s", 34 | product_id, ret, resp_str) 35 | end 36 | return M 37 | 38 | -------------------------------------------------------------------------------- /lualib/bw/payment/wxpay.lua: -------------------------------------------------------------------------------- 1 | local sign = require "bw.auth.sign" 2 | local lua2xml = require "bw.xml.lua2xml" 3 | local xml2lua = require "bw.xml.xml2lua" 4 | local http = require "bw.web.http_helper" 5 | local util = require "bw.util" 6 | local log = require "bw.log" 7 | local conf = require "conf" 8 | local def = require "def" 9 | local errcode = require "def.errcode" 10 | local trace = log.trace("wxpay") 11 | 12 | local M = {} 13 | function M.create_order(param) 14 | local order_no = assert(param.order_no) 15 | local uid = assert(param.uid) 16 | local appid = assert(param.appid) 17 | local mch_id = assert(param.mch_id) 18 | local key = assert(param.key) 19 | local item_desc = assert(param.item_desc) 20 | local pay_method = assert(param.pay_method) 21 | local pay_price = assert(param.pay_price) 22 | assert(param.pay_channel) 23 | assert(param.item_sn) 24 | 25 | local args = { 26 | appid = appid, 27 | mch_id = mch_id, 28 | nonce_str = math.random(10000)..uid, 29 | trade_type = pay_method == "wxpay" and "APP" or "NATIVE", 30 | body = item_desc, 31 | out_trade_no = order_no..'-'..os.time(), 32 | total_fee = pay_price*100//1 >> 0, 33 | spbill_create_ip= '127.0.0.1', 34 | notify_url = string.format("%s:%s/api/payment/wxpay_notify", conf.pay.host, conf.pay.port), 35 | } 36 | args.sign = sign.md5_args(args, key) 37 | local xml = lua2xml.encode("xml", args, true) 38 | local _, resp = http.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xml) 39 | local data = xml2lua.decode(resp).xml 40 | 41 | if data.return_code ~= "SUCCESS" and data.return_msg ~= "OK" then 42 | return errcode.WXORDER_FAIL 43 | end 44 | 45 | local ret 46 | if data.trade_type == "APP" then 47 | ret = { 48 | appid = appid, 49 | partnerid = mch_id, 50 | noncestr = data.nonce_str, 51 | package = 'sign=WXPay', 52 | prepayid = data.prepay_id, 53 | timestamp = os.time(), 54 | } 55 | ret.sign = sign.md5_args(ret, key) 56 | else 57 | ret = { 58 | code_url = data.code_url 59 | } 60 | end 61 | ret.order_no = order_no 62 | return ret 63 | end 64 | 65 | local WX_OK = { 66 | return_code = "SUCCESS", 67 | return_msg = "OK", 68 | } 69 | 70 | local WX_FAIL = { 71 | return_code = "FAIL", 72 | return_msg = "FAIL", 73 | } 74 | 75 | function M.notify(order, key, param) 76 | if order.item_state == def.PayState.SUCCESS then 77 | return WX_OK 78 | end 79 | local args = {} 80 | for k, v in pairs(param) do 81 | if k ~= "sign" then 82 | args[k] = v 83 | end 84 | end 85 | 86 | local sign1 = sign.md5_args(args, key) 87 | local sign2 = param.sign 88 | if sign1 ~= sign2 then 89 | return WX_FAIL 90 | end 91 | 92 | if param.result_code ~= "SUCCESS" or param.return_code ~= "SUCCESS" then 93 | trace("wxpay fail %s", util.dump(param)) 94 | else 95 | order.pay_time = os.time() 96 | order.tid = param.transaction_id 97 | end 98 | return WX_OK 99 | end 100 | return M 101 | -------------------------------------------------------------------------------- /lualib/bw/prop.lua: -------------------------------------------------------------------------------- 1 | local conf = require "conf" 2 | local json = require "cjson" 3 | local const = require "bw.const" 4 | local util = require "bw.util" 5 | 6 | local M = {} 7 | local props = {} 8 | function M.json(name) 9 | assert(name) 10 | if props[name] then 11 | return props[name] 12 | end 13 | local file = io.open(conf.workspace.."/script/def/prop/"..name..".json", "r") 14 | local str = file:read("*a") 15 | local prop = const(util.str2num(json.decode(str))) 16 | props[name] = prop 17 | return prop 18 | end 19 | 20 | return M 21 | -------------------------------------------------------------------------------- /lualib/bw/proto/code.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local env = nil 3 | local function run(source) 4 | local f, err = load(source, "@inject", "bt", env) 5 | if not f then 6 | print(err) 7 | return false 8 | end 9 | 10 | local r, err = xpcall(f, debug.traceback) 11 | if not r then 12 | print(err) 13 | end 14 | return r 15 | end 16 | 17 | local function _code_dispatch(_, addr, source) 18 | skynet.error('on run', addr) 19 | local injectcode = require "skynet.injectcode" 20 | return skynet.retpack(injectcode(source, nil, 1)) 21 | --return skynet.retpack(run(source)) 22 | end 23 | 24 | local M = {} 25 | function M.REG(_env) 26 | local REG = skynet.register_protocol 27 | REG { 28 | name = 'code', 29 | id = 12, 30 | unpack = skynet.unpack, 31 | pack = skynet.pack, 32 | dispatch = _code_dispatch, 33 | } 34 | env = _env 35 | 36 | end 37 | 38 | return M 39 | -------------------------------------------------------------------------------- /lualib/bw/random.lua: -------------------------------------------------------------------------------- 1 | local random = require "random.core" 2 | 3 | local M = {} 4 | local table_insert = table.insert 5 | local table_remove = table.remove 6 | 7 | function M.prob(value) 8 | return random.prob(value * 10) 9 | end 10 | 11 | --从数组中选出不重复的数,len为数组大小,num为选出数量, 12 | --返回数组索引 13 | function M.random_unrepeat(len, num) 14 | local arr = {} 15 | for i=1,len do 16 | table_insert(arr, i) 17 | end 18 | 19 | local ret = {} 20 | for i=1, num do 21 | len = #arr 22 | if len <= 0 then 23 | return ret 24 | end 25 | 26 | math.random(len) 27 | math.random(len) 28 | local idx = math.random(len) 29 | table_insert(ret, arr[idx]) 30 | table_remove(arr,idx) 31 | 32 | end 33 | 34 | return ret 35 | end 36 | 37 | --根据随机表,返回随机到的物品属性 38 | --基础随机函数,对应函数表格式: tbl = { { resultA, chanceA }, { resultB, chanceB }, ... } 39 | function M.random_item_attr(tbl) 40 | local t = {} 41 | for _, v in ipairs(tbl) do 42 | assert(v[1]) 43 | table.insert(t, v[2]) 44 | end 45 | --return tbl[1][1] 46 | local idx = random.range_prob(t) 47 | assert(tbl[idx], string.format("tbl len:%s, idx:%d", table.concat(t, ','), idx)) 48 | return tbl[idx][1] 49 | end 50 | 51 | -- 一维表随机函数 52 | -- tbl = { chanceA, chanceB, ... } 53 | function M.random_item_attr_1d( tbl ) 54 | return random.range_prob(tbl) 55 | end 56 | 57 | return M 58 | -------------------------------------------------------------------------------- /lualib/bw/schedule.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local service = require "skynet.service" 3 | 4 | local schedule = {} 5 | local service_addr 6 | 7 | -- { month=, day=, wday=, hour= , min= } 8 | function schedule.submit(ti) 9 | assert(ti) 10 | return skynet.call(service_addr, "lua", ti) 11 | end 12 | 13 | function schedule.changetime(ti) 14 | local tmp = {} 15 | for k,v in pairs(ti) do 16 | tmp[k] = v 17 | end 18 | tmp.changetime = true 19 | return skynet.call(service_addr, "lua", tmp) 20 | end 21 | 22 | -- curtime 23 | function schedule.time() 24 | local difftime = skynet.call(service_addr, "lua") 25 | return skynet.time() + difftime 26 | end 27 | 28 | skynet.init(function() 29 | local schedule_service = function() 30 | -- schedule service 31 | 32 | local skynet = require "skynet" 33 | 34 | local task = { session = 0, difftime = 0 } 35 | 36 | local function next_time(now, ti) 37 | local nt = { 38 | year = now.year , 39 | month = now.month , 40 | day = now.day, 41 | hour = ti.hour or 0, 42 | min = ti.min or 0, 43 | sec = ti.sec or 0, 44 | } 45 | if ti.wday then 46 | -- set week 47 | assert(ti.day == nil and ti.month == nil) 48 | nt.day = nt.day + ti.wday - now.wday 49 | local t = os.time(nt) 50 | if t < now.time then 51 | nt.day = nt.day + 7 52 | end 53 | else 54 | -- set day, no week day 55 | if ti.day then 56 | nt.day = ti.day 57 | end 58 | if ti.month then 59 | nt.month = ti.month 60 | end 61 | local t = os.time(nt) 62 | if t < now.time then 63 | if ti.month then 64 | nt.year = nt.year + 1 -- next year 65 | elseif ti.day then 66 | nt.month = nt.month + 1 -- next month 67 | else 68 | nt.day = nt.day + 1 -- next day 69 | end 70 | end 71 | end 72 | 73 | return os.time(nt) 74 | end 75 | 76 | local function changetime(ti) 77 | local ct = math.floor(skynet.time()) 78 | local current = os.date("*t", ct) 79 | current.time = ct 80 | ti.hour = ti.hour or current.hour 81 | ti.min = ti.min or current.min 82 | ti.sec = ti.sec or current.sec 83 | local nt = next_time(current, ti) 84 | skynet.error(string.format("Change time to %s", os.date(nil, nt))) 85 | task.difftime = os.difftime(nt,ct) 86 | for k,v in pairs(task) do 87 | if type(v) == "table" then 88 | skynet.wakeup(v.co) 89 | end 90 | end 91 | skynet.ret(skynet.pack(nt)) 92 | end 93 | 94 | local function submit(_, addr, ti) 95 | if not ti then 96 | return skynet.ret(skynet.pack(task.difftime)) 97 | end 98 | if ti.changetime then 99 | return changetime(ti) 100 | end 101 | local session = task.session + 1 102 | task.session = session 103 | repeat 104 | local ct = math.floor(skynet.time()) + task.difftime 105 | local current = os.date("*t", ct) 106 | current.time = ct 107 | local nt = next_time(current, ti) 108 | task[session] = { time = nt, co = coroutine.running(), address = addr } 109 | local diff = os.difftime(nt , ct) 110 | --print("sleep", diff) 111 | until skynet.sleep(diff * 100) ~= "BREAK" 112 | task[session] = nil 113 | skynet.ret() 114 | end 115 | 116 | skynet.start(function() 117 | skynet.dispatch("lua", submit) 118 | skynet.info_func(function() 119 | local info = {} 120 | for k, v in pairs(task) do 121 | if type(v) == "table" then 122 | table.insert( info, { 123 | time = os.date(nil, v.time), 124 | address = skynet.address(v.address), 125 | }) 126 | return info 127 | end 128 | end 129 | end) 130 | end) 131 | 132 | -- end of schedule service 133 | end 134 | 135 | service_addr = service.new("schedule", schedule_service) 136 | end) 137 | 138 | return schedule 139 | -------------------------------------------------------------------------------- /lualib/bw/share/autoid.lua: -------------------------------------------------------------------------------- 1 | local cluster = require "skynet.cluster" 2 | 3 | local M = {} 4 | function M.create(count) 5 | return cluster.call("share", "autoid", "create", count) 6 | end 7 | return M 8 | -------------------------------------------------------------------------------- /lualib/bw/share/init.lua: -------------------------------------------------------------------------------- 1 | -- 向share节点上报集群配置 2 | local cluster = require "skynet.cluster" 3 | local conf = require "conf" 4 | 5 | local M = {} 6 | function M.init() 7 | local name = conf.clustername 8 | local addr = conf.cluster[name] 9 | cluster.call("share", "svr", "node_start", name, addr) -- 向share上报集群配置 10 | end 11 | return M 12 | 13 | -------------------------------------------------------------------------------- /lualib/bw/share/operate.lua: -------------------------------------------------------------------------------- 1 | local cluster = require "skynet.cluster" 2 | 3 | local M = {} 4 | setmetatable(M, {__index = function(t, k) 5 | local v = rawget(t, k) 6 | if v then 7 | return v 8 | else 9 | return function(...) 10 | return cluster.call("share", "operate", k, ...) 11 | end 12 | end 13 | end}) 14 | return M 15 | -------------------------------------------------------------------------------- /lualib/bw/share/passport.lua: -------------------------------------------------------------------------------- 1 | local cluster = require "skynet.cluster" 2 | 3 | local M = {} 4 | setmetatable(M, {__index = function(t, k) 5 | local v = rawget(t, k) 6 | if v then 7 | return v 8 | else 9 | return function(...) 10 | return cluster.call("share", "passport", k, ...) 11 | end 12 | end 13 | end}) 14 | return M 15 | -------------------------------------------------------------------------------- /lualib/bw/sname.lua: -------------------------------------------------------------------------------- 1 | -- 一些通用服务名, 第一次引用的自动创建 2 | local skynet = require "skynet.manager" 3 | local reg = { 4 | WEB = "web/webclient", 5 | PROTO = "proto_env", 6 | REDIS = "db/redisd", 7 | MONGO = "db/mongod", 8 | MYSQL = "db/mysqld", 9 | ALERT = "alert", -- 警报服务 10 | REPORT = "report", -- 自动向monitor发送报告 11 | STDOUT = "stdout", 12 | GM = "gm", 13 | } 14 | 15 | local M = {} 16 | setmetatable(M, { 17 | __index = function (_, k) 18 | local name = assert(reg[k], string.format("sname %s not exist", k)) 19 | return skynet.uniqueservice(name) 20 | end, 21 | __newindex = function () 22 | assert("cannot overwrite sname") 23 | end 24 | }) 25 | 26 | return M 27 | -------------------------------------------------------------------------------- /lualib/bw/sock/network_t.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local socket = require "skynet.socket" 3 | local md5 = require "md5" 4 | local class = require "bw.class" 5 | local packet = require "bw.sock.packet" 6 | local bewater = require "bw.bewater" 7 | local protobuf = require "bw.protobuf" 8 | local def = require "def" 9 | local opcode = require "def.opcode" 10 | local errcode = require "def.errcode" 11 | --local util = require "bw.util" 12 | 13 | local M = class("network_t") 14 | function M:ctor(player) 15 | self.player = assert(player, "network need player") 16 | end 17 | 18 | function M:init(watchdog, gate, agent, fd, ip) 19 | self._watchdog = assert(watchdog) 20 | self._gate = assert(gate) 21 | self._agent = assert(agent) 22 | self._fd = assert(fd) 23 | self._ip = assert(ip) 24 | self._csn = 0 25 | self._ssn = 0 26 | self._crypt_key = 0 27 | self._crypt_type = 0 28 | self._token = nil 29 | self._ping_time = skynet.time() 30 | end 31 | 32 | function M:check_timeout() 33 | if skynet.time() - self._ping_time > def.PING_TIMEOUT and self._fd then 34 | self:close() 35 | end 36 | end 37 | 38 | function M:create_token() 39 | self._token = md5.crypt(string.format("%d%d", self.player.uid, os.time()), "Stupid") 40 | return self._token 41 | end 42 | 43 | function M:call_watchdog(...) 44 | return skynet.call(self._watchdog, "lua", ...) 45 | end 46 | 47 | function M:call_gate(...) 48 | return skynet.call(self._gate, "lua", ...) 49 | end 50 | 51 | function M:call_agent(...) 52 | return skynet.call(self._agent, "lua", ...) 53 | end 54 | 55 | function M:send(op, tbl, csn) 56 | if opcode.has_session(op) then 57 | self._ssn = self._ssn + 1 58 | end 59 | local data, len 60 | protobuf.encode(opcode.toname(op), tbl or {}, function(buffer, bufferlen) 61 | data, len = packet.pack(op, csn or 0, self._ssn, 62 | self._crypt_type, self._crypt_key, buffer, bufferlen) 63 | end) 64 | socket.write(self._fd, data, len) 65 | end 66 | 67 | function M:recv(op, csn, ssn, crypt_type, crypt_key, buff, sz) 68 | self._ping_time = skynet.time() 69 | 70 | local opname = opcode.toname(op) 71 | local modulename = opcode.tomodule(op) 72 | local simplename = opcode.tosimplename(op) 73 | if opcode.has_session(op) then 74 | skynet.error(string.format("recv package, 0x%x %s, csn:%d, ssn:%d, crypt_type:%s, crypt_key:%s, sz:%d", 75 | op, opname, csn, ssn, crypt_type, crypt_key, sz)) 76 | end 77 | 78 | local data = protobuf.decode(opname, buff, sz) 79 | assert(type(data) == "table", data) 80 | --util.printdump(data) 81 | 82 | local ret = 0 -- 返回整数为错误码,table为返回客户端数据 83 | local mod = assert(self.player[modulename], modulename) 84 | local f = assert(mod[simplename], simplename) 85 | if not bewater.try(function() 86 | ret = f(mod, data) or 0 87 | end) then 88 | ret = errcode.TRACEBACK 89 | end 90 | if type(ret) == "table" then 91 | ret.err = ret.err or 0 92 | else 93 | ret = {err = ret} 94 | end 95 | self:send(op+1, ret, csn) 96 | end 97 | 98 | function M:close() 99 | skynet.call(self._gate, "lua", "kick", self._fd) 100 | end 101 | 102 | -- fd, csn, ssn, passport 103 | function M:reconnect(fd, _, _, _, user_info) 104 | self.player.log("reconnect") 105 | self:send(opcode.user.s2c_kickout) 106 | self:close() 107 | self._fd = fd 108 | --self.player:online() 109 | self.player.cache_time = nil 110 | self.player.is_online = true 111 | self.player.user:init_by_data(user_info) 112 | self:call_watchdog("player_online", self:get_agent(), self.player.uid, fd) 113 | self.player:sync_all() 114 | return true 115 | end 116 | 117 | function M:get_fd() 118 | return self._fd 119 | end 120 | 121 | function M:get_csn() 122 | return self._csn 123 | end 124 | 125 | function M:get_ssn() 126 | return self._ssn 127 | end 128 | 129 | function M:get_agent() 130 | return self._agent 131 | end 132 | 133 | function M:get_ip() 134 | return self._ip 135 | end 136 | 137 | return M 138 | -------------------------------------------------------------------------------- /lualib/bw/sock/packet.lua: -------------------------------------------------------------------------------- 1 | local core = require "packet.core" 2 | 3 | -- op 协议号 4 | -- csn 客户端session 5 | -- ssn 服务器session 6 | -- crypt_type 加密类型 7 | -- crypt_key 加密key sn 8 | -- buff sz 要发送的数据和长度 9 | -- sock_buff sock_sz 缓冲区的数据和长度 10 | 11 | local HEADER_SIZE = 8 12 | 13 | local M = {} 14 | function M.pack(opcode, csn, ssn, crypt_type, crypt_key, buff, sz) 15 | local total = sz + HEADER_SIZE 16 | local data = core.new(total + 2) 17 | data:write_ushort(total) 18 | data:write_ushort(opcode) 19 | data:write_ushort(csn) 20 | data:write_ushort(ssn) 21 | data:write_ubyte(crypt_type) 22 | data:write_ubyte(crypt_key) 23 | data:write_bytes(buff, sz) 24 | return data:pack() -- sock_buff, sock_sz 25 | end 26 | function M.unpack(sock_buff, sock_sz) 27 | assert(type(sock_buff) == "userdata") 28 | assert(type(sock_sz) == "number") 29 | local data = core.new(sock_buff, sock_sz) 30 | --local total = data:read_ushort() -- skynet抠掉了这2个字节 31 | local opcode = data:read_ushort() 32 | local csn = data:read_ushort() 33 | local ssn = data:read_ushort() 34 | local crypt_type= data:read_ubyte() 35 | local crypt_key = data:read_ubyte() 36 | local sz = sock_sz - HEADER_SIZE 37 | local buff = data:read_bytes(sz) 38 | return opcode, csn, ssn, crypt_type, crypt_key, buff, sz 39 | end 40 | return M 41 | -------------------------------------------------------------------------------- /lualib/bw/sock/robot_t.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local socket = require "skynet.socket" 3 | local packet = require "bw.sock.packet" 4 | local protobuf = require "bw.protobuf" 5 | local class = require "bw.class" 6 | local bewater = require "bw.bewater" 7 | local opcode = require "def.opcode" 8 | local errcode = require "def.errcode" 9 | local packetc = require "packet.core" 10 | 11 | local coroutine = require "skynet.coroutine" 12 | 13 | local M = class("robot_t") 14 | function M:ctor(proj) 15 | self._proj = proj 16 | self._host = nil 17 | self._port = nil 18 | self._fd = nil 19 | self._csn = 0 -- client session 20 | self._ssn = 0 -- server session 21 | self._crypt_type = 0 22 | self._crypt_key = 0 23 | 24 | self._call_requests = {} -- op -> co 25 | self._waiting = {} -- co -> time 26 | self._cache = "" 27 | end 28 | 29 | function M:start(host, port) 30 | self._host = assert(host) 31 | self._port = assert(port) 32 | self._fd = socket.open(self._host, self._port) 33 | assert(self._fd) 34 | 35 | skynet.fork(function() 36 | while true do 37 | local buff = socket.read(self._fd) 38 | if not buff then 39 | self:offline() 40 | return 41 | end 42 | self._cache = self._cache .. buff 43 | while true do 44 | local cache = self._cache 45 | if self._cache == "" then 46 | break 47 | end 48 | local sz = string.unpack(">H", cache) 49 | if #cache < sz then 50 | break 51 | end 52 | buff = string.sub(cache, 3, 2 + sz) 53 | self._cache = string.sub(cache, 3 + sz, -1) 54 | self:_recv(buff) 55 | end 56 | 57 | end 58 | end) 59 | 60 | -- ping 61 | skynet.fork(function() 62 | while true do 63 | self:ping() 64 | skynet.sleep(100*30) 65 | end 66 | end) 67 | 68 | -- tick 69 | self.tick = 0 70 | skynet.fork(function() 71 | while true do 72 | self.tick = self.tick + 1 73 | skynet.sleep(1) 74 | for co, time in pairs(self._waiting) do 75 | if time <= 0 then 76 | self:_suspended(co) 77 | else 78 | self._waiting[co] = time - 1 79 | end 80 | end 81 | end 82 | end) 83 | end 84 | 85 | function M:test(func) 86 | local co = coroutine.create(function() 87 | bewater.try(func) 88 | end) 89 | self:_suspended(co) 90 | end 91 | 92 | function M:call(op, data) 93 | self:send(op, data) 94 | local ret = coroutine.yield(op) 95 | local code = ret and ret.err 96 | if code ~= 0 then 97 | skynet.error(string.format("call %s error:0x%x, desc:%s", 98 | opcode.toname(op), code, errcode.describe(code))) 99 | end 100 | return ret 101 | end 102 | 103 | function M:wait(time) 104 | return coroutine.yield(nil, time) 105 | end 106 | 107 | function M:send(op, tbl) 108 | self._csn = self._csn + 1 109 | 110 | local data, len 111 | protobuf.encode(opcode.toname(op), tbl or {}, function(buffer, bufferlen) 112 | data, len = packet.pack(op, self._csn, self._ssn, 113 | self._crypt_type, self._crypt_key, buffer, bufferlen) 114 | end) 115 | 116 | print(string.format("send %s, csn:%d, sz:%s", opcode.toname(op), self._csn, len)) 117 | socket.write(self._fd, data, len) 118 | end 119 | 120 | function M:ping() 121 | -- overwrite 122 | end 123 | 124 | function M:offline() 125 | -- overwrite 126 | end 127 | 128 | 129 | function M:_recv(sock_buff) 130 | local data = packetc.new(sock_buff) 131 | --local total = data:read_ushort() 132 | local op = data:read_ushort() 133 | local csn = data:read_ushort() 134 | local ssn = data:read_ushort() 135 | data:read_ubyte() -- crypt_type 136 | data:read_ubyte() -- crypt_key 137 | local sz = #sock_buff - 8 138 | local buff = data:read_bytes(sz) 139 | --local op, csn, ssn, crypt_type, crypt_key, buff, sz = packet.unpack(sock_buff) 140 | self._ssn = ssn 141 | 142 | local opname = opcode.toname(op) 143 | local modulename = opcode.tomodule(op) 144 | local simplename = opcode.tosimplename(op) 145 | local funcname = modulename .. "_" .. simplename 146 | 147 | data = protobuf.decode(opname, buff, sz) 148 | if self[funcname] then 149 | self[funcname](self, data) 150 | end 151 | 152 | local co = self._call_requests[op - 1] 153 | 154 | print(string.format("recv %s, csn:%d ssn:%d co:%s", opname, csn, ssn, co)) 155 | 156 | self._call_requests[op - 1] = nil 157 | if co and coroutine.status(co) == "suspended" then 158 | self:_suspended(co, op, data) 159 | end 160 | end 161 | 162 | function M:_suspended(co, _op, ...) 163 | assert(_op == nil or _op >= 0) 164 | local _, op, wait = coroutine.resume(co, ...) 165 | if coroutine.status(co) == "suspended" then 166 | if op then 167 | self._call_requests[op] = co 168 | end 169 | if wait then 170 | self._waiting[co] = wait 171 | end 172 | end 173 | end 174 | 175 | return M 176 | -------------------------------------------------------------------------------- /lualib/bw/timer.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local bewater = require "bw.bewater" 3 | 4 | local M = {} 5 | function M:ctor() 6 | self._top = nil 7 | self._cancel = nil 8 | end 9 | 10 | function M:destroy() 11 | if self._cancel then 12 | self._cancel() 13 | end 14 | self._top = nil 15 | self._cancel = nil 16 | end 17 | 18 | function M:cancelable_timeout(delta, func) 19 | if delta <= 0 then 20 | func() 21 | return 22 | end 23 | local function cb() 24 | if func then 25 | func() 26 | end 27 | end 28 | local function cancel() 29 | func = nil 30 | end 31 | skynet.timeout(delta*100//1, cb) 32 | return cancel 33 | end 34 | 35 | function M:start() 36 | assert(self._top) 37 | self._cancel = self:cancelable_timeout(self._top.ti - skynet.time(), function() 38 | bewater.try(function() 39 | self._top.cb() 40 | end) 41 | self:next() 42 | end) 43 | end 44 | 45 | function M:cancel() 46 | self._cancel() 47 | end 48 | 49 | function M:next() 50 | --print("next") 51 | self._top = self._top.next 52 | if self._top then 53 | self:start() 54 | end 55 | --self:dump() 56 | end 57 | 58 | function M:delay(expire, cb) 59 | assert(type(expire) == "number") 60 | assert(type(cb) == "function") 61 | 62 | local node = { 63 | ti = skynet.time() + expire, 64 | cb = cb, 65 | } 66 | 67 | if not self._top then 68 | self._top = node 69 | self:start() 70 | else 71 | if node.ti < self._top.ti then 72 | node.next = self._top 73 | self._top = node 74 | self:cancel() 75 | self:start() 76 | else 77 | local cur = self._top 78 | local prev 79 | while cur do 80 | if prev and prev.ti <= node.ti and cur.ti > node.ti then 81 | if prev then 82 | prev.next = node 83 | end 84 | node.next = cur 85 | return 86 | end 87 | prev = cur 88 | cur = cur.next 89 | end 90 | prev.next = node 91 | end 92 | end 93 | end 94 | 95 | function M:dump() 96 | local str = "" 97 | local cur = self._top 98 | while cur do 99 | str = str .. "," .. cur.ti 100 | cur = cur.next 101 | end 102 | --print("timer:"..str) 103 | end 104 | 105 | local timer = {} 106 | function timer.create() 107 | return setmetatable({}, {__index = M}) 108 | end 109 | return timer 110 | 111 | -------------------------------------------------------------------------------- /lualib/bw/util/activity_helper.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local schedule = require "bw.schedule" 3 | 4 | local M = {} 5 | -- t:{month=, day=, wday=, hour= , min=} wday 6 | function M.schedule(t, cb) 7 | assert(type(t) == "table") 8 | assert(cb) 9 | skynet.fork(function() 10 | while true do 11 | schedule.submit(t) 12 | cb() 13 | skynet.sleep(100) 14 | end 15 | end) 16 | end 17 | return M 18 | -------------------------------------------------------------------------------- /lualib/bw/util/clusterinfo.lua: -------------------------------------------------------------------------------- 1 | -- 集群节点相关信息 2 | -- 访问方式 clusterinfo.xxx or clusterinfo.get_xxx() 3 | -- 4 | local skynet = require "skynet" 5 | local http = require "bw.web.http_helper" 6 | local util = require "bw.util" 7 | local conf = require "conf" 8 | local bash = require "bw.bash" 9 | 10 | local M = {} 11 | local _cache = {} 12 | setmetatable(M, { 13 | __index = function (t, k) 14 | local v = rawget(t, k) 15 | if v then 16 | return v 17 | end 18 | local f = rawget(t, '_'..k) 19 | if f then 20 | v = _cache[k] or f() 21 | _cache[k] = v 22 | return v 23 | end 24 | f = rawget(t, 'get_'..k) 25 | assert(f, "no clusterinfo "..k) 26 | return f() 27 | end 28 | }) 29 | 30 | -- 公网ip 31 | function M._pnet_addr() 32 | if conf.remote_host then 33 | if conf.remote_port then 34 | return conf.remote_host .. ":" .. conf.remote_port 35 | else 36 | return conf.remote_host 37 | end 38 | end 39 | if conf.host then 40 | if conf.port then 41 | return conf.host .. ":" .. conf.port 42 | else 43 | return conf.host 44 | end 45 | end 46 | local _, resp = http.get('http://members.3322.org/dyndns/getip') 47 | local addr = string.gsub(resp, "\n", "") 48 | return addr 49 | end 50 | 51 | -- 内网ip 52 | function M.get_inet_addr() 53 | local ret = bash.bash "ifconfig eth0" 54 | return string.match(ret, "inet addr:([^%s]+)") or string.match(ret, "inet ([^%s]+)") 55 | end 56 | 57 | function M.get_run_time() 58 | return skynet.time() 59 | end 60 | 61 | -- 进程pid 62 | function M._pid() 63 | local filename = skynet.getenv "daemon" 64 | if not filename then 65 | return 66 | end 67 | local pid = bash.bash("cat %s", filename) 68 | return string.gsub(pid, "\n", "") 69 | end 70 | 71 | function M.get_profile() 72 | local pid = M.pid 73 | if not pid then return end 74 | local ret = bash.bash(string.format('ps -p %d u', pid)) 75 | local list = util.split(string.match(ret, '\n(.+)'), ' ') 76 | return { 77 | cpu = tonumber(list[3]), 78 | mem = tonumber(list[6]), 79 | } 80 | end 81 | 82 | function M._proj() 83 | return conf.proj 84 | end 85 | 86 | function M._clustername() 87 | return skynet.getenv "clustername" 88 | end 89 | 90 | -- 绝对路径 91 | function M._workspace() 92 | local path = bash.bash("cd %s && pwd", conf.workspace) 93 | return string.gsub(path, "\n", "") 94 | end 95 | 96 | 97 | return M 98 | -------------------------------------------------------------------------------- /lualib/bw/util/date_helper.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local assert = assert 3 | local os = os 4 | 5 | local M = {} 6 | 7 | function M.format(t) 8 | local str = os.date("%Y-%m-%d %H:%M:%S %w", t) 9 | return string.gsub(str, "%d$", function(c) 10 | if c == "0" then 11 | return "星期日" 12 | elseif c == "1" then 13 | return "星期一" 14 | elseif c == "2" then 15 | return "星期二" 16 | elseif c == "3" then 17 | return "星期三" 18 | elseif c == "4" then 19 | return "星期四" 20 | elseif c == "5" then 21 | return "星期五" 22 | elseif c == "6" then 23 | return "星期六" 24 | end 25 | end) 26 | end 27 | 28 | function M.format_now(t) 29 | t = t or skynet.now()//100 30 | local d = t // (24*3600) 31 | local h = (t - d*24*3600)//3600 32 | local m = (t // 60) % 60 33 | local s = t % 60 34 | if d > 0 then 35 | return string.format("%s天%s小时", d, h) 36 | end 37 | if h > 0 then 38 | return string.format("%s小时%s分钟", h, m) 39 | end 40 | return string.format("%s分%s秒", m, s) 41 | end 42 | 43 | function M.hour() 44 | return os.date("*t", os.time()).hour 45 | end 46 | 47 | -- 计算自然天的最后时刻点秒数(每日0点) 48 | function M.calc_last_daytime( cur_time, cur_date ) 49 | local last_time = cur_time 50 | return ( last_time + ((23 - cur_date.hour)*3600 + (59 - cur_date.min)*60 + (59 - cur_date.sec)) ) 51 | end 52 | 53 | -- 计算自然周的最后时刻点秒数(周一0点) 54 | function M.calc_last_weektime( cur_time, cur_date ) 55 | local last_time = cur_time 56 | --周日特殊处理 57 | if cur_date.wday == 1 then 58 | return M.calc_last_daytime( cur_time, cur_date ) 59 | else 60 | return ( last_time + (8 - cur_date.wday)*24*3600 + ((23 - cur_date.hour)*3600 61 | + (59 - cur_date.min)*60 + (59 - cur_date.sec)) ) 62 | end 63 | end 64 | 65 | function M.is_sameday(time1, time2, zero_point) 66 | zero_point = zero_point or 0 67 | assert(time1 and time2) 68 | 69 | time1 = time1 + (8 - zero_point) * 3600 -- 东八区 70 | time2 = time2 + (8 - zero_point) * 3600 71 | 72 | return time1 // (60 * 60 * 24) == time2 // (60 * 60 * 24) 73 | end 74 | 75 | function M.is_sameweek(time1, time2, zero_point) 76 | zero_point = zero_point or 0 77 | assert(time1 and time2) 78 | 79 | time1 = time1 + (8 - zero_point) * 3600 -- 东八区 80 | time2 = time2 + (8 - zero_point) * 3600 81 | 82 | return os.date("%Y%W", time1) == os.date("%Y%W", time2) 83 | end 84 | 85 | -- 计算是否是同天 86 | function M.is_today(time) 87 | return M.is_sameday(time, os.time()) 88 | end 89 | 90 | function M.is_this_week(time) 91 | return M.is_sameweek(time, os.time()) 92 | end 93 | 94 | --获取当前某个时刻的时间 95 | function M.get_time_today(time, h) 96 | local t = os.date("*t", time or os.time()) 97 | local todayTime = {year = t.year, month = t.month , day = t.day, hour=h or 0,min=0,sec=0} 98 | return os.time(todayTime) 99 | end 100 | 101 | function M.get_today_zero(cur_time, zero_point) 102 | zero_point = zero_point or 0 103 | cur_time = cur_time or os.time() 104 | 105 | local t = os.date("*t", cur_time) 106 | if t.hour < zero_point then 107 | t = os.date("*t", cur_time-24*3600) 108 | end 109 | local zero_date = { year = t.year, 110 | month = t.month, 111 | day = t.day, 112 | hour = zero_point, 113 | min = 0, 114 | sec = 0,} 115 | return os.time(zero_date) 116 | end 117 | 118 | function M.get_next_zero(cur_time, zero_point) 119 | zero_point = zero_point or 0 120 | cur_time = cur_time or os.time() 121 | 122 | local t = os.date("*t", cur_time) 123 | if t.hour >= zero_point then 124 | t = os.date("*t", cur_time + 24*3600) 125 | end 126 | local zero_date = { year = t.year, 127 | month = t.month, 128 | day = t.day, 129 | hour = zero_point, 130 | min = 0, 131 | sec = 0,} 132 | return os.time(zero_date) 133 | end 134 | function M:get_start_time() 135 | local date = os.date("*t", os.time()) 136 | if date.hour >= 18 then 137 | date = os.date("*t", os.time()+24*3600) 138 | end 139 | if date.hour <= 5 or date.hour >= 18 then 140 | date.hour = 9 141 | elseif date.hour <= 8 then 142 | date.hour = 12 143 | elseif date.hour <= 11 then 144 | date.hour = 15 145 | elseif date.hour <= 14 then 146 | date.hour = 18 147 | elseif date.hour <= 17 then 148 | date.hour = 21 149 | end 150 | date.min = 0 151 | date.sec = 0 152 | return os.time(date) 153 | end 154 | 155 | return M 156 | -------------------------------------------------------------------------------- /lualib/bw/util/wrapper_helper.lua: -------------------------------------------------------------------------------- 1 | local conf = require "conf" 2 | local json = require "cjson.safe" 3 | local bash = require "bw.bash" 4 | bash = bash.bash 5 | 6 | local function save_settings(settings) 7 | bash("mkdir -p %s/data", conf.workspace) 8 | local file = io.open(conf.workspace.."/data/wrapper_settings.json", "w+") 9 | file:write(json.encode(settings)) 10 | file:close() 11 | end 12 | 13 | local M = {} 14 | function M.get_settings() 15 | local file = io.open(conf.workspace.."/data/wrapper_settings.json", "r") 16 | if not file then 17 | return {} 18 | end 19 | local str = file:read("*a") 20 | file:close() 21 | return json.decode(str) or {} 22 | end 23 | 24 | function M.get_doc(name) 25 | local setting = M.get(name) 26 | local file = io.open(setting.path.."/version_doc.json", "r") 27 | if not file then 28 | return {} 29 | end 30 | local str = file:read("*a") 31 | file:close() 32 | return json.decode(str) or {} 33 | end 34 | 35 | function M.save_doc(name, tbl) 36 | local setting = M.get(name) 37 | local file = io.open(setting.path.."/version_doc.json", "w+") 38 | file:write(json.encode(tbl)) 39 | file:close() 40 | end 41 | 42 | function M.get(k) 43 | return M.get_settings()[k] 44 | end 45 | 46 | function M.set(k, v) 47 | assert(k) 48 | assert(v.name) 49 | local settings = M.get_settings() 50 | settings[k] = v 51 | save_settings(settings) 52 | end 53 | 54 | function M.remove_settings(names) 55 | assert(names) 56 | local settings = M.get_settings() 57 | for k in string.gmatch(names, "([^ ]+)") do 58 | settings[k] = nil 59 | end 60 | save_settings(settings) 61 | end 62 | 63 | function M.get_version_list(name) 64 | local settings = M.get_settings() 65 | local doc = M.get_doc(name) 66 | local setting = settings[name] 67 | local cur 68 | local list = {} 69 | local ret = bash("ls --full-time %s/assets", setting.path) 70 | for str in string.gmatch(ret, "[^\n]+") do 71 | if string.len(str) > 10 then 72 | local version = string.match(str, "[^ ]+$") 73 | local time = string.match(str, "(%d+-%d+-%d+ %d+:%d+:%d+)") 74 | if string.match(str, "current") then 75 | cur = version 76 | else 77 | local v = doc[version] or {} 78 | table.insert(list, { 79 | version = version, 80 | time = time, 81 | desc = v.desc, 82 | git = v.git 83 | }) 84 | end 85 | end 86 | end 87 | if cur then 88 | for _, v in pairs(list) do 89 | if cur == v.version then 90 | v.LAY_CHECKED = true 91 | end 92 | end 93 | end 94 | table.sort(list, function(a, b) 95 | return M.to_version_num(a.version) > M.to_version_num(b.version) 96 | end) 97 | return list 98 | end 99 | 100 | function M.get_current(name) 101 | local list = M.get_version_list(name) 102 | for _, v in pairs(list) do 103 | if v.LAY_CHECKED then 104 | return v.version 105 | end 106 | end 107 | end 108 | 109 | function M.to_version_num(version) 110 | assert(type(version) == "string") 111 | local v1, v2, v3 = string.match(version, "(%d+)%.(%d+)%.(%d+)") 112 | if not v1 then 113 | return 114 | end 115 | return v1*1000000 + v2*1000 + v3 116 | end 117 | 118 | function M.to_version_str(num) 119 | assert(type(version) == "number") 120 | return string.format("%d.%d.%d", num//1000000, num%1000000//1000, num%1000) 121 | end 122 | 123 | return M 124 | -------------------------------------------------------------------------------- /lualib/bw/web/html.lua: -------------------------------------------------------------------------------- 1 | local html = {} 2 | 3 | local function parse(param) 4 | local str = "" 5 | for k, v in pairs(param or {}) do 6 | str = str .. k .. '="' .. v .. '"' 7 | end 8 | return str 9 | end 10 | 11 | setmetatable(html, { 12 | __index = function(t, k) 13 | local v = rawget(t, k) 14 | if v then 15 | return v 16 | else 17 | return function(ctx, param) 18 | return string.format('<%s %s>%s', k, parse(param), ctx, k) 19 | end 20 | end 21 | end 22 | }) 23 | 24 | return html 25 | -------------------------------------------------------------------------------- /lualib/bw/web/http_helper.lua: -------------------------------------------------------------------------------- 1 | -- Http 请求 get post 2 | -- 3 | local skynet = require "skynet" 4 | local json = require "cjson.safe" 5 | local sname = require "bw.sname" 6 | --local Util = require "bw.util" 7 | 8 | local M = {} 9 | function M.get(url, get, header, no_reply) 10 | if no_reply then 11 | return skynet.send(sname.WEB, "lua", "request", url, get, nil, header, no_reply) 12 | else 13 | return skynet.call(sname.WEB, "lua", "request", url, get, nil, header, no_reply) 14 | end 15 | end 16 | 17 | function M.post(url, post, header, no_reply) 18 | --skynet.error("http post:", url, post) 19 | if no_reply then 20 | return skynet.send(sname.WEB, "lua", "request", url, nil, post, header, no_reply) 21 | else 22 | return skynet.call(sname.WEB, "lua", "request", url, nil, post, header, no_reply) 23 | end 24 | end 25 | 26 | function M.url_encoding(tbl, encode) 27 | local data = {} 28 | for k, v in pairs(tbl) do 29 | table.insert(data, string.format("%s=%s", k, v)) 30 | end 31 | 32 | local url = table.concat(data, "&") 33 | if encode then 34 | return string.gsub(url, "([^A-Za-z0-9])", function(c) 35 | return string.format("%%%02X", string.byte(c)) 36 | end) 37 | else 38 | return url 39 | end 40 | end 41 | 42 | --[[ 43 | { 44 | "code":0, 45 | "data":{ 46 | "ip":"202.104.71.210", 47 | "country":"中国", 48 | "area":"", 49 | "region":"广东", 50 | "city":"广州", 51 | "county":"XX", 52 | "isp":"电信", 53 | "country_id":"CN", 54 | "area_id":"", 55 | "region_id":"440000", 56 | "city_id":"440100", 57 | "county_id":"xx", 58 | "isp_id":"100017" 59 | } 60 | } 61 | ]] 62 | function M.ip_info(ip) 63 | assert(ip) 64 | local _, resp = M.get("http://ip.taobao.com/service/getIpInfo.php", {ip = ip}) 65 | resp = json.decode(resp) 66 | if not resp then 67 | skynet.error("get ip_info error", ip, resp) 68 | resp = {} 69 | end 70 | return resp.data or {} 71 | end 72 | 73 | return M 74 | -------------------------------------------------------------------------------- /lualib/bw/ws/bnf.lua: -------------------------------------------------------------------------------- 1 | local lpeg = require "lpeg" 2 | local R, S, V, P = lpeg.R, lpeg.S, lpeg.V, lpeg.P 3 | local C, Ct, Cmt, Cg, Cb, Cc = lpeg.C, lpeg.Ct, lpeg.Cmt, lpeg.Cg, lpeg.Cb, lpeg.Cc 4 | local Cf = lpeg.Cf 5 | local bnf ={} 6 | 7 | local l = {} 8 | lpeg.locale(l) 9 | 10 | 11 | --rfc1630 12 | function bnf.uri() 13 | local void = P"" 14 | local punctuation = S("<>") 15 | local national = S("{}[]\\^~") 16 | local hex = l.xdigit 17 | local escape = P"%" * hex * hex 18 | local reserved = S("=;/#?:") + l.space 19 | local extra = S("!*'\"()") 20 | local safe = S("$-_@.&") 21 | local digit = l.digit 22 | local alpha = l.alpha 23 | local xalpha = alpha + digit + safe + extra + escape 24 | local xalphas = xalpha^1 25 | local xpalpha = xalpha + P"+" 26 | local ialpha = alpha * xalphas^-1 27 | local xpalphas = xpalpha^1 28 | local fragmentid = xalphas 29 | local search = xalphas^1 30 | local path = void 31 | + xpalphas * (P"/" * xpalphas)^0 32 | local scheme = ialpha 33 | local uri = scheme * P":" * path * search^0 34 | return uri 35 | end 36 | 37 | --rfc822 38 | function bnf.email() 39 | local alpha = l.alpha 40 | local digit = l.digit 41 | local ctl = S("\t") --todo add ctl elements 42 | local cr = P"\r" 43 | local lf = P"\n" 44 | local space = l.space 45 | local htab = P"\t" 46 | local crlf = cr * lf 47 | local lwsp_char = space + htab 48 | local linear_white_space = (crlf^0 * lwsp_char)^1 49 | local specials = S("()<>$,;\\<.[]") 50 | local delimiters = specials + linear_white_space 51 | local atom = (l.alnum - space - ctl)^1 52 | local text = atom 53 | local qtext = atom - S('"\\') - cr 54 | local quoted_string = P'"' * qtext * P'"' 55 | local dtext = atom- S('[]\\') - cr 56 | local quoted_pair = P"\\" * alpha 57 | local domain_literal = P"[" * dtext + quoted_pair + P"]" 58 | local word = atom + quoted_string 59 | local phrase = word^1 60 | local domain_ref = atom 61 | local sub_domain = domain_ref + domain_literal 62 | local domain = sub_domain * (P"." * sub_domain)^0 63 | local local_part = word * (P"." * word)^0 64 | local addr_spec = local_part * P"@" * domain 65 | 66 | local route = (P"@"*domain)^1 * P":" 67 | local route_addr = P"<" * route^-1 * addr_spec * P">" 68 | local mailbox = addr_spec 69 | +phrase * route_addr 70 | return mailbox 71 | end 72 | 73 | return bnf -------------------------------------------------------------------------------- /lualib/bw/ws/network_t.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local socket = require "skynet.socket" 3 | local json = require "cjson" 4 | local ws_server = require "ws.server" 5 | local protobuf = require "bw.protobuf" 6 | local class = require "bw.class" 7 | local util = require "bw.util" 8 | local log = require "bw.log" 9 | local def = require "def" 10 | local opcode = require "def.opcode" 11 | local errcode = require "def.errcode" 12 | local print = log.print("network_t") 13 | 14 | local M = class("network_t") 15 | function M:ctor(player) 16 | self.player = assert(player, "network need player") 17 | end 18 | 19 | function M:init(watchdog, agent, fd, ip) 20 | self._watchdog = assert(watchdog) 21 | self._agent = assert(agent) 22 | self._fd = assert(fd) 23 | self._ip = assert(ip) 24 | self._csn = 0 25 | self._ssn = 0 26 | self._ping_time = skynet.time() 27 | 28 | local handler = {} 29 | function handler.open() 30 | self._ping_time = skynet.time() 31 | end 32 | function handler.text(t) 33 | self._ping_time = skynet.time() 34 | self.send_type = "text" 35 | self:_recv_text(t) 36 | end 37 | function handler.binary(sock_buff) 38 | self._ping_time = skynet.time() 39 | self.send_type = "binary" 40 | self:_recv_binary(sock_buff) 41 | end 42 | function handler.close() 43 | self:call_agent("socket_close", self._fd) 44 | end 45 | self._ws = ws_server.new(fd, handler) 46 | end 47 | 48 | function M:check_timeout() 49 | if skynet.time() - self._ping_time > def.PING_TIMEOUT and self._ws then 50 | if self._ws then 51 | self._ws:send_close() 52 | self._ws.sock:close() 53 | end 54 | self._ws = nil 55 | end 56 | end 57 | 58 | function M:call_watchdog(...) 59 | return skynet.call(self._watchdog, "lua", ...) 60 | end 61 | 62 | function M:call_agent(...) 63 | return skynet.call(self._agent, "lua", ...) 64 | end 65 | 66 | function M:get_fd() 67 | return self._fd 68 | end 69 | 70 | function M:get_csn() 71 | return self._csn 72 | end 73 | 74 | function M:get_ssn() 75 | return self._ssn 76 | end 77 | 78 | function M:send(...) 79 | if self.send_type == "binary" then 80 | self:_send_binary(...) 81 | elseif self.send_type == "text" then 82 | self:_send_text(...) 83 | else 84 | error(string.format("send error send_type:%s", self.send_type)) 85 | end 86 | end 87 | 88 | function M:_send_text(op, msg) -- 兼容text 89 | if not self._ws then 90 | return 91 | end 92 | self._ws:send_text(json.encode({ 93 | op = op, 94 | msg = msg, 95 | })) 96 | end 97 | 98 | function M:_send_binary(op, tbl) 99 | if not self._ws then 100 | return 101 | end 102 | local data = protobuf.encode(opcode.toname(op), tbl or {}) 103 | --print("send", #data) 104 | -- self._ws:send_binary(string.pack(">Hs2", op, data)) 105 | if opcode.has_session(op) then 106 | self._ssn = self._ssn + 1 107 | end 108 | self._ws:send_binary(string.pack(">HHH", op, self._csn, self._ssn)..data) end 109 | 110 | function M:_recv_text(t) 111 | local data = json.decode(t) 112 | local recv_op = data.op 113 | local modname, recv_op = string.match(data.op, "([^.]+).(.+)") 114 | local mod = assert(self.player[modname], modname) 115 | local f =assert(mod[recv_op], recv_op) 116 | local resp_op = modname..".s2c_"..string.match(recv_op, "c2s_(.+)") 117 | local msg = f(mod, data.msg) or {} 118 | self._ws:send_text(json.encode({ 119 | op = resp_op, 120 | msg = msg, 121 | })) 122 | end 123 | 124 | function M:_recv_binary(sock_buff) 125 | --local op, buff = string.unpack(">Hs2", sock_buff) 126 | local op, csn, ssn = string.unpack(">HHH", sock_buff) 127 | local buff = string.sub(sock_buff, 7, #sock_buff) or "" 128 | local opname = opcode.toname(op) 129 | local modulename = opcode.tomodule(op) 130 | local simplename = opcode.tosimplename(op) 131 | self._csn = csn 132 | self._ssn = ssn 133 | 134 | if opname ~= "Login.c2s_ping" then 135 | skynet.error(string.format("recv_binary %s %s %s", opname, op, #buff)) 136 | end 137 | local data = protobuf.decode(opname, buff) 138 | --util.printdump(data) 139 | 140 | local player = self.player 141 | if not util.try(function() 142 | assert(player, "player nil") 143 | assert(player[modulename], string.format("module nil [%s.%s]", modulename, simplename)) 144 | assert(player[modulename][simplename], string.format("handle nil [%s.%s]", modulename, simplename)) 145 | ret = player[modulename][simplename](player[modulename], data) or 0 146 | end) then 147 | ret = errcode.TRACEBACK 148 | end 149 | 150 | assert(ret, string.format("no respone, opname %s", opname)) 151 | if type(ret) == "table" then 152 | ret.err = ret.err or 0 153 | else 154 | ret = {err = ret} 155 | end 156 | self:send(op+1, ret) 157 | end 158 | 159 | function M:close() 160 | if self._ws then 161 | self._ws.sock:close() 162 | end 163 | end 164 | 165 | function M:reconnect(csn, ssn) 166 | assert(csn and ssn) 167 | self:close() 168 | if self._csn ~= csn or self._ssn ~= ssn then 169 | return errcode.RELOGIN, self.player:base_data() 170 | else 171 | return errcode.RECONNECTED, self.player:base_data() 172 | end 173 | end 174 | 175 | function M:get_agent() 176 | return self._agent 177 | end 178 | 179 | function M:get_ip() 180 | return self._ip 181 | end 182 | 183 | 184 | return M 185 | -------------------------------------------------------------------------------- /lualib/bw/ws/packet.lua: -------------------------------------------------------------------------------- 1 | local core = require "packet.core" 2 | 3 | -- op 协议号 4 | -- buff sz 要发送的数据和长度 5 | -- sock_buff sock_sz 缓冲区的数据和长度 6 | 7 | local HEADER_SIZE = 4 8 | 9 | local M = {} 10 | function M.pack(opcode, buff, sz) 11 | local total = sz + HEADER_SIZE 12 | local data = core.new(total) 13 | data:write_ushort(total) 14 | data:write_ushort(opcode) 15 | data:write_bytes(buff, sz) 16 | return data:pack() -- sock_buff, sock_sz 17 | end 18 | function M.unpack(sock_buff, sock_sz) 19 | assert(type(sock_buff) == "userdata") 20 | assert(type(sock_sz) == "number") 21 | local data = core.new(sock_buff, sock_sz) 22 | --local total = data:read_ushort() -- skynet抠掉了这2个字节 23 | local opcode = data:read_ushort() 24 | local sz = sock_sz - HEADER_SIZE 25 | local buff = data:read_bytes(sz) 26 | return opcode, buff, sz 27 | end 28 | return M 29 | -------------------------------------------------------------------------------- /lualib/bw/ws/robot_t.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local coroutine = require "skynet.coroutine" 3 | local json = require "cjson" 4 | local packet = require "bw.ws.packet" 5 | local ws_client = require "bw.ws.client" 6 | local protobuf = require "bw.protobuf" 7 | local util = require "bw.util" 8 | local class = require "bw.class" 9 | local opcode = require "def.opcode" 10 | local errcode = require "def.errcode" 11 | 12 | local M = class("robot_t") 13 | function M:ctor(url, send_type) 14 | self._url = url 15 | self._send_type = send_type or "text" 16 | self._ws = ws_client:new() 17 | self._csn = 0 18 | self._ssn = 0 19 | 20 | self._call_requests = {} -- op -> co 21 | self._waiting = {} -- co -> time 22 | 23 | self:start() 24 | end 25 | 26 | function M:start() 27 | assert(self._ws) 28 | self._ws:connect(self._url) 29 | 30 | -- recv 31 | skynet.fork(function() 32 | while true do 33 | local data, type, err = self._ws:recv_frame() 34 | if err then 35 | if self.offline then 36 | self:offline() 37 | end 38 | print("socket error", err) 39 | return 40 | end 41 | if type == "text" then 42 | self:_recv_text(data) 43 | elseif type == "binary" then 44 | self:_recv_binary(data) 45 | end 46 | --skynet.sleep(10) 47 | end 48 | end) 49 | 50 | -- ping 51 | if self.ping then 52 | skynet.fork(function() 53 | while true do 54 | self:ping() 55 | skynet.sleep(100*30) 56 | end 57 | end) 58 | end 59 | 60 | -- tick 61 | self.tick = 0 62 | skynet.fork(function() 63 | while true do 64 | self.tick = self.tick + 1 65 | skynet.sleep(1) 66 | for co, time in pairs(self._waiting) do 67 | if time <= 0 then 68 | self:_suspended(co) 69 | else 70 | self._waiting[co] = time - 1 71 | end 72 | end 73 | end 74 | end) 75 | end 76 | 77 | function M:test(func) 78 | local co = coroutine.create(function() 79 | util.try(func) 80 | end) 81 | self:_suspended(co) 82 | end 83 | 84 | function M:call(op, data) 85 | self:send(op, data) 86 | local ret = coroutine.yield(op) 87 | local code = ret and ret.err 88 | --[[assert(code, string.format("opcode %s no errcode", opcode.toname(op))) 89 | if code ~= 0 then 90 | skynet.error(string.format("call %s error:0x%x, desc:%s", 91 | opcode.toname(op), code, errcode.describe(code))) 92 | end]] 93 | return ret 94 | end 95 | 96 | function M:wait(time) 97 | return coroutine.yield(nil, time) 98 | end 99 | 100 | function M:send(...) 101 | if self._send_type == "text" then 102 | self:_send_text(...) 103 | elseif self._send_type == "binary" then 104 | self:_send_binary(...) 105 | end 106 | end 107 | 108 | function M:_suspended(co, op, ...) 109 | assert(op == nil or type(op) == "string" or op >= 0) -- 暂时兼容text 110 | local status, op, wait = coroutine.resume(co, ...) 111 | if coroutine.status(co) == "suspended" then 112 | if op then 113 | self._call_requests[op] = co 114 | end 115 | if wait then 116 | self._waiting[co] = wait 117 | end 118 | end 119 | end 120 | 121 | function M:_recv_text(text) 122 | local data = json.decode(text) 123 | --util.printdump(data) 124 | local recv_id = data.id 125 | --print("recv", recv_id) 126 | local req_id = "C2s"..string.match(recv_id, "S2c(.+)") 127 | if self[recv_id] then 128 | self[recv_id](self, data.msg) 129 | end 130 | 131 | local co = self._call_requests[req_id] 132 | self._call_requests[req_id] = nil 133 | if co and coroutine.status(co) == "suspended" then 134 | self:_suspended(co, recv_id, data.msg) 135 | end 136 | return 137 | end 138 | 139 | function M:_send_text(id, msg) 140 | self._ws:send_text(json.encode({ 141 | id = id, 142 | msg = msg, 143 | })) 144 | end 145 | 146 | function M:_dispatch(op, data) 147 | local modulename = opcode.tomodule(op) 148 | local simplename = opcode.tosimplename(op) 149 | local funcname = modulename .. "_" .. simplename 150 | if self[funcname] then 151 | self[funcname](self, data) 152 | end 153 | 154 | local co = self._call_requests[op - 1] 155 | self._call_requests[op - 1] = nil 156 | if co and coroutine.status(co) == "suspended" then 157 | self:_suspended(co, op, data) 158 | end 159 | end 160 | 161 | function M:_recv_binary(sock_buff) 162 | local op, csn, ssn = string.unpack(">HHH", sock_buff) 163 | local buff = string.sub(sock_buff, 3, #sock_buff) 164 | local opname = opcode.toname(op) 165 | print("recv_binary", opname, #sock_buff) 166 | 167 | self._ssn = ssn 168 | 169 | local data = protobuf.decode(opname, buff, sz) 170 | if data.err ~= 0 then 171 | skynet.error(string.format("recv %s error:0x%x, desc:%s", 172 | opcode.toname(op), data.err, errcode.describe(data.err))) 173 | end 174 | --util.printdump(data) 175 | self:_dispatch(op, data) 176 | end 177 | 178 | function M:_send_binary(op, tbl) 179 | --print("send_binary", opcode.toname(op), util.dump(tbl)) 180 | local data = protobuf.encode(opcode.toname(op), tbl or {}) 181 | --print("send", data, #data) 182 | if opcode.has_session(op) then 183 | self._csn = self._csn + 1 184 | end 185 | self._ws:send_binary(string.pack(">HHHs2", op, self._csn, self._ssn, data)) 186 | end 187 | 188 | return M 189 | -------------------------------------------------------------------------------- /lualib/bw/ws/server.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Yichun Zhang (agentzh) 2 | local skynet = require "skynet" 3 | local wbproto = require "bw.ws.proto" 4 | local new_tab = wbproto.new_tab 5 | local _recv_frame = wbproto.recv_frame 6 | local _send_frame = wbproto.send_frame 7 | local http_ver = 1.1 --ngx.req.http_version 8 | local str_lower = string.lower 9 | local char = string.char 10 | local str_find = string.find 11 | local crypto = require "skynet.crypt" 12 | local type = type 13 | local setmetatable = setmetatable 14 | -- local print = print 15 | local socket = require "bw.ws.socket_help" 16 | 17 | local _M = new_tab(0, 10) 18 | _M._VERSION = '0.03' 19 | 20 | local mt = { __index = _M } 21 | 22 | function mt:close() 23 | self.sock:close() 24 | end 25 | 26 | function _M.new(id,handle,opts) 27 | local sock = socket.new_sock(id) 28 | local str = sock:readline("\r\n\r\n") 29 | if not str then 30 | print("not valid protocol!") 31 | return nil , "not valid protocol" 32 | end 33 | local req = wbproto.parse(str.."\r\n\r\n") 34 | if not req then 35 | return nil, "bad req" 36 | end 37 | local headers = req.headers 38 | local val = headers.Upgrade or headers.upgrade 39 | if type(val) == "table" then 40 | val = val[1] 41 | end 42 | if not val or str_lower(val) ~= "websocket" then 43 | return nil, "bad \"upgrade\" request header" 44 | end 45 | local key = headers["Sec-WebSocket-Key"] or headers["sec-websocket-key"] 46 | if type(key) == "table" then 47 | key = key[1] 48 | end 49 | if not key then 50 | return nil, "bad \"sec-websocket-key\" request header" 51 | end 52 | 53 | local ver = headers["Sec-WebSocket-Version"] or headers["sec-websocket-version"] 54 | if type(ver) == "table" then 55 | ver = ver[1] 56 | end 57 | if not ver or ver ~= "13" then 58 | return nil, "bad \"sec-websock-version\" request header" 59 | end 60 | 61 | local protocols = headers["Sec-WebSocket-Protocol"] or headers["sec-websocket-protocol"] 62 | if type(protocols) == "table" then 63 | protocols = protocols[1] 64 | end 65 | 66 | local ngx_header = {} 67 | if protocols then 68 | ngx_header["Sec-WebSocket-Protocol"] = protocols 69 | end 70 | ngx_header["connection"] = "Upgrade" 71 | ngx_header["upgrade"] = "websocket" 72 | local sha1 = crypto.sha1(key.."258EAFA5-E914-47DA-95CA-C5AB0DC85B11",true) 73 | ngx_header["sec-websocket-accept"] = crypto.base64encode(sha1) 74 | local status = 101 75 | local request_line = "HTTP/1.1 ".. status .." Switching Protocols" 76 | local rep ={} 77 | table.insert(rep,request_line) 78 | local k,v 79 | for k,v in pairs(ngx_header) do 80 | local str = string.format('%s: %s',k,v) 81 | table.insert(rep,str) 82 | end 83 | rep = table.concat(rep,"\r\n") 84 | rep = rep.."\r\n\r\n" 85 | sock:write(rep) 86 | local max_payload_len, send_masked 87 | if opts then 88 | max_payload_len = opts.max_payload_len 89 | send_masked = opts.send_masked 90 | end 91 | 92 | local t1 = setmetatable({ 93 | sock = sock, 94 | max_payload_len = max_payload_len or 65535, 95 | send_masked = send_masked, 96 | headers = headers 97 | }, mt) 98 | assert((handle and type(handle)=="table"),"websocket must have handle,handle must table") 99 | skynet.fork(function() 100 | if handle.open then 101 | handle["open"]({}) 102 | end 103 | while true do 104 | local data ,typ,err = t1:recv_frame() 105 | if not data then 106 | typ = "close" 107 | if handle[typ] then 108 | handle[typ]() 109 | end 110 | sock:close() 111 | return 112 | end 113 | local f = handle[typ] 114 | if f then 115 | f(data) 116 | else 117 | print("no handle msg",data,typ,err) 118 | return 119 | end 120 | end 121 | end) 122 | return t1 123 | end 124 | 125 | function _M.abandon(self) 126 | self.sock:abandon() 127 | end 128 | 129 | function _M.start_fd(self, id) 130 | self.sock:start_id(id) 131 | end 132 | 133 | function _M.recv_frame(self) 134 | 135 | local sock = self.sock 136 | if not sock then 137 | return nil, nil, "not initialized yet" 138 | end 139 | local data, typ, err = _recv_frame(sock, self.max_payload_len, true) 140 | if not data and not str_find(err, ": timeout", 1, true) then 141 | self.fatal = true 142 | end 143 | return data, typ, err 144 | end 145 | 146 | 147 | local function send_frame(self, fin, opcode, payload) 148 | if self.fatal then 149 | return nil, "fatal error already happened" 150 | end 151 | 152 | local sock = self.sock 153 | if not sock then 154 | return nil, "not initialized yet" 155 | end 156 | 157 | local bytes, err = _send_frame(sock, fin, opcode, payload, 158 | self.max_payload_len, self.send_masked) 159 | return bytes, err 160 | end 161 | _M.send_frame = send_frame 162 | 163 | 164 | function _M.send_text(self, data) 165 | return send_frame(self, true, 0x1, data) 166 | end 167 | 168 | 169 | function _M.send_binary(self, data) 170 | return send_frame(self, true, 0x2, data) 171 | end 172 | 173 | 174 | function _M.send_close(self, code, msg) 175 | local payload 176 | if code then 177 | if type(code) ~= "number" or code > 0x7fff then 178 | end 179 | payload = char(((code>> 8) & 0xff), (code & 0xff)) 180 | .. (msg or "") 181 | end 182 | return send_frame(self, true, 0x8, payload) 183 | end 184 | 185 | 186 | function _M.send_ping(self, data) 187 | return send_frame(self, true, 0x9, data) 188 | end 189 | 190 | 191 | function _M.send_pong(self, data) 192 | return send_frame(self, true, 0xa, data) 193 | end 194 | 195 | 196 | return _M 197 | -------------------------------------------------------------------------------- /lualib/bw/ws/socket_help.lua: -------------------------------------------------------------------------------- 1 | local helper = {} 2 | local sock_M = {} 3 | local socket = require "skynet.socket" 4 | 5 | function sock_M:readbytes(sz) 6 | local id = self.id 7 | return socket.read(id,sz) 8 | end 9 | 10 | function sock_M:readline(sep) 11 | local id = self.id 12 | return socket.readline(id,sep) 13 | end 14 | 15 | function sock_M:readall() 16 | local id = self.id 17 | return socket.readall(id) 18 | end 19 | 20 | function sock_M:write(...) 21 | local id = self.id 22 | return socket.write(id,...) 23 | end 24 | 25 | function sock_M:abandon() 26 | return socket.abandon(self.id) 27 | end 28 | 29 | function sock_M:start_id(id) 30 | self.id = id 31 | socket.start(id) 32 | end 33 | 34 | function sock_M:id(...) 35 | return self.id 36 | end 37 | function sock_M:close() 38 | socket.close(self.id) 39 | end 40 | function helper.open(...) 41 | return socket.open(...) 42 | end 43 | function helper.new_sock(id) 44 | local t = {id=id} 45 | return setmetatable(t,{__index=sock_M}) 46 | end 47 | 48 | return helper 49 | -------------------------------------------------------------------------------- /lualib/bw/xml/dom.lua: -------------------------------------------------------------------------------- 1 | ---- @module Handler to generate a DOM-like node tree structure with 2 | -- a single ROOT node parent - each node is a table comprising 3 | -- fields below. 4 | -- 5 | -- node = { _name = , 6 | -- _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD, 7 | -- _attr = { Node attributes - see callback API }, 8 | -- _parent = 9 | -- _children = { List of child nodes - ROOT/NODE only } 10 | -- } 11 | -- where: 12 | -- - PI = XML Processing Instruction tag. 13 | -- - DECL = XML declaration tag 14 | -- 15 | -- The dom structure is capable of representing any valid XML document 16 | -- 17 | -- Options 18 | -- ======= 19 | -- options.(comment|pi|dtd|decl)Node = bool 20 | -- - Include/exclude given node types 21 | -- 22 | -- License: 23 | -- ======== 24 | -- 25 | -- This code is freely distributable under the terms of the [MIT license](LICENSE). 26 | -- 27 | --@author Paul Chakravarti (paulc@passtheaardvark.com) 28 | --@author Manoel Campos da Silva Filho 29 | local dom = { 30 | options = {commentNode=1, piNode=1, dtdNode=1, declNode=1}, 31 | root = { _children = {n=0}, _type = "ROOT" }, 32 | current = root 33 | } 34 | 35 | ---Parses a start tag. 36 | -- @param tag a {name, attrs} table 37 | -- where name is the name of the tag and attrs 38 | -- is a table containing the atributtes of the tag 39 | function dom:starttag(tag) 40 | local node = { _type = 'ELEMENT', 41 | _name = tag.name, 42 | _attr = tag.attrs, 43 | _parent = self.current, 44 | _children = {n=0} 45 | } 46 | 47 | table.insert(self.current._children, node) 48 | self.current = node 49 | end 50 | 51 | ---Parses an end tag. 52 | -- @param tag a {name, attrs} table 53 | -- where name is the name of the tag and attrs 54 | -- is a table containing the atributtes of the tag 55 | function dom:endtag(tag, s) 56 | if tag.name ~= self.current._name then 57 | error("XML Error - Unmatched Tag ["..s..":"..tag.name.."]\n") 58 | end 59 | self.current = self.current._parent 60 | end 61 | 62 | ---Parses a tag content. 63 | -- @param text text to process 64 | function dom:text(text) 65 | local node = { _type = "TEXT", 66 | _parent = self.current, 67 | _text = text 68 | } 69 | table.insert(self.current._children, node) 70 | end 71 | 72 | ---Parses a comment tag. 73 | -- @param text comment text 74 | function dom:comment(text) 75 | if self.options.commentNode then 76 | local node = { _type = "COMMENT", 77 | _parent = self.current, 78 | _text = text 79 | } 80 | table.insert(self.current._children, node) 81 | end 82 | end 83 | 84 | --- Parses a XML processing instruction (PI) tag 85 | -- @param tag a {name, attrs} table 86 | -- where name is the name of the tag and attrs 87 | -- is a table containing the atributtes of the tag 88 | function dom:pi(tag) 89 | if self.options.piNode then 90 | local node = { _type = "PI", 91 | _name = tag.name, 92 | _attr = tag.attrs, 93 | _parent = self.current 94 | } 95 | table.insert(self.current._children, node) 96 | end 97 | end 98 | 99 | ---Parse the XML declaration line (the line that indicates the XML version). 100 | -- @param tag a {name, attrs} table 101 | -- where name is the name of the tag and attrs 102 | -- is a table containing the atributtes of the tag 103 | function dom:decl(tag) 104 | if self.options.declNode then 105 | local node = { _type = "DECL", 106 | _name = tag.name, 107 | _attr = tag.attrs, 108 | _parent = self.current 109 | } 110 | table.insert(self.current._children, node) 111 | end 112 | end 113 | 114 | ---Parses a DTD tag. 115 | -- @param tag a {name, attrs} table 116 | -- where name is the name of the tag and attrs 117 | -- is a table containing the atributtes of the tag 118 | function dom:dtd(tag) 119 | if self.options.dtdNode then 120 | local node = { _type = "DTD", 121 | _name = tag.name, 122 | _attr = tag.attrs, 123 | _parent = self.current 124 | } 125 | table.insert(self.current._children, node) 126 | end 127 | end 128 | 129 | ---Parses CDATA tag content. 130 | dom.cdata = dom.text 131 | return dom 132 | -------------------------------------------------------------------------------- /lualib/bw/xml/lua2xml.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | -- 不带属性的key-value, CDATA标签用于说明数据不被XML解析器解析 3 | function M.encode(k, v, cdata) 4 | local str = '<'..k..'>' 5 | if type(v) == "table" then 6 | for kk, vv in pairs(v) do 7 | str = str .. '\n' .. M.encode(kk, vv, cdata) 8 | end 9 | else 10 | if cdata then 11 | str = str .. '' 12 | else 13 | str = str .. v 14 | end 15 | end 16 | str = str..'' 17 | return str 18 | end 19 | 20 | -- 带属性的key-value 21 | function M.attr_encode() 22 | -- todo 23 | end 24 | return M 25 | -------------------------------------------------------------------------------- /lualib/bw/xml/print.lua: -------------------------------------------------------------------------------- 1 | ---@module Handler to generate a simple event trace which 2 | --outputs messages to the terminal during the XML 3 | --parsing, usually for debugging purposes. 4 | -- 5 | -- License: 6 | -- ======== 7 | -- 8 | -- This code is freely distributable under the terms of the [MIT license](LICENSE). 9 | -- 10 | --@author Paul Chakravarti (paulc@passtheaardvark.com) 11 | --@author Manoel Campos da Silva Filho 12 | local print = {} 13 | 14 | ---Parses a start tag. 15 | -- @param tag a {name, attrs} table 16 | -- where name is the name of the tag and attrs 17 | -- is a table containing the atributtes of the tag 18 | -- @param s position where the tag starts 19 | -- @param e position where the tag ends 20 | function print:starttag(tag) 21 | io.write("Start : "..tag.name.."\n") 22 | if tag.attrs then 23 | for k,v in pairs(tag.attrs) do 24 | io.write(string.format(" + %s='%s'\n", k, v)) 25 | end 26 | end 27 | end 28 | 29 | ---Parses an end tag. 30 | -- @param tag a {name, attrs} table 31 | -- where name is the name of the tag and attrs 32 | -- is a table containing the atributtes of the tag 33 | -- @param s position where the tag starts 34 | -- @param e position where the tag ends 35 | function print:endtag(tag) 36 | io.write("End : "..tag.name.."\n") 37 | end 38 | 39 | ---Parses a tag content. 40 | -- @param text text to process 41 | -- @param s position where the tag starts 42 | -- @param e position where the tag ends 43 | function print:text(text) 44 | io.write("Text : "..text.."\n") 45 | end 46 | 47 | ---Parses CDATA tag content. 48 | -- @param text CDATA content to be processed 49 | -- @param s position where the tag starts 50 | -- @param e position where the tag ends 51 | function print:cdata(text) 52 | io.write("CDATA : "..text.."\n") 53 | end 54 | 55 | ---Parses a comment tag. 56 | -- @param text comment text 57 | -- @param s position where the tag starts 58 | -- @param e position where the tag ends 59 | function print:comment(text) 60 | io.write("Comment : "..text.."\n") 61 | end 62 | 63 | ---Parses a DTD tag. 64 | -- @param tag a {name, attrs} table 65 | -- where name is the name of the tag and attrs 66 | -- is a table containing the atributtes of the tag 67 | -- @param s position where the tag starts 68 | -- @param e position where the tag ends 69 | function print:dtd(tag) 70 | io.write("DTD : "..tag.name.."\n") 71 | if tag.attrs then 72 | for k,v in pairs(tag.attrs) do 73 | io.write(string.format(" + %s='%s'\n", k, v)) 74 | end 75 | end 76 | end 77 | 78 | --- Parse a XML processing instructions (PI) tag. 79 | -- @param tag a {name, attrs} table 80 | -- where name is the name of the tag and attrs 81 | -- is a table containing the atributtes of the tag 82 | -- @param s position where the tag starts 83 | -- @param e position where the tag ends 84 | function print:pi(tag) 85 | io.write("PI : "..tag.name.."\n") 86 | if tag.attrs then 87 | for k,v in pairs(tag.attrs) do 88 | io. write(string.format(" + %s='%s'\n",k,v)) 89 | end 90 | end 91 | end 92 | 93 | ---Parse the XML declaration line (the line that indicates the XML version). 94 | -- @param tag a {name, attrs} table 95 | -- where name is the name of the tag and attrs 96 | -- is a table containing the atributtes of the tag 97 | -- @param s position where the tag starts 98 | -- @param e position where the tag ends 99 | function print:decl(tag) 100 | io.write("XML Decl : "..tag.name.."\n") 101 | if tag.attrs then 102 | for k,v in pairs(tag.attrs) do 103 | io.write(string.format(" + %s='%s'\n", k, v)) 104 | end 105 | end 106 | end 107 | 108 | return print 109 | -------------------------------------------------------------------------------- /lualib/bw/xml/tree.lua: -------------------------------------------------------------------------------- 1 | local function init() 2 | local obj = { 3 | root = {}, 4 | options = {noreduce = {}} 5 | } 6 | 7 | obj._stack = {obj.root, n=1} 8 | return obj 9 | end 10 | 11 | --- @module XML Tree Handler. 12 | -- Generates a lua table from an XML content string. 13 | -- It is a simplified handler which attempts 14 | -- to generate a more 'natural' table based structure which 15 | -- supports many common XML formats. 16 | -- 17 | -- The XML tree structure is mapped directly into a recursive 18 | -- table structure with node names as keys and child elements 19 | -- as either a table of values or directly as a string value 20 | -- for text. Where there is only a single child element this 21 | -- is inserted as a named key - if there are multiple 22 | -- elements these are inserted as a vector (in some cases it 23 | -- may be preferable to always insert elements as a vector 24 | -- which can be specified on a per element basis in the 25 | -- options). Attributes are inserted as a child element with 26 | -- a key of '_attr'. 27 | -- 28 | -- Only Tag/Text & CDATA elements are processed - all others 29 | -- are ignored. 30 | -- 31 | -- This format has some limitations - primarily 32 | -- 33 | -- * Mixed-Content behaves unpredictably - the relationship 34 | -- between text elements and embedded tags is lost and 35 | -- multiple levels of mixed content does not work 36 | -- * If a leaf element has both a text element and attributes 37 | -- then the text must be accessed through a vector (to 38 | -- provide a container for the attribute) 39 | -- 40 | -- In general however this format is relatively useful. 41 | -- 42 | -- It is much easier to understand by running some test 43 | -- data through 'textxml.lua -simpletree' than to read this) 44 | -- 45 | -- Options 46 | -- ======= 47 | -- options.noreduce = { = bool,.. } 48 | -- - Nodes not to reduce children vector even if only 49 | -- one child 50 | -- 51 | -- License: 52 | -- ======== 53 | -- 54 | -- This code is freely distributable under the terms of the [MIT license](LICENSE). 55 | -- 56 | --@author Paul Chakravarti (paulc@passtheaardvark.com) 57 | --@author Manoel Campos da Silva Filho 58 | local tree = init() 59 | 60 | ---Instantiates a new handler object. 61 | --Each instance can handle a single XML. 62 | --By using such a constructor, you can parse 63 | --multiple XML files in the same application. 64 | --@return the handler instance 65 | function tree:new() 66 | local obj = init() 67 | 68 | obj.__index = self 69 | setmetatable(obj, self) 70 | 71 | return obj 72 | end 73 | 74 | --Gets the first key of a table 75 | --@param tb table to get its first key 76 | --@return the table's first key, nil if the table is empty 77 | --or the given parameter if it isn't a table 78 | local function getFirstKey(tb) 79 | if type(tb) == "table" then 80 | return next(tb) 81 | end 82 | return tb 83 | end 84 | 85 | --- Recursively removes redundant vectors for nodes 86 | -- with single child elements 87 | function tree:reduce(node, key, parent) 88 | for k,v in pairs(node) do 89 | if type(v) == 'table' then 90 | self:reduce(v,k,node) 91 | end 92 | end 93 | if #node == 1 and not self.options.noreduce[key] and 94 | node._attr == nil then 95 | parent[key] = node[1] 96 | else 97 | node.n = nil 98 | end 99 | end 100 | 101 | ---Parses a start tag. 102 | -- @param tag a {name, attrs} table 103 | -- where name is the name of the tag and attrs 104 | -- is a table containing the atributtes of the tag 105 | function tree:starttag(tag) 106 | local node = {} 107 | if self.parseAttributes == true then 108 | node._attr=tag.attrs 109 | end 110 | 111 | local current = self._stack[#self._stack] 112 | if current[tag.name] then 113 | table.insert(current[tag.name], node) 114 | else 115 | current[tag.name] = {node; n=1} 116 | end 117 | 118 | table.insert(self._stack, node) 119 | end 120 | 121 | ---Parses an end tag. 122 | -- @param tag a {name, attrs} table 123 | -- where name is the name of the tag and attrs 124 | -- is a table containing the atributtes of the tag 125 | function tree:endtag(tag, s) 126 | --Tabela que representa a tag atualmente sendo processada 127 | local current = self._stack[#self._stack] 128 | --Tabela que representa a tag na qual a tag 129 | --atual está contida. 130 | local prev = self._stack[#self._stack-1] 131 | if not prev[tag.name] then 132 | error("XML Error - Unmatched Tag ["..s..":"..tag.name.."]\n") 133 | end 134 | if prev == self.root then 135 | -- Once parsing complete recursively reduce tree 136 | self:reduce(prev, nil, nil) 137 | end 138 | 139 | local firstKey = getFirstKey(current) 140 | --Se a primeira chave da tabela que representa 141 | --a tag atual não possui nenhum elemento, 142 | --é porque não há nenhum valor associado à tag 143 | -- (como nos casos de tags automaticamente fechadas como ). 144 | --Assim, atribui uma string vazia a mesma para 145 | --que seja retornado vazio no lugar da tag e não 146 | --uma tabela. Retornando uma string vazia 147 | --simplifica para as aplicações NCLua 148 | --para imprimir tal valor. 149 | if firstKey == nil then 150 | current[tag.name] = "" 151 | prev[tag.name] = "" 152 | end 153 | 154 | table.remove(self._stack) 155 | end 156 | 157 | ---Parses a tag content. 158 | -- @param t text to process 159 | function tree:text(t) 160 | local current = self._stack[#self._stack] 161 | table.insert(current, t) 162 | end 163 | 164 | ---Parses CDATA tag content. 165 | tree.cdata = tree.text 166 | tree.__index = tree 167 | return tree 168 | -------------------------------------------------------------------------------- /lualib/bw/xml/xml2lua.lua: -------------------------------------------------------------------------------- 1 | --- @module Module providing a non-validating XML stream parser in Lua. 2 | -- 3 | -- Features: 4 | -- ========= 5 | -- 6 | -- * Tokenises well-formed XML (relatively robustly) 7 | -- * Flexible handler based event API (see below) 8 | -- * Parses all XML Infoset elements - ie. 9 | -- - Tags 10 | -- - Text 11 | -- - Comments 12 | -- - CDATA 13 | -- - XML Decl 14 | -- - Processing Instructions 15 | -- - DOCTYPE declarations 16 | -- * Provides limited well-formedness checking 17 | -- (checks for basic syntax & balanced tags only) 18 | -- * Flexible whitespace handling (selectable) 19 | -- * Entity Handling (selectable) 20 | -- 21 | -- Limitations: 22 | -- ============ 23 | -- 24 | -- * Non-validating 25 | -- * No charset handling 26 | -- * No namespace support 27 | -- * Shallow well-formedness checking only (fails 28 | -- to detect most semantic errors) 29 | -- 30 | -- API: 31 | -- ==== 32 | -- 33 | -- The parser provides a partially object-oriented API with 34 | -- functionality split into tokeniser and handler components. 35 | -- 36 | -- The handler instance is passed to the tokeniser and receives 37 | -- callbacks for each XML element processed (if a suitable handler 38 | -- function is defined). The API is conceptually similar to the 39 | -- SAX API but implemented differently. 40 | -- 41 | -- XML data is passed to the parser instance through the 'parse' 42 | -- method (Note: must be passed a single string currently) 43 | -- 44 | -- License: 45 | -- ======== 46 | -- 47 | -- This code is freely distributable under the terms of the [MIT license](LICENSE). 48 | -- 49 | -- 50 | --@author Paul Chakravarti (paulc@passtheaardvark.com) 51 | --@author Manoel Campos da Silva Filho 52 | local xml2lua = {} 53 | local XmlParser = require("bw.xml.XmlParser") 54 | 55 | ---Recursivelly prints a table in an easy-to-ready format 56 | --@param tb The table to be printed 57 | --@param level the indentation level to start with 58 | local function printableInternal(tb, level) 59 | if tb == nil then 60 | return 61 | end 62 | 63 | level = level or 1 64 | local spaces = string.rep(' ', level*2) 65 | for k,v in pairs(tb) do 66 | if type(v) == "table" then 67 | print(spaces .. k) 68 | printableInternal(v, level+1) 69 | else 70 | print(spaces .. k..'='..v) 71 | end 72 | end 73 | end 74 | 75 | ---Instantiates a XmlParser object to parse a XML string 76 | --@param handler Handler module to be used to convert the XML string 77 | --to another formats. See the available handlers at the handler directory. 78 | -- Usually you get an instance to a handler module using, for instance: 79 | -- local handler = require("xmlhandler/tree"). 80 | --@return a XmlParser object used to parse the XML 81 | --@see XmlParser 82 | function xml2lua.parser(handler) 83 | if handler == xml2lua then 84 | error("You must call xml2lua.parse(handler) instead of xml2lua:parse(handler)") 85 | end 86 | 87 | local options = { 88 | --Indicates if whitespaces should be striped or not 89 | stripWS = 1, 90 | expandEntities = 1, 91 | errorHandler = function(errMsg, pos) 92 | error(string.format("%s [char=%d]\n", errMsg or "Parse Error", pos)) 93 | end 94 | } 95 | 96 | return XmlParser.new(handler, options) 97 | end 98 | 99 | ---Recursivelly prints a table in an easy-to-ready format 100 | --@param tb The table to be printed 101 | function xml2lua.printable(tb) 102 | printableInternal(tb) 103 | end 104 | 105 | ---Handler to generate a string prepresentation of a table 106 | --Convenience function for printHandler (Does not support recursive tables). 107 | --@param t Table to be parsed 108 | --@return a string representation of the table 109 | function xml2lua.toString(t) 110 | local sep = '' 111 | local res = '' 112 | if type(t) ~= 'table' then 113 | return t 114 | end 115 | 116 | for k,v in pairs(t) do 117 | if type(v) == 'table' then 118 | v = xml2lua.toString(v) 119 | end 120 | res = res .. sep .. string.format("%s=%s", k, v) 121 | sep = ',' 122 | end 123 | res = '{'..res..'}' 124 | 125 | return res 126 | end 127 | 128 | --- Loads an XML file from a specified path 129 | -- @param xmlFilePath the path for the XML file to load 130 | -- @return the XML loaded file content 131 | function xml2lua.loadFile(xmlFilePath) 132 | local f, e = io.open(xmlFilePath, "r") 133 | if f then 134 | --Gets the entire file content and stores into a string 135 | return f:read("*a") 136 | end 137 | 138 | error(e) 139 | end 140 | 141 | function xml2lua.decode(xml) 142 | local handler = require "bw.xml.tree" 143 | local parser = xml2lua.parser(handler) 144 | parser:parse(xml) 145 | return handler.root 146 | end 147 | 148 | return xml2lua 149 | -------------------------------------------------------------------------------- /lualib/def.lua: -------------------------------------------------------------------------------- 1 | -- 项目目录新建def.lua覆盖些脚本 2 | local const = require "bw.const" 3 | return const {} 4 | -------------------------------------------------------------------------------- /lualib/def/errcode.lua: -------------------------------------------------------------------------------- 1 | local errcode = require "def.errcode_helper" 2 | --local REG = errcode.REG 3 | -- todo 项目自定义错误码 0x1000开始 4 | 5 | return errcode 6 | -------------------------------------------------------------------------------- /lualib/def/errcode_helper.lua: -------------------------------------------------------------------------------- 1 | -- 错误码规范 2 | -- 0x0000 ~ 0x0fff 通用错误码 3 | -- 0x1000 ~ 0xffff 项目自定错误码 4 | 5 | local errcode = {} 6 | local code2describe = {} 7 | local name2errcode = {} 8 | 9 | local function REG(err_name, code, describe) 10 | assert(not code2describe[code], string.format("errcode 0x%x exist", code)) 11 | name2errcode[err_name] = code 12 | code2describe[code] = string.format("0x%x:%s【%s】", code, err_name, describe) 13 | end 14 | errcode.REG = REG 15 | 16 | function errcode.describe(code) 17 | return code2describe[code] 18 | end 19 | 20 | function errcode.get_name2errcode() 21 | return name2errcode 22 | end 23 | 24 | setmetatable(errcode, {__index = function (_, name) 25 | return assert(name2errcode[name], name) 26 | end}) 27 | 28 | REG("OK", 0x0000, "执行成功") 29 | REG("TRACEBACK", 0x0001, "服务器报错!") 30 | REG("TODO", 0x0002, "功能开发中") 31 | REG("ARGS_ERROR", 0x0003, "参数错误") 32 | REG("AUTH_FAIL", 0x0004, "验证错误!") 33 | REG("OFFLINE", 0x0005, "已下线") 34 | REG("PROP_ERROR", 0x0006, "配置表错误") 35 | REG("RECONNECTED", 0x0007, "重连成功") 36 | REG("RELOGIN", 0x0008, "重登成功") 37 | REG("KICK", 0x0009, "在别处登陆") 38 | REG("SERVER_STOP", 0x000a, "服务器维护中") 39 | REG("VERSION_TOO_LOW", 0x000b, "版本号过低") 40 | REG("ACTIVITY_NOT_OPEN", 0x000c, "活动未开放") 41 | REG("REPEAT", 0x000d, "重复操作") 42 | REG("SIGN_ERROR", 0x000e, "签名错误") 43 | REG("SERVER_BUSY", 0x000f, "服务器忙!") 44 | REG("SERVER_CLOSED", 0x0010, "服役器未启动!") 45 | REG("BODY_ERROR", 0x001a, "body数据解析错误") 46 | REG("API_NOT_EXIST", 0x001b, "api不存在") 47 | REG("ACC_NOT_EXIST", 0x001c, "账号不存在") 48 | REG("PASSWD_ERROR", 0x001d, "密码错误") 49 | REG("CURRENT_VERSION", 0x001e, "该版本正在使用") 50 | 51 | return errcode 52 | -------------------------------------------------------------------------------- /lualib/def/opcode.lua: -------------------------------------------------------------------------------- 1 | local opcode = require "def.opcode_helper" 2 | --local REG = opcode.REG 3 | -- todo 注册项目的协议 4 | 5 | return opcode 6 | -------------------------------------------------------------------------------- /lualib/def/opcode_helper.lua: -------------------------------------------------------------------------------- 1 | -- 协议号规范 2 | -- 0x0100 ~ 0x0fff 服务器给客户端发 3 | -- 0x1000 ~ 0x4fff 与游戏服之间的rpc 4 | -- 0x9000 ~ 0xcfff 玩家离线操作 5 | 6 | local opcode = {} 7 | local code2name = {} 8 | local code2module = {} 9 | local code2simplename = {} 10 | local code2session = {} 11 | local code2urlrequest = {} 12 | 13 | local function REG(code, message_name, urlrequest, session) 14 | assert(not code2name[code], string.format("code 0x%x exist", code)) 15 | 16 | local namespace = opcode 17 | for v in string.gmatch(message_name, "([^.]+)[.]") do 18 | namespace[v] = rawget(namespace, v) or setmetatable({}, { 19 | __index = function(_, k) error(k) end}) 20 | namespace = namespace[v] 21 | end 22 | 23 | namespace[string.match(message_name, "[%w_]+$")] = code 24 | code2name[code] = message_name 25 | code2urlrequest[code] = urlrequest 26 | code2session[code] = session 27 | code2module[code] = string.lower(string.match(message_name, "^[^.]+")) 28 | code2simplename[code] = string.match(message_name, "[^.]+$") 29 | end 30 | opcode.REG = REG 31 | 32 | function opcode.toname(code) 33 | return code2name[code] 34 | end 35 | 36 | function opcode.tomodule(code) 37 | return code2module[code] 38 | end 39 | 40 | function opcode.tosimplename(code) 41 | return code2simplename[code] 42 | end 43 | 44 | function opcode.has_session(code) 45 | return code2session[code] 46 | end 47 | 48 | function opcode.urlrequest(code) 49 | return code2urlrequest[code] 50 | end 51 | 52 | function opcode.get_code2name() 53 | return code2name 54 | end 55 | 56 | return opcode 57 | -------------------------------------------------------------------------------- /script/check/cms.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local json = require "cjson.safe" 3 | local http = require "bw.web.http_helper" 4 | local wc = require "bw.cms.webconsole" 5 | local errcode = require "def.errcode" 6 | 7 | local authorization 8 | local host = "127.0.0.1:9999" 9 | 10 | local function check_login(account, password, expect_err) 11 | local ret, resp = http.post(host.."/cms/user/login", json.encode { 12 | account = account, 13 | password = password, 14 | }) 15 | resp = assert(json.decode(resp), resp) 16 | assert(ret) 17 | assert(resp.err == (expect_err or 0), errcode.describe(resp.err)) 18 | return resp 19 | end 20 | 21 | local function check_api(api, param, expect_err) 22 | local ret, resp = http.post(host..api, json.encode(param), {authorization = authorization}) 23 | resp = assert(json.decode(resp), resp) 24 | assert(ret) 25 | assert(resp.err == (expect_err or 0), errcode.describe(resp.err)) 26 | return resp 27 | end 28 | 29 | return function() 30 | wc.init({ 31 | port = "9999", 32 | users = { 33 | {account = "root", password = "123"} 34 | } 35 | }) 36 | 37 | check_login("aaa", "2222", errcode.ACC_NOT_EXIST) 38 | check_login("root", "xxx", errcode.PASSWD_ERROR) 39 | 40 | local ret = check_login("root", "123") 41 | authorization = assert(ret.authorization) 42 | 43 | check_api("/cms/user/gm", {}, errcode.ARGS_ERROR) 44 | return true 45 | end 46 | 47 | -------------------------------------------------------------------------------- /script/check/date_helper.lua: -------------------------------------------------------------------------------- 1 | local d = require "bw.util.date_helper" 2 | return function() 3 | assert(d.format_now(1) == "0分1秒") 4 | assert(d.format_now(305) == "5分5秒") 5 | assert(d.format_now(24*3600+1) == "1天0小时") 6 | assert(d.format_now(24*3600+3660) == "1天1小时") 7 | assert(d.format_now(29*24*3600+3660) == "29天1小时") 8 | return true 9 | end 10 | -------------------------------------------------------------------------------- /script/check/inject.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local function inject(source) 3 | return skynet.call("check", "code", source) 4 | end 5 | return function () 6 | inject([[print "hello"]]) 7 | inject([[print(skynet)]]) 8 | inject([[ 9 | local bewater = require "bw.bewater" 10 | print(bewater.traceback()) 11 | ]]) 12 | inject([[print(check_list)]]) 13 | end 14 | -------------------------------------------------------------------------------- /script/check/ip_country.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local ip_country = require "bw.ip.ip_country" 3 | return function() 4 | local cn = '113.111.109.39' 5 | local c = ip_country.get_country(cn) 6 | assert(c == "China", c) 7 | assert(ip_country.is_china(cn)) 8 | 9 | local us = '95.163.203.38' 10 | c = ip_country.get_country(us) 11 | assert(c == "United States", c) 12 | assert(not ip_country.is_china(us)) 13 | 14 | c = ip_country.get_country('127.0.0.1') 15 | assert(c == "local", c) 16 | assert(ip_country.is_china('127.0.0.1')) 17 | 18 | c = ip_country.get_country('localhost') 19 | assert(c == "local", c) 20 | assert(ip_country.is_china('localhost')) 21 | 22 | return true 23 | end 24 | -------------------------------------------------------------------------------- /script/check/logger.lua: -------------------------------------------------------------------------------- 1 | local log = require "bw.log" 2 | return function() 3 | log.error("test error.log") 4 | end 5 | -------------------------------------------------------------------------------- /script/check/schedule.lua: -------------------------------------------------------------------------------- 1 | local schedule = require "bw.schedule" 2 | return function () 3 | assert(schedule.time()) 4 | return true 5 | end 6 | -------------------------------------------------------------------------------- /script/conf.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local conf = { 3 | workspace = skynet.getenv('workspace'), 4 | clustername = skynet.getenv('clustername'), 5 | debug = true, 6 | 7 | proj = "test", 8 | desc = "测试服", 9 | 10 | mongo = { 11 | host = "127.0.0.1", 12 | name = "test", 13 | port = 27017, 14 | }, 15 | 16 | } 17 | 18 | return conf 19 | -------------------------------------------------------------------------------- /script/test/stdout.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local sname = require "bw.sname" 3 | 4 | return function() 5 | skynet.call(sname.STDOUT, "lua", "run", "cp -rvf ~/code ~/backup") 6 | skynet.fork(function() 7 | local offset = 0 8 | local str = "" 9 | local eof = false 10 | while true do 11 | print("running") 12 | str, offset, eof = skynet.call(sname.STDOUT, "lua", "log", offset) 13 | print(str) 14 | print(offset) 15 | if eof then 16 | break 17 | end 18 | skynet.sleep(10) 19 | end 20 | end) 21 | end 22 | 23 | -------------------------------------------------------------------------------- /service/alert.lua: -------------------------------------------------------------------------------- 1 | -- 钉钉警报系统 2 | local skynet = require "skynet" 3 | local http = require "bw.web.http_helper" 4 | local bewater= require "bw.bewater" 5 | local conf = require "conf" 6 | local log = require "bw.log" 7 | local json = require "cjson.safe" 8 | local lock = require "bw.lock" 9 | 10 | local trace = log.trace("alert") 11 | local bash = require "bw.bash" 12 | 13 | local send_lock = lock.new() 14 | local host = "https://oapi.dingtalk.com" 15 | local function get_token() 16 | local ret, resp = http.get(host.."/gettoken", {corpid = conf.alert.corpid, corpsecret = conf.alert.corpsecret}) 17 | if ret then 18 | local data = json.decode(resp) 19 | return data.access_token 20 | else 21 | skynet.error("cannot get token") 22 | end 23 | end 24 | 25 | 26 | local count = 0 -- 一分钟内累计报错次数 27 | local last = 0 -- 上次报错时间 28 | local function send_traceback() 29 | send_lock:lock() 30 | if skynet.time() - last < 60 or count == 0 then 31 | return 32 | end 33 | local info = require "bw.util.clusterinfo" 34 | local path = string.format("%s/log/error.log", info.workspace) 35 | local str = string.format("服务器出错了\n项目:%s\n节点:%s\n公网ip:%s\n内网ip:%s\n进程:%s\n日志:%s\n累计报错:%d次", 36 | conf.desc or conf.proj, info.clustername, info.pnet_addr, info.inet_addr, info.pid, path, count) 37 | 38 | count = 0 39 | last = skynet.time() 40 | 41 | local token = get_token() 42 | local sh = string.format('curl -H "Content-Type:application/json" -X POST -d \'%s\' %s/chat/send?access_token=%s', 43 | json.encode { 44 | sender = conf.alert.sender, 45 | chatid = conf.alert.chatid, 46 | msgtype = "text", 47 | text = { 48 | content = str, 49 | } 50 | }, host, token) 51 | bash.bash(sh) 52 | send_lock:unlock() 53 | end 54 | 55 | local CMD = {} 56 | function CMD.traceback(err) 57 | count = count + 1 58 | send_traceback(err) 59 | end 60 | 61 | function CMD.node_dead(proj, clustername, pnet_addr, inet_addr, pid, cpu, mem) 62 | local str = string.format("救命啊,有节点挂掉了!\n项目:%s\n节点:%s\n公网ip:%s\n内网ip:%s\n进程: pid:%s CPU:%s MEM:%.1fM", 63 | proj, clustername, pnet_addr, inet_addr, pid, cpu, mem/1024) 64 | trace(str) 65 | CMD.test(str) 66 | end 67 | 68 | function CMD.test(str) 69 | -- 暂时先用curl发https post 70 | local token = get_token() 71 | local sh = string.format('curl -H "Content-Type:application/json" -X POST -d \'%s\' %s/chat/send?access_token=%s', 72 | json.encode { 73 | sender = conf.alert.sender, 74 | chatid = conf.alert.chatid, 75 | msgtype = "text", 76 | text = { 77 | content = str, 78 | } 79 | }, host, token) 80 | bash.bash(sh) 81 | 82 | end 83 | 84 | skynet.start(function() 85 | skynet.dispatch("lua", function(_,_, cmd, ...) 86 | local f = assert(CMD[cmd], cmd) 87 | bewater.ret(f(...)) 88 | end) 89 | 90 | skynet.fork(function() 91 | while true do 92 | if count > 0 then 93 | send_traceback() 94 | end 95 | skynet.sleep(6000) 96 | end 97 | end) 98 | end) 99 | -------------------------------------------------------------------------------- /service/autoid.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | local mongo = require "bw.db.mongo_helper" 3 | local bewater = require "bw.bewater" 4 | local def = require "def" 5 | 6 | local RESERVE_COUNT = 100 7 | local INITIAL_ID = def.INITIAL_ID or 10000000 8 | 9 | local reserve_id 10 | local id 11 | 12 | local CMD = {} 13 | function CMD.start() 14 | id = mongo.get("autoid", INITIAL_ID) 15 | reserve_id = id + RESERVE_COUNT 16 | end 17 | 18 | function CMD.stop() 19 | mongo.set("autoid", id) 20 | end 21 | 22 | function CMD.create(count) 23 | count = count or 1 24 | local start_id = id 25 | id = id + count 26 | if id > reserve_id then 27 | reserve_id = id + RESERVE_COUNT 28 | mongo.set("autoid", reserve_id) 29 | end 30 | return start_id, count 31 | end 32 | 33 | skynet.start(function() 34 | skynet.dispatch("lua", function(_,_, cmd, ...) 35 | local f = assert(CMD[cmd], cmd) 36 | bewater.ret(f(...)) 37 | end) 38 | skynet.register "autoid" 39 | end) 40 | -------------------------------------------------------------------------------- /service/battle/agent.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local bewater = require "bw.bewater" 3 | local errcode = require "def.errcode" 4 | 5 | local battle_path = ... 6 | local battle_t = require(battle_path) 7 | 8 | local battles = {} 9 | 10 | local CMD = {} 11 | function CMD.create(battle_id, mode) 12 | local battle = battle_t.new() 13 | battle:init_by_data({ 14 | battle_id = battle_id, 15 | mode = mode 16 | }) 17 | battles[battle_id] = battle 18 | end 19 | 20 | function CMD.destroy(battle_id) 21 | local battle = battles[battle_id] 22 | battle:destroy() 23 | battles[battle_id] = nil 24 | end 25 | 26 | function CMD.call_battle(battle_id, cmd, ...) 27 | local battle = battles[battle_id] 28 | if not battle then 29 | print("battle not exist", battle_id) 30 | return errcode.BATTLE_NOT_EXIST 31 | end 32 | local f = assert(battle[cmd], cmd) 33 | return f(battle, ...) 34 | end 35 | 36 | skynet.start(function() 37 | skynet.dispatch("lua", function(_, _, cmd, ...) 38 | local f = assert(CMD[cmd], cmd) 39 | bewater.ret(f(...)) 40 | end) 41 | end) 42 | 43 | -------------------------------------------------------------------------------- /service/battle/match.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local bewater = require "bw.bewater" 3 | local log = require "bw.log" 4 | 5 | local print = log.print("match") 6 | 7 | local uid2info = {} -- uid -> info {uid, value, agent} 8 | local values = {} -- value -> uids 9 | 10 | local MODE -- 匹配模式 11 | local MAX_TIME -- 匹配时长 12 | local MAX_RANGE -- 匹配最大范围 13 | 14 | local CMD = {} 15 | function CMD.init(mode, max_time, max_range) 16 | MODE = mode 17 | MAX_TIME = max_time or 3 18 | MAX_RANGE = max_range or 0 19 | end 20 | 21 | function CMD.start(uid, value, agent) 22 | print("start match", uid, value) 23 | if uid2info[uid] then 24 | skynet.error(uid, "is matching") 25 | return 26 | end 27 | uid2info[uid] = { 28 | uid = uid, 29 | value = value, 30 | agent = agent, 31 | ret = -1, -- -1:未匹配到对手 0:机器人 >0:玩家uid 32 | } 33 | values[value] = values[value] or {} 34 | values[value][uid] = os.time() 35 | end 36 | 37 | function CMD.reconnect(uid, agent) 38 | local info = uid2info[uid] 39 | if info then 40 | info.agent = agent 41 | return MODE 42 | end 43 | end 44 | 45 | function CMD.cancel(uid) 46 | print("cancel match", uid) 47 | local info = uid2info[uid] 48 | if not info then 49 | skynet.error(uid, "not matching") 50 | return 51 | end 52 | uid2info[uid] = nil 53 | end 54 | 55 | -- 最粗暴的匹配算法 56 | local function update() 57 | if next(uid2info) then 58 | print("matching") 59 | --print(bewater.dump(uid2info)) 60 | end 61 | local cur_time = os.time() 62 | for uid, info in pairs(uid2info) do 63 | local value = info.value 64 | if cur_time - values[value][uid] > MAX_TIME then 65 | info.ret = skynet.call("usercenter", "lua", "create_robot", value) -- 这个服务需要自定义 66 | else 67 | local list = {values[value]} 68 | for i = 1, MAX_RANGE do 69 | list[#list+1] = values[value - i] 70 | list[#list+1] = values[value + i] 71 | end 72 | for _, vs in pairs(list) do 73 | for u, _ in pairs(vs) do 74 | if uid2info[u] and uid2info[u].ret < 0 and u ~= uid then 75 | uid2info[u].ret = uid 76 | info.ret = u 77 | break 78 | end 79 | end 80 | if info.ret >= 0 then 81 | break 82 | end 83 | end 84 | end 85 | end 86 | 87 | for uid, info in pairs(uid2info) do 88 | if info.ret >= 0 then 89 | -- 随机位置 90 | local list = {uid, info.ret} 91 | local r = math.random(2) 92 | local id1 = list[r] 93 | local id2 = list[r==1 and 2 or 1] 94 | if uid2info[id1] then 95 | bewater.try(function() 96 | skynet.call(uid2info[id1].agent, "lua", id1, "battle", "matched", MODE, id2) 97 | end) 98 | end 99 | if uid2info[id2] then 100 | bewater.try(function() 101 | skynet.call(uid2info[id2].agent, "lua", id2, "battle", "matched", MODE, id1) 102 | end) 103 | end 104 | -- 创建战斗 105 | local battle_id, battle_agent = skynet.call("battlecenter", "lua", "create_battle") 106 | skynet.call(battle_agent, "lua", "create", battle_id, MODE) 107 | for idx, id in pairs({id1, id2}) do 108 | local matched = uid2info[id] 109 | skynet.call(battle_agent, "lua", "call_battle", battle_id, "join", 110 | id, idx, matched and matched.agent or nil) 111 | if uid2info[id] then 112 | uid2info[id] = nil 113 | values[matched.value][id] = nil 114 | end 115 | end 116 | end 117 | end 118 | end 119 | 120 | skynet.start(function() 121 | skynet.dispatch("lua", function(_, _, cmd, ...) 122 | local f = assert(CMD[cmd], cmd) 123 | bewater.ret(f(...)) 124 | end) 125 | 126 | skynet.fork(function() 127 | while true do 128 | bewater.try(function() 129 | update() 130 | end) 131 | skynet.sleep(50) 132 | end 133 | end) 134 | end) 135 | -------------------------------------------------------------------------------- /service/battle/matchcenter.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local bewater = require "bw.bewater" 3 | 4 | local addrs = {} -- mode -> service 5 | 6 | local CMD = {} 7 | function CMD.add_mode(mode, max_time, max_range) 8 | assert(not addrs[mode]) 9 | addrs[mode] = skynet.newservice("battle/match") 10 | skynet.call(addrs[mode], "lua", "init", mode, max_time, max_range) 11 | end 12 | 13 | function CMD.match(mode, uid, value, agent) 14 | local addr = assert(addrs[mode]) 15 | skynet.call(addr, "lua", "start", uid, value, agent) 16 | end 17 | 18 | function CMD.reconnect(mode, uid, agent) 19 | local addr = assert(addrs[mode]) 20 | skynet.call(addr, "lua", "reconnect", uid, agent) 21 | end 22 | 23 | function CMD.cancel(mode, uid) 24 | local addr = assert(addrs[mode]) 25 | skynet.call(addr, "lua", "cancel", uid) 26 | end 27 | 28 | skynet.start(function() 29 | skynet.dispatch("lua", function(_, _, cmd, ...) 30 | local f = assert(CMD[cmd], cmd) 31 | bewater.ret(f(...)) 32 | end) 33 | end) 34 | -------------------------------------------------------------------------------- /service/battle/watchdog.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local autoid = require "bw.share.autoid" 3 | local bewater = require "bw.bewater" 4 | 5 | local agents = {} 6 | local id2agent = {} -- battle_id -> agent 7 | local balance = 1 8 | 9 | local CMD = {} 10 | function CMD.init(battle_path, preload) 11 | preload = preload or 10 12 | for i = 1, preload do 13 | agents[i] = skynet.newservice("battle/agent", battle_path) 14 | end 15 | end 16 | 17 | function CMD.create_battle() 18 | balance = balance + 1 19 | if balance > #agents then 20 | balance = 1 21 | end 22 | local battle_id = autoid.create() 23 | local agent = agents[balance] 24 | id2agent[battle_id] = agent 25 | return battle_id, agent 26 | end 27 | 28 | function CMD.destroy_battle(battle_id) 29 | local agent = id2agent[battle_id] 30 | skynet.call(agent, "lua", "destroy", battle_id) 31 | id2agent[battle_id] = nil 32 | end 33 | 34 | skynet.start(function() 35 | skynet.dispatch("lua", function(_,_, cmd, ...) 36 | local f = assert(CMD[cmd], cmd) 37 | bewater.ret(f(...)) 38 | end) 39 | end) 40 | 41 | -------------------------------------------------------------------------------- /service/db/mongod.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | local mongo = require "skynet.db.mongo" 3 | local util = require "bw.util" 4 | local conf = require "conf" 5 | 6 | local mod = ... 7 | 8 | if mod == "agent" then 9 | 10 | local db 11 | local CMD = {} 12 | function CMD.find_one(name, query, selector) 13 | local data = db[name]:findOne(query, selector) 14 | return util.str2num(data) 15 | end 16 | 17 | function CMD.find_one_with_default(name, query, default, selector) 18 | local data = db[name]:findOne(query, selector) 19 | if not data then 20 | CMD.insert(name, default) 21 | return default 22 | end 23 | return util.str2num(data) 24 | end 25 | 26 | -- todo 此方法返回可能大于消息长度 27 | function CMD.find(name, query, selector) 28 | local ret = db[name]:find(query, selector) 29 | local data = {} 30 | while ret:hasNext() do 31 | table.insert(data, ret:next()) 32 | end 33 | return util.str2num(data) 34 | end 35 | 36 | function CMD.update(name, query_tbl, update_tbl) 37 | update_tbl = util.num2str(update_tbl) 38 | local ok, err, r = db[name]:findAndModify({query = query_tbl, update = update_tbl}) 39 | if not ok then 40 | skynet.error("mongo update error") 41 | util.printdump(r) 42 | error(err) 43 | end 44 | return true 45 | end 46 | 47 | function CMD.insert(name, tbl) 48 | tbl = util.num2str(tbl) 49 | local ok, err, r = db[name]:safe_insert(tbl) 50 | if not ok then 51 | skynet.error("mongo update error") 52 | util.printdump(r) 53 | error(err) 54 | end 55 | return true 56 | end 57 | 58 | function CMD.delete(name, query_tbl) 59 | db[name]:delete(query_tbl) 60 | return true 61 | end 62 | 63 | function CMD.drop(name) 64 | return db[name]:drop() 65 | end 66 | 67 | function CMD.get(key, default) 68 | local ret = db.global:findOne({key = key}) 69 | if ret then 70 | return util.str2num(ret.value) 71 | else 72 | db.global:safe_insert({key = key, value = default}) 73 | return default 74 | end 75 | end 76 | 77 | function CMD.set(key, value) 78 | db.global:findAndModify({ 79 | query = {key = key}, 80 | update = {key = key, value = value}, 81 | }) 82 | end 83 | 84 | skynet.start(function() 85 | db = mongo.client(conf.mongo)[conf.mongo.name] 86 | skynet.dispatch("lua", function(_, _, cmd, ...) 87 | local f = assert(CMD[cmd], ...) 88 | util.ret(f(...)) 89 | end) 90 | end) 91 | 92 | else 93 | 94 | skynet.start(function() 95 | local preload = conf.preload or 10 96 | local agent = {} 97 | for i = 1, preload do 98 | agent[i] = skynet.newservice(SERVICE_NAME, "agent") 99 | end 100 | local balance = 1 101 | skynet.dispatch("lua", function(_,_, ...) 102 | balance = balance + 1 103 | if balance > #agent then 104 | balance = 1 105 | end 106 | local ret = skynet.call(agent[balance], "lua", ...) 107 | util.ret(ret) 108 | end) 109 | end) 110 | 111 | end 112 | -------------------------------------------------------------------------------- /service/db/mysqld.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | local mysql = require "skynet.db.mysql" 3 | local bewater = require "bw.bewater" 4 | local util = require "bw.util" 5 | local Conf = require "conf" 6 | 7 | local mod = ... 8 | 9 | if mod == "agent" then 10 | 11 | local db 12 | skynet.start(function() 13 | local function on_connect(_db) 14 | _db:query("set charset utf8") 15 | end 16 | db=mysql.connect({ 17 | host=Conf.mysql.host, 18 | port=Conf.mysql.port, 19 | database=Conf.mysql.name, 20 | user=Conf.mysql.user, 21 | password=Conf.mysql.password, 22 | max_packet_size = 1024 * 1024, 23 | on_connect = on_connect 24 | }) 25 | skynet.dispatch("lua", function(_, _, cmd, ...) 26 | local f = assert(db[cmd]) 27 | local ret = f(db, ...) 28 | assert(not ret.err,string.format("mysql error:%s\n%s", table.pack(...)[1], util.dump(ret))) 29 | bewater.ret(ret) 30 | end) 31 | end) 32 | 33 | else 34 | 35 | skynet.start(function() 36 | local preload = Conf.preload or 10 37 | local agent = {} 38 | for i = 1, preload do 39 | agent[i] = skynet.newservice(SERVICE_NAME, "agent") 40 | end 41 | local balance = 1 42 | skynet.dispatch("lua", function(_,_, ...) 43 | balance = balance + 1 44 | if balance > #agent then 45 | balance = 1 46 | end 47 | local ret = skynet.call(agent[balance], "lua", ...) 48 | bewater.ret(ret) 49 | end) 50 | end) 51 | 52 | end 53 | -------------------------------------------------------------------------------- /service/db/redisd.lua: -------------------------------------------------------------------------------- 1 | local Skynet = require "skynet.manager" 2 | local Redis = require "skynet.db.redis" 3 | local bewater = require "bw.bewater" 4 | local conf = require "conf" 5 | 6 | local mod = ... 7 | 8 | if mod == "agent" then 9 | 10 | local db 11 | Skynet.start(function() 12 | db = Redis.connect(conf.redis) 13 | Skynet.dispatch("lua", function(_, _, cmd, ...) 14 | bewater.ret(db[cmd](db, ...)) 15 | end) 16 | end) 17 | 18 | else 19 | 20 | Skynet.start(function() 21 | local preload = conf.preload or 10 22 | local agent = {} 23 | for i = 1, preload do 24 | agent[i] = Skynet.newservice(SERVICE_NAME, "agent") 25 | end 26 | local balance = 1 27 | Skynet.dispatch("lua", function(_,_, ...) 28 | balance = balance + 1 29 | if balance > #agent then 30 | balance = 1 31 | end 32 | local ret = Skynet.call(agent[balance], "lua", ...) 33 | bewater.ret(ret) 34 | end) 35 | end) 36 | 37 | end 38 | -------------------------------------------------------------------------------- /service/gm.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local log = require "bw.log" 3 | local schedule = require "bw.schedule" 4 | local bewater = require "bw.bewater" 5 | local date_helper = require "bw.util.date_helper" 6 | 7 | require "skynet.cluster" 8 | 9 | local trace = log.trace("gm") 10 | 11 | local skynet_cmd = {} 12 | local gmcmd = { 13 | skynet = skynet_cmd, 14 | } 15 | local CMD = {} 16 | function CMD.add_gmcmd(modname, gmcmd_path) 17 | gmcmd[modname] = require(gmcmd_path) 18 | end 19 | 20 | function CMD.run(modname, cmd, ...) 21 | modname = string.lower(modname) 22 | cmd = string.lower(cmd) 23 | local mod = gmcmd[modname] 24 | if not mod then 25 | return string.format("模块[%s]未初始化", modname) 26 | end 27 | local f = mod[cmd] 28 | if not f then 29 | return string.format("GM指令[%s][%s]不存在", modname, cmd) 30 | end 31 | local args = {...} 32 | local ret 33 | if not bewater.try(function() 34 | ret = f(table.unpack(args)) 35 | end) then 36 | return "服务器执行TRACEBACK了" 37 | end 38 | return ret or "执行成功" 39 | end 40 | 41 | local hotfix_addrs = {} 42 | function CMD.reg_hotfix(addr) 43 | --trace("reg_hotfix:%s", addr) 44 | hotfix_addrs[addr] = true 45 | end 46 | 47 | function CMD.unreg_hotfix(addr) 48 | hotfix_addrs[addr] = nil 49 | end 50 | 51 | skynet.start(function() 52 | skynet.dispatch("lua", function(_,_, cmd, ...) 53 | local f = assert(CMD[cmd], cmd) 54 | bewater.ret(f(...)) 55 | end) 56 | end) 57 | 58 | function skynet_cmd.gc() 59 | skynet.call(".launcher", "lua", "GC") 60 | end 61 | 62 | function skynet_cmd.call(addr, ...) 63 | addr = tonumber(addr, 16) or assert(addr) 64 | print("call", addr, ...) 65 | return skynet.call(addr, "lua", ...) 66 | end 67 | 68 | function skynet_cmd.list() 69 | local list = {} 70 | local all = skynet.call(".launcher", "lua", "LIST") 71 | for addr, desc in pairs(all) do 72 | table.insert(list, {addr = addr, desc = desc}) 73 | end 74 | 75 | for i, v in ipairs(list) do 76 | local addr = v.addr 77 | v.mem = skynet.call(addr, "debug", "MEM") 78 | if v.mem < 1024 then 79 | v.mem = math.floor(v.mem).." Kb" 80 | else 81 | v.mem = math.floor(v.mem/1024).." Mb" 82 | end 83 | 84 | local stat = skynet.call(addr, "debug", "STAT") 85 | v.task = stat.task 86 | v.mqlen = stat.mqlen 87 | v.id = i 88 | v.address = skynet.address(addr) 89 | end 90 | table.sort(list, function(a, b) 91 | return a.addr < b.addr 92 | end) 93 | local str = "" 94 | for i, v in ipairs(list) do 95 | str = str .. string.format("地址:%s 内存:%s 消息队列:%s 请求量:%s 启动命令:%s\n", 96 | v.addr, v.mem, v.mqlen, v.task, v.desc) 97 | end 98 | return str 99 | end 100 | 101 | function skynet_cmd.hotfix() 102 | trace("gm hotfix") 103 | for addr, _ in pairs(hotfix_addrs) do 104 | skynet.send(addr, "lua", "hotfix") 105 | end 106 | end 107 | 108 | function skynet_cmd.publish(nodename) 109 | trace("publish:%s", nodename) 110 | skynet.newservice("publish", nodename) 111 | end 112 | 113 | function skynet_cmd.alert() 114 | error("test alert") 115 | end 116 | 117 | function skynet_cmd.time(...) 118 | trace("gm time") 119 | local args = table.pack(...) 120 | local t = {} 121 | for i = 1, #args, 2 do 122 | t[args[i]] = tonumber(args[i+1]) 123 | end 124 | local cur = schedule.changetime(t) 125 | return string.format("时间修改至 %s", date_helper.format(cur)) 126 | end 127 | -------------------------------------------------------------------------------- /service/logger.lua: -------------------------------------------------------------------------------- 1 | -- 文件fd,保存一段时间,自动关闭 2 | -- 系统log分系统存, 一天一份日志 3 | -- 玩家log分uid存,一天一份日志 4 | -- 5 | 6 | local skynet = require "skynet.manager" 7 | local date_helper = require "bw.util.date_helper" 8 | local conf = require "conf" 9 | local sname = require "bw.sname" 10 | local bash = require "bw.bash" 11 | 12 | local mainfile = io.open(string.format("%s/log/%s.log", 13 | conf.workspace, conf.clustername), "w+") 14 | local errfile = io.open(string.format("%s/log/error.log", 15 | conf.workspace), "a+") 16 | 17 | local function write_log(file, addr, str) 18 | str = string.format("[%08x][%s] %s", addr, os.date("%Y-%m-%d %H:%M:%S", os.time()), str) 19 | if string.match(str, "\n(%w+ %w+)") == "stack traceback" then 20 | if conf.alert and conf.alert.enable then 21 | skynet.send(sname.ALERT, "lua", "traceback", str) 22 | end 23 | errfile:write(str.."\n") 24 | errfile:flush() 25 | end 26 | 27 | if file == mainfile or file == errfile then 28 | print(str) 29 | end 30 | 31 | file:write(str.."\n") 32 | file:flush() 33 | end 34 | 35 | local logs = {} -- key(sys or uid) -> {last_time, file} 36 | local CMD = {} 37 | function CMD.error(addr, str) 38 | write_log(errfile, addr, str) 39 | end 40 | 41 | function CMD.trace(addr, sys, str) 42 | str = string.format("[%s] %s", sys, str) 43 | local log = logs[sys] 44 | if not log or date_helper.is_sameday(os.time(), log.last_time) then 45 | if log then 46 | log.file:close() 47 | end 48 | bash.bash("mkdir -p %s/log/%s", conf.workspace, sys) 49 | local filename = string.format("%s/log/%s/%s.log", 50 | conf.workspace, sys, os.date("%Y%m%d", os.time())) 51 | local file = io.open(filename, "a+") 52 | log = {file = file} 53 | logs[sys] = log 54 | end 55 | log.last_time = os.time() 56 | 57 | write_log(log.file, addr, str) 58 | write_log(mainfile, addr, str) 59 | end 60 | 61 | function CMD.player(addr, uid, str) 62 | str = string.format("[%d] %s", uid, str) 63 | local log = logs[uid] 64 | if not log or date_helper.is_sameday(os.time(), log.last_time) then 65 | if log then 66 | log.file:close() 67 | end 68 | local dir = string.format("%d/%d/%d", uid//1000000, uid%1000000//1000, uid%1000) 69 | bash.bash("mkdir -p %s/log/player/%s", conf.workspace, dir) 70 | local filename = string.format("%s/log/player/%s/%s.log", 71 | conf.workspace, dir, os.date("%Y%m%d", os.time())) 72 | local file = io.open(filename, "a+") 73 | log = {file = file} 74 | logs[uid] = log 75 | end 76 | log.last_time = os.time() 77 | 78 | write_log(log.file, addr, str) 79 | write_log(mainfile, addr, str) 80 | end 81 | 82 | local sighup_addr = nil 83 | function CMD.register_sighup(addr) 84 | assert(not sighup_addr, "already register sighup") 85 | sighup_addr = addr 86 | end 87 | 88 | skynet.register_protocol { 89 | name = "text", 90 | id = skynet.PTYPE_TEXT, 91 | unpack = skynet.tostring, 92 | dispatch = function(_, addr, str) 93 | write_log(mainfile, addr, str) 94 | end 95 | } 96 | 97 | -- 捕捉sighup信号(kill -1) 98 | skynet.register_protocol { 99 | name = "SYSTEM", 100 | id = skynet.PTYPE_SYSTEM, 101 | unpack = function(...) return ... end, 102 | dispatch = function() 103 | -- reopen signal 104 | if sighup_addr then 105 | skynet.send(sighup_addr, "lua", "SIGHUP") 106 | else 107 | skynet.error("handle SIGHUP, skynet will be stop") 108 | skynet.abort() 109 | end 110 | end 111 | } 112 | 113 | skynet.start(function() 114 | skynet.register ".logger" 115 | skynet.dispatch("lua", function(_, _, cmd, ...) 116 | assert(CMD[cmd], cmd)(...) 117 | -- no return, don't call this service, use send 118 | end) 119 | skynet.fork(function() 120 | while true do 121 | local cur_time = os.time() 122 | for k, v in pairs(logs) do 123 | if cur_time - v.last_time > 3600 then 124 | v.file:close() 125 | logs[k] = nil 126 | end 127 | end 128 | skynet.sleep(100) 129 | end 130 | end) 131 | end) 132 | -------------------------------------------------------------------------------- /service/operate.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local cluster = require "skynet.cluster" 3 | local mongo = require "bw.db.mongo_helper" 4 | local bewater = require "bw.bewater" 5 | local log = require "bw.log" 6 | 7 | local trace = log.trace("operate") 8 | 9 | local M = {} 10 | function M:init() 11 | self.batch_list = mongo.get("batch_operate") or {} 12 | self.players = mongo.find("operate", {}) or {} 13 | end 14 | 15 | function M:save_batch() 16 | mongo.set("batch_operate", self.batch_list) 17 | end 18 | 19 | function M:save_player(uid) 20 | local player = self.players[uid] 21 | if not player then return end 22 | return mongo.update("operate", {uid = uid}, { 23 | uid = player.uid, 24 | time = player.time, 25 | operate_list = player.operate_list, 26 | }) 27 | end 28 | 29 | function M:remove_player(uid) 30 | self.players[uid] = nil 31 | mongo.delete("operate", {uid = uid}) 32 | end 33 | 34 | function M:get_player(uid) 35 | local player = self.players[uid] 36 | if not player then 37 | local data = mongo.find_one_with_default("operate", {uid = uid}, { 38 | uid = uid, 39 | time = os.time(), 40 | operate_list = {}, 41 | }) 42 | player = { 43 | uid = data.uid, 44 | time = data.time, 45 | operate_list = data.operate_list, 46 | } 47 | self.players[uid] = player 48 | trace("load player:%d", uid) 49 | end 50 | return player 51 | end 52 | 53 | function M:online(uid, cname, agent) 54 | local player = self:get_player(uid) 55 | player.cname = cname 56 | player.agent = agent 57 | 58 | local operate_list = player.operate_list or {} 59 | player.operate_list = {} 60 | 61 | for k, v in ipairs(self.batch_list) do 62 | if v.time > player.time then 63 | table.insert(operate_list, v) 64 | end 65 | end 66 | player.time = os.time() 67 | self:save_player(uid) 68 | return operate_list 69 | end 70 | 71 | function M:offline(uid) 72 | local player = self:get_player(uid) 73 | player.cname = nil 74 | player.agent = nil 75 | end 76 | 77 | -- 批量操作(离线&在线) 78 | function M:batch_operate(code, ...) 79 | local operate = { 80 | code = code, 81 | time = os.time(), 82 | params = table.pack(...) 83 | } 84 | table.insert(self.batch_list, operate) 85 | self:save_batch() 86 | for _, player in pairs(self.players) do 87 | if player.agent then 88 | self:operate(player.uid, code, ...) 89 | end 90 | end 91 | end 92 | 93 | -- 广播(针对在线玩家, id_list空表示全服广播) 94 | function M:broadcast_operate(id_list, code, ...) 95 | for _, v in pairs(id_list or self.players) do 96 | local player = type(v) == "table" and v or self.players[v] 97 | if player and player.agent then 98 | self:operate(player.uid, code, ...) 99 | end 100 | end 101 | end 102 | 103 | function M:operate(uid, code, ...) 104 | assert(type(uid) == "number" and type(code) == "number") 105 | -- 玩家在线 106 | local params = table.pack(...) 107 | local player = self:get_player(uid) 108 | if not player then 109 | return false 110 | end 111 | if player.agent then 112 | local ret = bewater.try(function() 113 | cluster.call(player.cname, player.agent, uid, "operate", "operate", code, table.unpack(params)) 114 | player.time = os.time() 115 | self:save_player(uid) 116 | end) 117 | if not ret then 118 | player.cname = nil 119 | player.agent = nil 120 | end 121 | return ret 122 | end 123 | 124 | -- 玩家离线 125 | local operate = { 126 | code = code, 127 | time = os.time(), 128 | params = params 129 | } 130 | table.insert(player.operate_list, operate) 131 | self:save_player(uid) 132 | return true 133 | end 134 | 135 | skynet.start(function() 136 | skynet.dispatch("lua", function(_, _, cmd, ...) 137 | local f = assert(M[cmd], cmd) 138 | bewater.ret(f(M, ...)) 139 | end) 140 | 141 | M:init() 142 | 143 | trace("start operate") 144 | 145 | skynet.register "operate" 146 | end) 147 | -------------------------------------------------------------------------------- /service/passport.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | local bewater = require "bw.util" 3 | local uuid = require "bw.uuid" 4 | 5 | local string_gsub = string.gsub 6 | local uid2passport = {} 7 | local passport2uid = {} 8 | 9 | local CMD = {} 10 | function CMD.create(uid) 11 | local passport = uid2passport[uid] 12 | if passport then 13 | passport2uid[passport] = nil 14 | end 15 | while true do 16 | passport = string_gsub(uuid(), '-', '') 17 | if not passport2uid[passport] then 18 | break 19 | end 20 | end 21 | uid2passport[uid] = passport 22 | passport2uid[passport] = uid 23 | return passport 24 | end 25 | 26 | function CMD.get_uid(passport) 27 | return passport2uid[passport] 28 | end 29 | 30 | function CMD.get_passport(uid) 31 | return uid2passport[uid] 32 | end 33 | 34 | skynet.start(function() 35 | skynet.dispatch("lua", function(_,_, cmd, ...) 36 | local f = assert(CMD[cmd], cmd) 37 | bewater.ret(f(...)) 38 | end) 39 | skynet.register "passport" 40 | end) 41 | -------------------------------------------------------------------------------- /service/proto_env.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | local bewater = require "bw.bewater" 3 | 4 | local CMD = {} 5 | function CMD.get_protobuf_env() 6 | return debug.getregistry().PROTOBUF_ENV 7 | end 8 | function CMD.register_file(path) 9 | local protobuf_c = require "protobuf.c" 10 | debug.getregistry().PROTOBUF_ENV = protobuf_c._env_new() 11 | local protobuf = require "bw.protobuf" 12 | protobuf.register_file(path) 13 | end 14 | 15 | skynet.start(function() 16 | skynet.dispatch("lua", function(_,_,cmd, ...) 17 | local f = assert(CMD[cmd]) 18 | bewater.ret(f(...)) 19 | end) 20 | 21 | end) 22 | -------------------------------------------------------------------------------- /service/publish.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local conf = require "conf" 3 | local util = require "bw.util" 4 | local bash = require "bw.bash" 5 | bash = bash.bash 6 | 7 | local nodename = require "publish.nodename" 8 | 9 | local function publish(pconf, confname) 10 | if conf.remote_host then 11 | skynet.error("请在开发模式下发布!") 12 | return 13 | end 14 | skynet.error("正在发布"..confname) 15 | skynet.error("创建临时目录") 16 | bash "rm -rf ../tmp" 17 | 18 | local tmp = "../tmp/"..confname 19 | local bewater = "../bewater" 20 | local projname = string.match(bash("cd %s && pwd", conf.workspace), "(%w+)$") 21 | local proj = tmp.."/proj/"..projname 22 | bash("mkdir -p %s", tmp) 23 | bash("cd %s && mkdir -p skynet bewater proj/%s", tmp, projname) 24 | bash("cp -r skynet luaclib lualib service cservice %s/skynet", tmp) 25 | bash("cp -r %s/lualib %s/luaclib %s/service %s/bewater", bewater, bewater, bewater, tmp) 26 | bash("cp -r %s/etc %s/script %s/service %s/shell %s", 27 | conf.workspace, conf.workspace, conf.workspace, conf.workspace, proj) 28 | 29 | -- 配置文件 30 | pconf.workspace = string.format("%s/proj/%s/", pconf.remote_path, projname) 31 | local str = "return ".. util.dump(pconf) 32 | local file = io.open(proj.."/script/conf.lua", "w+") 33 | file:write(str) 34 | file:close() 35 | 36 | file = io.open(proj.."/etc/"..pconf.etcname..".cfg", "r") 37 | str = file:read("*a") 38 | file:close() 39 | str = string.gsub(str, "workspace = [^\n]+", string.format('workspace = "../proj/%s/"', projname)) 40 | str = string.gsub(str, "clustername = [^\n]+", string.format('clustername = "%s"', pconf.clustername)) 41 | file = io.open(proj.."/etc/"..pconf.etcname..".cfg", "w") 42 | file:write(str) 43 | file:close() 44 | 45 | -- 启动脚本 46 | str = string.format("sh %s/proj/%s/shell/run.sh %s", pconf.remote_path, projname, pconf.etcname) 47 | bash("echo %s > %s/run.sh", str, tmp) 48 | bash("chmod 775 %s/run.sh", tmp) 49 | 50 | -- 停机脚本 51 | str = string.format("sh %s/proj/%s/shell/kill.sh %s", pconf.remote_path, projname, pconf.etcname) 52 | bash("echo %s > %s/kill.sh", str, tmp) 53 | bash("chmod 775 %s/kill.sh", tmp) 54 | 55 | -- 日志脚本 56 | str = string.format("sh %s/proj/%s/shell/log.sh %s", pconf.remote_path, projname, pconf.clustername) 57 | bash("echo %s > %s/log.sh", str, tmp) 58 | bash("chmod 775 %s/log.sh", tmp) 59 | 60 | if string.match(pconf.remote_host, "localhost") then 61 | -- 发布到本地 62 | skynet.error("正在关闭远程服务器") 63 | bash("sh %s/kill.sh", pconf.remote_path) 64 | skynet.sleep(200) 65 | bash("mkdir -p %s", pconf.remote_path) 66 | skynet.error("正在推送到远程服务器") 67 | bash("cp -r %s/* %s ", tmp, pconf.remote_path) 68 | skynet.error("正在重新启动远程服务器") 69 | bash("sh %s/run.sh", pconf.remote_path) 70 | else 71 | -- 发布到远程 72 | skynet.error("正在关闭远程服务器") 73 | bash("ssh -p %s %s sh %s/kill.sh", pconf.remote_port, pconf.remote_host, pconf.remote_path) 74 | skynet.sleep(200) 75 | bash("ssh -p %s %s mkdir -p %s", pconf.remote_port, pconf.remote_host, pconf.remote_path) 76 | skynet.error("正在推送到远程服务器") 77 | bash("scp -rpB -P %s %s/* %s:%s ", pconf.remote_port, tmp, pconf.remote_host, pconf.remote_path) 78 | skynet.error("正在重新启动远程服务器") 79 | bash("ssh -p %s %s sh %s/run.sh", pconf.remote_port, pconf.remote_host, pconf.remote_path) 80 | end 81 | 82 | -- 删除临时目录 83 | bash "rm -rf ../tmp" 84 | skynet.error("发布完成") 85 | end 86 | 87 | skynet.start(function() 88 | if nodename == "all" then 89 | local ret = bash("cd %s/script/publish/conf && ls", conf.workspace) 90 | for filename in string.gmatch(ret, "([^\n]+).lua") do 91 | local pconf = require("publish.conf."..filename) 92 | publish(pconf, filename) 93 | end 94 | else 95 | local pconf = require("publish.conf."..nodename) 96 | publish(pconf, nodename) 97 | end 98 | end) 99 | -------------------------------------------------------------------------------- /service/report.lua: -------------------------------------------------------------------------------- 1 | -- 向monitor节点报告本节点性能,状态等(已废置) 2 | -- 3 | local skynet = require "skynet" 4 | local cluster = require "skynet.cluster" 5 | local info = require "bw.util.clusterinfo" 6 | local conf = require "conf" 7 | local bewater = require "bw.bewater" 8 | local log = require "bw.log" 9 | local print = log.print("report") 10 | 11 | local function send(...) 12 | print("send", conf.clustername.monitor, ...) 13 | cluster.send("monitor", "svr", ...) 14 | end 15 | 16 | local function call(...) 17 | print("call", conf.clustername.monitor, ...) 18 | cluster.call("monitor", "svr", ...) 19 | end 20 | 21 | local name = info.clustername 22 | local addr = conf.cluster[name] 23 | 24 | local CMD = {} 25 | function CMD.start() 26 | bewater.try(function() 27 | call("node_start", name, addr, conf.proj, info.pnet_addr, info.inet_addr, 28 | info.pid, string.format("%s:%s", conf.webconsole.host, conf.webconsole.port)) 29 | cluster.call("share", "svr", "node_start", name, addr) -- 向share上报集群配置 30 | end) 31 | skynet.fork(function() 32 | while true do 33 | CMD.ping() 34 | skynet.sleep(100) 35 | end 36 | end) 37 | end 38 | 39 | function CMD.ping() 40 | if not info.pid then 41 | send("node_ping", addr, 0, 0) 42 | return 43 | end 44 | 45 | local profile = info.profile 46 | bewater.try(function() 47 | send("node_ping", addr, profile.cpu, profile.mem) 48 | end) 49 | end 50 | 51 | function CMD.stop() 52 | bewater.try(function() 53 | send("node_stop", addr) 54 | end) 55 | end 56 | 57 | skynet.start(function() 58 | skynet.dispatch("lua", function(_,_, cmd, ...) 59 | local f = assert(CMD[cmd], cmd) 60 | bewater.ret(f(...)) 61 | end) 62 | end) 63 | -------------------------------------------------------------------------------- /service/sock/agent.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local packet = require "bw.sock.packet" 3 | local bewater = require "bw.bewater" 4 | local protobuf = require "bw.protobuf" 5 | local log = require "bw.log" 6 | 7 | local trace = log.trace("agent") 8 | 9 | local player_path = ... 10 | local player_t = require(player_path) 11 | 12 | local WATCHDOG 13 | local GATE 14 | local MAX_COUNT 15 | 16 | local CMD = {} 17 | local fd2player = {} 18 | local uid2player = {} 19 | local count = 0 20 | 21 | skynet.register_protocol { 22 | name = "client", 23 | id = skynet.PTYPE_CLIENT, 24 | unpack = function (buff, sz) 25 | return packet.unpack(buff, sz) 26 | end, 27 | dispatch = function (fd, _, ...) 28 | skynet.ignoreret() -- session is fd, don't call skynet.ret 29 | local player = assert(fd2player[fd], "player not exist, fd:"..fd) 30 | player.net:recv(...) 31 | end 32 | } 33 | 34 | function CMD.init(gate, watchdog, max_count, proto) 35 | GATE = assert(gate) 36 | WATCHDOG = assert(watchdog) 37 | MAX_COUNT = max_count or 100 38 | protobuf.register_file(proto) 39 | end 40 | 41 | function CMD.stop() 42 | for _, player in pairs(uid2player) do 43 | bewater.try(function() 44 | player:offline() 45 | end) 46 | end 47 | skynet.call(WATCHDOG, "lua", "free_agent", skynet.self()) 48 | end 49 | 50 | -- from watchdog 51 | function CMD.new_player(fd, ip) 52 | local player = player_t.new() 53 | player.net:init(WATCHDOG, GATE, skynet.self(), fd, ip) 54 | fd2player[fd] = player 55 | skynet.call(GATE, "lua", "forward", fd) 56 | count = count + 1 57 | return count >= MAX_COUNT 58 | end 59 | 60 | -- from watchdog 61 | function CMD.socket_close(_, fd) 62 | local player = assert(fd2player[fd], fd) 63 | trace("socket_close player:%s, old_fd:%s, new_fd:%s", player, player.net:get_fd(), fd) 64 | if player.net:get_fd() == fd then 65 | player:offline() 66 | end 67 | fd2player[fd] = nil 68 | end 69 | 70 | -- from player 71 | function CMD.player_online(uid, fd) 72 | local player = assert(fd2player[fd]) 73 | trace("player_online, player:%s, uid:%s, fd:%s", player, uid, fd) 74 | uid2player[uid] = player 75 | end 76 | 77 | -- from player 78 | function CMD.free_player(uid) 79 | trace("free_player, player:%s, uid:%s", uid2player[uid], uid) 80 | uid2player[uid] = nil 81 | if count == MAX_COUNT then 82 | skynet.call(WATCHDOG, "lua", "set_free", skynet.self()) 83 | end 84 | count = count - 1 85 | end 86 | 87 | function CMD.reconnect(fd, uid, csn, ssn, passport, user_info) 88 | local player = uid2player[uid] 89 | if not player then 90 | return 91 | end 92 | --local old_fd = player.net:get_fd() 93 | if player.net:reconnect(fd, csn, ssn, passport, user_info) then 94 | --fd2player[old_fd] = nil 95 | fd2player[fd] = player 96 | skynet.call(GATE, "lua", "forward", fd) 97 | return player:base_data() 98 | end 99 | end 100 | 101 | function CMD.kick(uid) 102 | local player = uid2player[uid] 103 | if player then 104 | player:kickout() 105 | uid2player[uid] = nil 106 | end 107 | end 108 | 109 | local function check_timeout() 110 | for _, player in pairs(uid2player) do 111 | if player.check_timeout then 112 | bewater.try(function() 113 | player:check_timeout() 114 | end) 115 | end 116 | end 117 | end 118 | 119 | function CMD.online_count() 120 | local i = 0 121 | for _, player in pairs(uid2player) do 122 | if player.is_online then 123 | --trace("player online, player:%s, uid:%s", player, player.uid) 124 | i = i + 1 125 | end 126 | end 127 | return i 128 | end 129 | 130 | 131 | skynet.start(function() 132 | skynet.dispatch("lua", function(_, _, arg1, arg2, arg3, ...) 133 | local f = CMD[arg1] 134 | if f then 135 | bewater.ret(f(arg2, arg3, ...)) 136 | else 137 | --local player = assert(uid2player[arg1], string.format("%s %s %s", arg1, arg2, arg3)) 138 | local player = uid2player[arg1] 139 | if not player then 140 | -- todo fix this bug 141 | return bewater.ret() 142 | end 143 | local module = assert(player[arg2], arg2) 144 | if type(module) == "function" then 145 | bewater.ret(module(player, arg3, ...)) 146 | else 147 | bewater.ret(module[arg3](module, ...)) 148 | end 149 | end 150 | end) 151 | 152 | -- 定时检查超时,一分钟误差,如需要精准的触发,使用日程表schedule 153 | skynet.fork(function() 154 | while true do 155 | check_timeout() 156 | skynet.sleep(60*100) 157 | end 158 | end) 159 | end) 160 | -------------------------------------------------------------------------------- /service/sock/watchdog.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local bewater = require "bw.bewater" 3 | local log = require "bw.log" 4 | 5 | local trace = log.trace("watchdog") 6 | 7 | local server_path, player_path = ... 8 | assert(server_path) -- 服务器逻辑(xxx.xxxserver) 9 | assert(player_path) -- 玩家逻辑(xxx.xxxplayer_t) 10 | 11 | local server = require(server_path) 12 | 13 | local GATE 14 | local fd2uid = {} 15 | local uid2agent = {} -- 每个玩家对应的agent 16 | local free_agents = {} -- 空闲的agent addr -> true 17 | local full_agents = {} -- 满员的agent addr -> true 18 | 19 | local PLAYER_PER_AGENT -- 每个agent支持player最大值 20 | local PROTO 21 | 22 | local function create_agent() 23 | local agent = skynet.newservice("sock/agent", player_path) 24 | skynet.call(agent, "lua", "init", GATE, skynet.self(), PLAYER_PER_AGENT, PROTO) 25 | free_agents[agent] = true 26 | return agent 27 | end 28 | 29 | local SOCKET = {} 30 | function SOCKET.open(fd, addr) 31 | trace("New client from : " .. addr, fd) 32 | local agent = next(free_agents) 33 | if not agent then 34 | agent = create_agent() 35 | end 36 | local is_full = skynet.call(agent, "lua", "new_player", fd, addr) 37 | if is_full then 38 | free_agents[agent] = nil 39 | full_agents[agent] = true 40 | end 41 | end 42 | 43 | local function close_socket(fd) 44 | trace("close_socket", fd) 45 | local uid = fd2uid[fd] 46 | if not uid then 47 | skynet.error("uid not exist, fd:", fd) 48 | return 49 | end 50 | local agent = uid2agent[uid] 51 | if not agent then 52 | skynet.error("agent not exist, uid:", uid) 53 | return 54 | end 55 | skynet.call(agent, "lua", "socket_close", uid, fd) 56 | skynet.call(GATE, "lua", "kick", fd) 57 | fd2uid[fd] = nil 58 | end 59 | 60 | function SOCKET.close(fd) 61 | --print("socket close",fd) 62 | close_socket(fd) 63 | end 64 | 65 | function SOCKET.error(fd, msg) 66 | print("socket error",fd, msg) 67 | close_socket(fd) 68 | end 69 | 70 | function SOCKET.warning(fd, size) 71 | -- size K bytes havn't send out in fd 72 | print("socket warning", fd, size) 73 | end 74 | 75 | function SOCKET.data(fd, msg) 76 | print("socket data", fd, msg) 77 | end 78 | 79 | local CMD = {} 80 | function CMD.start(conf) 81 | PLAYER_PER_AGENT = conf.player_per_agent or 100 82 | PROTO = conf.proto 83 | server:start() 84 | conf.preload = conf.preload or 10 -- 预加载agent数量 85 | skynet.call(GATE, "lua", "open" , conf) 86 | for i = 1, conf.preload do 87 | local agent = skynet.newservice("sock/agent", player_path) 88 | skynet.call(agent, "lua", "init", GATE, skynet.self(), PLAYER_PER_AGENT, PROTO) 89 | free_agents[agent] = true 90 | end 91 | end 92 | 93 | function CMD.stop() 94 | for agent, _ in pairs(free_agents) do 95 | skynet.send(agent, "lua", "stop") 96 | end 97 | for agent, _ in pairs(full_agents) do 98 | skynet.send(agent, "lua", "stop") 99 | end 100 | while true do 101 | local count = 0 102 | for _, v in pairs(free_agents) do 103 | count = count + 1 104 | end 105 | for _, v in pairs(full_agents) do 106 | count = count + 1 107 | end 108 | skynet.error(string.format("left agent:%d", count)) 109 | if count == 0 then 110 | return 111 | end 112 | skynet.sleep(10) 113 | end 114 | end 115 | 116 | function CMD.set_free(agent) 117 | free_agents[agent] = true 118 | full_agents[agent] = nil 119 | end 120 | 121 | function CMD.free_agent(agent) 122 | free_agents[agent] = nil 123 | full_agents[agent] = nil 124 | end 125 | 126 | -- 上线后agent绑定uid,下线缓存一段时间 127 | function CMD.player_online(agent, uid, fd) 128 | uid2agent[uid] = agent 129 | fd2uid[fd] = uid 130 | end 131 | 132 | -- 下线一段时间后调用 133 | function CMD.free_player(agent, uid) 134 | uid2agent[uid] = nil 135 | free_agents[agent] = true 136 | full_agents[agent] = nil 137 | end 138 | 139 | function CMD.reconnect(fd, uid, csn, ssn, passport, user_info) 140 | assert(fd) 141 | assert(uid) 142 | assert(csn and ssn) 143 | local agent = uid2agent[uid] 144 | if agent then 145 | return skynet.call(agent, "lua", "reconnect", fd, uid, csn, ssn, passport, user_info) 146 | end 147 | end 148 | 149 | function CMD.kick(uid) 150 | local agent = uid2agent[uid] 151 | if agent then 152 | skynet.call(agent, "lua", "kick", uid) 153 | uid2agent[uid] = nil 154 | end 155 | end 156 | 157 | function CMD.online_count() 158 | local count = 0 159 | for v, _ in pairs(free_agents) do 160 | count = count + skynet.call(v, "lua", "online_count") 161 | end 162 | for v, _ in pairs(full_agents) do 163 | count = count + skynet.call(v, "lua", "online_count") 164 | end 165 | return count 166 | end 167 | 168 | skynet.start(function() 169 | skynet.dispatch("lua", function(_, _, cmd, subcmd, ...) 170 | if cmd == "socket" then 171 | local f = SOCKET[subcmd] 172 | f(...) 173 | return 174 | elseif CMD[cmd] then 175 | bewater.ret(CMD[cmd](subcmd, ...)) 176 | else 177 | local f = assert(server[cmd], cmd) 178 | if type(f) == "function" then 179 | bewater.ret(f(server, subcmd, ...)) 180 | else 181 | bewater.ret(f[subcmd](f, ...)) 182 | end 183 | end 184 | end) 185 | 186 | GATE = skynet.newservice("gate") 187 | end) 188 | -------------------------------------------------------------------------------- /service/stdout.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local conf = require "conf" 3 | 4 | local mode = ... 5 | if mode == 'agent' then 6 | local lock = require "bw.lock" 7 | local run_lock = lock.new() 8 | local runing = false 9 | local path 10 | skynet.start(function() 11 | skynet.dispatch("lua", function(_, _, expr, filename) 12 | run_lock:lock() 13 | path = filename or conf.workspace.."/log/stdout.log" 14 | os.execute('echo "%s" > %s', expr, path) 15 | skynet.retpack() 16 | expr = string.format('%s >%s 2>&1', expr, path) 17 | os.execute(expr) 18 | os.execute('echo "==EOF==" >>'..path) 19 | run_lock:unlock() 20 | end) 21 | end) 22 | else 23 | local bewater = require "bw.bewater" 24 | local agents = {} 25 | local CMD = {} 26 | function CMD.run(expr, filename) 27 | filename = filename or conf.workspace.."/log/stdout.log" 28 | local agent = agents[filename] or skynet.newservice(SERVICE_NAME, "agent") 29 | agents[filename] = agent 30 | skynet.call(agent, "lua", expr, filename) 31 | end 32 | function CMD.log(offset, filename) 33 | filename = filename or conf.workspace.."/log/stdout.log" 34 | local file = io.open(filename, "r") 35 | if not file then 36 | return "", 0, false 37 | end 38 | file:seek("set", offset or 0) 39 | local str = file:read("a") 40 | offset = file:seek() 41 | file:close() 42 | return str, offset, string.match(str, "==EOF==") ~= nil 43 | end 44 | skynet.start(function() 45 | skynet.dispatch("lua", function(_, _, cmd, ...) 46 | local f = assert(CMD[cmd], cmd) 47 | bewater.ret(f(...)) 48 | end) 49 | end) 50 | end 51 | 52 | -------------------------------------------------------------------------------- /service/web/webclient.lua: -------------------------------------------------------------------------------- 1 | --- webclient. (skynet服务). 2 | -- 3 | -- @module webclient 4 | -- @usage local webclient = skynet.newservice("webclient") 5 | 6 | local skynet = require "skynet" 7 | local webclientlib = require "webclient" 8 | local webclient = webclientlib.create() 9 | local requests = nil 10 | 11 | local function resopnd(request, result) 12 | if not request.response then 13 | return 14 | end 15 | 16 | local content, errmsg = webclient:get_respond(request.req) 17 | local info = webclient:get_info(request.req) 18 | 19 | if result == 0 then 20 | request.response(true, true, content, info) 21 | else 22 | request.response(true, false, errmsg, info) 23 | end 24 | end 25 | 26 | local function query() 27 | while next(requests) do 28 | local finish_key, result = webclient:query() 29 | if finish_key then 30 | local request = requests[finish_key]; 31 | assert(request) 32 | 33 | xpcall(resopnd, function() skynet.error(debug.traceback()) end, request, result) 34 | 35 | webclient:remove_request(request.req) 36 | requests[finish_key] = nil 37 | else 38 | skynet.sleep(1) 39 | end 40 | end 41 | requests = nil 42 | end 43 | 44 | --- 请求某个url 45 | -- @function request 46 | -- @string url url 47 | -- @tab[opt] get get的参数 48 | -- @param[opt] post post参数,table or string类型 49 | -- @bool[opt] no_reply 使用skynet.call则要设置为nil或false,使用skynet.send则要设置为true 50 | -- @treturn bool 请求是否成功 51 | -- @treturn string 当成功时,返回内容,当失败时,返回出错原因 52 | -- @usage skynet.call(webclient, "lua", "request", "http://www.dpull.com") 53 | -- @usage skynet.send(webclient, "lua", "request", "http://www.dpull.com", nil, nil, true) 54 | local function request(url, get, post, header, no_reply) 55 | if get then 56 | local i = 0 57 | for k, v in pairs(get) do 58 | k = webclient:url_encoding(k) 59 | v = webclient:url_encoding(v) 60 | 61 | url = string.format("%s%s%s=%s", url, i == 0 and "?" or "&", k, v) 62 | i = i + 1 63 | end 64 | end 65 | 66 | if post and type(post) == "table" then 67 | local data = {} 68 | for k,v in pairs(post) do 69 | k = webclient:url_encoding(k) 70 | v = webclient:url_encoding(v) 71 | 72 | table.insert(data, string.format("%s=%s", k, v)) 73 | end 74 | post = table.concat(data , "&") 75 | end 76 | 77 | local req, key = webclient:request(url, post) 78 | if not req then 79 | return skynet.ret() 80 | end 81 | assert(key) 82 | if type(header) == "table" then 83 | local list = {} 84 | for k, v in pairs(header) do 85 | list[#list+1] = k..':'..v 86 | end 87 | webclient:set_httpheader(req, table.unpack(list)) 88 | end 89 | 90 | local response = nil 91 | if not no_reply then 92 | response = skynet.response() 93 | end 94 | 95 | if requests == nil then 96 | requests = {} 97 | skynet.fork(query) 98 | end 99 | 100 | requests[key] = { 101 | url = url, 102 | req = req, 103 | response = response, 104 | } 105 | end 106 | 107 | skynet.start(function() 108 | skynet.dispatch("lua", function(_, _, command, ...) 109 | assert(command == "request") 110 | request(...) 111 | end) 112 | end) 113 | -------------------------------------------------------------------------------- /service/ws/agent.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local socket = require "skynet.socket" 3 | local bewater = require "bw.bewater" 4 | local errcode = require "def.errcode" 5 | local protobuf = require "bw.protobuf" 6 | 7 | local player_path = ... 8 | local Player = require(player_path) 9 | 10 | local WATCHDOG 11 | local MAX_COUNT 12 | 13 | local CMD = {} 14 | local fd2player = {} 15 | local uid2player = {} 16 | local player_count = 0 17 | 18 | 19 | function CMD.new_player(fd, ip) 20 | socket.start(fd) 21 | local player = Player.new() 22 | player.net:init(WATCHDOG, skynet.self(), fd, ip) 23 | fd2player[fd] = player 24 | player_count = player_count + 1 25 | return player_count >= MAX_COUNT 26 | end 27 | 28 | function CMD.init(watchdog, max_count, proto) 29 | WATCHDOG = assert(watchdog) 30 | MAX_COUNT = max_count or 100 31 | if proto then 32 | protobuf.register_file(proto) 33 | end 34 | end 35 | 36 | function CMD.stop() 37 | for _, player in pairs(uid2player) do 38 | bewater.try(function() 39 | player:kick(errcode.SERVER_STOP) 40 | player:offline() 41 | end) 42 | end 43 | skynet.call(WATCHDOG, "lua", "free_agent", skynet.self()) 44 | end 45 | 46 | -- from player 47 | function CMD.player_online(uid, fd) 48 | local player = assert(fd2player[fd]) 49 | uid2player[uid] = player 50 | end 51 | 52 | function CMD.free_player(uid) 53 | uid2player[uid] = nil 54 | if player_count == MAX_COUNT then 55 | skynet.call(WATCHDOG, "lua", "set_free", skynet.self()) 56 | end 57 | player_count = player_count - 1 58 | end 59 | 60 | -- from watchdog 61 | function CMD.socket_close(fd) 62 | local player = fd2player[fd] 63 | if player and player.offline then 64 | player:offline() 65 | end 66 | fd2player[fd] = nil 67 | end 68 | 69 | function CMD.reconnect(uid, csn, ssn) 70 | local player = uid2player[uid] 71 | if not player then 72 | return 73 | end 74 | fd2player[player.net:get_fd()] = nil 75 | return player.net:reconnect(csn, ssn) 76 | end 77 | 78 | function CMD.kick(uid) 79 | local player = uid2player[uid] 80 | if player then 81 | player:kick(errcode.KICK) 82 | uid2player[uid] = nil 83 | end 84 | end 85 | 86 | function CMD.online_count() 87 | local count = 0 88 | for _, player in pairs(uid2player) do 89 | if not player.cache_time then 90 | count = count + 1 91 | end 92 | end 93 | return count 94 | end 95 | 96 | function CMD.debug_fd2player() 97 | local count = 0 98 | for k, v in pairs(fd2player) do 99 | count = count + 1 100 | end 101 | return count 102 | end 103 | 104 | function CMD.debug_uid2player() 105 | local count = 0 106 | for k, v in pairs(uid2player) do 107 | count = count + 1 108 | end 109 | return count 110 | end 111 | 112 | local function check_timeout() 113 | for _, player in pairs(uid2player) do 114 | if player.check_timeout then 115 | bewater.try(function() 116 | player:check_timeout() 117 | end) 118 | end 119 | end 120 | end 121 | 122 | skynet.start(function() 123 | skynet.dispatch("lua", function(_, _, arg1, arg2, arg3, ...) 124 | local f = CMD[arg1] 125 | if f then 126 | bewater.ret(f(arg2, arg3, ...)) 127 | else 128 | --local player = assert(uid2player[arg1], string.format("%s %s %s", arg1, arg2, arg3)) 129 | local player = uid2player[arg1] 130 | if not player then 131 | -- todo fix this bug 132 | return bewater.ret() 133 | end 134 | local module = assert(player[arg2], arg2) 135 | if type(module) == "function" then 136 | bewater.ret(module(player, arg3, ...)) 137 | else 138 | bewater.ret(module[arg3](module, ...)) 139 | end 140 | end 141 | end) 142 | 143 | -- 定时检查超时,一秒误差,如需要精准的触发,使用日程表schedule 144 | skynet.fork(function() 145 | while true do 146 | check_timeout() 147 | skynet.sleep(100) 148 | end 149 | end) 150 | end) 151 | 152 | -------------------------------------------------------------------------------- /service/ws/watchdog.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local socket = require "skynet.socket" 3 | local bewater = require "bw.bewater" 4 | 5 | local server_path, player_path = ... 6 | assert(server_path) -- 服务器逻辑(xxx.xxxserver) 7 | assert(player_path) -- 玩家逻辑(xxx.xxxplayer) 8 | 9 | local server = require(server_path) 10 | 11 | local uid2agent = {} -- 每个账号对应的agent 12 | local free_agents = {} -- 空闲的agent addr -> true 13 | local full_agents = {} -- 满员的agent addr -> true 14 | 15 | local PLAYER_PER_AGENT -- 每个agent支持player最大值 16 | local PROTO 17 | 18 | local function create_agent() 19 | local agent = skynet.newservice("ws/agent", player_path) 20 | skynet.call(agent, "lua", "init", skynet.self(), PLAYER_PER_AGENT, PROTO) 21 | free_agents[agent] = true 22 | return agent 23 | end 24 | 25 | local CMD = {} 26 | function CMD.start(conf) 27 | PLAYER_PER_AGENT = conf.player_per_agent or 100 28 | PROTO = conf.proto 29 | 30 | server:start() 31 | 32 | local preload = conf.preload or 10 -- 预加载agent数量 33 | for i = 1, preload do 34 | create_agent() 35 | end 36 | 37 | local address = "0.0.0.0:"..conf.port 38 | skynet.error("Listening "..address) 39 | local fd = assert(socket.listen(address)) 40 | socket.start(fd , function(_fd, addr) 41 | local agent = next(free_agents) 42 | if not agent then 43 | agent = create_agent() 44 | end 45 | if skynet.call(agent, "lua", "new_player", _fd, addr) then 46 | -- agent已经满 47 | free_agents[agent] = nil 48 | full_agents[agent] = true 49 | end 50 | end) 51 | end 52 | 53 | function CMD.stop() 54 | for agent, _ in pairs(free_agents) do 55 | skynet.send(agent, "lua", "stop") 56 | end 57 | for agent, _ in pairs(full_agents) do 58 | skynet.send(agent, "lua", "stop") 59 | end 60 | while true do 61 | local count = 0 62 | for _, v in pairs(free_agents) do 63 | count = count + 1 64 | end 65 | for _, v in pairs(full_agents) do 66 | count = count + 1 67 | end 68 | skynet.error(string.format("left agent:%d", count)) 69 | if count == 0 then 70 | return 71 | end 72 | skynet.sleep(10) 73 | end 74 | end 75 | 76 | function CMD.set_free(agent) 77 | free_agents[agent] = true 78 | full_agents[agent] = nil 79 | end 80 | 81 | function CMD.free_agent(agent) 82 | free_agents[agent] = nil 83 | full_agents[agent] = nil 84 | end 85 | 86 | -- 上线后agent绑定uid,下线缓存一段时间 87 | function CMD.player_online(agent, uid) 88 | uid2agent[uid] = agent 89 | end 90 | 91 | -- 下线一段时间后调用 92 | function CMD.player_destroy(agent, uid) 93 | uid2agent[uid] = nil 94 | free_agents[agent] = true 95 | full_agents[agent] = nil 96 | end 97 | 98 | function CMD.reconnect(uid, csn, ssn) 99 | local agent = uid2agent[uid] 100 | if agent then 101 | return agent, skynet.call(agent, "lua", "reconnect", uid, csn, ssn) 102 | end 103 | end 104 | 105 | function CMD.kick(uid) 106 | local agent = uid2agent[uid] 107 | if agent then 108 | skynet.call(agent, "lua", "kick", uid) 109 | uid2agent[uid] = nil 110 | end 111 | end 112 | 113 | function CMD.online_count() 114 | local count = 0 115 | for v, _ in pairs(free_agents) do 116 | count = count + skynet.call(v, "lua", "online_count") 117 | end 118 | for v, _ in pairs(full_agents) do 119 | count = count + skynet.call(v, "lua", "online_count") 120 | end 121 | return count 122 | end 123 | 124 | skynet.start(function() 125 | skynet.dispatch("lua", function(_, _, cmd1, ...) 126 | local f = CMD[cmd1] or server[cmd1] 127 | assert(f, cmd1) 128 | bewater.ret(f(...)) 129 | end) 130 | end) 131 | -------------------------------------------------------------------------------- /shell/etc.sh: -------------------------------------------------------------------------------- 1 | #生成一份配置 2 | 3 | if [ $# -lt 2 ] 4 | then 5 | echo 至少需要两个参数, etc.sh 配置名 启动脚本 是否后台执行 6 | exit 7 | fi 8 | 9 | cd ../ 10 | workspace=$(cd $(dirname $0); pwd) 11 | root_name=$(basename $workspace) 12 | cd - 13 | 14 | etc_name=$1 #master 15 | start_script=$2 16 | clustername=$3 #master 17 | is_deamon=$4 #true 18 | 19 | config=${etc_name}.cfg 20 | 21 | echo $workspace 22 | mkdir -p ${workspace}/log 23 | mkdir -p ${workspace}/etc 24 | cd ${workspace}/etc 25 | 26 | echo workspace = \"../${root_name}/\" > ${config} 27 | echo thread = 8 >> ${config} 28 | echo logpath = \".\" >> ${config} 29 | echo harbor = 0 >> ${config} 30 | echo start = \"${start_script}\" >> ${config} 31 | echo 'bootstrap = "snlua bootstrap"' >> ${config} 32 | echo 'lualoader = "lualib/loader.lua"' >> ${config} 33 | echo 'snax = workspace.."service/?.lua"' >> ${config} 34 | echo 'luaservice = workspace.."examples/?.lua;"..workspace.."service/?.lua;"..workspace.."service/?.lua;".."./service/?.lua;".."./liblua/?.lua;"' >> ${config} 35 | echo 'cpath = workspace.."luaclib/?.so;"..workspace.."luaclib/?.so;".."./cservice/?.so;./luaclib/?.so"' >> ${config} 36 | echo 'lua_path = workspace.."script/?.lua;"..workspace.."lualib/?.lua;"..workspace.."lualib/?.lua;".."./lualib/?.lua;"' >> ${config} 37 | echo 'lua_cpath = workspace.."luaclib/?.so;"..workspace.."luaclib/?.so;".."./luaclib/?.so;"' >> ${config} 38 | echo logger = \"logger\" >> ${config} 39 | echo logservice = \"snlua\" >> ${config} 40 | 41 | if [ "${clustername}" != "" ] 42 | then 43 | echo clustername = \"${clustername}\" >> ${config} 44 | else 45 | echo clustername = \"${etc_name}\" >> ${config} 46 | fi 47 | 48 | if [ "${is_deamon}" == "true" ] 49 | then 50 | echo daemon = workspace..\"/log/pid/${etc_name}.pid\" >> ${config} 51 | fi 52 | 53 | -------------------------------------------------------------------------------- /shell/kill.sh: -------------------------------------------------------------------------------- 1 | #ps -Al | grep skynet | cut -c 10-16 | xargs kill -9 2 | 3 | workspace=$(cd "$(dirname "$0")"; pwd)/.. 4 | pid=`cat $workspace/log/pid/${1}.pid` 5 | if [ "$2" != "" ] 6 | then 7 | kill -$2 $pid 8 | else 9 | kill -1 $pid 10 | fi 11 | -------------------------------------------------------------------------------- /shell/log.sh: -------------------------------------------------------------------------------- 1 | workspace=$(cd "$(dirname "$0")"; pwd)/.. 2 | tail -f $workspace/log/$1.log 3 | -------------------------------------------------------------------------------- /shell/proto.sh: -------------------------------------------------------------------------------- 1 | workspace=$(cd $(dirname $0); pwd)/.. 2 | 3 | cd ${workspace}/script/def/proto 4 | find . -name "*.proto" | xargs ${workspace}/../../common/tools/protoc3 -o package.pb 5 | 6 | echo done. 7 | 8 | -------------------------------------------------------------------------------- /shell/run.sh: -------------------------------------------------------------------------------- 1 | workspace=$(cd "$(dirname "$0")"; pwd)/.. 2 | 3 | mkdir -p $workspace/log/pid/ 4 | 5 | if [ $# -le 0 ] 6 | then 7 | echo 请输入配置名,如: run.sh game 8 | exit 9 | fi 10 | 11 | cd $workspace/../skynet 12 | ./skynet ${workspace}/etc/${1}.cfg 13 | -------------------------------------------------------------------------------- /tools/install_lua_luarocks.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ##一键安装lua5.3 和 luarocks 脚本 3 | cd /usr/local 4 | wget http://www.lua.org/ftp/lua-5.3.5.tar.gz 5 | tar -zxvf lua-5.3.5.tar.gz 6 | cd lua-5.3.5 7 | make linux && make test && make install && make local 8 | 9 | echo "重新安装luarocks" 10 | if [ ! -d "/usr/local/luarocks-2.4.1" ];then 11 | cd /usr/local && wget http://luarocks.org/releases/luarocks-2.4.1.tar.gz && tar -zxvf luarocks-2.4.1.tar.gz 12 | else 13 | echo "/usr/local/luarocks-2.4.1 文件夹已经存在" 14 | fi 15 | cd /usr/local/luarocks-2.4.1 16 | ./configure --with-lua=/usr/local --with-lua-include=/usr/local/lua-5.3.5/install/include 17 | make build && make install && make bootstrap 18 | source ~/.bash_profile 19 | echo "测试luarocks安装luacheck" 20 | luarocks install luacheck 21 | lua -v 22 | -------------------------------------------------------------------------------- /tools/protoc3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yiyajunjun/bewater/a9ff302c8304f9d798f70c03a5755d22affb90a5/tools/protoc3 -------------------------------------------------------------------------------- /tools/workspace.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "skynet" ]; then 2 | git clone https://github.com/zhandouxiaojiji/skynet.git 3 | fi 4 | 5 | if [ ! -d "common" ]; then 6 | git clone https://github.com/zhandouxiaojiji/common.git 7 | fi 8 | 9 | mkdir -p proj 10 | cd proj 11 | 12 | if [ ! -d "monitor" ]; then 13 | git clone https://github.com/zhandouxiaojiji/monitor.git 14 | fi 15 | 16 | if [ ! -d "share" ]; then 17 | git clone https://github.com/zhandouxiaojiji/share.git 18 | fi 19 | --------------------------------------------------------------------------------