├── 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..''..k..'>'
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 |
--------------------------------------------------------------------------------