├── .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('', class or "", parse(param), ctx or "")
43 | end
44 |
45 | function layui.button(ctx, class, param, submit)
46 | return string.format('%s ',
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('%s ', 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('%s ',
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('', 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%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..''..k..'>'
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 |
--------------------------------------------------------------------------------