├── templates ├── lualib │ ├── test.lua │ ├── proto │ │ ├── opcode.lua │ │ └── errcode.lua │ ├── behavior3 │ │ ├── behavior_ret.lua │ │ ├── nodes │ │ │ ├── actions │ │ │ │ ├── log.lua │ │ │ │ └── wait.lua │ │ │ ├── conditions │ │ │ │ ├── check.lua │ │ │ │ └── cmp.lua │ │ │ ├── decorators │ │ │ │ ├── not.lua │ │ │ │ ├── always_fail.lua │ │ │ │ └── always_success.lua │ │ │ └── composites │ │ │ │ ├── parallel.lua │ │ │ │ ├── once.lua │ │ │ │ ├── selector.lua │ │ │ │ ├── sequence.lua │ │ │ │ ├── loop.lua │ │ │ │ ├── foreach.lua │ │ │ │ └── ifelse.lua │ │ ├── sample_process.lua │ │ ├── behavior_tree.lua │ │ └── behavior_node.lua │ ├── bw │ │ ├── util │ │ │ ├── inject_mt.lua │ │ │ ├── activity_helper.lua │ │ │ ├── hash_array.lua │ │ │ ├── clusterinfo.lua │ │ │ ├── ip_country.lua │ │ │ └── date_helper.lua │ │ ├── class.lua │ │ ├── const.lua │ │ ├── server │ │ │ ├── redisd.lua │ │ │ ├── web_api.lua │ │ │ ├── web_auth.lua │ │ │ ├── mysqld.lua │ │ │ ├── id_producer.lua │ │ │ ├── balance_gate.lua │ │ │ ├── alert.lua │ │ │ ├── gm.lua │ │ │ ├── mongod.lua │ │ │ ├── ws_agent.lua │ │ │ └── web_service.lua │ │ ├── xml │ │ │ ├── lua2xml.lua │ │ │ ├── print.lua │ │ │ ├── dom.lua │ │ │ ├── xml2lua.lua │ │ │ └── tree.lua │ │ ├── api.lua │ │ ├── helper │ │ │ ├── errcode_helper.lua │ │ │ └── opcode_helper.lua │ │ ├── auth │ │ │ ├── tt.lua │ │ │ ├── sign.lua │ │ │ ├── huawei.lua │ │ │ ├── jiguang.lua │ │ │ └── wx.lua │ │ ├── random.lua │ │ ├── payment │ │ │ ├── applepay.lua │ │ │ ├── vvpay.lua │ │ │ ├── oppay.lua │ │ │ ├── hwpay.lua │ │ │ ├── alipay.lua │ │ │ └── wxpay.lua │ │ ├── lock.lua │ │ ├── bw.lua │ │ ├── http.lua │ │ ├── timer.lua │ │ ├── schedule.lua │ │ ├── log.lua │ │ ├── bewater.lua │ │ ├── bash.lua │ │ ├── util.lua │ │ └── uuid.lua │ ├── revent.lua │ ├── fsm.lua │ └── fog.lua ├── .gitignore ├── service │ └── main.lua ├── test.sh ├── etc │ ├── config.test │ └── config.path ├── make │ ├── lfs.mk │ ├── packet.mk │ ├── bytebuffer.mk │ ├── jps.mk │ ├── profile.mk │ ├── cjson.mk │ ├── ecs.mk │ ├── hex-grid.mk │ ├── lz4.mk │ ├── quadtree.mk │ ├── curl.mk │ ├── snapshot.mk │ ├── crypto.mk │ ├── crab.mk │ ├── lua-zset.mk │ ├── pbc.mk │ ├── navigation.mk │ ├── skynet.mk │ └── openssl.mk ├── luacheck │ ├── .luacheckrc │ └── pre-commit └── Makefile ├── modules ├── fog.sh ├── fsm.sh ├── uuid.sh ├── behavior3.sh ├── revent.sh ├── argparse.sh ├── bewater.sh ├── crab.sh ├── ecs.sh ├── jps.sh ├── lz4.sh ├── pbc.sh ├── cjson.sh ├── curl.sh ├── profile.sh ├── lfs.sh ├── lua-zset.sh ├── packet.sh ├── quadtree.sh ├── crypto.sh ├── openssl.sh ├── snapshot.sh ├── hex-grid.sh ├── bytebuffer.sh ├── navigation.sh └── luacheck.sh ├── lualib ├── github.lua ├── libs.lua └── bash.lua ├── .gitmodules ├── Makefile ├── import.lua ├── main.lua ├── skynet-creator.sh └── README.md /templates/lualib/test.lua: -------------------------------------------------------------------------------- 1 | return {} -------------------------------------------------------------------------------- /templates/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | logs/ 3 | .vscode/ -------------------------------------------------------------------------------- /modules/fog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/lualib/fog.lua ./lualib 4 | -------------------------------------------------------------------------------- /modules/fsm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/lualib/fsm.lua ./lualib 4 | -------------------------------------------------------------------------------- /modules/uuid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/lualib/uuid.lua ./lualib 4 | -------------------------------------------------------------------------------- /modules/behavior3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -rv $RESOURCES_DIR/templates/lualib/behavior3 ./lualib 4 | -------------------------------------------------------------------------------- /modules/revent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/lualib/revent.lua ./lualib 4 | -------------------------------------------------------------------------------- /modules/argparse.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/lualib/argparse.lua ./lualib 4 | -------------------------------------------------------------------------------- /templates/service/main.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | 3 | skynet.start(function () 4 | print "hello skynet!" 5 | end) -------------------------------------------------------------------------------- /lualib/github.lua: -------------------------------------------------------------------------------- 1 | return { 2 | skynet = "https://github.com/cloudwu/skynet.git", 3 | argparse = "https://github.com/mpeterv/argparse.git", 4 | } -------------------------------------------------------------------------------- /modules/bewater.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -rv $RESOURCES_DIR/templates/lualib/bw ./lualib 4 | cp -rv $RESOURCES_DIR/templates/lualib/proto ./lualib 5 | -------------------------------------------------------------------------------- /templates/test.sh: -------------------------------------------------------------------------------- 1 | if [ ! -f "./etc/config.test" ]; then 2 | cp ./etc/.config.test ./etc/config.test 3 | fi 4 | ./build/bin/skynet ./etc/config.test 5 | -------------------------------------------------------------------------------- /modules/crab.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/crab.mk ./make 4 | git submodule add https://github.com/xjdrew/crab.git 3rd/crab 5 | -------------------------------------------------------------------------------- /modules/ecs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/ecs.mk ./make 4 | git submodule add https://github.com/cloudwu/luaecs.git 3rd/ecs 5 | -------------------------------------------------------------------------------- /modules/jps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/jps.mk ./make 4 | git submodule add https://github.com/rangercyh/jps.git 3rd/jps 5 | -------------------------------------------------------------------------------- /modules/lz4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/lz4.mk ./make 4 | git submodule add https://github.com/witchu/lua-lz4.git 3rd/lz4 5 | -------------------------------------------------------------------------------- /templates/lualib/proto/opcode.lua: -------------------------------------------------------------------------------- 1 | local opcode = require "bw.opcode_helper" 2 | --local REG = opcode.REG 3 | -- todo 注册项目的协议 4 | 5 | return opcode 6 | -------------------------------------------------------------------------------- /modules/pbc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/pbc.mk ./make 4 | git submodule add https://github.com/zhandouxiaojiji/pbc.git 3rd/pbc 5 | -------------------------------------------------------------------------------- /modules/cjson.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/cjson.mk ./make 4 | git submodule add https://github.com/cloudwu/lua-cjson.git 3rd/cjson 5 | -------------------------------------------------------------------------------- /modules/curl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/curl.mk ./make 4 | git submodule add https://github.com/Lua-cURL/Lua-cURLv3.git 3rd/curl 5 | -------------------------------------------------------------------------------- /modules/profile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/profile.mk ./make 4 | git submodule add https://github.com/lvzixun/luaprofile.git 3rd/profile -------------------------------------------------------------------------------- /modules/lfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/lfs.mk ./make 4 | git submodule add https://github.com/keplerproject/luafilesystem.git 3rd/lfs 5 | -------------------------------------------------------------------------------- /modules/lua-zset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/lua-zset.mk ./make 4 | git submodule add https://github.com/xjdrew/lua-zset.git 3rd/lua-zset 5 | -------------------------------------------------------------------------------- /modules/packet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/packet.mk ./make 4 | git submodule add https://github.com:zhandouxiaojiji/lua-packet.git 3rd/packet -------------------------------------------------------------------------------- /modules/quadtree.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/quadtree.mk ./make 4 | git submodule add https://github.com/rangercyh/quadtree.git 3rd/quadtree -------------------------------------------------------------------------------- /templates/lualib/behavior3/behavior_ret.lua: -------------------------------------------------------------------------------- 1 | return { 2 | FAIL = "FAIL", -- 失败 3 | SUCCESS = "SUCCESS", -- 成功 4 | RUNNING = "RUNNING", -- 正在运行 5 | } 6 | -------------------------------------------------------------------------------- /templates/lualib/proto/errcode.lua: -------------------------------------------------------------------------------- 1 | local errcode = require "bw.errcode_helper" 2 | --local REG = errcode.REG 3 | -- todo 项目自定义错误码 0x1000开始 4 | 5 | return errcode 6 | -------------------------------------------------------------------------------- /modules/crypto.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/crypto.mk ./make 4 | git submodule add https://github.com/zhandouxiaojiji/lua-crypto.git 3rd/crypto 5 | -------------------------------------------------------------------------------- /modules/openssl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/openssl.mk ./make 4 | git submodule add https://github.com/zhongfq/lua-openssl.git 3rd/openssl 5 | -------------------------------------------------------------------------------- /modules/snapshot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/snapshot.mk ./make 4 | git submodule add https://github.com/lvzixun/lua-snapshot.git 3rd/snapshot 5 | -------------------------------------------------------------------------------- /modules/hex-grid.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/hex-grid.mk ./make 4 | git submodule add https://github.com/zhandouxiaojiji/lua-hex-grid.git 3rd/hex-grid 5 | -------------------------------------------------------------------------------- /modules/bytebuffer.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/bytebuffer.mk ./make 4 | git submodule add https://github.com/zhandouxiaojiji/lua-bytebuffer.git 3rd/bytebuffer 5 | -------------------------------------------------------------------------------- /modules/navigation.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v $RESOURCES_DIR/templates/make/navigation.mk ./make 4 | git submodule add https://github.com/zhandouxiaojiji/lua-navigation.git 3rd/navigation 5 | -------------------------------------------------------------------------------- /modules/luacheck.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cp -v -n $RESOURCES_DIR/templates/luacheck/.luacheckrc ./ 4 | cp -v $RESOURCES_DIR/templates/luacheck/pre-commit ./.git/hooks/ 5 | chmod 775 ./.git/hooks/pre-commit 6 | -------------------------------------------------------------------------------- /templates/etc/config.test: -------------------------------------------------------------------------------- 1 | include "config.path" 2 | 3 | thread = 8 4 | logger = nil 5 | harbor = 0 6 | start = "main" -- main script 7 | bootstrap = "snlua bootstrap" -- The service for bootstrap 8 | enablessl = true 9 | -------------------------------------------------------------------------------- /templates/lualib/bw/util/inject_mt.lua: -------------------------------------------------------------------------------- 1 | return function(dst, dir, name) 2 | local src = require(string.format("%s.%s_mt", dir, name)) 3 | for k,v in pairs(src) do 4 | assert(not dst[k], k) 5 | dst[k] = v 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /templates/make/lfs.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/lfs.so 2 | 3 | LFS_SOURCE=3rd/lfs/src/lfs.c 4 | 5 | ${LFS_SOURCE}: 6 | git submodule update --init 3rd/lfs 7 | 8 | ${BUILD_CLUALIB_DIR}/lfs.so: ${LFS_SOURCE} 9 | ${CC} $(CFLAGS) $(SHARED) -I3rd/lfs/src/ -Iskynet/3rd/lua $^ -o $@ $(LDFLAGS) -------------------------------------------------------------------------------- /templates/lualib/bw/class.lua: -------------------------------------------------------------------------------- 1 | return function(mt) 2 | mt.__index = mt 3 | 4 | function mt.new(...) 5 | local obj = setmetatable({}, mt) 6 | if obj.ctor then 7 | obj:ctor(...) 8 | end 9 | return obj 10 | end 11 | return mt 12 | end 13 | -------------------------------------------------------------------------------- /templates/make/packet.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/packet.so 2 | 3 | PACKET_SOURCE=3rd/packet/lua-packet.c 4 | 5 | ${PACKET_SOURCE}: 6 | git submodule update --init 3rd/packet 7 | 8 | ${BUILD_CLUALIB_DIR}/packet.so: ${PACKET_SOURCE} 9 | ${CC} $(CFLAGS) $(SHARED) -I3rd/packet/ -Iskynet/3rd/lua $^ -o $@ $(LDFLAGS) -------------------------------------------------------------------------------- /templates/make/bytebuffer.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/bytebuffer.so 2 | 3 | BYTEBUFFER_SOURCE=3rd/bytebuffer/lua-bytebuffer.c 4 | 5 | ${BYTEBUFFER_SOURCE}: 6 | git submodule update --init 3rd/bytebuffer 7 | 8 | ${BUILD_CLUALIB_DIR}/bytebuffer.so: ${BYTEBUFFER_SOURCE} 9 | ${CC} $(CFLAGS) $(SHARED) -I3rd/bytebuffer/ -Iskynet/3rd/lua $^ -o $@ $(LDFLAGS) -------------------------------------------------------------------------------- /templates/make/jps.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/jps.so 2 | 3 | JPS_SOURCE=3rd/jps/jps.c \ 4 | 3rd/jps/heap.c \ 5 | 3rd/jps/intlist.c \ 6 | 3rd/jps/luabinding.c 7 | 8 | ${JPS_SOURCE}: 9 | git submodule update --init 3rd/jps 10 | 11 | ${BUILD_CLUALIB_DIR}/jps.so: ${JPS_SOURCE} 12 | ${CC} $(CFLAGS) $(SHARED) -I3rd/jps/ -Iskynet/3rd/lua $^ -o $@ -------------------------------------------------------------------------------- /templates/make/profile.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/profile.so 2 | 3 | LUAPROFILE_SOURCE=3rd/profile/imap.c \ 4 | 3rd/profile/profile.c 5 | 6 | 3rd/profile/profile.c.c: 7 | git submodule update --init 3rd/profile 8 | 9 | ${BUILD_CLUALIB_DIR}/profile.so: ${LUAPROFILE_SOURCE} 10 | gcc $(CFLAGS) $(SHARED) -I3rd/profile/ -Iskynet/3rd/lua $^ -o $@ $(LDFLAGS) -------------------------------------------------------------------------------- /templates/make/cjson.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/cjson.so 2 | 3 | CJSON_SOURCE=3rd/cjson/lua_cjson.c \ 4 | 3rd/cjson/strbuf.c \ 5 | 3rd/cjson/fpconv.c 6 | 7 | 3rd/cjson/lua_cjson.c: 8 | git submodule update --init 3rd/cjson 9 | 10 | ${BUILD_CLUALIB_DIR}/cjson.so:${CJSON_SOURCE} 11 | ${CC} $(CFLAGS) -I3rd/lua/cjson -Iskynet/3rd/lua $(SHARED) $^ -o $@ $(LDFLAGS) 12 | 13 | -------------------------------------------------------------------------------- /templates/make/ecs.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/ecs.so ${LUALIB_DIR}/ecs.lua 2 | 3 | ECS_SOURCE=3rd/ecs/luaecs.c 4 | 5 | ${ECS_SOURCE}: 6 | git submodule update --init 3rd/ecs 7 | 8 | ${LUALIB_DIR}/ecs.lua: 9 | cp 3rd/ecs/ecs.lua lualib/ecs.lua 10 | 11 | ${BUILD_CLUALIB_DIR}/ecs.so: ${ECS_SOURCE} 12 | ${CC} $(CFLAGS) $(SHARED) -DTEST_LUAECS -I 3rd/ecs -Iskynet/3rd/lua -o $@ $^ -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/etc/config.path: -------------------------------------------------------------------------------- 1 | root = "./" 2 | luaservice = root.."service/?.lua;" .. root .. "service/?/init.lua;" .. root .. "skynet/service/?.lua;" 3 | lualoader = root .. "skynet/lualib/loader.lua" 4 | lua_path = root.."lualib/?.lua;" .. root .. "skynet/lualib/?.lua;" 5 | lua_cpath = root .. "build/clualib/?.so;" 6 | snax = root .. "service/?.lua;" .. root .. "skynet/service/?.lua" 7 | cpath = root.."build/cservice/?.so;" -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/actions/log.lua: -------------------------------------------------------------------------------- 1 | -- Log 2 | -- 3 | 4 | local bret = require "behavior3.behavior_ret" 5 | 6 | local M = { 7 | name = "Log", 8 | type = "Action", 9 | desc = "打印日志", 10 | args = { 11 | {"str", "string", "日志"} 12 | }, 13 | } 14 | 15 | function M.run(node, env) 16 | print(node.args.str) 17 | return bret.SUCCESS 18 | end 19 | 20 | return M 21 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/redisd.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | local redis = require "skynet.db.redis" 3 | 4 | local db 5 | local M = {} 6 | return function(conf) 7 | skynet.start(function() 8 | db = redis.connect(conf) 9 | skynet.dispatch("lua", function(_, _, cmd, ...) 10 | skynet.ret(db[cmd](db, ...)) 11 | end) 12 | end) 13 | end 14 | 15 | -------------------------------------------------------------------------------- /templates/luacheck/.luacheckrc: -------------------------------------------------------------------------------- 1 | codes = true 2 | color = true 3 | 4 | std = "max" 5 | 6 | include_files = { 7 | "include_files/*", 8 | } 9 | 10 | exclude_files = { 11 | "exclude_files/*", 12 | } 13 | 14 | ignore = { 15 | "423", -- Shadowing a loop variable 16 | "211", -- Unused local variable 17 | "212", -- Unused argument 18 | "212/self", -- ignore self 19 | "213", -- Unused loop variable 20 | } -------------------------------------------------------------------------------- /templates/make/hex-grid.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/hex_grid.so 2 | 3 | HEX_GRID_SOURCE=3rd/hex-grid/luabinding.c \ 4 | 3rd/hex-grid/hex_grid.c \ 5 | 3rd/hex-grid/node_freelist.c \ 6 | 3rd/hex-grid/intlist.c 7 | 8 | ${HEX_GRID_SOURCE}: 9 | git submodule update --init 3rd/hex-grid 10 | 11 | ${BUILD_CLUALIB_DIR}/hex_grid.so: ${HEX_GRID_SOURCE} 12 | ${CC} $(CFLAGS) $(SHARED) -I3rd/hex-grid/ -Iskynet/3rd/lua $^ -o $@ 13 | -------------------------------------------------------------------------------- /templates/make/lz4.mk: -------------------------------------------------------------------------------- 1 | all: $(BUILD_CLUALIB_DIR)/lz4.so 2 | 3 | LZ4_SOURCE=3rd/lz4/lz4/lz4.c \ 4 | 3rd/lz4/lz4/lz4hc.c \ 5 | 3rd/lz4/lz4/lz4frame.c \ 6 | 3rd/lz4/lz4/xxhash.c \ 7 | 3rd/lz4/lua_lz4.c 8 | 9 | 3rd/lz4/lz4.c: 10 | git submodule update --init 3rd/lz4 11 | 12 | $(BUILD_CLUALIB_DIR)/lz4.so: $(LZ4_SOURCE) 13 | gcc $(CFLAGS) -std=c99 -Wno-unused-variable -DXXH_NAMESPACE=LZ4_ -Iskynet/3rd/lua $(SHARED) $^ -o $@ $(LDFLAGS) -------------------------------------------------------------------------------- /templates/make/quadtree.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/quadtree.so 2 | 3 | QUADTREE_SOURCE=3rd/quadtree/int_list/IntList.c \ 4 | 3rd/quadtree/quadtree/Quadtree.c \ 5 | 3rd/quadtree/quadtree/luabinding.c 6 | 7 | ${QUADTREE_SOURCE}: 8 | git submodule update --init 3rd/quadtree 9 | 10 | ${BUILD_CLUALIB_DIR}/quadtree.so: ${QUADTREE_SOURCE} 11 | ${CC} $(CFLAGS) $(SHARED) -I3rd/quadtree/ -I3rd/quadtree/int_list -Iskynet/3rd/lua $^ -o $@ -------------------------------------------------------------------------------- /templates/make/curl.mk: -------------------------------------------------------------------------------- 1 | # 依赖libcurl-devel库,自行安装,例: yum install libcurl-devel 2 | 3 | all: ${BUILD_CLUALIB_DIR}/curl.so ${LUALIB_DIR}/curl.lua 4 | 5 | CURL_SOURCE=3rd/curl/Makefile 6 | 7 | ${CURL_SOURCE}: 8 | git submodule update --init 3rd/curl 9 | 10 | ${LUALIB_DIR}/curl.lua: 11 | cp -r 3rd/curl/src/lua/* $(LUALIB_DIR)/ 12 | 13 | ${BUILD_CLUALIB_DIR}/curl.so: 14 | cd 3rd/curl && make 15 | cp 3rd/curl/lcurl.so $(BUILD_CLUALIB_DIR) -------------------------------------------------------------------------------- /templates/make/snapshot.mk: -------------------------------------------------------------------------------- 1 | .PHONY: lsnapshot 2 | 3 | all: ${BUILD_CLUALIB_DIR}/snapshot.so 4 | all: lsnapshot 5 | 6 | SNAPSHOT_SOURCE=3rd/snapshot/snapshot.c 7 | 8 | ${SNAPSHOT_SOURCE}: 9 | git submodule update --init 3rd/snapshot 10 | 11 | ${BUILD_CLUALIB_DIR}/snapshot.so: ${SNAPSHOT_SOURCE} 12 | $(CC) $(CFLAGS) $(SHARED) -I$(INCLUDE_DIR) -I3rd/snapshot/ -Iskynet/3rd/lua $^ -o $@ $(LDFLAGS) 13 | 14 | lsnapshot: 15 | cp 3rd/snapshot/lsnapshot.lua $(LUALIB_DIR) 16 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/conditions/check.lua: -------------------------------------------------------------------------------- 1 | local bret = require 'behavior3.behavior_ret' 2 | 3 | local M = { 4 | name = "Check", 5 | type = "Condition", 6 | desc = "检查True或False", 7 | args = { 8 | {"value", "code?", "值"}, 9 | }, 10 | doc = [[ 11 | + 做简单数值公式判定,返回成功或失败 12 | ]] 13 | } 14 | 15 | function M.run(node, env) 16 | return node:get_env_args("value", env) and bret.SUCCESS or bret.FAIL 17 | end 18 | 19 | return M 20 | -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/make/crypto.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/crypto.so 2 | 3 | SOURCE=3rd/crypto/luabinding.c \ 4 | 3rd/crypto/lcodec.c \ 5 | 3rd/crypto/lcrc.c \ 6 | 3rd/crypto/lmd5.c \ 7 | 3rd/crypto/lsha1.c \ 8 | 3rd/crypto/lsha2.c \ 9 | 10 | 3rd/crypto/luabinding.c: 11 | git submodule update --init 3rd/crypto/luabinding 12 | 13 | ${BUILD_CLUALIB_DIR}/crypto.so:${SOURCE} 14 | ${CC} $(CFLAGS) -I3rd/lua/crypto -Iskynet/3rd/lua $(SHARED) $^ -o $@ $(LDFLAGS) -lcrypto 15 | 16 | -------------------------------------------------------------------------------- /templates/make/crab.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/crab.so ${BUILD_CLUALIB_DIR}/utf8.so 2 | 3 | CRAB_SOURCE=3rd/crab/lua-crab.c 4 | UTF8_SOURCE=3rd/crab/lua-utf8.c 5 | 6 | ${CRAB_SOURCE}: 7 | git submodule update --init 3rd/crab 8 | 9 | ${BUILD_CLUALIB_DIR}/crab.so: ${CRAB_SOURCE} 10 | ${CC} $(CFLAGS) $(SHARED) -I3rd/crab/src/ -Iskynet/3rd/lua $^ -o $@ $(LDFLAGS) 11 | 12 | ${BUILD_CLUALIB_DIR}/utf8.so: ${UTF8_SOURCE} 13 | ${CC} $(CFLAGS) $(SHARED) -I3rd/crab/src/ -Iskynet/3rd/lua $^ -o $@ $(LDFLAGS) -------------------------------------------------------------------------------- /templates/make/lua-zset.mk: -------------------------------------------------------------------------------- 1 | all:${BUILD_CLUALIB_DIR}/skiplist.so 2 | 3 | LIB=skiplist.so 4 | LUA_ZSET_PATH=3rd/lua-zset 5 | SRC_FILES=$(wildcard $(LUA_ZSET_PATH)/*.c $(LUA_ZSET_PATH)/*.h $(LUA_ZSET_PATH)/*.lua) 6 | 7 | LUA_ZSET_SOURCE=3rd/lua-zset/lua-skiplist.c 8 | 9 | ${LUA_ZSET_SOURCE}: 10 | git submodule update --init 3rd/lua-zset 11 | 12 | ${BUILD_CLUALIB_DIR}/$(LIB): ${SRC_FILES} ${LUA_ZSET_SOURCE} 13 | $(MAKE) -C $(LUA_ZSET_PATH) 14 | cp $(LUA_ZSET_PATH)/$(LIB) $(BUILD_CLUALIB_DIR)/$(LIB) 15 | cp $(LUA_ZSET_PATH)/zset.lua lualib/zset.lua 16 | -------------------------------------------------------------------------------- /templates/make/pbc.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/protobuf.so 2 | 3 | PBC_SOURCE=3rd/pbc/pbc.h 4 | PBC_BINDING=lualib/protobuf.lua 5 | 6 | ${PBC_SOURCE}: 7 | git submodule update --init 3rd/pbc 8 | 9 | ${PBC_BINDING}: 3rd/pbc/binding/lua53/protobuf.lua 10 | cp $< $@ 11 | 12 | ${BUILD_CLUALIB_DIR}/protobuf.so: ${PBC_SOURCE} ${PBC_BINDING} 13 | cd 3rd/pbc && ${MAKE} LUADIR=../../skynet/3rd/lua CFLAGS="-O2 -fPIC -Wall -I../../skynet/3rd/lua" lib 14 | ${CC} ${CFLAGS} ${SHARED} -I3rd/pbc -Iskynet/3rd/lua 3rd/pbc/binding/lua53/pbc-lua53.c -o $@ -L3rd/pbc/build -lpbc 15 | -------------------------------------------------------------------------------- /templates/make/navigation.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/navigation.so 2 | 3 | NAVI_BINDING=lualib/navigation.lua 4 | NAVI_SOURCE=3rd/navigation/luabinding.c \ 5 | 3rd/navigation/map.c \ 6 | 3rd/navigation/jps.c \ 7 | 3rd/navigation/fibheap.c \ 8 | 3rd/navigation/smooth.c 9 | 10 | ${NAVI_SOURCE}: 11 | git submodule update --init 3rd/navigation 12 | 13 | ${NAVI_BINDING}: 14 | cp 3rd/navigation/navigation.lua lualib/navigation.lua 15 | 16 | ${BUILD_CLUALIB_DIR}/navigation.so: ${NAVI_SOURCE} ${NAVI_BINDING} 17 | ${CC} $(CFLAGS) $(SHARED) -o -I3rd/navigation/ -Iskynet/3rd/lua $^ -o $@ 18 | -------------------------------------------------------------------------------- /templates/lualib/bw/xml/lua2xml.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | -- 不带属性的key-value, CDATA标签用于说明数据不被XML解析器解析 3 | function M.encode(k, v, cdata) 4 | local str = '<'..k..'>' 5 | if type(v) == "table" then 6 | for kk, vv in pairs(v) do 7 | str = str .. '\n' .. M.encode(kk, vv, cdata) 8 | end 9 | else 10 | if cdata then 11 | str = str .. '' 12 | else 13 | str = str .. v 14 | end 15 | end 16 | str = str..'' 17 | return str 18 | end 19 | 20 | -- 带属性的key-value 21 | function M.attr_encode() 22 | -- todo 23 | end 24 | return M 25 | -------------------------------------------------------------------------------- /templates/luacheck/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #STAGED_FILES=$(find ./ -name *.lua) 3 | STAGED_FILES=$(git status -s | grep "^[A|M|R|C|U|??].*lua$" | awk '{printf $NF "\n"}') 4 | if [[ "$STAGED_FILES" = "" ]]; then 5 | exit 0 6 | fi 7 | 8 | echo -e "LUACHECK...\n" 9 | # Check for luacheck 10 | which luacheck &> /dev/null 11 | if [[ "$?" == 1 ]]; then 12 | echo -e "\e[1;31mplease install luacheck\e[0m" 13 | exit 1 14 | fi 15 | luacheck --config .luacheckrc $STAGED_FILES 16 | if [[ "$?" == 0 ]]; then 17 | echo -e "\e[1;32mCOMMIT SUCCESSED\e[0m\n" 18 | exit 0 19 | else 20 | echo -e "\e[1;31mCOMMIT FAILED\e[0m\n" 21 | exit 1 22 | fi 23 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/decorators/not.lua: -------------------------------------------------------------------------------- 1 | -- Not 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local M = { 7 | name = 'Not', 8 | type = 'Decorator', 9 | desc = '取反', 10 | doc = [[ 11 | + 将子节点的返回值取反 12 | ]] 13 | } 14 | 15 | function M.run(node, env) 16 | local r 17 | if node:resume(env) then 18 | r = env.last_ret 19 | else 20 | r = node.children[1]:run(env) 21 | end 22 | 23 | if r == bret.SUCCESS then 24 | return bret.FAIL 25 | elseif r == bret.FAIL then 26 | return bret.SUCCESS 27 | elseif r == bret.RUNNING then 28 | return node:yield(env) 29 | end 30 | end 31 | 32 | return M 33 | -------------------------------------------------------------------------------- /templates/lualib/bw/api.lua: -------------------------------------------------------------------------------- 1 | local api = {} 2 | 3 | function api.__call(_, url) 4 | return api[url] 5 | end 6 | 7 | local function not_found(_, k) 8 | error(string.format("index '%s' is not found")) 9 | end 10 | 11 | function api.typedef(protocol) 12 | api[protocol.url] = protocol 13 | 14 | -- for client event dispatcher 15 | local name = protocol.name 16 | if name then 17 | local ns = api 18 | for v in string.gmatch(name, "([^.]+)[.]") do 19 | ns[v] = rawget(ns, v) or setmetatable({}, {__index = not_found}) 20 | ns = ns[v] 21 | end 22 | ns[string.match(name, "[%w_]+$")] = protocol.url 23 | end 24 | end 25 | 26 | return setmetatable(api, api) -------------------------------------------------------------------------------- /templates/lualib/bw/server/web_api.lua: -------------------------------------------------------------------------------- 1 | local api = {} 2 | 3 | function api.__call(_, url) 4 | return api[url] 5 | end 6 | 7 | local function not_found(_, k) 8 | error(string.format("index '%s' is not found")) 9 | end 10 | 11 | function api.typedef(protocol) 12 | api[protocol.url] = protocol 13 | 14 | -- for client event dispatcher 15 | local name = protocol.name 16 | if name then 17 | local ns = api 18 | for v in string.gmatch(name, "([^.]+)[.]") do 19 | ns[v] = rawget(ns, v) or setmetatable({}, {__index = not_found}) 20 | ns = ns[v] 21 | end 22 | ns[string.match(name, "[%w_]+$")] = protocol.url 23 | end 24 | end 25 | 26 | return setmetatable(api, api) -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "3rd/argparse"] 2 | path = 3rd/argparse 3 | url = https://github.com/mpeterv/argparse.git 4 | [submodule "3rd/uuid"] 5 | path = 3rd/uuid 6 | url = https://github.com/Tieske/uuid.git 7 | [submodule "3rd/behavior3"] 8 | path = 3rd/behavior3 9 | url = https://github.com/zhandouxiaojiji/behavior3lua.git 10 | [submodule "3rd/fsm"] 11 | path = 3rd/fsm 12 | url = https://github.com/unindented/lua-fsm.git 13 | [submodule "3rd/revent"] 14 | path = 3rd/revent 15 | url = https://github.com/zhandouxiaojiji/skynet-remote-event.git 16 | [submodule "3rd/fog"] 17 | path = 3rd/fog 18 | url = https://github.com/zhandouxiaojiji/lua-fog.git 19 | [submodule "3rd/git-hooks"] 20 | path = 3rd/git-hooks 21 | url = https://github.com/zhandouxiaojiji/git-hooks.git 22 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/decorators/always_fail.lua: -------------------------------------------------------------------------------- 1 | -- AlwaysSuccess 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local M = { 7 | name = 'AlwaysFail', 8 | type = 'Decorator', 9 | desc = '始终返回失败', 10 | doc = [[ 11 | + 只能有一个子节点,多个仅执行第一个 12 | + 不管子节点是否成功都返回失败 13 | ]] 14 | } 15 | function M.run(node, env, enemy) 16 | local yeild, last_ret = node:resume(env) 17 | if yeild then 18 | if last_ret == bret.RUNNING then 19 | return last_ret 20 | end 21 | return bret.FAIL 22 | end 23 | 24 | local r = node.children[1]:run(env) 25 | if r == bret.RUNNING then 26 | return node:yield(env) 27 | end 28 | return bret.FAIL 29 | end 30 | 31 | return M 32 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all install 2 | 3 | all: 4 | git submodule update --init --recursive 5 | cp 3rd/argparse/src/argparse.lua lualib 6 | cp 3rd/argparse/src/argparse.lua templates/lualib 7 | cp 3rd/uuid/src/uuid.lua templates/lualib 8 | cp 3rd/fsm/src/fsm.lua templates/lualib 9 | rm -r templates/lualib/behavior3 10 | cp -r 3rd/behavior3/behavior3 templates/lualib 11 | cp 3rd/revent/revent.lua templates/lualib 12 | cp 3rd/fog/fog.lua templates/lualib 13 | rm -r templates/luacheck 14 | cp -r 3rd/git-hooks/luacheck templates 15 | 16 | install: 17 | install -m 0755 skynet-creator.sh /usr/local/bin/skynet-creator 18 | mkdir -p /usr/local/share/skynet-creator 19 | rm -rf /usr/local/share/skynet-creator/* 20 | cp -r lualib modules templates /usr/local/share/skynet-creator 21 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/decorators/always_success.lua: -------------------------------------------------------------------------------- 1 | -- AlwaysSuccess 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local M = { 7 | name = 'AlwaysSuccess', 8 | type = 'Decorator', 9 | desc = '始终返回成功', 10 | doc = [[ 11 | + 只能有一个子节点,多个仅执行第一个 12 | + 不管子节点是否成功都返回成功 13 | ]] 14 | } 15 | 16 | function M.run(node, env) 17 | local yeild, last_ret = node:resume(env) 18 | if yeild then 19 | if last_ret == bret.RUNNING then 20 | return last_ret 21 | end 22 | return bret.SUCCESS 23 | end 24 | 25 | local r = node.children[1]:run(env) 26 | if r == bret.RUNNING then 27 | return node:yield(env) 28 | end 29 | return bret.SUCCESS 30 | end 31 | 32 | return M 33 | -------------------------------------------------------------------------------- /templates/make/skynet.mk: -------------------------------------------------------------------------------- 1 | .PHONY: skynet 2 | 3 | all: skynet 4 | 5 | SKYNET_MAKEFILE=skynet/Makefile 6 | 7 | SKYNET_DEP_PATH=SKYNET_BUILD_PATH=../$(BIN_DIR) \ 8 | LUA_CLIB_PATH=../$(BUILD_CLUALIB_DIR) \ 9 | CSERVICE_PATH=../$(BUILD_CSERVICE_DIR) 10 | 11 | 12 | $(SKYNET_MAKEFILE): 13 | git submodule update --init 14 | 15 | build-skynet: | $(SKYNET_MAKEFILE) 16 | cd skynet && $(MAKE) PLAT=linux $(SKYNET_DEP_PATH) TLS_MODULE=ltls 17 | 18 | skynet: build-skynet 19 | cp skynet/skynet-src/skynet_malloc.h $(INCLUDE_DIR) 20 | cp skynet/skynet-src/skynet.h $(INCLUDE_DIR) 21 | cp skynet/skynet-src/skynet_env.h $(INCLUDE_DIR) 22 | cp skynet/skynet-src/skynet_socket.h $(INCLUDE_DIR) 23 | cp skynet/3rd/lua/*.h $(INCLUDE_DIR) 24 | cp skynet/3rd/lua/lua $(BIN_DIR) -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/actions/wait.lua: -------------------------------------------------------------------------------- 1 | -- Wait 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local M = { 7 | name = 'Wait', 8 | type = 'Action', 9 | desc = '等待', 10 | args = { 11 | {'time', 'int', '时间/tick'} 12 | } 13 | } 14 | 15 | local abs = math.abs 16 | local SPEED = 50 17 | 18 | function M.run(node, env) 19 | local args = node.args 20 | local t = node:resume(env) 21 | if t then 22 | if env.ctx.time >= t then 23 | print('CONTINUE') 24 | return bret.SUCCESS 25 | else 26 | print('WAITING') 27 | return bret.RUNNING 28 | end 29 | end 30 | print('Wait', args.time) 31 | return node:yield(env, env.ctx.time + args.time) 32 | end 33 | 34 | return M 35 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/sample_process.lua: -------------------------------------------------------------------------------- 1 | return { 2 | -- 复合节点 3 | Parallel = require "behavior3.nodes.composites.parallel", 4 | Selector = require "behavior3.nodes.composites.selector", 5 | Sequence = require "behavior3.nodes.composites.sequence", 6 | Once = require "behavior3.nodes.composites.once", 7 | 8 | -- 装饰节点 9 | Not = require "behavior3.nodes.decorators.not", 10 | AlwaysFail = require "behavior3.nodes.decorators.always_fail", 11 | AlwaysSuccess = require "behavior3.nodes.decorators.always_success", 12 | 13 | -- 条件节点 14 | Cmp = require "behavior3.nodes.conditions.cmp", 15 | Check = require "behavior3.nodes.conditions.check", 16 | 17 | -- 行为节点 18 | Log = require "behavior3.nodes.actions.log", 19 | Wait = require "behavior3.nodes.actions.wait", 20 | } -------------------------------------------------------------------------------- /lualib/libs.lua: -------------------------------------------------------------------------------- 1 | local bash = require "bash" 2 | 3 | local function echo(str) 4 | print(bash.format(str)) 5 | end 6 | 7 | local function file_exists(str) 8 | return bash.file_exists(bash.format(str)) 9 | end 10 | 11 | local M = {} 12 | function M.import(root, name) 13 | echo "import module ${name}" 14 | local conf = require("modules."..name) 15 | if conf.submodule then 16 | bash.execute "mkdir -p ${root}/3rd" 17 | if not file_exists("${root}/3rd/${name}") then 18 | bash.execute "cd ${root} && git submodule add ${conf.submodule} 3rd/${name}" 19 | end 20 | end 21 | 22 | if conf.make then 23 | bash.execute "cp -v templates/make/${conf.make} ${root}/make" 24 | bash.execute "cd ${root} && make" 25 | end 26 | 27 | if conf.process then 28 | conf.process(root) 29 | end 30 | end 31 | return M -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/composites/parallel.lua: -------------------------------------------------------------------------------- 1 | -- Parallel 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local M = { 7 | name = 'Parallel', 8 | type = 'Composite', 9 | desc = '并行执行', 10 | doc = [[ 11 | 执行所有子节点并返回成功 12 | ]] 13 | } 14 | function M.run(node, env) 15 | local last_idx, last_ret = node:resume(env) 16 | if last_idx then 17 | if last_ret == bret.RUNNING then 18 | return last_ret 19 | end 20 | last_idx = last_idx + 1 21 | else 22 | last_idx = 1 23 | end 24 | 25 | for i = last_idx, #node.children do 26 | local child = node.children[i] 27 | local r = child:run(env) 28 | if r == bret.RUNNING then 29 | return node:yield(env, i) 30 | end 31 | end 32 | return bret.SUCCESS 33 | end 34 | 35 | return M 36 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/composites/once.lua: -------------------------------------------------------------------------------- 1 | -- Once 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local sformat = string.format 7 | 8 | local M = { 9 | name = "Once", 10 | type = "Composite", 11 | desc = "只执行一次", 12 | doc = [[ 13 | + 可以接多个子节点,子节点默认全部执行 14 | + 被打断后该节点后的子节点依旧不会执行 15 | + 该节点执行后永远返回成功 16 | ]] 17 | } 18 | function M.run(node, env) 19 | local key = sformat("%s#%d_once", node.name, node.id) 20 | if env:get_var(key) == true then 21 | return bret.FAIL 22 | end 23 | 24 | for _, child in ipairs(node.children) do 25 | local r = child:run(env) 26 | if r == bret.RUNNING then 27 | error(sformat("%s should not return running status", node.info)) 28 | end 29 | end 30 | 31 | env:set_var(key, true) 32 | return bret.FAIL 33 | end 34 | 35 | return M 36 | -------------------------------------------------------------------------------- /templates/lualib/bw/helper/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(code, err_name, describe) 10 | assert(not code2describe[code], string.format("errcode 0x%x exist", code)) 11 | assert(not name2errcode[err_name], string.format("errcode '%s' exist", err_name)) 12 | name2errcode[err_name] = code 13 | code2describe[code] = string.format("0x%x:%s【%s】", code, err_name, describe) 14 | end 15 | errcode.REG = REG 16 | 17 | function errcode.describe(code) 18 | return code2describe[code] 19 | end 20 | 21 | function errcode.get_name2errcode() 22 | return name2errcode 23 | end 24 | 25 | function errcode.pack(code) 26 | return {err = code} 27 | end 28 | 29 | setmetatable(errcode, {__index = function (_, name) 30 | return assert(name2errcode[name], name) 31 | end}) 32 | 33 | return errcode -------------------------------------------------------------------------------- /templates/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | all: build skynet 3 | 4 | TOP=. 5 | BUILD_DIR=./build 6 | BIN_DIR=./build/bin 7 | LOG_DIR=./logs 8 | LUALIB_DIR=./lualib 9 | SERVICE_DIR=./service 10 | 11 | INCLUDE_DIR=$(BUILD_DIR)/include 12 | BUILD_CLUALIB_DIR=$(BUILD_DIR)/clualib 13 | BUILD_CSERVICE_DIR=$(BUILD_DIR)/cservice 14 | BUILD_CLIB_DIR=$(BUILD_DIR)/clib 15 | 16 | LUA_BIN="./skynet/3rd/lua/lua" 17 | export LUA_CPATH=$(TOP)/$(BUILD_CLUALIB_DIR)/?.so 18 | export LUA_PATH=$(TOP)/lualib/?.lua;$(TOP)/skynet/lualib/?.lua; 19 | 20 | build: 21 | -mkdir -p $(BUILD_DIR) 22 | -mkdir -p $(BIN_DIR) 23 | -mkdir -p $(LOG_DIR) 24 | -mkdir -p $(INCLUDE_DIR) 25 | -mkdir -p $(BUILD_CLUALIB_DIR) 26 | -mkdir -p $(BUILD_CSERVICE_DIR) 27 | -mkdir -p $(BUILD_CLIB_DIR) 28 | 29 | CC = gcc 30 | CFLAGS = -g -O2 31 | SHARED = -fPIC --shared 32 | 33 | MAKES=$(shell find ./make -name *.mk) 34 | include ${MAKES} 35 | 36 | clean: 37 | cd skynet && $(MAKE) clean 38 | -rm -rf $(BUILD_DIR) -------------------------------------------------------------------------------- /templates/lualib/bw/server/web_auth.lua: -------------------------------------------------------------------------------- 1 | local uuid = require "uuid" 2 | local log = require "bw.log" 3 | 4 | local string_gsub = string.gsub 5 | local uid2auth = {} 6 | local auth2uid = {} 7 | 8 | local M = {} 9 | function M.create(uid) 10 | local auth = uid2auth[uid] 11 | if auth then 12 | auth2uid[auth] = nil 13 | end 14 | while true do 15 | auth = string_gsub(uuid(), '-', '') 16 | if not auth2uid[auth] then 17 | break 18 | end 19 | end 20 | uid2auth[uid] = auth 21 | auth2uid[auth] = uid 22 | log.infof("create auth: %d %s", uid, auth) 23 | return auth 24 | end 25 | 26 | function M.remove(uid) 27 | local auth = uid2auth[uid] 28 | if auth then 29 | auth2uid[auth] = nil 30 | end 31 | uid2auth[uid] = nil 32 | log.infof("remove auth: %d %s", uid, auth) 33 | end 34 | 35 | function M.get_uid(auth) 36 | return auth2uid[auth] 37 | end 38 | 39 | function M.get_auth(uid) 40 | return uid2auth[uid] or M.create(uid) 41 | end 42 | 43 | return M 44 | -------------------------------------------------------------------------------- /import.lua: -------------------------------------------------------------------------------- 1 | package.path = "lualib/?.lua;"..package.path 2 | 3 | local argparse = require "argparse" 4 | local bash = require "bash" 5 | local github = require "github" 6 | local libs = require "libs" 7 | 8 | local function echo(str) 9 | print(bash.format(str)) 10 | end 11 | 12 | local function file_exists(str) 13 | return bash.file_exists(bash.format(str)) 14 | end 15 | 16 | echo "welcome to skynet creator !" 17 | 18 | local parser = argparse("main.lua") 19 | parser:description("skynet creator import tool") 20 | parser:option("--force"):default("false"):description("force remove if workdir is exist") 21 | parser:argument("workdir"):description("the path of skynet project you want to import.") 22 | parser:argument("modules"){args = "*"}:description("the modules you want to import.") 23 | 24 | local args = parser:parse() 25 | 26 | local root = args.workdir 27 | if not file_exists(root) then 28 | echo "workdir ${root} is not exist" 29 | return 30 | end 31 | 32 | for _, name in pairs(args.modules) do 33 | libs.import(root, name) 34 | end -------------------------------------------------------------------------------- /templates/lualib/bw/auth/tt.lua: -------------------------------------------------------------------------------- 1 | -- 头条验证(与微信基本一致) 2 | local wx = require "bw.auth.wx" 3 | 4 | local M = {} 5 | function M.request_access_token(appid, secret) 6 | return wx.request_access_token(appid, secret, 7 | 'https://developer.toutiao.com/api/apps/token') 8 | end 9 | 10 | function M.jscode2session(appid, secret, js_code) 11 | return wx.jscode2session(appid, secret, js_code, 12 | 'https://developer.toutiao.com/api/apps/jscode2session') 13 | end 14 | 15 | -- data {score = 100, gold = 300} 16 | function M.set_user_storage(appid, access_token, openid, session_key, data) 17 | return wx.set_user_storage(appid, access_token, openid, session_key, data, 18 | 'https://developer.toutiao.com/api/apps/set_user_storage') 19 | end 20 | 21 | -- key_list {"score", "gold"} 22 | function M.remove_user_storage(appid, access_token, openid, session_key, key_list) 23 | return wx.remove_user_storage(appid, access_token, openid, session_key, key_list, 24 | 'https://developer.toutiao.com/api/apps/remove_user_storage') 25 | end 26 | 27 | return M 28 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/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 | 6 | local db 7 | return function(conf) 8 | skynet.start(function() 9 | local function on_connect(_db) 10 | _db:query("set charset utf8") 11 | end 12 | db=mysql.connect({ 13 | host = conf.host, 14 | port = conf.port, 15 | database = conf.name, 16 | user = conf.user, 17 | password = conf.pswd, 18 | max_packet_size = conf.max_packet_size or 1024 * 1024, 19 | on_connect = on_connect 20 | }) 21 | skynet.dispatch("lua", function(_, _, cmd, ...) 22 | local f = assert(db[cmd]) 23 | local ret = f(db, ...) 24 | assert(not ret.err,string.format("mysql error:%s\n%s", table.pack(...)[1], util.dump(ret))) 25 | skynet.ret(ret) 26 | end) 27 | end) 28 | end 29 | 30 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/composites/selector.lua: -------------------------------------------------------------------------------- 1 | -- Selector 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local M = { 7 | name = 'Selector', 8 | type = 'Composite', 9 | desc = '选择执行', 10 | doc = [[ 11 | + 一直往下执行,有子节点返回成功则返回成功,若全部节点返回失败则返回失败 12 | + 子节点是或 (OR) 的关系 13 | ]] 14 | } 15 | function M.run(node, env) 16 | local last_idx, last_ret = node:resume(env) 17 | if last_idx then 18 | if last_ret == bret.SUCCESS or last_ret == bret.RUNNING then 19 | return last_ret 20 | elseif last_ret == bret.FAIL then 21 | last_idx = last_idx + 1 22 | else 23 | error('wrong ret') 24 | end 25 | else 26 | last_idx = 1 27 | end 28 | 29 | for i = last_idx, #node.children do 30 | local child = node.children[i] 31 | local r = child:run(env) 32 | if r == bret.RUNNING then 33 | return node:yield(env, i) 34 | end 35 | if r == bret.SUCCESS then 36 | return r 37 | end 38 | end 39 | return bret.FAIL 40 | end 41 | 42 | return M 43 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/composites/sequence.lua: -------------------------------------------------------------------------------- 1 | -- Sequence 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local M = { 7 | name = 'Sequence', 8 | type = 'Composite', 9 | desc = '顺序执行', 10 | doc = [[ 11 | + 一直往下执行,只有当所有子节点都返回成功, 才返回成功 12 | + 子节点是与(AND)的关系 13 | ]] 14 | } 15 | 16 | function M.run(node, env) 17 | local last_idx, last_ret = node:resume(env) 18 | if last_idx then 19 | -- print("last", last_idx, last_ret) 20 | if last_ret == bret.FAIL or last_ret == bret.RUNNING then 21 | return last_ret 22 | elseif last_ret == bret.SUCCESS then 23 | last_idx = last_idx + 1 24 | else 25 | error('wrong ret') 26 | end 27 | else 28 | last_idx = 1 29 | end 30 | 31 | for i = last_idx, #node.children do 32 | local child = node.children[i] 33 | local r = child:run(env) 34 | if r == bret.RUNNING then 35 | return node:yield(env, i) 36 | end 37 | if r == bret.FAIL then 38 | return r 39 | end 40 | end 41 | return bret.SUCCESS 42 | end 43 | 44 | return M 45 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/id_producer.lua: -------------------------------------------------------------------------------- 1 | local lock = require "bw.lock" 2 | local bewater = require "bw.bewater" 3 | 4 | local reserve_id 5 | local id 6 | 7 | local reserve_count -- 预分配数 8 | local initial_id -- 初始id 9 | local load_id, save_id -- load & save function 10 | 11 | local lock_create = lock.new() 12 | 13 | local M = {} 14 | function M.start(handler) 15 | load_id = assert(handler.load_id) 16 | save_id = assert(handler.save_id) 17 | reserve_count = handler.reserve_count or 100 18 | initial_id = handler.initial_id or 10000000 19 | id = load_id() 20 | if not id then 21 | id = initial_id 22 | end 23 | reserve_id = id + reserve_count 24 | save_id(reserve_id) 25 | end 26 | 27 | function M.save() 28 | save_id(id) 29 | end 30 | 31 | function M.create(count) 32 | local start_id 33 | lock_create:lock() 34 | bewater.try(function() 35 | count = count or 1 36 | start_id = id 37 | id = id + count 38 | if id > reserve_id then 39 | reserve_id = id + reserve_count 40 | save_id(reserve_id) 41 | end 42 | end) 43 | lock_create:unlock() 44 | return start_id, count 45 | end 46 | 47 | return M 48 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/conditions/cmp.lua: -------------------------------------------------------------------------------- 1 | -- Cmp 2 | 3 | local bret = require 'behavior3.behavior_ret' 4 | 5 | local M = { 6 | name = 'Cmp', 7 | type = 'Condition', 8 | desc = '比较值大小', 9 | args = { 10 | {'value', 'code?', '值'}, 11 | {'gt', 'int?', '>'}, 12 | {'ge', 'int?', '>='}, 13 | {'eq', 'int?', '=='}, 14 | {'le', 'int?', '<='}, 15 | {'lt', 'int?', '<'} 16 | }, 17 | input = {'值(int)'}, 18 | doc = [[ 19 | + 若值为空,返回失败 20 | + 非整数类型可能会报错 21 | ]] 22 | } 23 | 24 | local function ret(r) 25 | return r and bret.SUCCESS or bret.FAIL 26 | end 27 | 28 | function M.run(node, env, value) 29 | value = value or node:get_env_args("value", env) 30 | assert(type(value) == 'number') 31 | local args = node.args 32 | if args.gt then 33 | return ret(value > args.gt) 34 | elseif args.ge then 35 | return ret(value >= args.ge) 36 | elseif args.eq then 37 | return ret(value == args.eq) 38 | elseif args.lt then 39 | return ret(value < args.lt) 40 | elseif args.le then 41 | return ret(value <= args.le) 42 | else 43 | error('args error') 44 | end 45 | end 46 | 47 | return M -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/composites/loop.lua: -------------------------------------------------------------------------------- 1 | local bret = require "behavior3.behavior_ret" 2 | 3 | local M = { 4 | name = "Loop", 5 | type = 'Composite', 6 | desc = "循环执行", 7 | args = { 8 | {"count", "int?", "次数"}, 9 | }, 10 | input = {"次数(int)?"}, 11 | } 12 | 13 | function M.run(node, env, count) 14 | count = count or node.args.count 15 | local resume_data, resume_ret = node:resume(env) 16 | local last_i = 1 17 | local last_j = 1 18 | if resume_data then 19 | last_i = resume_data[1] 20 | last_j = resume_data[2] 21 | if resume_ret == bret.RUNNING then 22 | return resume_ret 23 | else 24 | last_j = last_j + 1 25 | if last_j > #node.children then 26 | last_j = 1 27 | last_i = last_i + 1 28 | end 29 | end 30 | end 31 | 32 | for i = last_i, count do 33 | for j = last_j, #node.children do 34 | local child = node.children[j] 35 | local r = child:run(env) 36 | if r == bret.RUNNING then 37 | return node:yield(env, { i, j }) 38 | end 39 | end 40 | end 41 | return bret.SUCCESS 42 | end 43 | 44 | return M -------------------------------------------------------------------------------- /templates/lualib/bw/util/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 | if not tail_obj then 19 | return 20 | end 21 | self._array[idx] = tail_obj 22 | self._array[#self._array] = nil 23 | self._hash[obj] = nil 24 | self._hash[tail_obj] = idx 25 | end 26 | 27 | function mt:has(obj) 28 | return self._hash[obj] ~= nil 29 | end 30 | 31 | function mt:random_one() 32 | return self._array[math.random(1, #self._array)] 33 | end 34 | 35 | function mt:random_index() 36 | return math.random(1, #self._array) 37 | end 38 | 39 | function mt:index(idx) 40 | return self._array[idx] 41 | end 42 | 43 | function mt:len() 44 | return #self._array 45 | end 46 | 47 | function mt:clear() 48 | self._array = {} 49 | self._hash = {} 50 | end 51 | 52 | local M = {} 53 | function M.new() 54 | local obj = { 55 | _array = {}, 56 | _hash = {}, 57 | } 58 | return setmetatable(obj, mt) 59 | end 60 | return M 61 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/composites/foreach.lua: -------------------------------------------------------------------------------- 1 | local bret = require "behavior3.behavior_ret" 2 | 3 | local M = { 4 | name = "ForEach", 5 | type = 'Composite', 6 | desc = "遍历数组", 7 | input = { "[{数组}]" }, 8 | output = { "{变量}" }, 9 | doc = [[ 10 | + 每次执行子节点前会设置当前遍历到的变量 11 | + 会执行所有子节点 12 | + 永远返回成功/正在运行 13 | ]] 14 | } 15 | 16 | function M.run(node, env, arr) 17 | local resume_data, resume_ret = node:resume(env) 18 | local last_i = 1 19 | local last_j = 1 20 | if resume_data then 21 | last_i = resume_data[1] 22 | last_j = resume_data[2] 23 | if resume_ret == bret.RUNNING then 24 | return resume_ret 25 | else 26 | last_j = last_j + 1 27 | if last_j > #node.children then 28 | last_j = 1 29 | last_i = last_i + 1 30 | end 31 | end 32 | end 33 | 34 | for i = last_i, #arr do 35 | local var = arr[i] 36 | env:set_var(node.data.output[1], var) 37 | for j = last_j, #node.children do 38 | local child = node.children[j] 39 | local r = child:run(env) 40 | if r == bret.RUNNING then 41 | return node:yield(env, { i, j }) 42 | end 43 | end 44 | end 45 | return bret.SUCCESS 46 | end 47 | 48 | return M 49 | -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/nodes/composites/ifelse.lua: -------------------------------------------------------------------------------- 1 | -- IfElse 2 | -- 3 | 4 | local bret = require 'behavior3.behavior_ret' 5 | 6 | local M = { 7 | name = 'IfElse', 8 | type = 'Composite', 9 | desc = 'If判断', 10 | doc = [[ 11 | + 拥有三个子节点(至少两个) 12 | + 当第一个子节点返回SUCCESS的时候执行第二个子节点并返回此子节点的返回值 13 | + 否则执行第三个子节点并返回这个节点的返回值,若无第三个子节点,则返回FAIL 14 | ]] 15 | } 16 | 17 | local function child_ret(node, env, idx) 18 | local r = node.children[idx]:run(env) 19 | return r == bret.RUNNING and node:yield(env, idx) or r 20 | end 21 | 22 | local function ifelse(node, env, ret) 23 | if ret == bret.RUNNING then 24 | return ret 25 | end 26 | if ret == bret.SUCCESS then 27 | return child_ret(node, env, 2) 28 | elseif node.children[3] then 29 | return child_ret(node, env, 3) 30 | else 31 | return bret.FAIL 32 | end 33 | end 34 | 35 | function M.run(node, env) 36 | assert(#node.children >= 2, "at least two children") 37 | 38 | local last_idx, last_ret = node:resume(env) 39 | if last_ret == bret.RUNNING then 40 | return last_ret 41 | end 42 | if last_idx == 1 then 43 | return ifelse(node, env, last_ret) 44 | elseif last_idx == 2 or last_idx == 3 then 45 | return last_ret 46 | end 47 | 48 | local r = node.children[1]:run(env) 49 | if r == bret.RUNNING then 50 | return node:yield(env, 1) 51 | end 52 | return ifelse(node, env, r) 53 | end 54 | 55 | return M 56 | -------------------------------------------------------------------------------- /templates/lualib/bw/payment/applepay.lua: -------------------------------------------------------------------------------- 1 | -- 苹果支付 2 | local json = require "cjson.safe" 3 | local log = require "bw.log" 4 | local http = require "bw.http" 5 | 6 | local M = {} 7 | function M.verify_receipt(receipt, product_id) 8 | local is_sandbox = false 9 | local receipt_data = json.encode({["receipt-data"] = receipt}) 10 | local ret, resp_str = http.post("https://buy.itunes.apple.com/verifyReceipt", receipt_data) 11 | local resp = json.decode(resp_str) 12 | if not ret then 13 | log.errorf("verify_receipt error, post:buy, product_id:%s, receipt:%s", 14 | product_id, receipt) 15 | return 16 | end 17 | if not resp or resp.status ~= 0 then 18 | log.debug("try sandbox") 19 | ret, resp_str = http.post("https://sandbox.itunes.apple.com/verifyReceipt", receipt_data) 20 | resp = json.decode(resp_str) 21 | is_sandbox = true 22 | end 23 | if not ret or not resp or resp.status ~= 0 then 24 | log.errorf("verify_receipt error, ret:%s, resp:%s", ret, resp_str) 25 | return 26 | end 27 | if not product_id then 28 | return resp.receipt.in_app[1].original_transaction_id, is_sandbox 29 | end 30 | for i, v in pairs(resp.receipt.in_app) do 31 | if v.product_id == product_id then 32 | return v.original_transaction_id, is_sandbox 33 | end 34 | end 35 | log.errorf("verify_receipt error, product_id is wrong, product_id:%s, ret:%s, resp_str:%s", 36 | product_id, ret, resp_str) 37 | end 38 | return M 39 | 40 | -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/lualib/bw/payment/vvpay.lua: -------------------------------------------------------------------------------- 1 | -- vivo 支付 2 | local crypto = require "crypto" 3 | local sign = require "bw.auth.sign" 4 | 5 | local md5 = crypto.md5_encode 6 | 7 | local M = {} 8 | function M.create_order(param) 9 | assert(param.appid) 10 | assert(param.order_no) 11 | local url = param.url 12 | 13 | local args = { 14 | appId = param.appid, 15 | cpOrderNumber = param.order_no, 16 | orderAmount = param.pay_price, 17 | productName = param.item_desc, 18 | productDesc = param.item_desc, 19 | notifyUrl = url, 20 | } 21 | 22 | local str1 = sign.concat_args(args) 23 | local str2 = string.lower(md5(param.appsecret)) 24 | local str = string.lower(md5(str1 .. "&" .. str2)) 25 | 26 | return { 27 | appid = param.appid, 28 | order_no = param.order_no, 29 | notify_url = param.url, 30 | product_price = param.pay_price, 31 | product_name = param.item_desc, 32 | product_des = param.item_desc, 33 | sign = str, 34 | } 35 | end 36 | 37 | function M.notify(param, app_secret) 38 | local args = {} 39 | for k, v in pairs(param) do 40 | if k ~= "signature" and k ~= "signMethod" then 41 | args[k] = v 42 | end 43 | end 44 | 45 | local str1 = sign.concat_args(args) 46 | local str2 = string.lower(md5(app_secret)) 47 | local str = string.lower(md5(str1 .. "&" .. str2)) 48 | 49 | return str == param.signature and param.tradeStatus == '0000' 50 | and param.respCode == '200' 51 | end 52 | 53 | return M 54 | -------------------------------------------------------------------------------- /templates/lualib/bw/auth/sign.lua: -------------------------------------------------------------------------------- 1 | local md5 = require "md5" 2 | local openssl = require "openssl" 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 | table_sort(list, function(a, b) 26 | return a < b 27 | end) 28 | return table_concat(list, "&") 29 | end 30 | 31 | function M.md5_args(args, key, mark) 32 | local str = M.concat_args(args, mark) 33 | if key then 34 | str = str .. (#str > 0 and "&key=" or "key=") .. key 35 | end 36 | return string_upper(md5.sumhexa(str)) 37 | end 38 | 39 | local function rsa_sign(args, private_key, mark, sign_type) 40 | local evp = openssl.pkey.read(private_key, true) 41 | local str = M.concat_args(args, mark) 42 | return encode_uri(openssl.base64(evp:sign(str, sign_type))) 43 | end 44 | 45 | function M.rsa_sign(args, private_key, mark) 46 | return rsa_sign(args, private_key, mark, "sha1") 47 | end 48 | 49 | function M.rsa_sha256_sign(args, private_key, mark) 50 | return rsa_sign(args, private_key, mark, "sha256") 51 | end 52 | 53 | return M 54 | -------------------------------------------------------------------------------- /templates/lualib/bw/helper/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 -------------------------------------------------------------------------------- /templates/make/openssl.mk: -------------------------------------------------------------------------------- 1 | all: ${BUILD_CLUALIB_DIR}/openssl.so 2 | 3 | OPENSSL_SOUCE=3rd/openssl/src/asn1.c \ 4 | 3rd/openssl/src/asn1.c \ 5 | 3rd/openssl/src/bio.c \ 6 | 3rd/openssl/src/cipher.c \ 7 | 3rd/openssl/src/cms.c \ 8 | 3rd/openssl/src/compat.c \ 9 | 3rd/openssl/src/crl.c \ 10 | 3rd/openssl/src/csr.c \ 11 | 3rd/openssl/src/dh.c \ 12 | 3rd/openssl/src/digest.c \ 13 | 3rd/openssl/src/dsa.c \ 14 | 3rd/openssl/src/ec.c \ 15 | 3rd/openssl/src/engine.c \ 16 | 3rd/openssl/src/hmac.c \ 17 | 3rd/openssl/src/lbn.c \ 18 | 3rd/openssl/src/lhash.c \ 19 | 3rd/openssl/src/misc.c \ 20 | 3rd/openssl/src/ocsp.c \ 21 | 3rd/openssl/src/openssl.c \ 22 | 3rd/openssl/src/ots.c \ 23 | 3rd/openssl/src/pkcs12.c \ 24 | 3rd/openssl/src/pkcs7.c \ 25 | 3rd/openssl/src/pkey.c \ 26 | 3rd/openssl/src/rsa.c \ 27 | 3rd/openssl/src/ssl.c \ 28 | 3rd/openssl/src/th-lock.c \ 29 | 3rd/openssl/src/util.c \ 30 | 3rd/openssl/src/x509.c \ 31 | 3rd/openssl/src/xattrs.c \ 32 | 3rd/openssl/src/xexts.c \ 33 | 3rd/openssl/src/xname.c \ 34 | 3rd/openssl/src/xstore.c \ 35 | 3rd/openssl/src/xalgor.c \ 36 | 3rd/openssl/src/callback.c \ 37 | 3rd/openssl/src/srp.c \ 38 | 3rd/openssl/deps/auxiliar/subsidiar.c \ 39 | 3rd/openssl/deps/auxiliar/auxiliar.c 40 | 41 | SUBSIDIAR_C=3rd/openssl/deps/auxiliar/subsidiar.c 42 | 43 | $(SUBSIDIAR_C): 44 | cd 3rd/openssl && git submodule update --init 45 | 46 | ${BUILD_CLUALIB_DIR}/openssl.so:${OPENSSL_SOUCE} 47 | ${CC} $(CFLAGS) -I3rd/openssl/src -I3rd/openssl/deps/auxiliar -Iskynet/3rd/lua $(SHARED) $^ -o $@ -lssl -lcrypto -------------------------------------------------------------------------------- /templates/lualib/bw/payment/oppay.lua: -------------------------------------------------------------------------------- 1 | -- oppo支付 2 | local crypto = require "crypto" 3 | local sign = require "bw.auth.sign" 4 | local util = require "bw.util" 5 | local http = require "bw.http" 6 | local log = require "bw.log" 7 | local errcode = require "def.errcode" 8 | 9 | local CALLBACK_OK = "OK" 10 | local CALLBACK_FAIL = "FAIL" 11 | 12 | local M = {} 13 | function M.create_order(param) 14 | local order_no = assert(param.order_no) 15 | local item_desc = assert(param.item_name) 16 | local pay_price = assert(param.pay_price) 17 | local secret = assert(param.secret) 18 | local url = assert(param.url) 19 | assert(param.pay_channel) 20 | assert(param.item_sn) 21 | 22 | return { 23 | order_no = order_no, 24 | price = pay_price*100//1 >> 0, 25 | name = item_desc, 26 | desc = item_desc, 27 | url = url, 28 | attach = crypto.md5_encode(order_no..secret), 29 | } 30 | end 31 | 32 | function M.notify(param, public_key, secret) 33 | local list = { 34 | string.format('%s=%s', 'notifyId', param.notifyId), 35 | string.format('%s=%s', 'partnerOrder', param.partnerOrder), 36 | string.format('%s=%s', 'productName', param.productName), 37 | string.format('%s=%s', 'productDesc', param.productDesc), 38 | string.format('%s=%d', 'price', param.price), 39 | string.format('%s=%d', 'count', param.count), 40 | string.format('%s=%s', 'attach', param.attach), 41 | } 42 | local src = table.concat(list, "&") 43 | local bs = crypto.base64_decode(param.sign) 44 | local pem = public_key 45 | return crypto.rsa_verify(src, bs, pem, 2) 46 | 47 | end 48 | return M 49 | -------------------------------------------------------------------------------- /templates/lualib/bw/payment/hwpay.lua: -------------------------------------------------------------------------------- 1 | -- 华为支付 2 | local skynet = require "skynet" 3 | local crypto = require "crypto" 4 | local sign = require "bw.auth.sign" 5 | local http = require "bw.http" 6 | 7 | local M = {} 8 | function M.create_order(param) 9 | local order_no = assert(param.order_no, 'no order no') 10 | local url = assert(param.url) 11 | assert(param.appid, 'no appid') 12 | assert(param.item_name, 'no item name') 13 | assert(param.pay_channel, 'no pay channel') 14 | assert(param.pay_method, 'no pay method') 15 | assert(param.catalog, 'no catalog') 16 | 17 | 18 | local args = { 19 | productNo = param.item_name, 20 | applicationID = param.appid, 21 | merchantId = param.cpid, 22 | requestId = order_no, 23 | sdkChannel = '1', 24 | urlver = '2', 25 | url = url, 26 | } 27 | local str = sign.concat_args(args) 28 | local bs = crypto.rsa_sha256_sign(str, param.private_key) 29 | str = crypto.base64_encode(bs) 30 | 31 | return { 32 | appid = param.appid, 33 | cpid = param.cpid, 34 | cp = param.cp, 35 | pid = param.item_name, 36 | order_no = order_no, 37 | url = url, 38 | catalog = param.catalog, 39 | sign = str, 40 | } 41 | end 42 | 43 | 44 | function M.notify(public_key, param) 45 | local args = {} 46 | for k, v in pairs(param) do 47 | if k ~= "sign" and k ~= "signType" then 48 | args[k] = v 49 | end 50 | end 51 | 52 | local src = sign.concat_args(args) 53 | local bs = crypto.base64_decode(http.decode_uri(param.sign)) 54 | local pem = public_key 55 | return crypto.rsa_sha256_verify(src, bs, pem, 2) 56 | end 57 | 58 | return M 59 | -------------------------------------------------------------------------------- /templates/lualib/bw/auth/huawei.lua: -------------------------------------------------------------------------------- 1 | local json = require "cjson.safe" 2 | local crypto = require "crypto" 3 | local sign = require "bw.auth.sign" 4 | local log = require "bw.log" 5 | local util = require "bw.util" 6 | local http = require "bw.http" 7 | 8 | local table_insert = table.insert 9 | local table_sort = table.sort 10 | local table_concat = table.concat 11 | 12 | local API = 'https://gss-cn.game.hicloud.com/gameservice/api/gbClientApi' 13 | 14 | local function encode_uri(s) 15 | assert(s) 16 | s = string.gsub(s, "([^A-Za-z0-9])", function(c) 17 | return string.format("%%%02X", string.byte(c)) 18 | end) 19 | return s 20 | end 21 | 22 | local M = {} 23 | function M.gen_token(params, private_key) 24 | local method = 'methodexternal.hms.gs.checkPlayerSign' 25 | local args = { 26 | method = 'external.hms.gs.checkPlayerSign', 27 | appId = encode_uri(params.app_id), 28 | cpId = encode_uri(params.cp_id), 29 | ts = encode_uri(params.ts), 30 | playerId = encode_uri(params.player_id), 31 | playerLevel = encode_uri(params.player_level), 32 | playerSSign = encode_uri(params.player_ssign), 33 | } 34 | local data = sign.concat_args(args) 35 | local sign_str = crypto.rsa_sha256_sign(data, private_key) 36 | sign_str = crypto.base64_encode(sign_str) 37 | args.cpSign = encode_uri(sign_str) 38 | local ret, resp_str = http.post(API, sign.concat_args(args)) 39 | if not ret then 40 | log.error('cannot request huawei api') 41 | return 42 | end 43 | local resp = json.decode(resp_str) 44 | if not resp or not resp.rtnSign then 45 | log.error('huawei api decode error, resp:' 46 | ..resp_str..' params:'..util.dump(params)) 47 | return 48 | end 49 | return resp.rtnSign 50 | end 51 | 52 | return M 53 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/balance_gate.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local socket = require "skynet.socket" 3 | local log = require "bw.log" 4 | 5 | local gateserver = {} 6 | local agents = {} 7 | 8 | local CMD = {} 9 | function CMD.call_agent(...) 10 | return skynet.call(agents[1], "lua", ...) 11 | end 12 | 13 | function CMD.call_all_agent(...) 14 | for _, agent in pairs(agents) do 15 | skynet.pcall(agent, "lua", ...) 16 | end 17 | end 18 | 19 | function gateserver.start(conf, ...) 20 | local agentname = assert(conf.agentname) 21 | local port = assert(conf.port) 22 | local preload = assert(conf.preload or 10) 23 | local command = assert(conf.command) 24 | local start_func = conf.start_func 25 | log.infof("gateserver start, agentname:%s, port:%d, preload:%d", agentname, port, preload) 26 | 27 | for k, v in pairs(CMD) do 28 | command[k] = command[k] or v 29 | end 30 | 31 | local args = {...} 32 | skynet.start(function() 33 | for i= 1, preload or 10 do 34 | agents[i] = skynet.newservice(agentname, table.unpack(args)) 35 | end 36 | local balance = 1 37 | local fd = socket.listen("0.0.0.0", port) 38 | log.infof("listen port:%s", port) 39 | socket.start(fd , function(in_fd, ip) 40 | --log.debugf("%s connected, pass it to agent :%08x", _fd, agents[balance]) 41 | skynet.send(agents[balance], "lua", "open", in_fd, ip) 42 | balance = balance + 1 43 | if balance > #agents then 44 | balance = 1 45 | end 46 | end) 47 | 48 | skynet.dispatch("lua", function(_, _, cmd, ...) 49 | local f = assert(command[cmd], cmd) 50 | skynet.retpack(f(...)) 51 | end) 52 | if start_func then 53 | start_func() 54 | end 55 | end) 56 | end 57 | 58 | return gateserver -------------------------------------------------------------------------------- /templates/lualib/bw/util/clusterinfo.lua: -------------------------------------------------------------------------------- 1 | -- 集群节点相关信息 2 | -- 访问方式 clusterinfo.xxx or clusterinfo.get_xxx() 3 | -- 4 | local skynet = require "skynet" 5 | local http = require "bw.http" 6 | local util = require "bw.util" 7 | local bash = require "bw.bash" 8 | 9 | local M = {} 10 | local _cache = {} 11 | setmetatable(M, { 12 | __index = function (t, k) 13 | local v = rawget(t, k) 14 | if v then 15 | return v 16 | end 17 | local f = rawget(t, '_'..k) 18 | if f then 19 | v = _cache[k] or f() 20 | _cache[k] = v 21 | return v 22 | end 23 | f = rawget(t, 'get_'..k) 24 | assert(f, "no clusterinfo "..k) 25 | return f() 26 | end 27 | }) 28 | 29 | -- 公网ip 30 | function M._pnet_addr() 31 | local _, resp = http.get('http://members.3322.org/dyndns/getip') 32 | local addr = string.gsub(resp, "\n", "") 33 | return addr 34 | end 35 | 36 | -- 内网ip 37 | function M.get_inet_addr() 38 | local ret = bash.execute "ifconfig eth0" 39 | return string.match(ret, "inet addr:([^%s]+)") or string.match(ret, "inet ([^%s]+)") 40 | end 41 | 42 | function M.get_run_time() 43 | return skynet.time() 44 | end 45 | 46 | -- 进程pid 47 | function M._pid() 48 | local filename = skynet.getenv "daemon" 49 | if not filename then 50 | return 51 | end 52 | local pid = bash.execute "cat ${filename}" 53 | return string.gsub(pid, "\n", "") 54 | end 55 | 56 | function M.get_profile() 57 | local pid = M.pid 58 | if not pid then return end 59 | local ret = bash.execute 'ps -p ${pid} u' 60 | local list = util.split(string.match(ret, '\n(.+)'), ' ') 61 | return { 62 | cpu = tonumber(list[3]), 63 | mem = tonumber(list[6]), 64 | } 65 | end 66 | 67 | function M._clustername() 68 | return skynet.getenv "clustername" 69 | end 70 | 71 | 72 | 73 | return M 74 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/alert.lua: -------------------------------------------------------------------------------- 1 | -- 警报系统 2 | local skynet = require "skynet" 3 | local json = require "cjson.safe" 4 | local clusterinfo = require "bw.util.clusterinfo" 5 | local bewater = require "bw.bewater" 6 | local log = require "bw.log" 7 | local util = require "bw.util" 8 | local http = require "bw.http" 9 | 10 | local pid = clusterinfo.pid 11 | local appname = skynet.getenv 'APPNAME' 12 | local desc = skynet.getenv 'DESC' 13 | 14 | local sample_html = [[ 15 | 16 | 17 | 18 | 31 | 32 | 33 |
34 |
节点:%s
35 |
备注:%s
36 |
进程:%s
37 |
日志:%s
38 | 39 | 40 | ]] 41 | 42 | 43 | local sformat = string.format 44 | local max_count = 10 45 | local count = 0 46 | local logs = "" 47 | 48 | local function format_html(msg) 49 | return sformat(sample_html, appname, desc, pid, msg) 50 | end 51 | 52 | local M = {} 53 | function M.traceback(err) 54 | if count >= max_count then 55 | return 56 | end 57 | logs = logs .. err .. '\n' 58 | count = count + 1 59 | end 60 | 61 | function M.start(handler) 62 | skynet.register ".alert" 63 | 64 | local send_func = assert(handler.send) 65 | local interval = handler.interval or 60 66 | skynet.fork(function() 67 | while true do 68 | if logs ~= "" then 69 | send_func(format_html(logs)) 70 | logs = "" 71 | count = 0 72 | end 73 | skynet.sleep(interval*100) 74 | end 75 | end) 76 | end 77 | 78 | return M 79 | -------------------------------------------------------------------------------- /templates/lualib/bw/payment/alipay.lua: -------------------------------------------------------------------------------- 1 | -- 支付宝支付 2 | local crypto = require "crypto" 3 | local sign = require "bw.auth.sign" 4 | local cjson = require "cjson" 5 | 6 | local M = {} 7 | function M.create_order(param) 8 | local order_no = assert(param.order_no) 9 | local private_key = assert(param.private_key) 10 | local item_desc = assert(param.item_desc) 11 | local pay_price = assert(param.pay_price) 12 | local appid = assert(param.appid) 13 | local url = assert(param.url) 14 | assert(param.uid) 15 | assert(param.item_sn) 16 | assert(param.pay_channel) 17 | assert(param.pay_method) 18 | 19 | local args = { 20 | app_id = appid, 21 | charset = 'utf-8', 22 | method = 'alipay.trade.app.pay', 23 | sign_type = 'RSA2', 24 | version = '1.0', 25 | timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time()), 26 | notify_url = url, 27 | biz_content = cjson.encode({ 28 | timeout_express = '30m', 29 | total_amount = pay_price, 30 | body = item_desc, 31 | subject = item_desc, 32 | out_trade_no = order_no, 33 | }) 34 | } 35 | 36 | local sv = sign.rsa_sha256_sign(args, private_key, false) 37 | return { 38 | order_no = order_no, 39 | order = sign.concat_args(args, false) .. '&sign=' .. sv, 40 | } 41 | end 42 | 43 | function M.notify(public_key, param) 44 | if param.trade_status ~= "TRADE_SUCCESS" then 45 | return 46 | end 47 | local args = {} 48 | for k, v in pairs(param) do 49 | if k ~= "sign" and k ~= "sign_type" then 50 | args[k] = v 51 | end 52 | end 53 | 54 | local src = sign.concat_args(args) 55 | local bs = crypto.base64_decode(param.sign) 56 | local pem = public_key 57 | return crypto.rsa_sha256_verify(src, bs, pem, 2) 58 | end 59 | 60 | return M 61 | -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | package.path = "lualib/?.lua;"..package.path 2 | 3 | local argparse = require "argparse" 4 | local bash = require "bash" 5 | local github = require "github" 6 | 7 | local function echo(str) 8 | print(bash.format(str)) 9 | end 10 | 11 | local function file_exists(str) 12 | return bash.file_exists(bash.format(str)) 13 | end 14 | 15 | echo "welcome to skynet creator !" 16 | 17 | local parser = argparse("main.lua") 18 | parser:description("skynet creator") 19 | parser:option("--force"):default("false"):description("force remove if workdir is exist") 20 | parser:argument("workdir"):description("the path of skynet project you want to create.") 21 | 22 | local args = parser:parse() 23 | local root = args.workdir 24 | 25 | -- mkdir 26 | echo "workdir: ${root}" 27 | if args.force == "true" then 28 | bash.execute "rm -rf ${root}/etc" 29 | bash.execute "rm -rf ${root}/make" 30 | bash.execute "rm -rf ${root}/service" 31 | bash.execute "rm -rf ${root}/lualib" 32 | else 33 | if file_exists(root) then 34 | echo "${root} is already create!" 35 | return 36 | end 37 | end 38 | bash.execute "mkdir -p ${root}" 39 | bash.execute "cd ${root} && git init" 40 | 41 | -- skynet 42 | if not file_exists("${root}/skynet") then 43 | echo "add skynet: ${github.skynet}" 44 | bash.execute "cd ${root} && git submodule add ${github.skynet}" 45 | end 46 | 47 | bash.execute "cp templates/.gitignore ${root}/" 48 | 49 | bash.execute "mkdir -p ${root}/lualib" 50 | bash.execute "cp -r templates/lualib/* ${root}/lualib/" 51 | 52 | bash.execute "mkdir -p ${root}/service" 53 | bash.execute "cp templates/service/* ${root}/service/" 54 | 55 | bash.execute "mkdir -p ${root}/etc" 56 | bash.execute "cp templates/etc/* ${root}/etc/" 57 | 58 | bash.execute "mkdir -p ${root}/make" 59 | bash.execute "cp templates/Makefile ${root}" 60 | bash.execute "cp templates/make/skynet.mk ${root}/make/" 61 | 62 | bash.execute "cp templates/test.sh ${root}" 63 | -------------------------------------------------------------------------------- /templates/lualib/bw/bw.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local bewater = require "bw.bewater" 3 | local log = require "bw.log" 4 | 5 | local M = {} 6 | 7 | local function status(v) 8 | return v ~= nil and 'OK' or 'NO' 9 | end 10 | 11 | local function lookup_service(t, name, is_send) 12 | local svr 13 | if skynet.localname('.' .. name) then 14 | svr = bewater.proxy('.' .. name, is_send) 15 | -- log.debugf("[%s] lookup local service: .%s", status(svr), name) 16 | else 17 | svr = bewater.proxy(name, is_send) 18 | -- log.debugf("[%s] lookup remote service: %s", status(svr), name) 19 | end 20 | t[name] = svr 21 | return svr 22 | end 23 | 24 | local function create_route(t, name, ri, is_send) 25 | local svrs = {} 26 | local idx = 0 27 | local slaves = ri.slaves 28 | local policy = ri.policy 29 | for i = 1, slaves do 30 | svrs[i] = lookup_service({}, name .. i, is_send) 31 | end 32 | t[name] = setmetatable({}, { 33 | __index = function (_, fn) 34 | return function (arg, ...) 35 | local svr 36 | if policy == 'hash' then 37 | svr = svrs[arg % slaves + 1] 38 | else 39 | svr = svrs[idx % slaves + 1] 40 | idx = idx + 1 41 | end 42 | return svr[fn](arg, ...) 43 | end 44 | end, 45 | }) 46 | return t[name] 47 | end 48 | 49 | local function lookup_call_service(t, name) 50 | local ri = bewater.route[name] 51 | if ri and ri.slaves > 1 then 52 | return create_route(t, name, ri, false) 53 | else 54 | return lookup_service(t, name, false) 55 | end 56 | end 57 | 58 | local function lookup_send_service(t, name) 59 | local ri = bewater.route[name] 60 | if ri and ri.slaves > 1 then 61 | return create_route(t, name, ri, true) 62 | else 63 | return lookup_service(t, name, true) 64 | end 65 | end 66 | 67 | M.noret = setmetatable({}, {__index = lookup_send_service}) 68 | 69 | return setmetatable(M, {__index = lookup_call_service}) -------------------------------------------------------------------------------- /templates/lualib/bw/http.lua: -------------------------------------------------------------------------------- 1 | -- Http 请求 get post 2 | -- 3 | local skynet = require "skynet" 4 | local json = require "cjson.safe" 5 | local log = require "bw.log" 6 | local bw = require "bw.bw" 7 | 8 | local M = {} 9 | function M.get(url, get, header, no_reply) 10 | if no_reply then 11 | return bw.noret.webclient.request(url, get, nil, header, no_reply) 12 | else 13 | return bw.webclient.request(url, get, nil, header, no_reply) 14 | end 15 | end 16 | 17 | function M.post(url, post, header, no_reply) 18 | if no_reply then 19 | return bw.noret.webclient.request(url, nil, post, header, no_reply) 20 | else 21 | return bw.webclient.request(url, nil, post, header, no_reply) 22 | end 23 | end 24 | 25 | function M.encode_uri(s) 26 | assert(s) 27 | s = string.gsub(s, "([^A-Za-z0-9])", function(c) 28 | return string.format("%%%02X", string.byte(c)) 29 | end) 30 | return s 31 | end 32 | 33 | function M.decode_uri(s) 34 | s = string.gsub(s, '%%(%x%x)', function(h) 35 | return string.char(tonumber(h, 16)) 36 | end) 37 | return s 38 | end 39 | 40 | 41 | function M.parse_uri(s) 42 | assert(s) 43 | local data = {} 44 | for ss in string.gmatch(s, "([^&]+)") do 45 | local k, v = string.match(ss, "(.+)=(.+)") 46 | data[k] = v 47 | end 48 | return data 49 | end 50 | 51 | 52 | --[[ 53 | { 54 | "code":0, 55 | "data":{ 56 | "ip":"202.104.71.210", 57 | "country":"中国", 58 | "area":"", 59 | "region":"广东", 60 | "city":"广州", 61 | "county":"XX", 62 | "isp":"电信", 63 | "country_id":"CN", 64 | "area_id":"", 65 | "region_id":"440000", 66 | "city_id":"440100", 67 | "county_id":"xx", 68 | "isp_id":"100017" 69 | } 70 | } 71 | ]] 72 | function M.ip_info(ip) 73 | assert(ip) 74 | local _, resp = M.get("http://ip.taobao.com/service/getIpInfo.php", {ip = ip}) 75 | resp = json.decode(resp) 76 | if not resp then 77 | log.error("get ip_info error", ip, resp) 78 | resp = {} 79 | end 80 | return resp.data or {} 81 | end 82 | 83 | return M 84 | -------------------------------------------------------------------------------- /templates/lualib/bw/auth/jiguang.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local http = require "bw.http" 3 | local log = require "bw.log" 4 | local json = require "cjson.safe" 5 | local crypto = require "crypto" 6 | 7 | local function encodeBase64(source_str) 8 | local b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' 9 | local s64 = '' 10 | local str = source_str 11 | 12 | while #str > 0 do 13 | local bytes_num = 0 14 | local buf = 0 15 | 16 | for byte_cnt=1,3 do 17 | buf = (buf * 256) 18 | if #str > 0 then 19 | buf = buf + string.byte(str, 1, 1) 20 | str = string.sub(str, 2) 21 | bytes_num = bytes_num + 1 22 | end 23 | end 24 | 25 | for group_cnt=1,(bytes_num+1) do 26 | local b64char = math.fmod(math.floor(buf/262144), 64) + 1 27 | s64 = s64 .. string.sub(b64chars, b64char, b64char) 28 | buf = buf * 64 29 | end 30 | 31 | for fill_cnt=1,(3-bytes_num) do 32 | s64 = s64 .. '=' 33 | end 34 | end 35 | 36 | return s64 37 | end 38 | 39 | local function post(url, data, auth) 40 | local ret, res = http.post(url, json.encode(data), { 41 | ["Content-Type"] = "application/json", 42 | ["Authorization"] = auth, 43 | }) 44 | if ret then 45 | return json.decode(res) 46 | end 47 | end 48 | 49 | local M = {} 50 | function M.auth(appkey, secret) 51 | return "Basic "..encodeBase64(appkey..":"..secret) 52 | end 53 | 54 | function M.get_mobile(login_token, pem, auth) 55 | local res = post('https://api.verification.jpush.cn/v1/web/loginTokenVerify', { 56 | loginToken = login_token, 57 | }, auth) 58 | if res and res.code == 8000 then 59 | local bs = crypto.base64_decode(res.phone) 60 | return crypto.rsa_private_decrypto(bs, pem) 61 | end 62 | end 63 | 64 | function M.send_code(mobile, sign_id, temp_id, auth) 65 | local res = post("https://api.sms.jpush.cn/v1/codes", { 66 | mobile = mobile, 67 | sign_id = sign_id, 68 | temp_id = temp_id, 69 | }, auth) 70 | return res and res.msg_id or nil 71 | end 72 | 73 | function M.verify_code(msg_id, code, auth) 74 | local url = string.format('https://api.sms.jpush.cn/v1/codes/%s/valid', msg_id) 75 | local res = post(url, { 76 | code = code, 77 | }, auth) 78 | return res and res.is_valid 79 | end 80 | 81 | return M 82 | -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/lualib/bw/util/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.http" 10 | local mongo = require "db.mongo" 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 | log.errorf("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 | log.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 | -------------------------------------------------------------------------------- /skynet-creator.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RESOURCES_DIR="/usr/local/share/skynet-creator" 4 | SKYNET_REPO="https://github.com/cloudwu/skynet.git" 5 | 6 | function usage() { 7 | cat < [参数] 9 | 10 | 选项: 11 | -f, --force 如果目标目录已存在,强制覆盖 12 | 13 | 操作: 14 | create <路径> 创建一个新的 skynet 项目 15 | import <模块...> 向当前目录的项目导入一个或多个模块 16 | 17 | 示例: 18 | skynet-creator create /path/to/new/project 19 | skynet-creator --force create /path/to/new/project 20 | skynet-creator import module1 module2 module3 21 | EOF 22 | } 23 | 24 | function create_project() { 25 | local force="$1" 26 | local workdir="$2" 27 | 28 | echo "workdir: ${workdir}" 29 | 30 | if [[ "$force" == "true" ]]; then 31 | rm -rf "${workdir}/etc" 32 | rm -rf "${workdir}/make" 33 | rm -rf "${workdir}/service" 34 | rm -rf "${workdir}/lualib" 35 | else 36 | if [ -d "${workdir}" ]; then 37 | echo "${workdir} is already created!" 38 | return 39 | fi 40 | fi 41 | 42 | mkdir -p "${workdir}" 43 | 44 | cp "${RESOURCES_DIR}/templates/.gitignore" "${workdir}/" 45 | 46 | mkdir -p "${workdir}/lualib" 47 | # cp -r "${RESOURCES_DIR}/templates/lualib"/* "${workdir}/lualib/" 48 | 49 | mkdir -p "${workdir}/service" 50 | cp "${RESOURCES_DIR}/templates/service"/* "${workdir}/service/" 51 | 52 | mkdir -p "${workdir}/etc" 53 | cp -r "${RESOURCES_DIR}/templates/etc"/* "${workdir}/etc/" 54 | 55 | mkdir -p "${workdir}/make" 56 | cp "${RESOURCES_DIR}/templates/Makefile" "${workdir}/" 57 | cp "${RESOURCES_DIR}/templates/make/skynet.mk" "${workdir}/make/" 58 | 59 | cp "${RESOURCES_DIR}/templates/test.sh" "${workdir}/" 60 | 61 | cd "${workdir}" 62 | git init 63 | git branch -m master 64 | 65 | # skynet 66 | if [ ! -d "${workdir}/skynet" ]; then 67 | echo "add skynet: ${SKYNET_REPO}" 68 | git submodule add "${SKYNET_REPO}" 69 | fi 70 | } 71 | 72 | function import_modules() { 73 | for module in "$@"; do 74 | echo "导入模块: $module" 75 | module_script="${RESOURCES_DIR}/modules/${module}.sh" 76 | if [ -f "$module_script" ]; then 77 | RESOURCES_DIR="${RESOURCES_DIR}" bash "$module_script" 78 | echo "导入完成" 79 | else 80 | echo "模块导入脚本不存在: $module_script" 81 | fi 82 | done 83 | } 84 | 85 | # 解析命令行选项 86 | while true; do 87 | case "$1" in 88 | -f | --force) 89 | force=true 90 | shift 91 | ;; 92 | *) 93 | break 94 | ;; 95 | esac 96 | done 97 | 98 | # 检查是否提供了足够的参数 99 | if [[ $# -lt 1 ]]; then 100 | usage 101 | exit 1 102 | fi 103 | 104 | action="$1" 105 | shift 106 | 107 | if [[ "$action" == "create" ]]; then 108 | if [[ $# -lt 1 ]]; then 109 | usage 110 | exit 1 111 | fi 112 | create_project "$force" "$1" 113 | elif [[ "$action" == "import" ]]; then 114 | if [[ $# -lt 1 ]]; then 115 | usage 116 | exit 1 117 | fi 118 | import_modules "$@" 119 | else 120 | echo "未知操作: $action" 121 | exit 1 122 | fi 123 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/behavior_tree.lua: -------------------------------------------------------------------------------- 1 | local behavior_node = require 'behavior3.behavior_node' 2 | local behavior_ret = require 'behavior3.behavior_ret' 3 | 4 | local meta = { 5 | __newindex = function(_, k) 6 | error(string.format('readonly:%s', k), 2) 7 | end 8 | } 9 | local function const(t) 10 | setmetatable(t, meta) 11 | for _, v in pairs(t) do 12 | if type(v) == 'table' then 13 | const(v) 14 | end 15 | end 16 | return t 17 | end 18 | 19 | local trees = {} 20 | 21 | local mt = {} 22 | mt.__index = mt 23 | function mt:init(name, tree_data) 24 | self.name = name 25 | local data = const(tree_data) 26 | self.root = behavior_node.new(data.root, self) 27 | end 28 | 29 | function mt:run(env) 30 | if #env.stack > 0 then 31 | local last_node = env.stack[#env.stack] 32 | local last_ret 33 | while last_node do 34 | last_ret = last_node:run(env) 35 | if last_ret == behavior_ret.RUNNING then 36 | break 37 | end 38 | last_node = env.stack[#env.stack] 39 | end 40 | return last_ret 41 | else 42 | return self.root:run(env) 43 | end 44 | end 45 | 46 | function mt:interrupt(env) 47 | if #env.stack > 0 then 48 | env.inner_vars = {} 49 | env.stack = {} 50 | end 51 | end 52 | 53 | local function new_tree(name, tree_data) 54 | local tree = setmetatable({}, mt) 55 | tree:init(name, tree_data) 56 | trees[name] = tree 57 | return tree 58 | end 59 | 60 | local function new_env(params) 61 | local env = { 62 | inner_vars = {}, -- [k.."_"..node.id] => vars 63 | vars = {}, 64 | stack = {}, 65 | last_ret = nil 66 | } 67 | for k, v in pairs(params) do 68 | env[k] = v 69 | end 70 | 71 | function env:get_var(k) 72 | return env.vars[k] 73 | end 74 | function env:set_var(k, v) 75 | if k == "" then return end 76 | self.vars[k] = v 77 | end 78 | function env:get_inner_var(node, k) 79 | return self.inner_vars[k .. '_' .. node.id] 80 | end 81 | function env:set_inner_var(node, k, v) 82 | self.inner_vars[k .. '_' .. node.id] = v 83 | end 84 | function env:push_stack(node) 85 | self.stack[#self.stack + 1] = node 86 | end 87 | function env:pop_stack() 88 | local node = self.stack[#self.stack] 89 | self.stack[#self.stack] = nil 90 | return node 91 | end 92 | return env 93 | end 94 | 95 | local M = {} 96 | function M.new(name, tree_data, env_params) 97 | local env = new_env(env_params) 98 | local tree = trees[name] or new_tree(name, tree_data) 99 | return { 100 | tree = tree, 101 | run = function() 102 | return tree:run(env) 103 | end, 104 | interrupt = function() 105 | tree:interrupt(env) 106 | end, 107 | is_running = function () 108 | return #env.stack > 0 109 | end, 110 | set_env = function (_, k, v) 111 | if k == "" then return end 112 | env[k] = v 113 | end 114 | } 115 | end 116 | return M 117 | -------------------------------------------------------------------------------- /templates/lualib/revent.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local cluster = require "skynet.cluster" 3 | 4 | local tinsert = table.insert 5 | local tunpack = table.unpack 6 | 7 | local M = {} 8 | 9 | local function agent_call(agent, ...) 10 | if agent.cluster_name then 11 | return cluster.call(agent.cluster_name, agent.service, ...) 12 | else 13 | return skynet.call(agent.service, "lua", ...) 14 | end 15 | end 16 | 17 | local function agent_send(agent, ...) 18 | if agent.cluster_name then 19 | return cluster.send(agent.cluster_name, agent.service, ...) 20 | else 21 | return skynet.send(agent.service, "lua", ...) 22 | end 23 | end 24 | 25 | -- 订阅方 26 | function M.sub(cluster_name, service, event, callback_func) 27 | assert(callback_func) 28 | local agent = { 29 | id = nil, 30 | service = service, 31 | cluster_name = cluster_name, 32 | event = event, 33 | watching = true, 34 | } 35 | agent.id = agent_call(agent, "register", event) 36 | skynet.fork(function () 37 | while agent.watching do 38 | local args = agent_call(agent, "wait", agent.id) 39 | if not agent.watching then 40 | break 41 | end 42 | for _, arg in ipairs(args) do 43 | xpcall(callback_func, debug.traceback, tunpack(arg)) 44 | end 45 | end 46 | end) 47 | return agent 48 | end 49 | 50 | function M.unsub(agent) 51 | agent.watching = false 52 | agent_send(agent, "unregister", agent.id) 53 | end 54 | 55 | 56 | -- 派发方 57 | local event2agents = {} 58 | local id2agent = {} 59 | local auto_id = 0 60 | local function get_agents(event) 61 | local agents = event2agents[event] or {} 62 | event2agents[event] = agents 63 | return agents 64 | end 65 | function M.register(event) 66 | assert(event) 67 | local agents = get_agents(event) 68 | auto_id = auto_id + 1 69 | local agent = { 70 | id = auto_id, 71 | event = event, 72 | args = {}, 73 | } 74 | agents[agent.id] = agent 75 | id2agent[agent.id] = agent 76 | skynet.retpack(agent.id) 77 | end 78 | 79 | function M.unregister(id) 80 | local agent = assert(id2agent[id], id) 81 | id2agent[id] = nil 82 | local agents = event2agents[agent.event] 83 | agents[id] = nil 84 | Skynet.wakeup(agent.co) 85 | end 86 | 87 | function M.wait(id) 88 | local agent = assert(id2agent[id], id) 89 | if #agent.args > 0 then 90 | skynet.retpack(agent.args) 91 | return 92 | end 93 | agent.co = coroutine.running() 94 | skynet.wait() 95 | skynet.retpack(agent.args) 96 | agent.args = {} 97 | agent.co = nil 98 | end 99 | 100 | function M.pub(event, ...) 101 | local agents = event2agents[event] 102 | if not agents then 103 | return 104 | end 105 | for _, agent in pairs(agents) do 106 | tinsert(agent.args, {...}) 107 | if agent.co then 108 | skynet.wakeup(agent.co) 109 | end 110 | end 111 | end 112 | 113 | function M.pub_to_agent(agent, ...) 114 | tinsert(agent.args, {...}) 115 | Skynet.wakeup(agent.co) 116 | end 117 | 118 | return M 119 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/gm.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local log = require "bw.log" 3 | local bewater = require "bw.bewater" 4 | local date_helper = require "bw.util.date_helper" 5 | 6 | local skynet_cmd = {} 7 | function skynet_cmd.gc() 8 | skynet.call(".launcher", "lua", "GC") 9 | end 10 | 11 | function skynet_cmd.call(addr, ...) 12 | addr = tonumber(addr, 16) or assert(addr) 13 | print("call", addr, ...) 14 | return skynet.call(addr, "lua", ...) 15 | end 16 | 17 | function skynet_cmd.list() 18 | local list = {} 19 | local all = skynet.call(".launcher", "lua", "LIST") 20 | for addr, desc in pairs(all) do 21 | table.insert(list, {addr = addr, desc = desc}) 22 | end 23 | 24 | for i, v in ipairs(list) do 25 | local addr = v.addr 26 | v.mem = skynet.call(addr, "debug", "MEM") 27 | if v.mem < 1024 then 28 | v.mem = math.floor(v.mem).." Kb" 29 | else 30 | v.mem = math.floor(v.mem/1024).." Mb" 31 | end 32 | 33 | local stat = skynet.call(addr, "debug", "STAT") 34 | v.task = stat.task 35 | v.mqlen = stat.mqlen 36 | v.id = i 37 | v.address = skynet.address(addr) 38 | end 39 | table.sort(list, function(a, b) 40 | return a.addr < b.addr 41 | end) 42 | local str = "" 43 | for i, v in ipairs(list) do 44 | str = str .. string.format("地址:%s 内存:%s 消息队列:%s 请求量:%s 启动命令:%s\n", 45 | v.addr, v.mem, v.mqlen, v.task, v.desc) 46 | end 47 | return str 48 | end 49 | 50 | function skynet_cmd.alert() 51 | error("test alert") 52 | end 53 | 54 | function skynet_cmd.time(...) 55 | log.debug("gm time") 56 | local args = table.pack(...) 57 | local t = {} 58 | for i = 1, #args, 2 do 59 | t[args[i]] = tonumber(args[i+1]) 60 | end 61 | local schedule = require "bw.schedule" 62 | local cur = schedule.changetime(t) 63 | return string.format("时间修改至 %s", date_helper.format(cur)) 64 | end 65 | 66 | local gmcmd = { 67 | skynet = skynet_cmd, 68 | } 69 | 70 | local M = {} 71 | function M.add_gmcmd(modname, gmcmd_path) 72 | gmcmd[modname] = require(gmcmd_path) 73 | assert(type(gmcmd[modname]) == "table", modname) 74 | end 75 | 76 | function M.run(modname, cmd, ...) 77 | modname = string.lower(modname) 78 | cmd = cmd and string.lower(cmd) or nil 79 | local mod = gmcmd[modname] 80 | if not mod then 81 | return string.format("模块[%s]未初始化", modname) 82 | end 83 | 84 | local f 85 | local ret 86 | local args = {...} 87 | if type(mod) == "function" then 88 | f = mod 89 | if not bewater.try(function() ret = f(cmd, table.unpack(args)) end) then 90 | return "服务器执行TRACEBACK了" 91 | end 92 | 93 | else 94 | f = mod[cmd] 95 | if not f then 96 | return string.format("GM指令[%s][%s]不存在", modname, cmd) 97 | end 98 | if not bewater.try(function() ret = f(table.unpack(args)) end) then 99 | return "服务器执行TRACEBACK了" 100 | end 101 | end 102 | return ret or "执行成功" 103 | end 104 | 105 | function M.init(cmds) 106 | for k, v in pairs(cmds) do 107 | gmcmd[k] = v 108 | end 109 | end 110 | 111 | return M 112 | 113 | 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Skynet Creator 2 | 这是一个轻便的skynet脚手架,能一键生成一个全新的项目(包含引用skynet,启动配置,测试示例,Makefile等),编译过后就能直接上手写lua服务。另外还收藏了一些游戏开发常用的c/lua库还有一些服务,可以在后续的开发中按需导入。 3 | 4 | ## 使用 5 | ```sh 6 | # 安装 7 | make 8 | sudo make install 9 | 10 | # 创建项目 11 | skynet-creator create /path/to/new/project 12 | 13 | # 导入第三方库 14 | skyent-creator import cjson openssl pbc ... 15 | 16 | # 查看参数 17 | skynet-creator --help 18 | ``` 19 | 20 | ## 生成项目结构 21 | + 3rd 引入的第三方库(主要是c库) 22 | + build 编译目录,所有生成的目标都在这,包括可执行文件skynet,lua还有各种so文件等 23 | + lualib 引用的lua库,或者是用户自己的lua库 24 | + service 引用的lua服务,或者是用户自己的lua库 25 | + make 第三方库的makefile目录,每次编译的时候会遍历这一个目录的所有.mk文件 26 | + skynet 子模块 27 | + Makefile 主makefile文件,编译skynet和第三方库 28 | + test.sh 运行test测试 29 | ## 示例项目 30 | + [skynet-creator-sample](https://github.com/zhandouxiaojiji/skynet-creator-sample) 31 | 32 | ## 第三方库 33 | + 需要编译的c库都是以submodule的形式导入项目,导入的时候引用源仓库的主干,最新的文档和说明请参考原仓库。 34 | + lua和service是直接从creator拷贝过去的(非submodule),后续有需要的自行手动更新。 35 | 36 | | 包名 | 类型 | 说明 | 来源 | 37 | | ---- | ---- | ---- | ---- | 38 | | cjson | c | json库 | https://github.com/cloudwu/lua-cjson | 39 | | curl | c | curl库 | https://github.com/Lua-cURL/Lua-cURLv3 | 40 | | openssl | c | 各类加解密算法库 | https://github.com/zhongfq/lua-openssl | 41 | | lz4 | c | 字符串压缩 | https://github.com/witchu/lua-lz4 | 42 | | pbc | c | protobuf库 | https://github.com/zhandouxiaojiji/pbc | 43 | | ecs | c | ecs框架 | https://github.com/cloudwu/luaecs | 44 | | crab | c | 敏感字过滤 | https://github.com/xjdrew/crab | 45 | | lfs | c | lua文件系统 | https://github.com/keplerproject/luafilesystem | 46 | | jps | c | JPS寻路算法 | https://github.com/rangercyh/jps | 47 | | navigation | lua | 平滑的网格寻路 | https://github.com/zhandouxiaojiji/lua-navigation | 48 | | profile | c | lua性能分析 | https://github.com/lvzixun/luaprofile | 49 | | snapshot | c | lua快照(检测内存泄漏用) | https://github.com/lvzixun/lua-snapshot | 50 | | uuid | lua | uuid生成 | https://github.com/Tieske/uuid | 51 | | argparse | lua | lua参数解析 | https://github.com/mpeterv/argparse | 52 | | behavior3 | lua | 行为树 | https://github.com/zhandouxiaojiji/behavior3lua | 53 | | fsm | lua | 有限状态机 | https://github.com/unindented/lua-fsm | 54 | | revent | lua | 远程消息 | https://github.com/zhandouxiaojiji/skynet-remote-event | 55 | | bewater | lua | 一些常用lua库集合 | 原仓库已经弃用,现由skynet-creator继续维护 | 56 | | fog | lua | 迷雾算法 | https://github.com/zhandouxiaojiji/lua-fog | 57 | | crypto | c | 加解密算法库 | https://github.com/zhandouxiaojiji/lua-crypto | 58 | | hex-grid | c | 六边形网格 | https://github.com/zhandouxiaojiji/lua-hex-grid | 59 | | packet | c | 二进制流打包与解析 | https://github.com/zhandouxiaojiji/lua-packet | 60 | | bytebuffer | c | 二进制流打包与解析 | https://github.com/zhandouxiaojiji/lua-bytebuffer | 61 | | quadtree | c | 四叉树 | https://github.com/rangercyh/quadtree | 62 | | lua-zset | c | 有序集合 | https://github.com/xjdrew/lua-zset | 63 | 64 | 更多的c库和lua库已在路上,大佬们有发现什么好用的库,欢迎pr 65 | 66 | ## 相关库安装 67 | 如果生成的项目在make的时候报缺失相关依赖,可以参考以下脚本 68 | ### ubuntu 69 | ```shell 70 | sudo apt-get install autoconf 71 | sudo apt-get install libcurl4-openssl-dev 72 | sudo apt-get install openssl libssl-dev 73 | sudo apt-get install build-essential 74 | ``` 75 | 76 | ### centos 77 | ```shell 78 | sudo yum install autoconf 79 | sudo yum install curl-devel 80 | sudo yum install openssl-devel 81 | ``` 82 | 83 | ### 配置luacheck 84 | ```shell 85 | skynet-creator import luacheck #配置默认的.luacheckrc,并安装git pre-commit钩子 86 | ``` 87 | 88 | ## TODO 89 | + 添加精简/缺省/完全等创建选项 90 | + 启动配置及mongo等配置的生成 91 | + 常用skynet服务导入 92 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/mongod.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | local mongo = require "skynet.db.mongo" 3 | local util = require "bw.util" 4 | local log = require "bw.log" 5 | 6 | local db 7 | 8 | local M = {} 9 | function M.find_one(name, query, selector) 10 | local data = db[name]:findOne(query, selector) 11 | return util.str2num(data) 12 | end 13 | 14 | function M.find_one_with_default(name, query, default, selector) 15 | local data = db[name]:findOne(query, selector) 16 | if not data then 17 | M.insert(name, default) 18 | return default 19 | end 20 | return util.str2num(data) 21 | end 22 | 23 | -- todo 此方法返回可能大于消息长度 24 | function M.find(name, query, selector) 25 | local ret = db[name]:find(query, selector) 26 | local data = {} 27 | while ret:hasNext() do 28 | table.insert(data, ret:next()) 29 | end 30 | return util.str2num(data) 31 | end 32 | 33 | function M.update(name, query_tbl, update_tbl) 34 | update_tbl = util.num2str(update_tbl) 35 | local ok, err, r = db[name]:findAndModify({query = query_tbl, update = update_tbl}) 36 | if not ok then 37 | log.error("mongo update error", r) 38 | error(err) 39 | end 40 | return true 41 | end 42 | 43 | function M.insert(name, tbl) 44 | tbl = util.num2str(tbl) 45 | local ok, err, r = db[name]:safe_insert(tbl) 46 | if not ok then 47 | log.error("mongo update error", r) 48 | error(err) 49 | end 50 | return true 51 | end 52 | 53 | function M.delete(name, query_tbl) 54 | db[name]:delete(query_tbl) 55 | return true 56 | end 57 | 58 | function M.drop(name) 59 | return db[name]:drop() 60 | end 61 | 62 | function M.get(key, default, key_str) 63 | local ret = db.global:findOne({key = key}) 64 | if ret then 65 | if key_str then 66 | return ret.value 67 | else 68 | return util.str2num(ret.value) 69 | end 70 | else 71 | db.global:safe_insert({key = key, value = default}) 72 | return default 73 | end 74 | end 75 | 76 | function M.set(key, value, keep_str) 77 | if not keep_str then 78 | value = util.num2str(value) 79 | end 80 | db.global:findAndModify({ 81 | query = {key = key}, 82 | update = {key = key, value = value}, 83 | }) 84 | end 85 | 86 | return function(conf) 87 | skynet.start(function() 88 | assert(conf.host and conf.port and conf.name) 89 | db = mongo.client({ 90 | host = conf.host, 91 | port = conf.port, 92 | })[conf.name] 93 | 94 | if conf.collections then 95 | for cname, collection in pairs(conf.collections) do 96 | local obj = db[cname] 97 | for _, v in ipairs(collection.indexes or {}) do 98 | local ret = obj:ensureIndex(v.key, v.option or {}) 99 | if ret.ok then 100 | if ret.numIndexesBefore ~= ret.numIndexesAfter then 101 | log.info("create_index", v.key, ret) 102 | end 103 | else 104 | log.error("create_index error", ret) 105 | end 106 | end 107 | end 108 | end 109 | 110 | skynet.dispatch("lua", function(_, _, cmd, ...) 111 | local f = assert(M[cmd], cmd) 112 | skynet.ret(f(...)) 113 | end) 114 | end) 115 | end 116 | -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/lualib/behavior3/behavior_node.lua: -------------------------------------------------------------------------------- 1 | local bret = require 'behavior3.behavior_ret' 2 | local process = require 'behavior3.sample_process' 3 | local debugger 4 | 5 | local sformat = string.format 6 | local table = table 7 | local print = print 8 | 9 | local mt = {} 10 | mt.__index = mt 11 | 12 | local function new_node(...) 13 | local obj = setmetatable({}, mt) 14 | obj:init(...) 15 | return obj 16 | end 17 | 18 | function mt:init(node_data, tree) 19 | self.tree = tree 20 | self.name = node_data.name 21 | self.id = node_data.id 22 | self.info = sformat('node %s.%s %s', tree.name, self.id, self.name) 23 | 24 | self.data = node_data 25 | self.args = self.data.args or {} 26 | self.children = {} 27 | for _, child_data in ipairs(node_data.children or {}) do 28 | local child = new_node(child_data, tree) 29 | table.insert(self.children, child) 30 | end 31 | end 32 | 33 | function mt:run(env) 34 | --print("start", self.name, self.node_id) 35 | if env:get_inner_var(self, "YIELD") == nil then 36 | env:push_stack(self) 37 | end 38 | local vars = {} 39 | for i, var_name in ipairs(self.data.input or {}) do 40 | vars[i] = env:get_var(var_name) 41 | end 42 | assert(process[self.name], self.name) 43 | local func = assert(process[self.name].run, self.name) 44 | local ok, errmsg = xpcall(function () 45 | if self.data.input then 46 | vars = table.pack(func(self, env, table.unpack(vars, 1, #self.data.input))) 47 | else 48 | vars = table.pack(func(self, env, table.unpack(vars))) 49 | end 50 | end, debug.traceback) 51 | if not ok then 52 | error(sformat("node %s run error:%s", self.info, errmsg)) 53 | end 54 | 55 | local ret = vars[1] 56 | assert(ret, self.info) 57 | if ret ~= bret.RUNNING then 58 | for i, var_name in ipairs(self.data.output or {}) do 59 | env:set_var(var_name, vars[i + 1]) 60 | end 61 | env:set_inner_var(self, "YIELD", nil) 62 | env:pop_stack() 63 | end 64 | 65 | env.last_ret = ret 66 | --print("fini", self.name, self.node_id, table.unpack(vars, 1, #self.data.input)) 67 | 68 | if self.data.debug then 69 | debugger(self, env, ret) 70 | end 71 | return ret 72 | end 73 | 74 | function mt:yield(env, arg) 75 | env:set_inner_var(self, "YIELD", arg or true) 76 | return bret.RUNNING 77 | end 78 | 79 | function mt:resume(env) 80 | return env:get_inner_var(self, "YIELD"), env.last_ret 81 | end 82 | 83 | function mt:get_debug_info(env, ret) 84 | local var_str = '' 85 | for k, v in pairs(env.vars) do 86 | var_str = var_str .. sformat("[%s]=%s,", k, v) 87 | end 88 | return sformat("[DEBUG] btree:%s, ret:%s vars:{%s}", self.info, ret, var_str) 89 | end 90 | 91 | local btree_funcs = {} 92 | local function btree_func(code, env) 93 | local func = btree_funcs[code] 94 | if not func then 95 | func = load("return function(vars, math) _ENV = vars return " .. code .. " end")() 96 | btree_funcs[code] = func 97 | end 98 | return func(env.vars, math) 99 | end 100 | 101 | function mt:get_env_args(key, env) 102 | if not self.data.args or not self.data.args[key] then 103 | return 104 | end 105 | return btree_func(assert(self.data.args[key], key), env) 106 | end 107 | 108 | local M = {} 109 | function M.new(...) 110 | return new_node(...) 111 | end 112 | 113 | function M.process(custom) 114 | process = custom 115 | end 116 | 117 | debugger = function(node, env, ret) 118 | print(node:get_debug_info(env, ret)) 119 | end 120 | 121 | function M.set_debugger(func) 122 | debugger = func 123 | end 124 | 125 | return M 126 | -------------------------------------------------------------------------------- /templates/lualib/bw/schedule.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local service = require "skynet.service" 3 | local log = require "bw.log" 4 | 5 | local schedule = {} 6 | local service_addr 7 | 8 | -- { month=, day=, wday=, hour= , min= } 9 | function schedule.submit(ti) 10 | assert(ti) 11 | return skynet.call(service_addr, "lua", ti) 12 | end 13 | 14 | function schedule.changetime(ti) 15 | local tmp = {} 16 | for k,v in pairs(ti) do 17 | tmp[k] = v 18 | end 19 | tmp.changetime = true 20 | return skynet.call(service_addr, "lua", tmp) 21 | end 22 | 23 | -- curtime 24 | function schedule.time() 25 | local difftime = skynet.call(service_addr, "lua") 26 | return skynet.time() + difftime 27 | end 28 | 29 | skynet.init(function() 30 | local schedule_service = function() 31 | -- schedule service 32 | 33 | local skynet = require "skynet" 34 | 35 | local task = { session = 0, difftime = 0 } 36 | 37 | local function next_time(now, ti) 38 | local nt = { 39 | year = now.year , 40 | month = now.month , 41 | day = now.day, 42 | hour = ti.hour or 0, 43 | min = ti.min or 0, 44 | sec = ti.sec or 0, 45 | } 46 | if ti.wday then 47 | -- set week 48 | assert(ti.day == nil and ti.month == nil) 49 | nt.day = nt.day + ti.wday - now.wday 50 | local t = os.time(nt) 51 | if t < now.time then 52 | nt.day = nt.day + 7 53 | end 54 | else 55 | -- set day, no week day 56 | if ti.day then 57 | nt.day = ti.day 58 | end 59 | if ti.month then 60 | nt.month = ti.month 61 | end 62 | local t = os.time(nt) 63 | if t < now.time then 64 | if ti.month then 65 | nt.year = nt.year + 1 -- next year 66 | elseif ti.day then 67 | nt.month = nt.month + 1 -- next month 68 | else 69 | nt.day = nt.day + 1 -- next day 70 | end 71 | end 72 | end 73 | 74 | return os.time(nt) 75 | end 76 | 77 | local function changetime(ti) 78 | local ct = math.floor(skynet.time()) 79 | local current = os.date("*t", ct) 80 | current.time = ct 81 | ti.hour = ti.hour or current.hour 82 | ti.min = ti.min or current.min 83 | ti.sec = ti.sec or current.sec 84 | local nt = next_time(current, ti) 85 | log.debug("change time to %s", os.date(nil, nt)) 86 | task.difftime = os.difftime(nt,ct) 87 | for k,v in pairs(task) do 88 | if type(v) == "table" then 89 | skynet.wakeup(v.co) 90 | end 91 | end 92 | skynet.ret(skynet.pack(nt)) 93 | end 94 | 95 | local function submit(_, addr, ti) 96 | if not ti then 97 | return skynet.ret(skynet.pack(task.difftime)) 98 | end 99 | if ti.changetime then 100 | return changetime(ti) 101 | end 102 | local session = task.session + 1 103 | task.session = session 104 | repeat 105 | local ct = math.floor(skynet.time()) + task.difftime 106 | local current = os.date("*t", ct) 107 | current.time = ct 108 | local nt = next_time(current, ti) 109 | task[session] = { time = nt, co = coroutine.running(), address = addr } 110 | local diff = os.difftime(nt , ct) 111 | --print("sleep", diff) 112 | until skynet.sleep(diff * 100) ~= "BREAK" 113 | task[session] = nil 114 | skynet.ret() 115 | end 116 | 117 | skynet.start(function() 118 | skynet.dispatch("lua", submit) 119 | skynet.info_func(function() 120 | local info = {} 121 | for k, v in pairs(task) do 122 | if type(v) == "table" then 123 | table.insert( info, { 124 | time = os.date(nil, v.time), 125 | address = skynet.address(v.address), 126 | }) 127 | return info 128 | end 129 | end 130 | end) 131 | end) 132 | 133 | -- end of schedule service 134 | end 135 | 136 | service_addr = service.new("schedule", schedule_service) 137 | end) 138 | 139 | return schedule 140 | -------------------------------------------------------------------------------- /templates/lualib/bw/payment/wxpay.lua: -------------------------------------------------------------------------------- 1 | -- 微信支付 2 | local sign = require "bw.auth.sign" 3 | local lua2xml = require "bw.xml.lua2xml" 4 | local xml2lua = require "bw.xml.xml2lua" 5 | local util = require "bw.util" 6 | local http = require "bw.http" 7 | local log = require "bw.log" 8 | local uuid = require "uuid" 9 | local errcode = require "def.errcode" 10 | 11 | local M = {} 12 | function M.create_order(param) 13 | local order_no = assert(param.order_no) 14 | local uid = assert(param.uid) 15 | local appid = assert(param.appid) 16 | local mch_id = assert(param.mch_id) 17 | local key = assert(param.key) 18 | local item_desc = assert(param.item_desc) 19 | local pay_method = assert(param.pay_method) 20 | local pay_price = assert(param.pay_price) 21 | local url = assert(param.url) 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, 32 | total_fee = pay_price*100//1 >> 0, 33 | spbill_create_ip = '127.0.0.1', 34 | notify_url = url, 35 | } 36 | args.sign = sign.md5_args(args, key) 37 | local xml = lua2xml.encode("xml", args, true) 38 | local _, resp_str = http.post("https://api.mch.weixin.qq.com/pay/unifiedorder", xml) 39 | local data = xml2lua.decode(resp_str).xml 40 | 41 | if data.return_code ~= "SUCCESS" and data.return_msg ~= "OK" then 42 | log.errorf("wxpay create_order error, param:%s, resp:%s", util.dump(param), resp_str) 43 | return errcode.ORDER_FAIL 44 | end 45 | 46 | local ret 47 | if data.trade_type == "APP" then 48 | ret = { 49 | appid = appid, 50 | partnerid = mch_id, 51 | noncestr = data.nonce_str, 52 | package = 'Sign=WXPay', 53 | prepayid = data.prepay_id, 54 | timestamp = string.format('%d', os.time()), 55 | } 56 | ret.sign = sign.md5_args(ret, key) 57 | else 58 | ret = { 59 | code_url = data.code_url 60 | } 61 | end 62 | ret.order_no = order_no 63 | return ret 64 | end 65 | 66 | local WX_OK = { 67 | return_code = "SUCCESS", 68 | return_msg = "OK", 69 | } 70 | 71 | local WX_FAIL = { 72 | return_code = "FAIL", 73 | return_msg = "FAIL", 74 | } 75 | 76 | function M.notify(order, key, param) 77 | if order.item_state == 'SUCCESS' then 78 | return WX_OK 79 | end 80 | local args = {} 81 | for k, v in pairs(param) do 82 | if k ~= "sign" then 83 | args[k] = v 84 | end 85 | end 86 | 87 | local sign1 = sign.md5_args(args, key) 88 | local sign2 = param.sign 89 | if sign1 ~= sign2 then 90 | return WX_FAIL 91 | end 92 | 93 | if param.result_code ~= "SUCCESS" or param.return_code ~= "SUCCESS" then 94 | log.errorf("wxpay fail %s", util.dump(param)) 95 | else 96 | order.pay_time = os.time() 97 | order.tid = param.transaction_id 98 | end 99 | return WX_OK 100 | end 101 | 102 | function M.query(param) 103 | local appid = assert(param.appid) 104 | local mch_id = assert(param.mch_id) 105 | local key = assert(param.key) 106 | local transaction_id = param.transaction_id 107 | local out_trade_no = param.out_trade_no 108 | assert(transaction_id or out_trade_no) 109 | 110 | local args = { 111 | appid = appid, 112 | mch_id = mch_id, 113 | transaction_id = transaction_id, 114 | nonce_str = string.gsub(uuid(), '-', ''), 115 | } 116 | args.sign = sign.md5_args(args, key) 117 | log.debug(args) 118 | 119 | local xml = lua2xml.encode("xml", args, true) 120 | local _, resp_str = http.post("https://api.mch.weixin.qq.com/pay/orderquery", xml) 121 | local resp = xml2lua.decode(resp_str).xml 122 | 123 | if resp.result_code == "SUCCESS" then 124 | return resp 125 | end 126 | end 127 | 128 | return M 129 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/ws_agent.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local bewater = require "bw.bewater" 3 | local websocket = require "http.websocket" 4 | local json = require "cjson.safe" 5 | local log = require "bw.log" 6 | 7 | local fd2user = {} 8 | 9 | local protocol, pack, unpack, process, is_binary, onclose, errcode 10 | 11 | local function default_pack(ret) 12 | return json.encode(ret) 13 | end 14 | 15 | local function default_unpack(str) 16 | return json.decode(str) 17 | end 18 | 19 | local function create_user(fd, ip) 20 | local user = { 21 | fd = fd, 22 | ip = ip, 23 | session = nil, 24 | } 25 | fd2user[fd] = user 26 | return user 27 | end 28 | 29 | local function get_user(fd) 30 | return fd2user[fd] 31 | end 32 | 33 | local function destroy_user(fd) 34 | local user = fd2user[fd] 35 | if user then 36 | onclose(user) 37 | fd2user[fd] = nil 38 | end 39 | end 40 | 41 | local CMD = {} 42 | 43 | local ws = {} 44 | function ws.connect(fd) 45 | log.debugf("ws connect from: %s", fd) 46 | end 47 | 48 | function ws.handshake(fd, header, url) 49 | local addr = websocket.addrinfo(fd) 50 | log.debugf("ws handshake from: %s, url:%s, addr:%s", fd, url, addr) 51 | end 52 | 53 | function ws.message(fd, msg) 54 | -- log.debugf("on message, fd:%s, msg:%s", fd, msg) 55 | local req = unpack(msg) 56 | local user = get_user(fd) 57 | local resp = { 58 | op = req.op + 1, 59 | session = req.session, 60 | data = process(user, req.op, req.data) 61 | } 62 | user.session = req.session 63 | if resp.data then 64 | websocket.write(fd, pack(resp), is_binary and "binary" or "text") 65 | end 66 | end 67 | 68 | function ws.ping(fd) 69 | log.debug("ws ping from: " .. tostring(fd) .. "\n") 70 | end 71 | 72 | function ws.pong(fd) 73 | log.debug("ws pong from: " .. tostring(fd)) 74 | end 75 | 76 | function ws.close(fd, code, reason) 77 | log.debug("ws close from: " .. tostring(fd), code, reason) 78 | CMD.close(fd) 79 | end 80 | 81 | function ws.error(fd) 82 | log.debug("ws error from: " .. tostring(fd)) 83 | CMD.close(fd) 84 | end 85 | 86 | function CMD.open(fd, addr) 87 | log.debug("open", fd, protocol, addr) 88 | local user = create_user(fd, addr) 89 | fd2user[fd] = user 90 | local ok, err = websocket.accept(fd, ws, protocol, addr) 91 | -- log.debug("open result", ok, err) 92 | if not ok then 93 | log.error(err) 94 | else 95 | fd2user[fd] = nil 96 | end 97 | end 98 | 99 | function CMD.close(fd) 100 | destroy_user(fd) 101 | websocket.close(fd) 102 | end 103 | 104 | 105 | function CMD.send(fd, op, data, session) 106 | assert(fd) 107 | assert(op) 108 | 109 | log.debug("send", fd, op, data, session) 110 | 111 | websocket.write(fd, pack { 112 | op = op, 113 | data = data or {}, 114 | session = session or 0, 115 | }, is_binary and "binary" or "text") 116 | end 117 | 118 | local M = { 119 | open = CMD.open, 120 | close = CMD.close, 121 | } 122 | function M.start(conf) 123 | protocol = conf.protocol or "ws" 124 | pack = conf.pack or default_pack 125 | unpack = conf.unpack or default_unpack 126 | onclose = conf.onclose 127 | is_binary = conf.is_binary 128 | process = assert(conf.process) 129 | local start_func = conf.start_func 130 | 131 | local command = assert(conf.command) 132 | for k, v in pairs(CMD) do 133 | command[k] = command[k] or v 134 | end 135 | 136 | skynet.start(function() 137 | skynet.dispatch("lua", function(_,_, cmd, ...) 138 | local f = assert(command[cmd], cmd) 139 | skynet.retpack(f(...)) 140 | end) 141 | 142 | if start_func then 143 | start_func() 144 | end 145 | end) 146 | end 147 | 148 | function M.send(fd, op, data) 149 | assert(fd) 150 | local resp = { 151 | op = assert(op), 152 | session = 0, 153 | data = data 154 | } 155 | 156 | local ok, errmsg = xpcall(function () 157 | websocket.write(fd, pack(resp), is_binary and "binary" or "text") 158 | end, debug.traceback) 159 | if not ok then 160 | log.warningf("send 0x%x error", op) 161 | log.warning("send data", data) 162 | log.warning(errmsg) 163 | end 164 | end 165 | 166 | return M -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/lualib/bw/log.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local util = require "bw.util" 3 | 4 | local tconcat = table.concat 5 | local tinsert = table.insert 6 | local sformat = string.format 7 | local srep = string.rep 8 | local tostring = tostring 9 | local select = select 10 | local os = os 11 | 12 | local log = {} 13 | 14 | local llevel_desc = { 15 | [0] = "EMG", 16 | [1] = "ALT", 17 | [2] = "CRI", 18 | [3] = "ERR", 19 | [4] = "WAR", 20 | [5] = "NTC", 21 | [6] = "INF", 22 | [7] = "DBG", 23 | } 24 | 25 | local llevel = { 26 | NOLOG = 99, 27 | DEBUG = 7, 28 | INFO = 6, 29 | NOTICE = 5, 30 | WARNING = 4, 31 | ERROR = 3, 32 | CRITICAL = 2, 33 | ALERT = 1, 34 | EMERG = 0, 35 | } 36 | 37 | 38 | local color = { 39 | red = 31, 40 | green = 32, 41 | blue = 36, 42 | yellow = 33, 43 | other = 37 44 | } 45 | 46 | local color_level_map = { 47 | [4] = "green", 48 | [5] = "blue", 49 | [6] = "other", 50 | [7] = "yellow", 51 | } 52 | 53 | local log_src = false 54 | if skynet.getenv("LOG_SRC") == "true" then 55 | log_src = true 56 | end 57 | 58 | local function format_now() 59 | return os.date("%Y-%m-%d %H:%M:%S", skynet.time()//1) 60 | end 61 | 62 | local function highlight(s, level) 63 | local c = color_level_map[level] or "red" 64 | return sformat("\x1b[1;%dm%s\x1b[0m", color[c], tostring(s)) 65 | end 66 | 67 | local function get_log_src(level) 68 | local info = debug.getinfo(level+1, "Sl") 69 | local src = info.short_src 70 | return src .. ":" .. info.currentline .. ":" 71 | end 72 | 73 | local function format_log(addr, str) 74 | return sformat("[:%.8x] [%s] %s", addr, format_now() , str) 75 | end 76 | 77 | local function dump_args(...) 78 | local n = select("#",...) 79 | local out = {} 80 | local v_str 81 | for i=1,n do 82 | local v = select(i,...) 83 | if type(v) == "table" then 84 | v_str = "table:\n" .. log.dump(v) 85 | else 86 | v_str = tostring(v) 87 | end 88 | tinsert(out, v_str) 89 | end 90 | return tconcat(out," ") 91 | end 92 | 93 | local function syslog(level, ...) 94 | local str = dump_args(...) 95 | if log_src then 96 | str = sformat("[%s] %s", get_log_src(3), str) 97 | end 98 | str = format_log(skynet.self(), str) 99 | print(highlight(str, level)) 100 | end 101 | 102 | 103 | function log.highlight(...) 104 | return highlight(...) 105 | end 106 | 107 | function log.format_log(addr, ...) 108 | return format_log(addr, ...) 109 | end 110 | 111 | function log.debug(...) 112 | syslog(llevel.DEBUG, ...) 113 | end 114 | 115 | function log.debugf(fmt, ...) 116 | syslog(llevel.DEBUG, sformat(fmt, ...)) 117 | end 118 | 119 | function log.info(...) 120 | syslog(llevel.INFO, ...) 121 | end 122 | 123 | function log.infof(fmt, ...) 124 | syslog(llevel.INFO, sformat(fmt, ...)) 125 | end 126 | 127 | function log.error(...) 128 | syslog(llevel.ERROR, ...) 129 | end 130 | 131 | function log.errorf(fmt, ...) 132 | syslog(llevel.ERROR, sformat(fmt, ...)) 133 | end 134 | 135 | function log.warning(...) 136 | syslog(llevel.WARNING, ...) 137 | end 138 | 139 | function log.warningf(fmt, ...) 140 | syslog(llevel.WARNING, sformat(fmt, ...)) 141 | end 142 | 143 | function log.assert(value, ...) 144 | if not value then 145 | error(dump_args(...)) 146 | end 147 | end 148 | 149 | function log.assertf(value, fmt, ...) 150 | if not value then 151 | error(sformat(fmt, ...)) 152 | end 153 | end 154 | 155 | function log.syslog(level, str, addr) 156 | assert(llevel[level], level) 157 | syslog(level, str) 158 | end 159 | 160 | function log.stat(filename, str) 161 | filename = sformat("%s/%s.log", skynet.getenv "LOG_PATH", filename) 162 | local file = io.open(filename, "a+") 163 | file:write(format_now() .. " " .. str .. "\n") 164 | file:close() 165 | end 166 | 167 | function log.statf(filename, fmt, ...) 168 | log.stat(filename, sformat(fmt, ...)) 169 | end 170 | 171 | function log.dump(root, depth) 172 | depth = depth or 10 173 | local cache = { [root] = "." } 174 | local function _dump(t, space, name, d) 175 | if d <= 0 then 176 | return "" 177 | end 178 | local temp = {} 179 | for k,v in pairs(t) do 180 | local key = tostring(k) 181 | if cache[v] then 182 | tinsert(temp,"+" .. key .. " {" .. cache[v].."}") 183 | elseif type(v) == "table" then 184 | local new_key = name .. "." .. key 185 | cache[v] = new_key 186 | tinsert(temp,"+" .. key .. _dump(v,space .. "|" .. srep(" ",#key), new_key, d - 1)) 187 | else 188 | tinsert(temp,"+" .. key .. " [" .. tostring(v).."]") 189 | end 190 | end 191 | return tconcat(temp,"\n"..space) 192 | end 193 | return (_dump(root, "","", depth)) 194 | end 195 | 196 | return log 197 | -------------------------------------------------------------------------------- /templates/lualib/bw/auth/wx.lua: -------------------------------------------------------------------------------- 1 | -- 微信验证(access_token和ticket需要在服务中缓存!) 2 | local skynet = require "skynet" 3 | local json = require "cjson.safe" 4 | local bewater = require "bw.bewater" 5 | local sha256 = require "bw.auth.sha256" 6 | local http = require "bw.http" 7 | local log = require "bw.log" 8 | 9 | local function url_encoding(tbl, encode) 10 | local data = {} 11 | for k, v in pairs(tbl) do 12 | table.insert(data, string.format("%s=%s", k, v)) 13 | end 14 | 15 | local url = table.concat(data, "&") 16 | if encode then 17 | return string.gsub(url, "([^A-Za-z0-9])", function(c) 18 | return string.format("%%%02X", string.byte(c)) 19 | end) 20 | else 21 | return url 22 | end 23 | end 24 | 25 | local M = {} 26 | 27 | function M.request_user_access_token(appid, secret, code) 28 | assert(appid and secret and code) 29 | local ret, resp = http.get('https://api.weixin.qq.com/sns/oauth2/access_token', { 30 | appid = appid, 31 | secret = secret, 32 | code = code, 33 | grant_type = 'authorization_code', 34 | }) 35 | resp = json.decode(resp) 36 | if resp then 37 | return resp.access_token, resp.openid 38 | else 39 | error(string.format("request_user_access_token error, appid:%s, secret:%s", appid, secret)) 40 | end 41 | end 42 | 43 | function M.request_user_info(appid, secret, code) 44 | assert(appid and secret and code) 45 | 46 | local access_token, openid = M.request_user_access_token(appid, secret, code) 47 | local ret, resp = http.get('https://api.weixin.qq.com/sns/userinfo', { 48 | access_token = access_token, 49 | openid = openid, 50 | }) 51 | resp = json.decode(resp) 52 | if resp then 53 | return resp 54 | else 55 | error(string.format("request_user_info error, appid:%s, secret:%s", appid, secret)) 56 | end 57 | end 58 | 59 | function M.request_access_token(appid, secret, api) 60 | assert(appid and secret) 61 | local ret, resp = http.get(api or "https://api.weixin.qq.com/cgi-bin/token", { 62 | grant_type = "client_credential", 63 | appid = appid, 64 | secret = secret, 65 | }) 66 | resp = json.decode(resp) 67 | if resp then 68 | return resp.access_token, resp.expires_in 69 | else 70 | error(string.format("request_access_token error, appid:%s, secret:%s", appid, secret)) 71 | end 72 | end 73 | 74 | function M.request_ticket(appid, token, api) 75 | assert(appid) 76 | local ret, resp = http.get(api or "https://api.weixin.qq.com/cgi-bin/ticket/getticket", { 77 | access_token = token, 78 | type = 2, 79 | }) 80 | resp = json.decode(resp) 81 | if resp then 82 | return resp.ticket, resp.expires_in 83 | else 84 | error(string.format("request_ticket error, appid:%s, token:%s", appid, token)) 85 | end 86 | end 87 | 88 | function M.jscode2session(appid, secret, js_code, api) 89 | assert(appid and secret and js_code) 90 | local ret, resp = http.get(api or "https://api.weixin.qq.com/sns/jscode2session",{ 91 | js_code = not api and js_code or nil, 92 | code = api and js_code or nil, 93 | grant_type = "authorization_code", 94 | appid = appid, 95 | secret = secret, 96 | }) 97 | if resp then 98 | return json.decode(resp) 99 | else 100 | error(string.format("jscode2session error, appid:%s, secret:%s, js_code:%s", 101 | appid, secret, js_code)) 102 | end 103 | end 104 | 105 | -- data {score = 100, gold = 300} 106 | function M.set_user_storage(appid, access_token, openid, session_key, data, api) 107 | local kv_list = {} 108 | for k, v in pairs(data) do 109 | table.insert(kv_list, {key = k, value = v}) 110 | end 111 | local post = json.encode({kv_list = kv_list}) 112 | local url = (api or "https://api.weixin.qq.com/wxa/set_user_storage?")..url_encoding({ 113 | access_token = access_token, 114 | openid = openid, 115 | appid = appid, 116 | signature = sha256.hmac_sha256(post, session_key), 117 | sig_method = "hmac_sha256", 118 | }) 119 | local ret, resp = http.post(url, post) 120 | if resp then 121 | return json.decode(resp) 122 | else 123 | error(string.format("set_user_storage error, appid:%s, access_token:%s, openid:%s, session_key:%s, data:%s", 124 | appid, access_token, openid, session_key, data)) 125 | end 126 | end 127 | 128 | -- key_list {"score", "gold"} 129 | function M.remove_user_storage(appid, access_token, openid, session_key, key_list, api) 130 | local post = json.encode({key = key_list}) 131 | local url = (api or "https://api.weixin.qq.com/wxa/remove_user_storage?")..url_encoding({ 132 | access_token = access_token, 133 | openid = openid, 134 | appid = appid, 135 | signature = sha256.hmac_sha256(post, session_key), 136 | sig_method = "hmac_sha256", 137 | }) 138 | local ret, resp = http.post(url, post) 139 | if resp then 140 | return json.decode(resp) 141 | else 142 | error(string.format("remove_user_storage error, appid:%s, access_token:%s, openid:%s, session_key:%s", 143 | appid, access_token, openid, session_key)) 144 | end 145 | end 146 | 147 | return M 148 | -------------------------------------------------------------------------------- /templates/lualib/bw/bewater.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | local log = require "bw.log" 3 | 4 | local M = {} 5 | 6 | M.route = {} 7 | 8 | local function __TRACEBACK__(errmsg) 9 | local track_text = debug.traceback(tostring(errmsg), 2) 10 | log.error("---------------------------------------- TRACKBACK ----------------------------------------") 11 | log.error(track_text) 12 | if skynet.getenv "ALERT_ENABLE" == "true" then 13 | skynet.send(".alert", "lua", "traceback", track_text) 14 | end 15 | log.error("---------------------------------------- TRACKBACK ----------------------------------------") 16 | return false 17 | end 18 | 19 | local skynet_start = skynet.start 20 | local started = false 21 | function skynet.start(...) 22 | if started then 23 | error("do not call skynet.start many times") 24 | end 25 | started = true 26 | return skynet_start(...) 27 | end 28 | 29 | -- 尝试调一个function, 如果被调用的函数有异常,返回false, 30 | function M.try(func, ...) 31 | return xpcall(func, __TRACEBACK__, ...) 32 | end 33 | 34 | -- 给一个服务注入一段代码 35 | -- return ok, output 36 | function M.inject(addr, source) 37 | return skynet.call(addr, "debug", "RUN", source) 38 | --return skynet.call(addr, "code", source) 39 | --return skynet.call(addr, "debug", "INJECTCODE", source, filename) 40 | --local injectcode = require "skynet.injectcode" 41 | --return injectcode(source) 42 | end 43 | 44 | function M.timeout_call(ti, ...) 45 | local co = coroutine.running() 46 | local ret 47 | 48 | skynet.fork(function(...) 49 | ret = table.pack(pcall(skynet.call, ...)) 50 | if co then 51 | skynet.wakeup(co) 52 | co = nil 53 | end 54 | end, ...) 55 | 56 | skynet.sleep(ti/10) 57 | 58 | if co then 59 | co = nil 60 | log.warning("call timeout:", ...) 61 | return false 62 | else 63 | if ret[1] then 64 | return table.unpack(ret, 1, ret.n) 65 | else 66 | error(ret[2]) 67 | end 68 | end 69 | end 70 | 71 | function M.locals(f) 72 | f = f or 2 73 | local variables = {} 74 | local idx = 1 75 | while true do 76 | local ln, lv = debug.getlocal(f, idx) 77 | if ln ~= nil then 78 | variables[ln] = lv 79 | else 80 | break 81 | end 82 | idx = 1 + idx 83 | end 84 | return variables 85 | end 86 | 87 | function M.traceback(start_level, max_level) 88 | start_level = start_level or 2 89 | max_level = max_level or 20 90 | 91 | for level = start_level, max_level do 92 | 93 | local info = debug.getinfo( level, "nSl") 94 | if info == nil then break end 95 | print( string.format("[ line : %-4d] %-20s :: %s", 96 | info.currentline, info.name or "", info.source or "" ) ) 97 | 98 | local index = 1 99 | while true do 100 | local name, value = debug.getlocal(level, index) 101 | if name == nil then break end 102 | print( string.format( "\t%s = %s", name, value ) ) 103 | index = index + 1 104 | end 105 | end 106 | end 107 | 108 | function M.protect(tbl, depth) 109 | setmetatable(tbl, { 110 | __index = function(t, k) 111 | error(string.format("key '%s' not found", k)) 112 | end, 113 | __newindex = function(t, k, v) 114 | error(string.format("readonly table, write key '%s' error", k)) 115 | end 116 | }) 117 | if depth and depth > 0 then 118 | for k, v in pairs(tbl) do 119 | if type(v) == "table" then 120 | M.protect(v, depth - 1) 121 | end 122 | end 123 | end 124 | return tbl 125 | end 126 | 127 | function M.proxy(addr, is_send) 128 | assert(addr) 129 | return setmetatable({}, { 130 | __index = function(_, k) 131 | return function(...) 132 | if is_send then 133 | skynet.send(addr, "lua", k, ...) 134 | else 135 | return skynet.call(addr, "lua", k, ...) 136 | end 137 | end 138 | end, 139 | }) 140 | end 141 | 142 | function M.start(command) 143 | assert(command) 144 | skynet.start(function() 145 | skynet.dispatch("lua", function(_,_, cmd, ...) 146 | local f = assert(command[cmd], cmd) 147 | skynet.ret(f(...)) 148 | end) 149 | if command.start then 150 | command.start() 151 | end 152 | end) 153 | end 154 | 155 | function M.set_route(route) 156 | for _, v in pairs(route) do 157 | v.slaves = v.slaves or 1 158 | if v.slaves > 1 and not v.policy then 159 | v.policy = 'rr' 160 | end 161 | end 162 | M.route = M.protect(route, 1) 163 | return M.route 164 | end 165 | 166 | function M.newservice(conf, ...) 167 | if type(conf) == 'string' then 168 | return skynet.newservice(conf, ...) 169 | else 170 | local slaves = conf.slaves or 1 171 | local arr = {} 172 | local name = assert(conf.name, 'no service name') 173 | for i = 1, slaves do 174 | local s = skynet.newservice(conf.service, ...) 175 | arr[i] = s 176 | if slaves == 1 then 177 | skynet.name(name, s) 178 | else 179 | skynet.name(name .. i, s) 180 | end 181 | end 182 | return slaves == 1 and arr[1] or arr 183 | end 184 | end 185 | 186 | return M 187 | 188 | -------------------------------------------------------------------------------- /templates/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 | -------------------------------------------------------------------------------- /templates/lualib/fsm.lua: -------------------------------------------------------------------------------- 1 | -- luacheck: globals unpack 2 | local unpack = unpack or table.unpack 3 | 4 | local M = {} 5 | 6 | M.WILDCARD = "*" 7 | M.DEFERRED = 0 8 | M.SUCCEEDED = 1 9 | M.NO_TRANSITION = 2 10 | M.PENDING = 3 11 | M.CANCELLED = 4 12 | 13 | local function do_callback(handler, args) 14 | if handler then 15 | return handler(unpack(args)) 16 | end 17 | end 18 | 19 | local function before_event(self, event, _, _, args) 20 | local specific = do_callback(self["on_before_" .. event], args) 21 | local general = do_callback(self["on_before_event"], args) 22 | 23 | if specific == false or general == false then 24 | return false 25 | end 26 | end 27 | 28 | local function leave_state(self, _, from, _, args) 29 | local specific = do_callback(self["on_leave_" .. from], args) 30 | local general = do_callback(self["on_leave_state"], args) 31 | 32 | if specific == false or general == false then 33 | return false 34 | end 35 | if specific == M.DEFERRED or general == M.DEFERRED then 36 | return M.DEFERRED 37 | end 38 | end 39 | 40 | local function enter_state(self, _, _, to, args) 41 | do_callback(self["on_enter_" .. to] or self["on_" .. to], args) 42 | do_callback(self["on_enter_state"] or self["on_state"], args) 43 | end 44 | 45 | local function after_event(self, event, _, _, args) 46 | do_callback(self["on_after_" .. event] or self["on_" .. event], args) 47 | do_callback(self["on_after_event"] or self["on_event"], args) 48 | end 49 | 50 | local function build_transition(self, event, states) 51 | return function (...) 52 | local from = self.current 53 | local to = states[from] or states[M.WILDCARD] or from 54 | local args = {self, event, from, to, ...} 55 | 56 | assert(not self.is_pending(), 57 | "previous transition still pending") 58 | 59 | assert(self.can(event), 60 | "invalid transition from state '" .. from .. "' with event '" .. event .. "'") 61 | 62 | local before = before_event(self, event, from, to, args) 63 | if before == false then 64 | return M.CANCELLED 65 | end 66 | 67 | if from == to then 68 | after_event(self, event, from, to, args) 69 | return M.NO_TRANSITION 70 | end 71 | 72 | self.confirm = function () 73 | self.confirm = nil 74 | self.cancel = nil 75 | 76 | self.current = to 77 | 78 | enter_state(self, event, from, to, args) 79 | after_event(self, event, from, to, args) 80 | 81 | return M.SUCCEEDED 82 | end 83 | 84 | self.cancel = function () 85 | self.confirm = nil 86 | self.cancel = nil 87 | 88 | after_event(self, event, from, to, args) 89 | 90 | return M.CANCELLED 91 | end 92 | 93 | local leave = leave_state(self, event, from, to, args) 94 | if leave == false then 95 | return M.CANCELLED 96 | end 97 | if leave == M.DEFERRED then 98 | return M.PENDING 99 | end 100 | 101 | if self.confirm then 102 | return self.confirm() 103 | end 104 | end 105 | end 106 | 107 | function M.create(cfg, target) 108 | local self = target or {} 109 | 110 | -- Initial state. 111 | local initial = cfg.initial 112 | -- Allow for a string, or a map like `{state = "foo", event = "setup"}`. 113 | initial = type(initial) == "string" and {state = initial} or initial 114 | 115 | -- Initial event. 116 | local initial_event = initial and initial.event or "startup" 117 | 118 | -- Terminal state. 119 | local terminal = cfg.terminal 120 | 121 | -- Events. 122 | local events = cfg.events or {} 123 | 124 | -- Callbacks. 125 | local callbacks = cfg.callbacks or {} 126 | 127 | -- Track state transitions allowed for an event. 128 | local states_for_event = {} 129 | 130 | -- Track events allowed from a state. 131 | local events_for_state = {} 132 | 133 | local function add(e) 134 | -- Allow wildcard transition if `from` is not specified. 135 | local from = type(e.from) == "table" and e.from or (e.from and {e.from} or {M.WILDCARD}) 136 | local to = e.to 137 | local event = e.name 138 | 139 | states_for_event[event] = states_for_event[event] or {} 140 | for _, fr in ipairs(from) do 141 | events_for_state[fr] = events_for_state[fr] or {} 142 | table.insert(events_for_state[fr], event) 143 | 144 | -- Allow no-op transition if `to` is not specified. 145 | states_for_event[event][fr] = to or fr 146 | end 147 | end 148 | 149 | if initial then 150 | add({name = initial_event, from = "none", to = initial.state}) 151 | end 152 | 153 | for _, event in ipairs(events) do 154 | add(event) 155 | end 156 | 157 | for event, states in pairs(states_for_event) do 158 | self[event] = build_transition(self, event, states) 159 | end 160 | 161 | for name, callback in pairs(callbacks) do 162 | self[name] = callback 163 | end 164 | 165 | self.current = "none" 166 | 167 | function self.is(state) 168 | if type(state) == "table" then 169 | for _, s in ipairs(state) do 170 | if self.current == s then 171 | return true 172 | end 173 | end 174 | 175 | return false 176 | end 177 | 178 | return self.current == state 179 | end 180 | 181 | function self.can(event) 182 | local states = states_for_event[event] 183 | local to = states[self.current] or states[M.WILDCARD] 184 | return to ~= nil 185 | end 186 | 187 | function self.cannot(event) 188 | return not self.can(event) 189 | end 190 | 191 | function self.transitions() 192 | return events_for_state[self.current] 193 | end 194 | 195 | function self.is_pending() 196 | return self.confirm ~= nil 197 | end 198 | 199 | function self.is_finished() 200 | return self.is(terminal) 201 | end 202 | 203 | if initial and not initial.defer then 204 | self[initial_event]() 205 | end 206 | 207 | return self 208 | end 209 | 210 | return M 211 | -------------------------------------------------------------------------------- /lualib/bash.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local function lookup(level, key) 4 | assert(key and #key > 0, key) 5 | 6 | local value 7 | 8 | for i = 1, 256 do 9 | local k, v = debug.getlocal(level, i) 10 | if k == key then 11 | value = v 12 | elseif not k then 13 | break 14 | end 15 | end 16 | 17 | if value then 18 | return value 19 | end 20 | 21 | local info1 = debug.getinfo(level, 'Sn') 22 | local info2 = debug.getinfo(level + 1, 'Sn') 23 | if info1.source == info2.source or 24 | info1.short_src == info2.short_src then 25 | return lookup(level + 1, key) 26 | end 27 | end 28 | 29 | local function eval(line) 30 | return string.gsub(line, '${[%w_.?]+}', function (str) 31 | -- search caller file path 32 | local level = 1 33 | local path 34 | while true do 35 | local info = debug.getinfo(level, 'Sn') 36 | if info then 37 | if info.source == "=[C]" then 38 | level = level + 1 39 | else 40 | path = path or info.source 41 | if path ~= info.source then 42 | break 43 | else 44 | level = level + 1 45 | end 46 | end 47 | else 48 | break 49 | end 50 | end 51 | 52 | -- search in the functin local value 53 | local indent = string.match(line, ' *') 54 | local key = string.match(str, '[%w_]+') 55 | local opt = string.match(str, '%?+') 56 | local value = lookup(level + 1, key) or _G[key] 57 | for field in string.gmatch(string.match(str, "[%w_.]+"), '[^.]+') do 58 | if not value then 59 | break 60 | elseif field ~= key then 61 | value = value[field] 62 | end 63 | end 64 | 65 | if value == nil and not opt then 66 | error("value not found for '" .. str .. "'") 67 | end 68 | 69 | -- indent the value if value has multiline 70 | local prefix, posfix = '', '' 71 | if type(value) == 'table' then 72 | local mt = getmetatable(value) 73 | if mt and mt.__tostring then 74 | value = tostring(value) 75 | else 76 | error("no meta method '__tostring' for " .. str) 77 | end 78 | elseif value == nil then 79 | value = 'nil' 80 | elseif type(value) == 'string' then 81 | value = value:gsub('[\n]*$', '') 82 | if opt then 83 | value = M.trim(value) 84 | if string.find(value, '[\n\r]') then 85 | value = '\n' .. value 86 | prefix = '[[' 87 | posfix = '\n' .. indent .. ']]' 88 | indent = indent .. ' ' 89 | elseif string.find(value, '[\'"]') then 90 | value = '[[' .. value .. ']]' 91 | else 92 | value = "'" .. value .. "'" 93 | end 94 | end 95 | else 96 | value = tostring(value) 97 | end 98 | 99 | return prefix .. string.gsub(value, '\n', '\n' .. indent) .. posfix 100 | end) 101 | end 102 | 103 | local function doeval(expr) 104 | local arr = {} 105 | local idx = 1 106 | while idx <= #expr do 107 | local from, to = string.find(expr, '[\n\r]', idx) 108 | if not from then 109 | from = #expr + 1 110 | to = from 111 | end 112 | arr[#arr + 1] = eval(string.sub(expr, idx, from - 1)) 113 | idx = to + 1 114 | end 115 | return table.concat(arr, '\n') 116 | end 117 | 118 | function M.trim(expr, indent) 119 | if type(expr) == 'string' then 120 | expr = string.gsub(expr, '[\n\r]', '\n') 121 | expr = string.gsub(expr, '^[\n]*', '') -- trim head '\n' 122 | expr = string.gsub(expr, '[ \n]*$', '') -- trim tail '\n' or ' ' 123 | 124 | local space = string.match(expr, '^[ ]*') 125 | indent = string.rep(' ', indent or 0) 126 | expr = string.gsub(expr, '^[ ]*', '') -- trim head space 127 | expr = string.gsub(expr, '\n' .. space, '\n' .. indent) 128 | expr = indent .. expr 129 | end 130 | return expr 131 | end 132 | 133 | function M.format(expr, indent) 134 | expr = doeval(M.trim(expr, indent)) 135 | 136 | while true do 137 | local s, n = string.gsub(expr, '\n[ ]+\n', '\n\n') 138 | expr = s 139 | if n == 0 then 140 | break 141 | end 142 | end 143 | 144 | while true do 145 | local s, n = string.gsub(expr, '\n\n\n', '\n\n') 146 | expr = s 147 | if n == 0 then 148 | break 149 | end 150 | end 151 | 152 | expr = string.gsub(expr, '{\n\n', '{\n') 153 | expr = string.gsub(expr, '\n\n}', '\n}') 154 | 155 | return expr 156 | end 157 | 158 | local function io_popen(cmd, mode) 159 | local file = io.popen(cmd) 160 | local ret = file:read(mode or "*a") 161 | file:close() 162 | return ret 163 | end 164 | 165 | function M.execute(cmd) 166 | return io_popen(M.format(cmd)) 167 | end 168 | 169 | function M.list(dir, pattern) 170 | local f = io.popen(string.format('cd %s && find -L . -name "%s"', dir, pattern or "*.*")) 171 | local arr = {} 172 | for path in string.gmatch(f:read("*a"), '[^\n\r]+') do 173 | path = string.gsub(path, '%./', '') 174 | if string.find(path, '[^./\\]+%.[^.]+$') then 175 | arr[#arr + 1] = path 176 | end 177 | end 178 | return arr 179 | end 180 | 181 | function M.file_exists(path) 182 | local file = io.open(path, "rb") 183 | if file then 184 | file:close() 185 | end 186 | return file ~= nil 187 | end 188 | 189 | return M -------------------------------------------------------------------------------- /templates/lualib/bw/bash.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local function lookup(level, key) 4 | assert(key and #key > 0, key) 5 | 6 | local value 7 | 8 | for i = 1, 256 do 9 | local k, v = debug.getlocal(level, i) 10 | if k == key then 11 | value = v 12 | elseif not k then 13 | break 14 | end 15 | end 16 | 17 | if value then 18 | return value 19 | end 20 | 21 | local info1 = debug.getinfo(level, 'Sn') 22 | local info2 = debug.getinfo(level + 1, 'Sn') 23 | if info1.source == info2.source or 24 | info1.short_src == info2.short_src then 25 | return lookup(level + 1, key) 26 | end 27 | end 28 | 29 | local function eval(line) 30 | return string.gsub(line, '${[%w_.?]+}', function (str) 31 | -- search caller file path 32 | local level = 1 33 | local path 34 | while true do 35 | local info = debug.getinfo(level, 'Sn') 36 | if info then 37 | if info.source == "=[C]" then 38 | level = level + 1 39 | else 40 | path = path or info.source 41 | if path ~= info.source then 42 | break 43 | else 44 | level = level + 1 45 | end 46 | end 47 | else 48 | break 49 | end 50 | end 51 | 52 | -- search in the functin local value 53 | local indent = string.match(line, ' *') 54 | local key = string.match(str, '[%w_]+') 55 | local opt = string.match(str, '%?+') 56 | local value = lookup(level + 1, key) or _G[key] 57 | for field in string.gmatch(string.match(str, "[%w_.]+"), '[^.]+') do 58 | if not value then 59 | break 60 | elseif field ~= key then 61 | value = value[field] 62 | end 63 | end 64 | 65 | if value == nil and not opt then 66 | error("value not found for '" .. str .. "'") 67 | end 68 | 69 | -- indent the value if value has multiline 70 | local prefix, posfix = '', '' 71 | if type(value) == 'table' then 72 | local mt = getmetatable(value) 73 | if mt and mt.__tostring then 74 | value = tostring(value) 75 | else 76 | error("no meta method '__tostring' for " .. str) 77 | end 78 | elseif value == nil then 79 | value = 'nil' 80 | elseif type(value) == 'string' then 81 | value = value:gsub('[\n]*$', '') 82 | if opt then 83 | value = M.trim(value) 84 | if string.find(value, '[\n\r]') then 85 | value = '\n' .. value 86 | prefix = '[[' 87 | posfix = '\n' .. indent .. ']]' 88 | indent = indent .. ' ' 89 | elseif string.find(value, '[\'"]') then 90 | value = '[[' .. value .. ']]' 91 | else 92 | value = "'" .. value .. "'" 93 | end 94 | end 95 | else 96 | value = tostring(value) 97 | end 98 | 99 | return prefix .. string.gsub(value, '\n', '\n' .. indent) .. posfix 100 | end) 101 | end 102 | 103 | local function doeval(expr) 104 | local arr = {} 105 | local idx = 1 106 | while idx <= #expr do 107 | local from, to = string.find(expr, '[\n\r]', idx) 108 | if not from then 109 | from = #expr + 1 110 | to = from 111 | end 112 | arr[#arr + 1] = eval(string.sub(expr, idx, from - 1)) 113 | idx = to + 1 114 | end 115 | return table.concat(arr, '\n') 116 | end 117 | 118 | function M.trim(expr, indent) 119 | if type(expr) == 'string' then 120 | expr = string.gsub(expr, '[\n\r]', '\n') 121 | expr = string.gsub(expr, '^[\n]*', '') -- trim head '\n' 122 | expr = string.gsub(expr, '[ \n]*$', '') -- trim tail '\n' or ' ' 123 | 124 | local space = string.match(expr, '^[ ]*') 125 | indent = string.rep(' ', indent or 0) 126 | expr = string.gsub(expr, '^[ ]*', '') -- trim head space 127 | expr = string.gsub(expr, '\n' .. space, '\n' .. indent) 128 | expr = indent .. expr 129 | end 130 | return expr 131 | end 132 | 133 | function M.format(expr, indent) 134 | expr = doeval(M.trim(expr, indent)) 135 | 136 | while true do 137 | local s, n = string.gsub(expr, '\n[ ]+\n', '\n\n') 138 | expr = s 139 | if n == 0 then 140 | break 141 | end 142 | end 143 | 144 | while true do 145 | local s, n = string.gsub(expr, '\n\n\n', '\n\n') 146 | expr = s 147 | if n == 0 then 148 | break 149 | end 150 | end 151 | 152 | expr = string.gsub(expr, '{\n\n', '{\n') 153 | expr = string.gsub(expr, '\n\n}', '\n}') 154 | 155 | return expr 156 | end 157 | 158 | local function io_popen(cmd, mode) 159 | local file = io.popen(cmd) 160 | local ret = file:read(mode or "*a") 161 | file:close() 162 | return ret 163 | end 164 | 165 | function M.execute(cmd) 166 | return io_popen(M.format(cmd)) 167 | end 168 | 169 | function M.list(dir, pattern) 170 | local f = io.popen(string.format('cd %s && find -L . -name "%s"', dir, pattern or "*.*")) 171 | local arr = {} 172 | for path in string.gmatch(f:read("*a"), '[^\n\r]+') do 173 | path = string.gsub(path, '%./', '') 174 | if string.find(path, '[^./\\]+%.[^.]+$') then 175 | arr[#arr + 1] = path 176 | end 177 | end 178 | return arr 179 | end 180 | 181 | function M.file_exists(path) 182 | local file = io.open(path, "rb") 183 | if file then 184 | file:close() 185 | end 186 | return file ~= nil 187 | end 188 | 189 | return M 190 | -------------------------------------------------------------------------------- /templates/lualib/fog.lua: -------------------------------------------------------------------------------- 1 | local DISPEL = 0 -- 全驱散 2 | local MIX = 1 -- 混合 3 | local FOG = 2 -- 全迷雾 4 | 5 | local slen = string.len 6 | local ssub = string.sub 7 | local type = type 8 | 9 | local b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' 10 | local n2c = {} 11 | local c2n = {} 12 | 13 | for i = 1, 64 do 14 | local c = ssub(b64chars, i, i) 15 | local n = i - 1 16 | n2c[n] = c 17 | c2n[c] = n 18 | end 19 | 20 | local function create_node(parent, tag, min, max) 21 | return { 22 | tag = tag, 23 | parent = parent, 24 | min = min, 25 | max = max, 26 | } 27 | end 28 | 29 | local M = { 30 | DISPEL = DISPEL, 31 | FOG = FOG, 32 | MIX = MIX, 33 | } 34 | function M.create(size, tag) 35 | local map = { 36 | size = size, 37 | } 38 | map.root = create_node(nil, tag or FOG, 0, size - 1) 39 | return map 40 | end 41 | 42 | local function encode_node(node, arr) 43 | if not node then 44 | return 45 | end 46 | arr[#arr+1] = node.tag 47 | encode_node(node.left, arr) 48 | encode_node(node.right, arr) 49 | end 50 | 51 | function M.encode(map) 52 | local arr = {} 53 | encode_node(map.root, arr) 54 | local num = 0 55 | local str = "" 56 | for i = 0, #arr - 1 do 57 | local mod = i % 3 58 | if mod == 0 and i > 0 then 59 | str = str .. n2c[num] 60 | num = 0 61 | end 62 | local n = arr[i+1] 63 | n = n << 2 * mod 64 | num = num | n 65 | end 66 | str = str .. n2c[num] 67 | return str 68 | end 69 | 70 | function M.decode(str, size) 71 | local len = slen(str) 72 | local chars = {} 73 | for i = 1, len do 74 | local c = ssub(str, i, i) 75 | chars[i - 1] = c 76 | end 77 | local idx = 0 78 | local function pop_tag() 79 | local c = chars[idx//3] 80 | local mod = idx % 3 81 | local tag = c2n[c] >> 2 * mod & 3 82 | assert(tag <= FOG, tag) 83 | idx = idx + 1 84 | return tag 85 | end 86 | local function pop_create_node(parent, min, max) 87 | local node = { 88 | parent = parent, 89 | tag = pop_tag(), 90 | min = min, 91 | max = max, 92 | } 93 | if node.tag == MIX then 94 | local center = min + (max - min) // 2 95 | node.left = pop_create_node(node, min, center) 96 | node.right = pop_create_node(node, center + 1 < max and center + 1 or max, max) 97 | end 98 | return node 99 | end 100 | local map = { 101 | size = size, 102 | } 103 | map.root = pop_create_node(nil, 0, size - 1) 104 | return map 105 | end 106 | 107 | local function set_tag(map, pos, tag) 108 | local function revert_parent(node) 109 | if not node then 110 | return 111 | end 112 | if node.left.tag == node.right.tag then 113 | node.tag = node.left.tag 114 | node.left = nil 115 | node.right = nil 116 | revert_parent(node.parent) 117 | end 118 | end 119 | local function find_and_insert(node) 120 | if node.tag == tag then 121 | return 122 | end 123 | if node.min == node.max then 124 | node.tag = tag 125 | revert_parent(node.parent) 126 | return 127 | end 128 | local center = node.min + (node.max - node.min) // 2 129 | if not node.left then 130 | node.left = create_node(node, node.tag, node.min, center) 131 | node.right = create_node(node, node.tag, center + 1 < node.max and center + 1 or node.max, node.max) 132 | node.tag = MIX 133 | end 134 | 135 | if pos <= center then 136 | find_and_insert(node.left) 137 | else 138 | find_and_insert(node.right) 139 | end 140 | end 141 | find_and_insert(map.root) 142 | end 143 | 144 | function M.dispel(map, pos) 145 | set_tag(map, pos, DISPEL) 146 | end 147 | 148 | function M.fog(map, pos) 149 | set_tag(map, pos, FOG) 150 | end 151 | 152 | local function find(node, pos) 153 | if pos <= node.max and pos >= node.min and node.tag ~= MIX then 154 | return node.tag 155 | end 156 | local center = node.min + (node.max - node.min) // 2 157 | if pos <= center then 158 | return find(node.left, pos) 159 | else 160 | return find(node.right, pos) 161 | end 162 | end 163 | function M.is_fog(map, pos) 164 | return find(map.root, pos) == FOG 165 | end 166 | function M.is_dispel(map, pos) 167 | return find(map.root, pos) == DISPEL 168 | end 169 | 170 | local function clone_node(node, parent) 171 | if not node then 172 | return 173 | end 174 | local new = { 175 | parent = parent, 176 | tag = node.tag, 177 | max = node.max, 178 | min = node.min, 179 | } 180 | new.left = clone_node(node.left, new) 181 | new.right = clone_node(node.right, new) 182 | return new 183 | end 184 | 185 | function M.union(map1, map2) 186 | assert(map1.size == map2.size) 187 | local map = { 188 | size = map1.size 189 | } 190 | local function union(node1, node2, parent) 191 | if node1.tag == MIX and node2.tag == MIX then 192 | local node = { 193 | parent = parent, 194 | tag = MIX, 195 | min = node1.min, 196 | max = node2.max, 197 | } 198 | node.left = union(node1.left, node2.left, node) 199 | node.right = union(node1.right, node2.right, node) 200 | if node.left.tag == node.right.tag and node.left.tag ~= MIX then 201 | node.tag = node.left.tag 202 | node.left = nil 203 | node.right = nil 204 | end 205 | return node 206 | elseif node1.tag == node2.tag or node1.tag < node2.tag then 207 | return clone_node(node1, parent) 208 | elseif node2.tag < node1.tag then 209 | return clone_node(node2, parent) 210 | end 211 | end 212 | map.root = union(map1.root, map2.root) 213 | return map 214 | end 215 | 216 | function M.cmp(old_map, new_map) 217 | assert(old_map.size == new_map.size) 218 | local new_fog_list, new_dispel_list = {}, {} 219 | local function cmp(old, new) 220 | local old_tag = type(old) == "number" and old or old.tag 221 | local new_tag = type(new) == "number" and new or new.tag 222 | if old_tag == new_tag then 223 | if old_tag == MIX then 224 | cmp(old.left, new.left) 225 | cmp(old.right, new.right) 226 | else 227 | return 228 | end 229 | elseif old_tag == MIX then 230 | cmp(old.left, new_tag) 231 | cmp(old.right, new_tag) 232 | elseif new_tag == MIX then 233 | cmp(old_tag, new.left) 234 | cmp(old_tag, new.right) 235 | else 236 | local node = type(old) == "table" and old or new 237 | for pos = node.min, node.max do 238 | if new_tag == FOG then 239 | new_fog_list[#new_fog_list+1] = pos 240 | else 241 | new_dispel_list[#new_dispel_list+1] = pos 242 | end 243 | end 244 | end 245 | end 246 | cmp(old_map.root, new_map.root) 247 | return new_fog_list, new_dispel_list 248 | end 249 | 250 | return M 251 | -------------------------------------------------------------------------------- /templates/lualib/bw/util.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet.manager" 2 | 3 | local util = {} 4 | 5 | function util.shell(cmd, ...) 6 | cmd = string.format(cmd, ...) 7 | return io.popen(cmd):read("*all") 8 | end 9 | 10 | function util.run_cluster(clustername) 11 | local conf = require "conf" 12 | local cmd = string.format("cd %s/shell && sh start.sh %s", conf.workspace, clustername) 13 | os.execute(cmd) 14 | end 15 | 16 | function util.gc() 17 | if skynet.getenv "DEBUG" then 18 | collectgarbage("collect") 19 | return collectgarbage("count") 20 | end 21 | end 22 | 23 | -- 字符串分割 24 | function util.split(s, delimiter, t) 25 | assert(string.len(delimiter) == 1) 26 | 27 | local arr = {} 28 | local idx = 1 29 | 30 | for value in string.gmatch(s, "[^" .. delimiter .. "]+") do 31 | if t == "number" then 32 | value = tonumber(value) 33 | end 34 | arr[idx] = value 35 | idx = idx + 1 36 | end 37 | 38 | return arr 39 | end 40 | 41 | function util.dump(root, ...) 42 | local tbl = {} 43 | local filter = {[root] = tostring(root)} 44 | for _, v in ipairs({...}) do 45 | filter[v] = tostring(v) 46 | end 47 | local function _to_key(k) 48 | if tonumber(k) then 49 | return '[' .. k .. ']' 50 | else 51 | return '["' .. k .. '"]' 52 | end 53 | end 54 | local function _dump(t, name, space) 55 | space = space .. " " 56 | for k, v in pairs(t) do 57 | if filter[v] then 58 | table.insert(tbl, space .. _to_key(k) .. " = " .. filter[v]) 59 | elseif filter[v] or type(v) ~= "table" then 60 | local val = tostring(v) 61 | if type(v) == "string" then 62 | val = '"' .. tostring(v) .. '"' 63 | end 64 | table.insert(tbl, space .. _to_key(k) .. " = " .. val ..",") 65 | else 66 | filter[v] = name .. "." .. _to_key(k) 67 | table.insert(tbl, space .. _to_key(k) .. " = {") 68 | _dump(v, name .. "." .. _to_key(k), space) 69 | table.insert(tbl, space .. "},") 70 | end 71 | end 72 | end 73 | 74 | table.insert(tbl, "{") 75 | _dump(root, "", "") 76 | table.insert(tbl, "}") 77 | 78 | return table.concat(tbl, "\n") 79 | end 80 | 81 | function util.is_in_list(list, obj) 82 | for _, o in pairs(list) do 83 | if o == obj then 84 | return true 85 | end 86 | end 87 | return false 88 | end 89 | 90 | -- 把table中类型为string的数字key转换成number 91 | function util.str2num(tbl) 92 | if type(tbl) ~= "table" then return tbl end 93 | local data = {} 94 | for k,v in pairs(tbl) do 95 | k = tonumber(k) or k 96 | v = type(v) == "table" and util.str2num(v) or v 97 | data[k] = v 98 | end 99 | return data 100 | end 101 | 102 | function util.num2str(tbl) 103 | if type(tbl) ~= "table" then return tbl end 104 | local data = {} 105 | for k,v in pairs(tbl) do 106 | k = tostring(k) 107 | v = type(v) == "table" and util.num2str(v) or v 108 | data[k] = v 109 | end 110 | return data 111 | end 112 | 113 | local function new_module(modname) 114 | skynet.cache.clear() 115 | local module = package.loaded[modname] 116 | if module then 117 | package.loaded[modname] = nil 118 | end 119 | local new_mod = require(modname) 120 | package.loaded[modname] = module 121 | return new_mod 122 | end 123 | 124 | function util.reload_module(modname) 125 | if not package.loaded[modname] then 126 | require(modname) 127 | return require(modname) 128 | end 129 | local old_mod = require(modname) 130 | local new_mod = new_module(modname) 131 | 132 | for k,v in pairs(new_mod) do 133 | if type(k) == "function" then 134 | old_mod[k] = v 135 | end 136 | end 137 | return old_mod 138 | end 139 | 140 | function util.clone(_obj, _deep) 141 | local lookup = {} 142 | local function _clone(obj, deep) 143 | if type(obj) ~= "table" then 144 | return obj 145 | elseif lookup[obj] then 146 | return lookup[obj] 147 | end 148 | 149 | local new = {} 150 | lookup[obj] = new 151 | for key, value in pairs(obj) do 152 | if deep then 153 | new[_clone(key, deep)] = _clone(value, deep) 154 | else 155 | new[key] = value 156 | end 157 | end 158 | 159 | return setmetatable(new, getmetatable(obj)) 160 | end 161 | 162 | return _clone(_obj, _deep) 163 | end 164 | 165 | -- t2是不是t1的内容一样 166 | function util.cmp_table(t1, t2) 167 | for k,v1 in pairs(t1) do 168 | local v2 = t2[k] 169 | if type(v1)=="table" and type(v2)=="table" then 170 | if not util.cmp_table(v1, v2) then 171 | return false 172 | end 173 | elseif v1~=v2 then 174 | return false 175 | end 176 | end 177 | 178 | for k, _ in pairs(t2) do 179 | if t1[k]==nil then 180 | return false 181 | end 182 | end 183 | return true 184 | end 185 | 186 | 187 | function util.short_name(name) 188 | return string.match(name, "_(%S+)") or name 189 | end 190 | 191 | function util.merge_list(list1, list2) 192 | local list = {} 193 | for _, v in ipairs(list1) do 194 | table.insert(list, v) 195 | end 196 | for _, v in ipairs(list2) do 197 | table.insert(list, v) 198 | end 199 | return list 200 | end 201 | 202 | local function tostring_ex(value) 203 | if type(value)=='table' then 204 | return util.tbl2str(value) 205 | elseif type(value)=='string' then 206 | return "\'"..value.."\'" 207 | else 208 | return tostring(value) 209 | end 210 | end 211 | 212 | function util.tbl2str(t) 213 | if t == nil then return "" end 214 | local retstr= "{" 215 | 216 | local i = 1 217 | for key,value in pairs(t) do 218 | local signal = "," 219 | if i==1 then 220 | signal = "" 221 | end 222 | 223 | if key == i then 224 | retstr = retstr..signal..tostring_ex(value) 225 | else 226 | if type(key)=='number' or type(key) == 'string' then 227 | retstr = retstr..signal..'['..tostring_ex(key).."]="..tostring_ex(value) 228 | else 229 | if type(key)=='userdata' then 230 | retstr = retstr..signal.."*s"..util.tbl2str(getmetatable(key)).."*e".."="..tostring_ex(value) 231 | else 232 | retstr = retstr..signal..key.."="..tostring_ex(value) 233 | end 234 | end 235 | end 236 | 237 | i = i+1 238 | end 239 | 240 | retstr = retstr.."}" 241 | return retstr 242 | end 243 | 244 | function util.str2tbl(str) 245 | if str == nil or type(str) ~= "string" then 246 | return 247 | end 248 | return load("return " .. str)() 249 | end 250 | 251 | -- todo 格式化json, 临时用,字符串中不能包含单双引号,否则出错 252 | function util.format_json(str) 253 | local depth = 0 254 | local mark 255 | return string.gsub(str, '([,{}\'\"])', function(c) 256 | if mark then 257 | if mark == c then 258 | mark = nil 259 | return c 260 | else 261 | return c 262 | end 263 | end 264 | if c == '{' then 265 | depth = depth + 1 266 | return '{\n'..string.rep(' ', depth*4) 267 | elseif c == '}' then 268 | depth = depth - 1 269 | return '\n'..string.rep(' ', depth*4)..'}' 270 | elseif c == ',' then 271 | return ',\n'..string.rep(' ', depth*4) 272 | elseif c == '\"' or c == '\'' then 273 | mark = c 274 | return c 275 | end 276 | end) 277 | end 278 | 279 | -- 方法本身 280 | function util.callee() 281 | return debug.getinfo(2, "f").func 282 | end 283 | 284 | function util.printbuff(buff) 285 | local str = "" 286 | for i=1,#buff do 287 | str = str .. string.format("%x", string.byte(buff, i)) 288 | end 289 | print(str) 290 | end 291 | 292 | -- 获取节点内的protobuf 293 | function util.get_protobuf(proto_service) 294 | local protobuf_env = skynet.call(proto_service, "lua", "get_protobuf_env") 295 | assert(type(protobuf_env) == "userdata") 296 | assert(not package.loaded["protobuf"]) 297 | debug.getregistry().PROTOBUF_ENV = protobuf_env 298 | return require "bw.protobuf" 299 | end 300 | 301 | return util 302 | -------------------------------------------------------------------------------- /templates/lualib/bw/uuid.lua: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------------- 2 | -- Copyright 2012 Rackspace (original), 2013 Thijs Schreijer (modifications) 3 | -- 4 | -- Licensed under the Apache License, Version 2.0 (the "License"); 5 | -- you may not use this file except in compliance with the License. 6 | -- You may obtain a copy of the License at 7 | -- 8 | -- http://www.apache.org/licenses/LICENSE-2.0 9 | -- 10 | -- Unless required by applicable law or agreed to in writing, software 11 | -- distributed under the License is distributed on an "AS-IS" BASIS, 12 | -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | -- See the License for the specific language governing permissions and 14 | -- limitations under the License. 15 | -- 16 | -- see http://www.ietf.org/rfc/rfc4122.txt 17 | -- 18 | -- Note that this is not a true version 4 (random) UUID. Since `os.time()` precision is only 1 second, it would be hard 19 | -- to guarantee spacial uniqueness when two hosts generate a uuid after being seeded during the same second. This 20 | -- is solved by using the node field from a version 1 UUID. It represents the mac address. 21 | -- 22 | -- 28-apr-2013 modified by Thijs Schreijer from the original [Rackspace code] 23 | -- (https://github.com/kans/zirgo/blob/807250b1af6725bad4776c931c89a784c1e34db2/util/uuid.lua) as a generic Lua module. 24 | -- Regarding the above mention on `os.time()`; the modifications use the `socket.gettime()` function from LuaSocket 25 | -- if available and hence reduce that problem (provided LuaSocket has been loaded before uuid). 26 | -- 27 | -- **6-nov-2015 Please take note of this issue**; 28 | -- [https://github.com/Mashape/kong/issues/478](https://github.com/Mashape/kong/issues/478) 29 | -- It demonstrates the problem of using time as a random seed. Specifically when used from multiple processes. 30 | -- So make sure to seed only once, application wide. And to not have multiple processes do that 31 | -- simultaneously (like nginx does for example). 32 | 33 | local M = {} 34 | local math = require('math') 35 | local os = require('os') 36 | local string = require('string') 37 | 38 | local bitsize = 32 -- bitsize assumed for Lua VM. See randomseed function below. 39 | local lua_version = tonumber(_VERSION:match("%d%.*%d*")) -- grab Lua version used 40 | 41 | local MATRIX_AND = {{0,0},{0,1} } 42 | local MATRIX_OR = {{0,1},{1,1}} 43 | local HEXES = '0123456789abcdef' 44 | 45 | local math_floor = math.floor 46 | local math_random = math.random 47 | local math_abs = math.abs 48 | local string_sub = string.sub 49 | local to_number = tonumber 50 | local assert = assert 51 | local type = type 52 | 53 | -- performs the bitwise operation specified by truth matrix on two numbers. 54 | local function BITWISE(x, y, matrix) 55 | local z = 0 56 | local pow = 1 57 | while x > 0 or y > 0 do 58 | z = z + (matrix[x%2+1][y%2+1] * pow) 59 | pow = pow * 2 60 | x = math_floor(x/2) 61 | y = math_floor(y/2) 62 | end 63 | return z 64 | end 65 | 66 | local function INT2HEX(x) 67 | local s,base = '',16 68 | local d 69 | while x > 0 do 70 | d = x % base + 1 71 | x = math_floor(x/base) 72 | s = string_sub(HEXES, d, d)..s 73 | end 74 | while #s < 2 do s = "0" .. s end 75 | return s 76 | end 77 | 78 | ---------------------------------------------------------------------------- 79 | -- Creates a new uuid. Either provide a unique hex string, or make sure the 80 | -- random seed is properly set. The module table itself is a shortcut to this 81 | -- function, so `my_uuid = uuid.new()` equals `my_uuid = uuid()`. 82 | -- 83 | -- For proper use there are 3 options; 84 | -- 85 | -- 1. first require `luasocket`, then call `uuid.seed()`, and request a uuid using no 86 | -- parameter, eg. `my_uuid = uuid()` 87 | -- 2. use `uuid` without `luasocket`, set a random seed using `uuid.randomseed(some_good_seed)`, 88 | -- and request a uuid using no parameter, eg. `my_uuid = uuid()` 89 | -- 3. use `uuid` without `luasocket`, and request a uuid using an unique hex string, 90 | -- eg. `my_uuid = uuid(my_networkcard_macaddress)` 91 | -- 92 | -- @return a properly formatted uuid string 93 | -- @param hwaddr (optional) string containing a unique hex value (e.g.: `00:0c:29:69:41:c6`), 94 | -- to be used to compensate for the lesser `math_random()` function. Use a mac address for solid results. If omitted, 95 | -- a fully randomized uuid will be generated, but then you must ensure that the random seed is set properly! 96 | -- @usage 97 | -- local uuid = require("uuid") 98 | -- print("here's a new uuid: ",uuid()) 99 | function M.new(hwaddr) 100 | -- bytes are treated as 8bit unsigned bytes. 101 | local bytes = { 102 | math_random(0, 255), 103 | math_random(0, 255), 104 | math_random(0, 255), 105 | math_random(0, 255), 106 | math_random(0, 255), 107 | math_random(0, 255), 108 | math_random(0, 255), 109 | math_random(0, 255), 110 | math_random(0, 255), 111 | math_random(0, 255), 112 | math_random(0, 255), 113 | math_random(0, 255), 114 | math_random(0, 255), 115 | math_random(0, 255), 116 | math_random(0, 255), 117 | math_random(0, 255) 118 | } 119 | 120 | if hwaddr then 121 | assert(type(hwaddr)=="string", "Expected hex string, got "..type(hwaddr)) 122 | -- Cleanup provided string, assume mac address, so start from back and cleanup until we've got 12 characters 123 | local i,str = #hwaddr, hwaddr 124 | hwaddr = "" 125 | while i>0 and #hwaddr<12 do 126 | local c = str:sub(i,i):lower() 127 | if HEXES:find(c, 1, true) then 128 | -- valid HEX character, so append it 129 | hwaddr = c..hwaddr 130 | end 131 | i = i - 1 132 | end 133 | assert(#hwaddr == 12, "Provided string did not contain at least 12 hex characters, retrieved '" 134 | ..hwaddr.."' from '"..str.."'") 135 | 136 | -- no split() in lua. :( 137 | bytes[11] = to_number(hwaddr:sub(1, 2), 16) 138 | bytes[12] = to_number(hwaddr:sub(3, 4), 16) 139 | bytes[13] = to_number(hwaddr:sub(5, 6), 16) 140 | bytes[14] = to_number(hwaddr:sub(7, 8), 16) 141 | bytes[15] = to_number(hwaddr:sub(9, 10), 16) 142 | bytes[16] = to_number(hwaddr:sub(11, 12), 16) 143 | end 144 | 145 | -- set the version 146 | bytes[7] = BITWISE(bytes[7], 0x0f, MATRIX_AND) 147 | bytes[7] = BITWISE(bytes[7], 0x40, MATRIX_OR) 148 | -- set the variant 149 | bytes[9] = BITWISE(bytes[7], 0x3f, MATRIX_AND) 150 | bytes[9] = BITWISE(bytes[7], 0x80, MATRIX_OR) 151 | return INT2HEX(bytes[1])..INT2HEX(bytes[2])..INT2HEX(bytes[3])..INT2HEX(bytes[4]).."-".. 152 | INT2HEX(bytes[5])..INT2HEX(bytes[6]).."-".. 153 | INT2HEX(bytes[7])..INT2HEX(bytes[8]).."-".. 154 | INT2HEX(bytes[9])..INT2HEX(bytes[10]).."-".. 155 | INT2HEX(bytes[11])..INT2HEX(bytes[12])..INT2HEX(bytes[13])..INT2HEX(bytes[14]) 156 | ..INT2HEX(bytes[15])..INT2HEX(bytes[16]) 157 | end 158 | 159 | ---------------------------------------------------------------------------- 160 | -- Improved randomseed function. 161 | -- Lua 5.1 and 5.2 both truncate the seed given if it exceeds the integer 162 | -- range. If this happens, the seed will be 0 or 1 and all randomness will 163 | -- be gone (each application run will generate the same sequence of random 164 | -- numbers in that case). This improved version drops the most significant 165 | -- bits in those cases to get the seed within the proper range again. 166 | -- @param seed the random seed to set (integer from 0 - 2^32, negative values will be made positive) 167 | -- @return the (potentially modified) seed used 168 | -- @usage 169 | -- local socket = require("socket") -- gettime() has higher precision than os.time() 170 | -- local uuid = require("uuid") 171 | -- -- see also example at uuid.seed() 172 | -- uuid.randomseed(socket.gettime()*10000) 173 | -- print("here's a new uuid: ",uuid()) 174 | function M.randomseed(seed) 175 | seed = math_floor(math_abs(seed)) 176 | if seed >= (2^bitsize) then 177 | -- integer overflow, so reduce to prevent a bad seed 178 | seed = seed - math_floor(seed / 2^bitsize) * (2^bitsize) 179 | end 180 | if lua_version < 5.2 then 181 | -- 5.1 uses (incorrect) signed int 182 | math.randomseed(seed - 2^(bitsize-1)) 183 | else 184 | -- 5.2 uses (correct) unsigned int 185 | math.randomseed(seed) 186 | end 187 | return seed 188 | end 189 | 190 | ---------------------------------------------------------------------------- 191 | -- Seeds the random generator. 192 | -- It does so in 2 possible ways; 193 | -- 194 | -- 1. use `os.time()`: this only offers resolution to one second (used when 195 | -- LuaSocket hasn't been loaded yet 196 | -- 2. use luasocket `gettime()` function, but it only does so when LuaSocket 197 | -- has been required already. 198 | -- @usage 199 | -- local socket = require("socket") -- gettime() has higher precision than os.time() 200 | -- -- LuaSocket loaded, so below line does the same as the example from randomseed() 201 | -- uuid.seed() 202 | -- print("here's a new uuid: ",uuid()) 203 | function M.seed() 204 | if package.loaded["socket"] and package.loaded["socket"].gettime then 205 | return M.randomseed(package.loaded["socket"].gettime()*10000) 206 | else 207 | return M.randomseed(os.time()) 208 | end 209 | end 210 | 211 | return setmetatable( M, { __call = function(self, hwaddr) return self.new(hwaddr) end} ) 212 | -------------------------------------------------------------------------------- /templates/lualib/bw/server/web_service.lua: -------------------------------------------------------------------------------- 1 | local skynet = require "skynet" 2 | local socket = require "skynet.socket" 3 | local bewater = require "bw.bewater" 4 | local log = require "bw.log" 5 | local httpd = require "http.httpd" 6 | local sockethelper = require "http.sockethelper" 7 | local urllib = require "http.url" 8 | local json = require "cjson.safe" 9 | local api = require "bw.server.web_api" 10 | local errcode = require "proto.errcode" -- TODO 耦合了本地的errcode 11 | 12 | local string = string 13 | 14 | local M = {} 15 | function M.start(handler, agentname, port, num_agents) 16 | skynet.start(function() 17 | local agents = {} 18 | for i = 1, num_agents or 10 do 19 | agents[i] = skynet.newservice(agentname) 20 | end 21 | 22 | assert(port) 23 | 24 | local curr = 1 25 | local fd = socket.listen("0.0.0.0", port) 26 | log.infof("%s listen 0.0.0.0:%d", agentname, port) 27 | socket.start(fd, function(...) 28 | skynet.send(agents[curr], "lua", ...) 29 | curr = curr + 1 30 | if curr > #agents then curr = 1 end 31 | end) 32 | if handler then 33 | skynet.dispatch("lua", function(_,_, cmd, ...) 34 | local f = assert(handler[cmd], cmd) 35 | skynet.retpack(f(...)) 36 | end) 37 | if handler.start then 38 | handler.start() 39 | end 40 | end 41 | end) 42 | end 43 | 44 | -- handler message 45 | local map = {} 46 | 47 | local function default_pack(ret) 48 | if type(ret) == "table" then 49 | ret.err = ret.err or 0 50 | return json.encode(ret) 51 | else 52 | return json.encode({err = ret}) 53 | end 54 | end 55 | 56 | local function default_unpack(str) return json.decode(str) end 57 | 58 | local function default_auth(p) error("auth function not provide") end 59 | 60 | local function response(fd, ...) 61 | local writefunc = sockethelper.writefunc(fd) 62 | local ok, err = httpd.write_response(writefunc, ...) 63 | if not ok then 64 | -- if err == sockethelper.socket_error , that means socket closed. 65 | log.errorf("fd = %d, %s", fd, err) 66 | end 67 | end 68 | 69 | local function check_data(def, data) 70 | if not data then return errcode.ARGS_ERROR, "data nil" end 71 | for k, t in pairs(def) do 72 | if t and t ~= '?' then 73 | local tn, opt = string.match(t, '(%w+)(%?*)') 74 | local tv = type(data[k]) 75 | if tv ~= tn and (opt ~= '?' or tv ~= 'nil') then 76 | return errcode.ARGS_ERROR, 77 | string.format("args error, %s must %s", k, t) 78 | end 79 | end 80 | end 81 | return errcode.OK 82 | end 83 | 84 | local function on_message(process, args, body, header) 85 | local url = process.url 86 | local pack = process.pack or default_pack 87 | local unpack = process.unpack or default_unpack 88 | 89 | local authorization = header.authorization 90 | 91 | local function errf(err, fmt, ...) 92 | return pack {err = err, desc = string.format(fmt, ...), url = url} 93 | end 94 | 95 | local ret, req = bewater.try(function() return unpack(body, url) end) 96 | if not ret then return errf(errcode.BODY_ERROR, "body error") end 97 | local uid 98 | if process.auth and default_auth then 99 | uid = default_auth(authorization) 100 | if not uid then 101 | return errf(errcode.AUTH_FAIL, "authorization fail") 102 | end 103 | end 104 | if process.request then 105 | local err, errmsg = check_data(process.request, req) 106 | if err ~= errcode.OK then errf(err, errmsg) end 107 | end 108 | local res = {} 109 | if not bewater.try(function() 110 | local func = process.handler 111 | res = process.handler(req, uid, header) or {} 112 | if type(res) == "number" then 113 | res = {err = res} 114 | if res.err ~= errcode.OK then 115 | res.errmsg = errcode.describe(res.err) 116 | end 117 | end 118 | assert(type(res) == "table") 119 | res.err = res.err or errcode.OK 120 | assert(process.response, res) 121 | end) then return errf(errcode.TRACEBACK, "server traceback") end 122 | 123 | return pack(res) 124 | end 125 | 126 | local function resp_options(fd, header) 127 | response(fd, 200, nil, { 128 | ['Access-Control-Allow-Origin'] = header['origin'], 129 | ['Access-Control-Allow-Methons'] = 'PUT, POST, GET, OPTIONS, DELETE', 130 | ['Access-Control-Allow-Headers'] = header['access-control-request-headers'] 131 | }) 132 | socket.close(fd) 133 | end 134 | 135 | local function trim_lf(str) return string.gsub(str, '[\n\r]', '') end 136 | 137 | local function trim_body(str) 138 | if not str then 139 | return '' 140 | elseif #str < 200 then 141 | return trim_lf(str) 142 | else 143 | return trim_lf(str:sub(1, 200) .. '...') 144 | end 145 | end 146 | 147 | --[[ 148 | host=dev.coding1024.com 149 | connection=close 150 | x-forwarded-for=113.109.247.71 151 | content-type=application/x-www-form-urlencoded 152 | x-real-ip=113.109.247.71 153 | user-agent=Dalvik/2.1.0 (Linux; U; Android 10; PCAM00 Build/QKQ1.190918.001) 154 | remote-host=113.109.247.71 155 | content-length=92 156 | accept-encoding=identity 157 | ]] 158 | local header_filter = { 159 | ["connection"] = true, 160 | ["x-forwarded-for"] = true, 161 | ["user-agent"] = true, 162 | ["remote-host"] = true, 163 | ["accept-encoding"] = true 164 | } 165 | local function trim_header(header) 166 | if not header then 167 | return '' 168 | else 169 | local t = {} 170 | for k, v in pairs(header) do 171 | if not header_filter[k] then 172 | t[#t + 1] = string.format('%s=%s', k, v) 173 | end 174 | end 175 | return table.concat(t, ', ') 176 | end 177 | end 178 | 179 | function M.start_agent(handler) 180 | skynet.start(function() 181 | handler = handler or {} 182 | if handler.start then 183 | handler.start() 184 | end 185 | -- 如果是非字符串,handler需要提供pack和unpack方法 186 | default_pack = handler.pack or default_pack 187 | default_unpack = handler.unpack or default_unpack 188 | default_auth = handler.auth or default_auth 189 | on_message = handler.on_message or on_message 190 | 191 | skynet.dispatch("lua", function(_, _, fd, ip) 192 | socket.start(fd) 193 | -- limit request body size to 8192 (you can pass nil to unlimit) 194 | local code, url, method, header, body = httpd.read_request( 195 | sockethelper.readfunc(fd),nil) 196 | log.infof('http request(fd:%d):%s %s 200 header:[%s] request:[%s]', 197 | fd, method, url, trim_header(header), trim_body(body)) 198 | local process = map[url] 199 | code = process and code or 404 200 | if (code == 200 or code == 404) and method ~= "OPTIONS" then 201 | local data 202 | local _, query = urllib.parse(url) 203 | if query then data = urllib.parse_query(query) end 204 | if not header['x-real-ip'] then 205 | header['x-real-ip'] = string.match(ip, "[^:]+") 206 | end 207 | local resp_body, resp_header 208 | if code == 200 then 209 | resp_body, resp_header = 210 | on_message(process, data, body, header) 211 | else 212 | code = 200 213 | resp_body = default_pack({err = errcode.API_NOT_FOUND}) 214 | end 215 | log.debugf('http response(fd:%d):%s %s 200 request:[%s] respose:[%s]', 216 | fd, method, url, trim_body(body), trim_body(resp_body)) 217 | response(fd, code, resp_body, resp_header or { 218 | ['Access-Control-Allow-Origin'] = header['origin'], 219 | ['Access-Control-Allow-Methons'] = 'PUT, POST, GET, OPTIONS, DELETE', 220 | ['Access-Control-Allow-Headers'] = header['access-control-request-headers'] 221 | }) 222 | else 223 | if url == sockethelper.socket_error then 224 | log.debug("socket closed") 225 | end 226 | if method == "OPTIONS" then 227 | return resp_options(fd, header) 228 | else 229 | response(fd, code) 230 | end 231 | end 232 | socket.close(fd) 233 | end) 234 | end) 235 | end 236 | 237 | function M.register(protocol, handler) 238 | if type(protocol) == 'string' then 239 | protocol = assert(api(protocol), 'no api protocol define: ' .. protocol) 240 | end 241 | local url = assert(protocol.url) 242 | assert(protocol.response, protocol.url) 243 | map[url] = setmetatable({ 244 | handler = assert(handler, 'no http handler: ' .. url) 245 | }, {__index = protocol}) 246 | end 247 | 248 | function M.def(def, handler) 249 | api.typedef(def) 250 | M.register(def.url, handler) 251 | end 252 | 253 | return M 254 | --------------------------------------------------------------------------------