904118851 пре 9 месеци
комит
c1af712cde
51 измењених фајлова са 5407 додато и 0 уклоњено
  1. 1 0
      .gitignore
  2. 1 0
      bin/jl_tg_config_back.pid
  3. 3 0
      bin/kill.sh
  4. 1 0
      bin/kill_back.sh
  5. 3 0
      bin/run.sh
  6. 3 0
      bin/run_back.sh
  7. BIN
      common/dbproxy/.DS_Store
  8. 61 0
      common/dbproxy/db_filter_config.lua
  9. 24 0
      common/dbproxy/dbproxy.lua
  10. 66 0
      common/dbproxy/mongodb/mongodb_slave.lua
  11. 101 0
      common/dbproxy/mongodb/mongodbpool.lua
  12. 73 0
      common/dbproxy/mongodbx.lua
  13. 45 0
      common/dbproxy/mongohelper.lua
  14. 45 0
      common/dbproxy/mysqldb/mysqldb_slave.lua
  15. 63 0
      common/dbproxy/mysqldb/mysqldbpool.lua
  16. 27 0
      common/dbproxy/mysqldbx.lua
  17. 16 0
      common/dbproxy/mysqlhelper.lua
  18. 248 0
      common/dbproxy/redisdb/redisbackup.lua
  19. 210 0
      common/dbproxy/redisdb/redisdb_slave.lua
  20. 64 0
      common/dbproxy/redisdb/redisdbpool.lua
  21. 19 0
      common/dbproxy/redisdbx.lua
  22. 9 0
      common/dbproxy/redishelper.lua
  23. 57 0
      common/dbproxy/tg_app.lua
  24. 187 0
      common/dbproxy/tg_main.lua
  25. 151 0
      common/dbproxy/tg_max_zhuanhua.lua
  26. 192 0
      common/dbproxy/tg_platform.lua
  27. 51 0
      common/dbproxy/tg_temp_app.lua
  28. 188 0
      common/dbproxy/tg_zhanghu.lua
  29. 1598 0
      common/preload/functions.lua
  30. 334 0
      common/preload/inspect.lua
  31. 41 0
      common/preload/inspect_api.lua
  32. 56 0
      common/preload/logger_api.lua
  33. 8 0
      etc/config.path
  34. 17 0
      etc/config_node1
  35. 18 0
      etc/prodconfig
  36. 223 0
      log/2024_11_28.log
  37. 87 0
      lualib/service.lua
  38. 129 0
      lualib/tools.lua
  39. 13 0
      preload.lua
  40. 169 0
      service/agent.lua
  41. 116 0
      service/agent_manager.lua
  42. 12 0
      service/backmgr/back_response.lua
  43. 224 0
      service/backmgr/filter_task.lua
  44. 76 0
      service/backmgr/init.lua
  45. 17 0
      service/backmgr/push_msg.lua
  46. 24 0
      service/backmgr/user.lua
  47. 148 0
      service/doc/cmd_sql.sql
  48. 28 0
      service/http_work/init.lua
  49. 78 0
      service/main.lua
  50. 20 0
      service/tools_work/init.lua
  51. 62 0
      service/userlog.lua

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+etc/run_config.lua

+ 1 - 0
bin/jl_tg_config_back.pid

@@ -0,0 +1 @@
+11969

+ 3 - 0
bin/kill.sh

@@ -0,0 +1,3 @@
+lsof -i :9879 | grep LISTEN | awk '{print $2}' | xargs sudo kill -9
+# lsof -i :9902 | grep LISTEN | awk '{print $2}' | xargs sudo kill -9
+# lsof -i :9904 | grep LISTEN | awk '{print $2}' | xargs sudo kill -9

+ 1 - 0
bin/kill_back.sh

@@ -0,0 +1 @@
+kill -9 `cat jl_tg_config_back.pid`

+ 3 - 0
bin/run.sh

@@ -0,0 +1,3 @@
+bash /home/auto_book/bin/kill.sh
+# bash ./start_nginx.sh
+/home/skynet/skynet /home/auto_book/etc/config_node$1

+ 3 - 0
bin/run_back.sh

@@ -0,0 +1,3 @@
+kill -9 `cat jl_tg_config_back.pid`
+sleep 1
+../../skynet/skynet ../etc/prodconfig 

BIN
common/dbproxy/.DS_Store


+ 61 - 0
common/dbproxy/db_filter_config.lua

@@ -0,0 +1,61 @@
+--主体
+local M = {}
+local mysqldbx = require "mysqldbx"
+local tools = require "tools"
+local skynet = require "skynet"
+local cjson = require "cjson"
+local shaixuan_config = {}
+--platform_select 1是黑岩 2是番茄 3是全部
+--is_guajian 1 是打开 0 是关闭
+--like_num 点在数大于等于
+--kepp_num 收藏数大于等于
+--shared_num 分享数大于等于
+--comment_num 评论数大于等于
+--material_time 素材时效 天数
+--status 1 是开启 0 是关闭
+--genre 1是长篇 2是短片 3是全部
+--数据库筛选
+function M.modifyConfig(msg_body)
+    local isok ,key =  tools.checkData({"platform_select","is_guajian","like_num","kepp_num","shared_num","comment_num","material_time","status","genre","source_filter"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local obj = {}
+    local sql = string.format("UPDATE `db_filter_config` SET  config = '%s'  WHERE config_id = 1 ",
+    cjson.encode(msg_body))
+    local res = mysqldbx.query(sql) 
+    if res.Warnings == 0 then
+        shaixuan_config = msg_body
+    end
+    skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="updateFilterConfig"}))
+    return true
+end
+
+function M.getConfig()
+    if #shaixuan_config <=0 then
+        local sql = string.format("select config from `db_filter_config` WHERE config_id = 1 ")
+        local res = mysqldbx.query(sql)
+        local obj = {}
+        if res[1].config~=nil then
+            obj = cjson.decode(res[1].config)
+        else
+            obj = {
+                platform_select = 2,
+                is_guajian = 1,
+                like_num = 10,
+                kepp_num = 10,
+                shared_num = 10,
+                comment_num = 10,
+                material_time =2,
+                status = 1,
+                genre = 1,
+                source_filter = {"来源1","来源2"}
+            }
+            M.config(obj)
+        end
+        shaixuan_config = obj;
+    end
+    return true,shaixuan_config
+end
+
+return M

+ 24 - 0
common/dbproxy/dbproxy.lua

@@ -0,0 +1,24 @@
+local skynet = require "skynet"
+require "skynet.manager"
+local settings = require "run_config"
+
+local skynet_node_name = ...
+
+local CMD = {}
+
+
+local function start()
+    local conf = settings.db_cnf[skynet_node_name]
+    for _, proxy in ipairs(conf.dbproxy) do
+        skynet.uniqueservice(proxy .. "pool", skynet_node_name)
+    end
+end
+
+skynet.start(function()
+    start()
+    skynet.dispatch("lua", function(_, _, cmd, ...)
+        local f = assert(CMD[cmd], cmd .. "not found")
+        skynet.retpack(f(...))
+    end)
+    skynet.register('.' .. SERVICE_NAME)
+end)

+ 66 - 0
common/dbproxy/mongodb/mongodb_slave.lua

@@ -0,0 +1,66 @@
+local skynet = require "skynet"
+require "skynet.manager"
+local cjson = require "cjson"
+local mongodb_tb = require "settings".mongodb_tb
+
+local CMD = {}
+
+local db = {}
+
+
+local function init_db(cnf)
+    local dbc = require "mongodb.mongodb"
+    return dbc:start(cnf)
+end
+
+function CMD.start(cnf)
+    for _, v in pairs(mongodb_tb) do
+        db[v] = init_db({host = cnf.host, port = cnf.port, db_name = v})
+        assert(db[v])
+    end
+end
+
+--cname -> collection name
+
+function CMD.find(dbname, cname, ...)
+    skynet.error("call_mongodb_slave:",dbname,cname,cjson.encode(...))
+    local res =  db[dbname]:find(cname, ...)
+    skynet.error("call_mongodb_slave:",cjson.encode(res))
+    return res
+end
+
+function CMD.findOne(dbname, cname, select)
+    return db[dbname]:findOne(cname, select)
+end
+
+function CMD.aggregate(dbname, cname, operation)
+    return db[dbname]:aggregate(cname, operation)
+end
+
+function CMD.update(dbname, cname, select, datas)
+    return db[dbname]:update(cname, select, datas, true)
+end
+
+function CMD.updateMany(dbname, cname, select, datas)
+    return db[dbname]:updateMany(cname, select, datas)
+end
+
+function CMD.insert(dbname, cname, data)
+    return db[dbname]:insert(cname, data)
+end
+
+function CMD.batch_insert(dbname, cname, data)
+    return db[dbname]:batch_insert(cname, data)
+end
+
+function CMD.del(dbname, cname, select)
+    return db[dbname]:delete(cname, select)
+end
+
+
+skynet.start(function()
+    skynet.dispatch("lua", function(_, _, cmd, ...)
+        local f = assert(CMD[cmd], cmd .. "not found")
+        skynet.retpack(f(...))
+    end)
+end)

+ 101 - 0
common/dbproxy/mongodb/mongodbpool.lua

@@ -0,0 +1,101 @@
+
+local skynet = require "skynet"
+require "skynet.manager"
+local setting_template = require "settings"
+
+local skynet_node_name = ...
+
+local CMD = {}
+local pool = {}
+
+local next_id = 0
+local maxconn = 1
+
+local function next_conn()
+    local id = next_id % maxconn + 1
+    next_id = next_id + 1
+    if id > maxconn then
+        id = 1
+    end
+    return pool[id]
+end
+
+local function getconn(key)
+    if key and (type(key) == "number" or tonumber(key)) then
+       local id = math.floor((tonumber(key) - 1) % maxconn) + 1
+        return pool[id]
+    else
+        return next_conn()
+    end
+end
+
+local function call_mongodb_slave(addr, cmd, ...)
+    return skynet.call(addr, "lua", cmd, ...)
+end
+
+local function send_mongodb_slave(addr, cmd, ...)
+    skynet.send(addr, "lua", cmd, ...)
+end
+
+local function start()
+    local settings = setting_template.db_cnf[skynet_node_name]
+    INFO("mongodbpool 启动", skynet_node_name, inspect(settings))
+    maxconn = tonumber(settings.mongodb_maxinst) or 1
+    for i = 1, maxconn do
+        local mongodb_slave = skynet.newservice("mongodb_slave")
+        skynet.call(mongodb_slave, "lua", "start", settings.mongodb_cnf)
+        table.insert(pool, mongodb_slave)
+    end
+end
+
+function CMD.find(table_name, cname, ...)
+    local executer = getconn()
+    return call_mongodb_slave(executer, "find", table_name, cname, ...)
+end
+
+function CMD.findOne(table_name, cname, conds)
+    local executer = getconn()
+    return call_mongodb_slave(executer, "findOne", table_name, cname, conds)
+end
+
+function CMD.aggregate(dbname, cname, operation)
+    local executer = getconn()
+    return call_mongodb_slave(executer, "aggregate", table_name, cname, operation)
+end
+
+function CMD.upsert(table_name, cname, datas, conds)
+    local executer = getconn()
+    return call_mongodb_slave(executer, "update", table_name, cname, conds, datas)
+end
+
+
+function CMD.updateMany(table_name, cname, datas, conds)
+    local executer = getconn()
+    return call_mongodb_slave(executer, "updateMany", table_name, cname, conds, datas)
+end
+
+function CMD.insert(table_name, cname, datas)
+    local executer = getconn()
+    return call_mongodb_slave(executer, "insert", table_name, cname, datas)
+end
+
+function CMD.batch_insert(table_name, cname, datas)
+    local executer = getconn()
+    return call_mongodb_slave(executer, "batch_insert", table_name, cname, datas)
+end
+
+function CMD.del(table_name, cname, conds)
+    local executer = getconn()
+    return call_mongodb_slave(executer, "del", table_name, cname, conds)
+end
+
+skynet.start(function()
+    start()
+
+    skynet.dispatch("lua", function(_, _, cmd, ...)
+        local f = assert(CMD[cmd], cmd .. " not found")
+        skynet.retpack(f(...))
+    end)
+
+    skynet.register('.' .. SERVICE_NAME)
+end)

+ 73 - 0
common/dbproxy/mongodbx.lua

@@ -0,0 +1,73 @@
+local mongodbx = {}
+
+local skynet = require "skynet"
+
+local MONGODBL_POOL
+
+-- 有些 服务 不允许在 init 阶段处理
+-- 暂时需改成 第一次调用 查询
+-- skynet.init(function ()
+--     MONGODBL_POOL = skynet.queryservice("mongodbpool")
+-- end)
+
+--show dbs;
+-- use ant_account
+--db.dropDatabase()
+-- show collections
+-- db.collection.find() --collection需替换对应具体名字
+--db.collection.find( { qty: { $gt: 4 } } )
+
+local function block_query()
+    -- body
+    if not MONGODBL_POOL then
+        MONGODBL_POOL = skynet.queryservice("mongodbpool")
+    end
+end
+
+function mongodbx.find(table_name, cname, conds)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", "find", table_name, cname, conds)
+end
+
+function mongodbx.findOne(table_name, cname, conds)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", "findOne", table_name, cname, conds)
+end
+
+function mongodbx.aggregate(table_name, cname, operation)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", "aggregate", table_name, cname, operation)
+end
+
+function mongodbx.upsert(table_name, cname, conds, datas)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", "upsert", table_name, cname, conds, datas)
+end
+
+
+function mongodbx.updateMany(table_name, cname, conds, datas)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", "updateMany", table_name, cname, conds, datas)
+end
+
+function mongodbx.insert(table_name, cname, datas)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", "insert", table_name, cname, datas)
+end
+
+function mongodbx.batch_insert(table_name, cname, datas)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", "batch_insert", table_name, cname, datas)
+end
+
+function mongodbx.del(table_name, cname, conds)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", "del", table_name, cname, conds)
+end
+
+function mongodbx.exec(cmd, ...)
+    block_query()
+    return skynet.call(MONGODBL_POOL, "lua", cmd, ...)
+end
+
+return mongodbx

+ 45 - 0
common/dbproxy/mongohelper.lua

@@ -0,0 +1,45 @@
+local M = {}
+
+local mongodbx = require "dbproxy.mongodbx"
+
+function M.find(...)
+    return mongodbx.find(...)
+end
+
+function M.findOne(...)
+    return mongodbx.findOne(...)
+end
+
+function M.aggregate(...)
+    return mongodbx.aggregate(...)
+end
+
+function M.upsert(...)
+    return mongodbx.upsert(...)
+end
+
+function M.updateMany(...)
+    return mongodbx.updateMany(...)
+end
+
+function M.insert(...)
+    return mongodbx.insert(...)
+end
+
+function M.batch_insert(...)
+    return mongodbx.batch_insert(...)
+end
+
+function M.del(...)
+    return mongodbx.del(...)
+end
+
+function M.fetch_all(...)
+    return mongodbx.fetch_all(...)
+end
+
+function M.exec(cmd, ...)
+    return mongodbx.exec(cmd, ...)
+end
+
+return M

+ 45 - 0
common/dbproxy/mysqldb/mysqldb_slave.lua

@@ -0,0 +1,45 @@
+local skynet = require "skynet"
+require "skynet.manager"
+local mysql = require "skynet.db.mysql"
+-- local sql_template = require "sql_template"
+
+local CMD = {}
+local db
+
+
+function CMD.start(conf)
+    local function on_connect(db)
+        db:query("set charset utf8mb4");
+    end
+
+    db = mysql.connect{
+        host=conf.ip,
+        port=conf.port,
+        database=conf.db,
+        user=conf.user,
+        password=conf.password,
+        charset="utf8mb4",
+        max_packet_size = 1024 * 1024,
+        on_connect = on_connect
+    }
+    if not db then
+        error("mysql connect fail")
+    end
+    skynet.fork(function()
+        while true do
+            db:ping()
+            skynet.sleep(300)
+        end
+    end)
+end
+
+function CMD.query(sql)
+    return db:query(sql)
+end
+
+skynet.start(function()
+    skynet.dispatch("lua", function(_, _, cmd, ...)
+        local f = assert(CMD[cmd], cmd .. "not found")
+        skynet.retpack(f(...))
+    end)
+end)

+ 63 - 0
common/dbproxy/mysqldb/mysqldbpool.lua

@@ -0,0 +1,63 @@
+
+local skynet = require "skynet"
+require "skynet.manager"
+local setting_template = require "run_config"
+
+local skynet_node_name = ...
+
+local CMD = {}
+local pool = {}
+
+local next_id = 0
+local maxconn = 1
+
+local function next_conn()
+    local id = next_id % maxconn + 1
+    next_id = next_id + 1
+    if id > maxconn then
+        id = 1
+    end
+    return pool[id]
+end
+
+local function getconn(key)
+    if key and (type(key) == "number" or tonumber(key)) then
+        local id = math.floor((tonumber(key) - 1) % maxconn) + 1
+        return pool[id]
+    else
+        return next_conn()
+    end
+end
+
+local function call_mysqldb_slave(addr, ...)
+    return skynet.call(addr, "lua", "query", ...)
+end
+
+local function start()
+    local settings = setting_template.db_cnf[skynet_node_name]
+    INFO("mysqldbpool 启动", skynet_node_name, inspect(settings))
+    maxconn = tonumber(settings.mysqldb_maxinst) or 1
+    for i = 1, maxconn do
+        local mysqldb_slave = skynet.newservice("mysqldb_slave")
+        skynet.call(mysqldb_slave, "lua", "start", settings.mysqldb_cnf)
+        table.insert(pool, mysqldb_slave)
+    end
+end
+
+
+function CMD.query(sql)
+    local executer = getconn()
+    return call_mysqldb_slave(executer, sql)
+end
+
+
+skynet.start(function()
+    start()
+
+    skynet.dispatch("lua", function(_, _, cmd, ...)
+        local f = assert(CMD[cmd], cmd .. "not found")
+        skynet.retpack(f(...))
+    end)
+
+    skynet.register('.' .. SERVICE_NAME)
+end)

+ 27 - 0
common/dbproxy/mysqldbx.lua

@@ -0,0 +1,27 @@
+local mysqldbx = {}
+
+local skynet = require "skynet"
+
+local MYSQLABL_POOL
+
+-- 有些 服务 不允许在 init 阶段处理
+-- 暂时需改成 第一次调用 查询
+-- skynet.init(function ()
+--     MYSQLABL_POOL = skynet.queryservice("mysqldbpool")
+-- end)
+
+
+local function block_query()
+    -- body
+    if not MYSQLABL_POOL then
+        MYSQLABL_POOL = skynet.queryservice("mysqldbpool")
+    end
+end
+
+function mysqldbx.query(sql)
+    block_query()
+    return skynet.call(MYSQLABL_POOL, "lua", "query", sql)
+end
+
+
+return mysqldbx

+ 16 - 0
common/dbproxy/mysqlhelper.lua

@@ -0,0 +1,16 @@
+local M = {}
+
+local mysqldbx = require "mysqldbx"
+-- local tg_app = require "tg_app"
+
+
+-- function M.loaduser(id)
+--     local sql = string.format("select * from `sg_user` where id = %d", id)
+--     return mysqldbx.query(sql)
+-- end
+
+function M.selectSql(tab_name,key,value)
+    return  string.format("select * from `%s` where %s = %d",tab_name, key,value)
+end
+
+return M

+ 248 - 0
common/dbproxy/redisdb/redisbackup.lua

@@ -0,0 +1,248 @@
+--[[  config
+root = "./"
+
+listen = "127.0.0.1:8786"
+redisaddr = "127.0.0.1:6379[1]"
+dbfile = root .. "backup.db"
+
+thread = 4
+logger = nil
+harbor = 1
+address = "127.0.0.1:8788"
+master = "127.0.0.1:8787"
+start = "redisbackup"
+standalone = "127.0.0.1:8787"
+luaservice = root.."service/?.lua"
+cpath = root.."service/?.so"
+]]
+
+local skynet = require "skynet"
+local socket = require "socket"
+
+local NAME = "redisbackup"
+
+local mode, id , db = ...
+local fd = nil	-- redis socket fd
+
+if mode == nil then
+	local listen_addr = skynet.getenv "listen"
+	local addr, port = string.match(listen_addr, "([^:%s]+)%s*:%s*([^:%s]+)")
+	print(string.format("Listen on %s:%d", addr, port))
+
+	skynet.start(function()
+		local db = skynet.newservice(NAME , "dbserver")
+		local id = socket.listen(addr, port)
+		socket.start(id , function(id, addr)
+			-- you can also call skynet.newservice for this socket id
+			skynet.newservice(NAME, "dispatcher", id, db)
+		end)
+	end)
+
+elseif mode == "dispatcher" then
+	id = tonumber(id)
+	db = tonumber(db)
+
+	local function mainloop()
+		while true do
+			local str = socket.readline(id,"\n")
+			if str then
+				local cmd, key = string.match(str, "(%w+)%s*(.*)")
+				if cmd == "S" or cmd == "L" or cmd == "C" then
+					skynet.send(db, "lua", cmd, key)
+				elseif cmd == "V" then
+					local ret = skynet.call(db, "lua", cmd, key)
+					if ret then
+						socket.write(id, tostring(ret))
+					end
+				else
+					print("Unknown command", cmd, key)
+				end
+			else
+				socket.close(id)
+				skynet.exit()
+				return
+			end
+		end
+	end
+
+	skynet.start(function()
+		socket.start(id)
+		skynet.fork(mainloop)
+	end)
+
+elseif mode == "dbserver" then
+	local unqlite = require "unqlite"
+
+	local dbfile = skynet.getenv "dbfile"
+	local unqlite_db = unqlite.open(dbfile)
+	print("Open db file : ", dbfile)
+	-- mark in _G
+	unqlite_db_gc = setmetatable({} , { __gc = function() unqlite.close(unqlite_db) end })
+
+	local redis_addr = skynet.getenv "redisaddr"
+	local addr, port, db = string.match(redis_addr, "([^:%s]+)%s*:%s*([^:%s%[]+)%s*%[%s*(%d+)%]")
+	port = tonumber(port)
+	db = tostring(db)
+	print(string.format("Redis %s : %d select(%d)", addr, port, db))
+
+----- redis response
+
+	local function readline()
+		return assert(socket.readline(fd, "\r\n"))
+	end
+
+	local function readbytes(bytes)
+		return assert(socket.read(fd, bytes))
+	end
+
+	local function read_response(firstline)
+		local firstchar = string.byte(firstline)
+		local data = string.sub(firstline,2)
+		if firstchar == 42 then -- '*'
+			local n = tonumber(data)
+			if n <= 0 then
+				return n
+			end
+			local bulk = {}
+			for i = 1,n do
+				local line = readline()
+				bulk[i*2-1] = line .. "\r\n"
+				local bytes = tonumber(string.sub(line,2))
+				if bytes >= 0 then
+					local data = readbytes(bytes + 2)
+					-- bulk[i] = nil when bytes < 0
+					bulk[i*2] = data
+				else
+					bulk[i*2] = ""
+				end
+			end
+			return n, table.concat(bulk)
+		end
+		if firstchar == 36 then -- '$'
+			local bytes = tonumber(data)
+			if bytes < 0 then
+				return data
+			end
+			local firstline = skynet.readbytes(fd, bytes+2)
+			return data .. "\r\n" .. firstline
+		end
+		return firstline
+	end
+-----------------------
+
+	local command = {}
+	local dbcmd = { head = 1, tail = 1 }
+
+	local cache = {}
+
+	local function push(v)
+		dbcmd[dbcmd.tail] = v
+		dbcmd.tail = dbcmd.tail + 1
+	end
+
+	local function pop()
+		if dbcmd.head == dbcmd.tail then
+			return
+		end
+		local v = dbcmd[dbcmd.head]
+		dbcmd[dbcmd.head] = nil
+		dbcmd.head = dbcmd.head + 1
+		if dbcmd.head == dbcmd.tail then
+			dbcmd.head = 1
+			dbcmd.tail = 1
+		end
+		return v
+	end
+
+	function command.S(key)
+		local load_command = string.format("*2\r\n$7\r\nHGETALL\r\n$%d\r\n%s\r\n",#key,key)
+		push(load_command)
+		pcall(socket.write,fd,load_command)
+	end
+
+	function command.L(key)
+		local v = unqlite.load(unqlite_db , key)
+		if v then
+			push(v)
+			pcall(socket.write,fd,v)
+		end
+	end
+
+	function command.C()
+		local ok, err = pcall(unqlite.commit,unqlite_db)
+		if not ok then
+			print("Commit error:", err)
+		end
+	end
+
+	function command.D(key)
+		print("delete", key)
+	end
+
+	function command.V(key)
+		local v = unqlite.load(unqlite_db , key)
+		skynet.ret(skynet.pack(v))
+	end
+
+	local dispatcher
+
+	local function connect_redis(addr, port, db)
+		fd = socket.open(addr, port)
+		if fd then
+			socket.write(fd, string.format("*2\r\n$6\r\nSELECT\r\n$%d\r\n%d\r\n",#db,db))
+			local ok = readline()
+			assert(ok == "+OK", string.format("Select %d failed", db))
+			for i = dbcmd.head, dbcmd.tail -1 do
+				socket.write(fd, dbcmd[i])
+			end
+			print("connect ok")
+			skynet.fork(dispatcher)
+			return true
+		end
+	end
+
+	local function dispatch_one()
+		local firstline = readline()
+		if firstline == "+OK" then
+			pop()
+		else
+			local r,data = read_response(firstline)
+			if type(r) == "number" and r > 0 then
+				-- save key
+				local cmd = pop()
+				local key = string.match(cmd,"\r\n([^%s]+)\r\n$")
+				unqlite.save(unqlite_db , key, string.format("*%d\r\n$5\r\nHMSET\r\n$%d\r\n%s\r\n%s", r+2, #key, key, data))
+			else
+				print("error:", r, data)
+				pop()
+			end
+		end
+	end
+
+	-- local function
+	function dispatcher()
+		while true do
+			local ok , err = pcall(dispatch_one)
+			if not ok then
+				-- reconnect
+				print("redis disconnected:" , err)
+				local ok, err = pcall(connect_redis, addr, port, db)
+				if not ok then
+					fd = nil
+					print("Connect redis error: " ..  tostring(err))
+					skynet.sleep(1000)
+				end
+				return
+			end
+		end
+	end
+
+	skynet.start(function()
+		assert(connect_redis(addr,port,db) , "Connect failed")
+		skynet.dispatch("lua", function(session,addr, cmd, ...)
+			command[cmd](...)
+		end)
+	end)
+else
+	error ("Invalid mode " .. mode)
+end

+ 210 - 0
common/dbproxy/redisdb/redisdb_slave.lua

@@ -0,0 +1,210 @@
+local skynet = require "skynet"
+require "skynet.manager"
+local redis = require "skynet.db.redis"
+
+
+local CMD = {}
+local db = nil
+
+
+function CMD.start(cnf)
+    -- DEBUG("redis slave cnf = ", DUMP(cnf))
+    local ok, d = pcall(redis.connect, cnf)
+    if ok then
+        db = d
+        -- db:flushall()
+    else
+        ERROR("---redis connect error---", inspect(cnf) )
+    end
+    skynet.fork(function()
+        while true do
+            local ping = db:ping()
+            -- DEBUG("ping = ", ping)
+            skynet.sleep(1000)
+        end
+    end)
+end
+
+function CMD.set(key, value, type, time)
+    if type ~= nil then
+        return db:set(key, value, type, time)
+    else
+        return db:set(key,value)
+    end
+end
+
+function CMD.expire(key, ex)
+    return db:expire(key, ex)
+end
+
+function CMD.get(key)
+    return db:get(key)
+end
+
+function CMD.hmset(key, t)
+    local data = {}
+    for k, v in pairs(t) do
+        table.insert(data, k)
+        table.insert(data, v)
+    end
+    return db:hmset(key, table.unpack(data))
+end
+
+function CMD.hmget(key, ...)
+    return db:hmget(key, ...)
+end
+
+function CMD.hset(key, filed, value)
+    return db:hset(key,filed,value)
+end
+
+function CMD.hget(key, filed)
+    return db:hget(key, filed)
+end
+
+function CMD.hgetall(key)
+    return db:hgetall(key)
+end
+
+function CMD.zadd(...)
+    return db:zadd(...)
+end
+
+function CMD.keys(key)
+    return db:keys(key)
+end
+
+function CMD.zrange(key, from, to, scores)
+    if not scores then
+        return db:zrange(key, from, to)
+    else
+        return db:zrange(key, from, to, scores)
+    end
+end
+
+function CMD.zincrby(key, score, member)
+    return db:zincrby(key, score, member)
+end
+
+function CMD.zrevrange(key, from, to, scores)
+    if not scores then
+        return db:zrevrange(key,from,to)
+    else
+        return db:zrevrange(key,from,to,scores)
+    end
+end
+
+function CMD.zrangebyscore(key, from, to, scores, limit, offset, count)
+    if not scores then
+        if not limit then
+            return db:zrangebyscore(key,from,to)
+        else
+            return db:zrangebyscore(key,from,to, limit,offset, count)
+        end
+    else
+        if not limit then
+            return db:zrangebyscore(key,from,to,scores)
+        else
+            return db:zrangebyscore(key,from,to,scores,limit, offset, count)
+        end
+    end
+end
+
+function CMD.zrevrangebyscore(key, max, min, scores, limit, offset, count)
+    if not scores then
+        if not limit then
+            return db:zrevrangebyscore(key, max, min)
+        else
+            return db:zrevrangebyscore(key,max, min, limit, offset, count)
+        end
+    else
+        if not limit then
+            return db:zrevrangebyscore(key,max, min,scores)
+        else
+            return db:zrevrangebyscore(key,max, min,scores,limit, offset, count)
+        end
+    end
+end
+
+function CMD.zrank(key, member)
+    return db:zrank(key,member)
+end
+
+function CMD.zrevrank(key, member)
+    return db:zrevrank(key,member)
+end
+
+function CMD.zscore(key, member)
+    return db:zscore(key, member)
+end
+
+function CMD.zcount(key, from, to)
+    return db:zcount(key,from,to)
+end
+
+function CMD.zcard(key)
+    return db:zcard(key)
+end
+
+function CMD.incr(key)
+    return db:incr(key)
+end
+
+function CMD.del(key)
+    return db:del(key)
+end
+
+function CMD.hexists(key )
+    local r = db:hexists(key)
+    return r == 1 and true or false
+end
+
+function CMD.exists(key)
+    return db:exists(key) == 1
+end
+
+function CMD.hdel(... )
+    return db:hdel(...)
+end
+
+function CMD.hincrby(key, field, increment)
+    return tonumber(db:hincrby(key, field, increment))
+end
+
+function CMD.incrby(key, increment)
+    return tonumber(db:incrby(key, increment))
+end
+
+function CMD.setnx(key, value)
+    return db:setnx(key, value) == 1
+end
+
+function CMD.hsetnx(key, field, value)
+    return db:hsetnx(key, field, value) == 1
+end
+
+function CMD.hkeys(key)
+    return db:hkeys(key)
+end
+
+function CMD.getbit(key, offset)
+    return db:getbit(key, offset)
+end
+
+
+function CMD.setbit(key, offset, value)
+    return db:setbit(key, offset, value)
+end
+
+
+function CMD.eval(...)
+    return db:eval(...)
+end
+
+skynet.start(function()
+    skynet.dispatch("lua", function(_, _, cmd, ...)
+        -- DEBUG("redis slave cmd = ", cmd)
+        local f = assert(CMD[cmd], cmd .. " not found")
+        skynet.retpack(f(...))
+    end)
+end)

+ 64 - 0
common/dbproxy/redisdb/redisdbpool.lua

@@ -0,0 +1,64 @@
+local skynet = require "skynet"
+require "skynet.manager"
+local setting_template = require "settings"
+
+local skynet_node_name = ...
+
+local CMD = {}
+local pool = {}
+
+local next_id = 0
+local maxconn = 1
+
+local function next_conn()
+    local id = next_id % maxconn + 1
+    next_id = next_id + 1
+    if id > maxconn then
+        id = 1
+    end
+    return pool[id]
+end
+
+local function getconn(key)
+    if key and (type(key) == "number" or tonumber(key)) then
+        local id = math.floor((tonumber(key) - 1) % maxconn) + 1
+        return pool[id]
+    else
+        return next_conn()
+    end
+end
+
+local function call_redis_slave(addr, cmd, ...)
+    return skynet.call(addr, "lua", cmd, ...)
+end
+
+local function send_redis_slave(addr, cmd, ...)
+    skynet.send(addr, "lua", cmd, ...)
+end
+
+local function start()
+    local settings = setting_template.db_cnf[skynet_node_name]
+    INFO("redisdbpool 启动", skynet_node_name, inspect(settings))
+    maxconn = tonumber(settings.redisdb_maxinst) or 1
+    for i = 1, maxconn do
+        local redis_slave = skynet.newservice("redisdb_slave")
+        skynet.call(redis_slave, "lua", "start", settings.redisdb_cnf)
+        table.insert(pool, redis_slave)
+    end
+end
+
+function CMD.exec(cmd, uid, ...)
+    local db = getconn(uid)
+    return call_redis_slave(db, cmd, ...)
+end
+
+skynet.start(function()
+    start()
+
+    skynet.dispatch("lua", function(_, _, cmd, ...)
+        local f = assert(CMD[cmd], cmd .. "not found")
+        skynet.retpack(f(...))
+    end)
+
+    skynet.register("." .. SERVICE_NAME)
+end)

+ 19 - 0
common/dbproxy/redisdbx.lua

@@ -0,0 +1,19 @@
+local redisdbx = {}
+
+local skynet = require "skynet"
+
+local REDISABL_POOL
+
+
+local function block_query()
+    if not REDISABL_POOL then
+        REDISABL_POOL = skynet.queryservice("redisdbpool")
+    end
+end
+
+function redisdbx.exec(cmd, uid, ...)
+    block_query()
+    return skynet.call(REDISABL_POOL, "lua", "exec", cmd, uid, ...)
+end
+
+return redisdbx

+ 9 - 0
common/dbproxy/redishelper.lua

@@ -0,0 +1,9 @@
+local M = {}
+
+local redisdbx = require "dbproxy.redisdbx"
+
+
+function M.exec(cmd, uid, ...)
+    return redisdbx.exec(cmd, uid, ...)
+end
+return M

+ 57 - 0
common/dbproxy/tg_app.lua

@@ -0,0 +1,57 @@
+--小程序
+local M = {}
+local skynet = require "skynet"
+local mysqldbx = require "mysqldbx"
+local tools = require "tools"
+local cjson = require "cjson"
+
+--获取所有小程序
+function M.getAppList()
+    local sql = string.format("select * from `tg_app` ")
+    local isok,res;
+    res = mysqldbx.query(sql)
+    if #res <= 0 then
+        return true ,{}
+    end
+    return true, res
+end
+--所属账户ID advertiser_id
+--资产ID instance_id
+--小程序ID app_id
+--小程序名称 name
+--添加小程序
+function M.addApp(msg_body)
+    local isok ,key =  tools.checkData({"tg_platform_id","app_id","instance_id","name","advertiser_id","landing_page","titles"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.create_time = current_time
+    local sql = string.format("INSERT INTO `tg_app` (tg_platform_id,app_id, instance_id, name,advertiser_id,landing_page,titles)  VALUES (%d,'%s','%s','%s','%s','%s','%s')",
+    msg_body.tg_platform_id,
+    msg_body.app_id,
+    msg_body.instance_id,msg_body.name,msg_body.advertiser_id,msg_body.landing_page,msg_body.titles)
+    mysqldbx.query(sql)
+    skynet.send("backmgr","lua","on_recv",nil,"push_msg","updateAppConfig")
+    return true
+end
+
+
+--修改小程序
+function M.modifyApp(msg_body)
+    local isok ,key =  tools.checkData({"id","tg_platform_id","app_id","instance_id","name","advertiser_id","landing_page","titles"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.update_time = current_time
+    local sql = string.format("UPDATE `tg_app` SET  tg_platform_id =%d ,app_id ='%s' , instance_id ='%s' , name ='%s' , advertiser_id ='%s'  , update_time ='%s'   , landing_page ='%s'  , titles ='%s' WHERE id = %d ",
+    msg_body.tg_platform_id,msg_body.app_id,msg_body.instance_id,msg_body.name,msg_body.advertiser_id,msg_body.update_time,msg_body.landing_page,msg_body.titles,msg_body.id)
+    mysqldbx.query(sql)
+    skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="updateAppConfig"}))
+    return true
+end
+
+
+
+return M

+ 187 - 0
common/dbproxy/tg_main.lua

@@ -0,0 +1,187 @@
+--主体
+local M = {}
+local mysqldbx = require "mysqldbx"
+local tools = require "tools"
+local skynet = require "skynet"
+local cjson = require "cjson"
+local mysql = require "skynet.db.mysql"
+local config = require "run_config"
+local mysqldtaskbx = {}
+local db
+
+function M.getOpenMainList()
+    local sql = string.format("select * from `tg_main` where running_status = 1 ")
+    local isok,res;
+    res = mysqldbx.query(sql)
+    if #res <= 0 then
+        return true , {}
+    end
+    return true, res
+end
+--page_size  是你想要在每页中显示的记录数。
+--page_number 页数
+--获取所有主体
+function M.getMainList()
+    local sql = string.format("select * from `tg_main` ")
+    local isok,res;
+    res = mysqldbx.query(sql)
+    if #res <= 0 then
+        return true , {}
+    end
+    return true, res
+end
+-- `main_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '主体名称',
+-- `app_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '' COMMENT '小程序ID',
+-- `running_status` tinyint(1) DEFAULT '1' COMMENT '运行状态 0-停止 1-运行中',
+-- `ad_quantity` int NOT NULL DEFAULT '40' COMMENT '广告数量',
+-- `cpa_bid` bigint NOT NULL DEFAULT '1750' COMMENT 'CPA出价(分), 默认17.5元',
+-- `bid_type` tinyint(1) DEFAULT '1' COMMENT '出价方式 0-常规 1-最大化 2 两种存储',
+-- `bid_ratio` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '1' COMMENT '出价方式比例(如 1:2)',
+-- `budget` bigint NOT NULL DEFAULT '9000000' COMMENT '预算金额(分), 默认9万元',
+-- `tg_platform_id` int NOT NULL DEFAULT '0' COMMENT '平台',
+-- `daily_new_limit` int DEFAULT '0' COMMENT '今天新上数量上限',
+
+function M.addMain(msg_body)
+    local isok ,key =  tools.checkData({"no_bid_budget","max_ad_quantity","tg_link_config","tg_platform_id","app_id","main_name","running_status","ad_quantity","cpa_bid","bid_type","bid_ratio","custom_budget","daily_new_limit","valid_time"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.create_time = current_time
+    local sql = string.format("INSERT INTO `tg_main` (no_bid_budget,max_ad_quantity,tg_link_config,tg_platform_id,app_id,main_name,running_status,ad_quantity,cpa_bid,bid_type,bid_ratio,custom_budget,daily_new_limit,valid_time)  VALUES (%d,%d,'%s',%d,'%s','%s',%d,%d,%d,%d,'%s',%d,%d,%d)",
+        msg_body.no_bid_budget,msg_body.max_ad_quantity,cjson.encode(msg_body.tg_link_config),msg_body.tg_platform_id,msg_body.app_id,msg_body.main_name
+    ,msg_body.running_status,msg_body.ad_quantity,msg_body.cpa_bid,msg_body.bid_type,msg_body.bid_ratio,msg_body.custom_budget,msg_body.daily_new_limit,msg_body.valid_time)
+    tools.dump(mysqldbx.query(sql))
+    skynet.error("sql:",sql)
+    skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="updateMainConfig"}))
+    pushAddMainMsg(msg_body)
+    return true
+end
+
+
+function pushAddMainMsg(msg_body)
+    local sql = string.format("select * from `tg_main` where main_name = '%s' and app_id = '%s'  LIMIT 1 ",msg_body.main_name,msg_body.app_id)
+    local isok,res;
+    res = mysqldbx.query(sql)
+    skynet.error("sql:",sql)
+    tools.dump(res)
+    if #res > 0 then
+        local main_info =  res[1]
+        skynet.fork(function ()
+        
+            -- local getMainInfoByAppid = function(app_id)
+            --     local temp_list = {}
+            --     for i = 1, #main_list, 1 do
+            --         local main_item = main_list[i]
+            --         if (main_item.app_id==app_id) then
+            --             table.insert(temp_list,#temp_list+1,main_item)
+            --         end
+            --     end
+            --     return temp_list
+            -- end
+            --获取书籍小程序列表
+            sql = string.format("SELECT * FROM video_applet_product ")
+    
+            res = mysqldtaskbx.Singleton().query(sql)
+    
+            local video_applet_product_list = {}
+    
+            if #res>0 then
+                for i = 1, #res, 1 do
+                    table.insert(video_applet_product_list,i,res[i])
+                end
+            end
+    
+            local need_create_link_list = {}
+    
+            -- local isCreateLinkByMainIdAndProductId = function(main_id,product_id)
+            --     local isCreate = false
+            --     for i = 1, #video_applet_product_list, 1 do
+            --         local item = video_applet_product_list[i]
+            --         if (item.product_id==product_id and item.main_id == main_id) then
+            --             isCreate = true
+            --             break
+            --         end
+            --     end
+            --     return isCreate
+            -- end
+            --根据小程序id 筛选出所有需要创建的书籍
+            local video_applet_product_of_main_list = {}
+            for i = 1, #video_applet_product_list, 1 do
+                local applet_item = video_applet_product_list[i]
+                if video_applet_product_of_main_list[applet_item.product_id]==nil then
+                    if applet_item.status == 1 and applet_item.dy_small_applet_app_id == main_info.app_id then
+                        video_applet_product_of_main_list[applet_item.product_id] = {product_name=applet_item.product_name,product_id=applet_item.product_id,book_platform=applet_item.book_platform,dy_small_applet_app_id=applet_item.dy_small_applet_app_id}
+                    end
+                end
+            end
+            skynet.error("找到所有小程序!")
+            tools.dump(video_applet_product_of_main_list)
+            skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="addMain",data={list=video_applet_product_of_main_list,main_info=main_info}}))
+        end)
+    end
+   
+end
+function M.modifyMain(msg_body)
+    local isok ,key =  tools.checkData({"no_bid_budget","max_ad_quantity","tg_link_config","id","tg_platform_id","app_id","main_name","running_status","ad_quantity","cpa_bid","bid_type","bid_ratio","custom_budget","daily_new_limit","valid_time"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.update_time = current_time
+    local sql = string.format("UPDATE  `tg_main` SET no_bid_budget = %d , max_ad_quantity = %d ,tg_platform_id = %d , app_id = '%s' ,main_name = '%s' , update_time = '%s' , running_status = %d ,ad_quantity = %d ,cpa_bid = %d ,bid_type = %d ,bid_ratio = '%s' ,custom_budget = %d ,daily_new_limit = %d ,valid_time = %d ,tg_link_config = '%s'  WHERE id = %d ",
+    msg_body.no_bid_budget,msg_body.max_ad_quantity,msg_body.tg_platform_id,msg_body.app_id,msg_body.main_name,msg_body.update_time,msg_body.running_status,msg_body.ad_quantity,msg_body.cpa_bid,msg_body.bid_type,msg_body.bid_ratio,msg_body.custom_budget,
+    msg_body.daily_new_limit,msg_body.valid_time,cjson.encode(msg_body.tg_link_config),msg_body.id)
+    mysqldbx.query(sql)
+    skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="updateMainConfig"}))
+    return true
+end
+
+--配置主体推广链接
+function M.tgLinkConfig(msg_body)
+    local isok ,key =  tools.checkData({"id","is_open","huichuan_id","chongzhi_id","kadian_id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("select tg_link_config from `tg_main` WHERE id = %d ",msg_body.id)
+    local res = mysqldbx.query(sql)
+    sql = string.format("UPDATE `tg_main` SET  tg_link_config = '%s'  WHERE id = %d ",
+    cjson.encode(msg_body),msg_body.id)
+    mysqldbx.query(sql)
+    return true, {}
+end
+
+
+function mysqldtaskbx.start()
+    local function on_connect(db)
+        db:query("set charset utf8mb4");
+    end
+    local conf = config.db_cnf.book_server.mysqldb_task_cnf
+    db = mysql.connect{
+        host=conf.ip,
+        port=conf.port,
+        database=conf.db,
+        user=conf.user,
+        password=conf.password,
+        charset="utf8mb4",
+        max_packet_size = 1024 * 1024,
+        on_connect = on_connect
+    }
+    if not db then
+        error("mysql connect fail")
+    end
+end
+
+
+
+function mysqldtaskbx.Singleton()
+    if db == nil then
+        mysqldtaskbx.start()
+    end
+    return mysqldtaskbx
+end
+function mysqldtaskbx.query(sql)
+    return db:query(sql)
+end
+
+return M

+ 151 - 0
common/dbproxy/tg_max_zhuanhua.lua

@@ -0,0 +1,151 @@
+--最大转化
+local M = {}
+local db
+local mysqldtaskbx = {}
+local mysqldbx = require "mysqldbx"
+require "skynet.manager"
+local mysql = require "skynet.db.mysql"
+local config = require "run_config"
+local tools = require "tools"
+local skynet = require "skynet"
+
+--添加转化账户
+function M.addZhuanHuaZhangHu(msg_body)
+    local isok ,key =  tools.checkData({"advertiser_id","advertiser_name","status","is_deleted","budget"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local isok , find_data = M.findZhuangHuById({id=msg_body.advertiser_id})
+    if find_data==nil then
+        return false,string.format("advertiser_id 失败 : %d.", msg_body.advertiser_id)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.create_time = current_time
+    local sql = string.format("INSERT INTO `ad_cbo_advertiser_id` (advertiser_id,advertiser_name, create_time, update_time,status,is_deleted,budget)  VALUES (%d,'%s','%s','%s',%d,%d,%d)",
+    msg_body.advertiser_id,
+    msg_body.advertiser_name,
+    msg_body.create_time,
+    msg_body.create_time,
+    msg_body.status,msg_body.is_deleted,msg_body.budget)
+    local res = mysqldtaskbx.Singleton().query(sql)
+    skynet.error(sql)
+    tools.dump(res)
+    skynet.error(res)
+    return true
+end
+
+--modify
+function M.modifyZhuanHuaZhangHu(msg_body)
+    local isok ,key =  tools.checkData({"advertiser_id","advertiser_name","status","is_deleted","budget"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.update_time = current_time
+    local sql = string.format("UPDATE `ad_cbo_advertiser_id` SET update_time ='%s', advertiser_id =%d ,advertiser_name ='%s' , status =%d , is_deleted =%d , budget =%d  WHERE id = %d ",
+    msg_body.update_time,msg_body.advertiser_id,msg_body.advertiser_name,msg_body.status,msg_body.is_deleted,msg_body.budget,msg_body.id)
+    skynet.error(sql)
+    mysqldtaskbx.Singleton().query(sql)
+    return true
+end
+
+
+--delete
+function M.deleteZhuanHuaZhangHu(msg_body)
+    local isok ,key =  tools.checkData({"id_list"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.update_time = current_time
+    for i = 1, #msg_body.id_list, 1 do
+       local id = msg_body.id_list[i]
+       local sql = string.format("UPDATE `ad_cbo_advertiser_id` SET update_time ='%s', is_deleted =%d WHERE id = %d ",
+       msg_body.update_time,1,id)
+       mysqldtaskbx.Singleton().query(sql)
+    end
+    return true
+end
+
+--获取转换列表
+function M.getZhuanHuanList(msg_body)
+    local isok ,key =  tools.checkData({"page_size","page_number","status"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local status = msg_body.status --状态 1:正常 0:禁用 2:全部
+    local status_cmd = "SELECT * FROM ad_cbo_advertiser_id WHERE is_deleted = 0 " ..string.format("and status = %d  ",status)
+    if status == 2 then
+        status_cmd = "SELECT * FROM ad_cbo_advertiser_id WHERE is_deleted = 0 "
+    end
+    local offset = (page_number - 1) * page_size
+    local sql = status_cmd .. string.format(" ORDER BY id LIMIT %d OFFSET %d",page_size, offset)
+    local isok,res;
+    res = mysqldtaskbx.Singleton().query(sql)
+    -- tools.dump(res)
+    -- skynet.error(sql)
+    if #res <= 0 then
+        return true ,{}
+    end
+    return true, res
+end
+
+--获取转换总数
+function M.getTotal()
+    local sql = "SELECT COUNT(*) AS total FROM ad_cbo_advertiser_id WHERE is_deleted = 0"
+    local res = mysqldtaskbx.Singleton().query(sql)
+    return true,res[1]
+end
+
+
+function mysqldtaskbx.start()
+    local function on_connect(db)
+        db:query("set charset utf8mb4");
+    end
+    local conf = config.db_cnf.book_server.mysqldb_task_cnf
+    db = mysql.connect{
+        host=conf.ip,
+        port=conf.port,
+        database=conf.db,
+        user=conf.user,
+        password=conf.password,
+        charset="utf8mb4",
+        max_packet_size = 1024 * 1024,
+        on_connect = on_connect
+    }
+    if not db then
+        error("mysql connect fail")
+    end
+end
+
+
+--根据id获取账户
+function M.findZhuangHuById(msg_body)
+    local isok ,key =  tools.checkData({"id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.update_time = current_time
+    local sql = string.format("select * from advertiser WHERE advertiser_id = '%s'  LIMIT 1",tostring(msg_body.id))
+    local res = mysqldbx.query(sql)
+    local info = nil
+    if #res>0 then
+        info = res
+    end
+    return true,info
+end
+
+function mysqldtaskbx.Singleton()
+    if db == nil then
+        mysqldtaskbx.start()
+    end
+    return mysqldtaskbx
+end
+function mysqldtaskbx.query(sql)
+    return db:query(sql)
+end
+
+return M

+ 192 - 0
common/dbproxy/tg_platform.lua

@@ -0,0 +1,192 @@
+--小程序
+local M = {}
+local skynet = require "skynet"
+local mysqldbx = require "mysqldbx"
+local tools = require "tools"
+local cjson = require "cjson"
+
+--获取所有平台
+function M.getPlatformList()
+    local sql = string.format("select * from `tg_platform` ")
+    local isok,res;
+    res = mysqldbx.query(sql)
+    if #res <= 0 then
+        return true , {}
+    end
+    return true, res
+end
+
+--添加平台
+function M.addPlatform(msg_body)
+    local isok ,key ,id=  tools.checkData({"tg_platform_name"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local _,data = M.getTotal()
+    local id = data.total + 1
+    local sql = string.format("INSERT INTO `tg_platform` (tg_platform_id,tg_platform_name)  VALUES (%d,'%s')",id,msg_body.tg_platform_name)
+    skynet.error(sql)
+    mysqldbx.query(sql)
+    skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="updatePlatformConfig"}))
+    return true
+end
+
+
+--修改平台
+function M.modifyPlatform(msg_body)
+    local isok ,key =  tools.checkData({"tg_platform_name","id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("UPDATE `tg_platform` SET  tg_platform_name = '%s'  WHERE id = %d ",
+    msg_body.tg_platform_name,msg_body.id)
+    mysqldbx.query(sql)
+    skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="updatePlatformConfig"}))
+    return true
+end
+
+
+
+--添加回传规则
+function M.addHuiChuanRule(msg_body)
+    local isok ,key =  tools.checkData({"name","id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("select huichuan from `tg_platform` WHERE id = %d ",msg_body.id)
+    local res = mysqldbx.query(sql)
+    local obj = {}
+    if res[1].huichuan~=nil then
+        obj = cjson.decode(res[1].huichuan)
+        tools.dump(obj)
+    end
+    local id = #obj+1
+    table.insert(obj,id,{id=id,name=msg_body.name})
+    sql = string.format("UPDATE `tg_platform` SET  huichuan = '%s'  WHERE id = %d ",
+    cjson.encode(obj),msg_body.id)
+    mysqldbx.query(sql)
+    skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="updatePlatformConfig"}))
+    return true, obj
+end
+
+--修改回传规则
+function M.modifyHuiChuanRule(msg_body)
+    local isok ,key =  tools.checkData({"name","id","table_id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("select huichuan from `tg_platform` WHERE id = %d ",msg_body.id)
+    local res = mysqldbx.query(sql)
+    local obj = {}
+    if res[1].huichuan~=nil then
+        obj = cjson.decode(res[1].huichuan)
+    end
+    for i = 1, #obj, 1 do
+        if obj[i].id == msg_body.table_id then
+            obj[i].name = msg_body.name
+            break
+        end
+    end
+    sql = string.format("UPDATE `tg_platform` SET  huichuan = '%s'  WHERE id = %d ",
+    cjson.encode(obj),msg_body.id)
+    mysqldbx.query(sql)
+    skynet.send("backmgr","lua","on_recv",nil,"ws_push_msg",cjson.encode({cmd="updatePlatformConfig"}))
+    return true,obj
+end
+
+--添加收费卡点
+function M.addShouFeiKaDian(msg_body)
+    local isok ,key =  tools.checkData({"name","id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("select kadian from `tg_platform` WHERE id = %d ",msg_body.id)
+    local res = mysqldbx.query(sql)
+    local obj = {}
+    if res[1].kadian~=nil then
+        obj = cjson.decode(res[1].kadian)
+        tools.dump(obj)
+    end
+    local id = #obj+1
+    table.insert(obj,id,{id=id,name=msg_body.name})
+    sql = string.format("UPDATE `tg_platform` SET  kadian = '%s'  WHERE id = %d ",
+    cjson.encode(obj),msg_body.id)
+    mysqldbx.query(sql)
+    return true, obj
+end
+
+--修改收费卡点
+function M.modifyShouFeiKaDian(msg_body)
+    local isok ,key =  tools.checkData({"name","id","table_id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("select kadian from `tg_platform` WHERE id = %d ",msg_body.id)
+    local res = mysqldbx.query(sql)
+    local obj = {}
+    if res[1].kadian~=nil then
+        obj = cjson.decode(res[1].kadian)
+    end
+    for i = 1, #obj, 1 do
+        if obj[i].id == msg_body.table_id then
+            obj[i].name = msg_body.name
+            break
+        end
+    end
+    sql = string.format("UPDATE `tg_platform` SET  kadian = '%s'  WHERE id = %d ",
+    cjson.encode(obj),msg_body.id)
+    mysqldbx.query(sql)
+    return true,obj
+end
+
+--添加充值模板
+function M.addChongZhiTemplate(msg_body)
+    local isok ,key =  tools.checkData({"name","id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("select chongzhi from `tg_platform` WHERE id = %d ",msg_body.id)
+    local res = mysqldbx.query(sql)
+    local obj = {}
+    if res[1].chongzhi~=nil then
+        obj = cjson.decode(res[1].chongzhi)
+    end
+    local id = #obj+1
+    table.insert(obj,id,{id=id,name=msg_body.name})
+    sql = string.format("UPDATE `tg_platform` SET  chongzhi = '%s'  WHERE id = %d ",
+    cjson.encode(obj),msg_body.id)
+    mysqldbx.query(sql)
+    return true, obj
+end
+
+--修改充值模板
+function M.modifyChongZhiTemplate(msg_body)
+    local isok ,key =  tools.checkData({"name","id","table_id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("select chongzhi from `tg_platform` WHERE id = %d ",msg_body.id)
+    local res = mysqldbx.query(sql)
+    local obj = {}
+    if res[1].chongzhi ~=nil then
+        obj = cjson.decode(res[1].chongzhi)
+    end
+    for i = 1, #obj, 1 do
+        if obj[i].id == msg_body.table_id then
+            obj[i].name = msg_body.name
+            break
+        end
+    end
+    sql = string.format("UPDATE `tg_platform` SET  chongzhi = '%s'  WHERE id = %d ",
+    cjson.encode(obj),msg_body.id)
+    mysqldbx.query(sql)
+    return true,obj
+end
+
+function M.getTotal()
+    local sql = "SELECT COUNT(*) AS total FROM tg_platform"
+    local res = mysqldbx.query(sql)
+    return true,res[1]
+end
+
+return M

+ 51 - 0
common/dbproxy/tg_temp_app.lua

@@ -0,0 +1,51 @@
+--小程序
+local M = {}
+local skynet = require "skynet"
+local mysqldbx = require "mysqldbx"
+local tools = require "tools"
+
+--获取所有小程序
+function M.getAppList()
+    local sql = string.format("select * from `tools_micro_app` ")
+    local isok,res;
+    res = mysqldbx.query(sql)
+    if #res <= 0 then
+        return true ,{}
+    end
+    return true, res
+end
+
+--添加小程序
+function M.addApp(msg_body)
+    local isok ,key =  tools.checkData({"tg_platform_id","app_id","instance_id","name","advertiser_id","reason","audit_status","landing_page","titles","source","cpa_bid","budget"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.create_time = current_time
+    local sql = string.format("INSERT INTO `tools_micro_app` (tg_platform_id,app_id, instance_id, name,advertiser_id,reason,create_time,audit_status,landing_page,titles,source,cpa_bid,budget,update_time)  VALUES (%d,'%s','%s','%s' ,'%s','%s','%s', '%s','%s','%s', '%s',%d, %d, '%s')",
+    msg_body.tg_platform_id,
+    msg_body.app_id,
+    msg_body.instance_id,msg_body.name,msg_body.advertiser_id,msg_body.reason,msg_body.create_time,msg_body.audit_status,msg_body.landing_page,msg_body.titles,msg_body.source,msg_body.cpa_bid,msg_body.budget,msg_body.create_time)
+    skynet.error(sql)
+    mysqldbx.query(sql)
+    return true
+end
+
+
+--修改小程序
+function M.modifyApp(msg_body)
+    local isok ,key =  tools.checkData({"tg_platform_id","id","app_id","instance_id","name","name","advertiser_id","reason","audit_status","landing_page","titles","source","cpa_bid","budget"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.update_time = current_time
+    local sql = string.format("UPDATE `tools_micro_app` SET  tg_platform_id =%d ,app_id ='%s' , instance_id ='%s' , name ='%s' , advertiser_id ='%s'  , reason ='%s'  , audit_status ='%s'  , landing_page ='%s'   , titles ='%s'  , source ='%s'   , cpa_bid =%d   , budget =%d  , update_time ='%s'  WHERE id = %d ",
+    msg_body.tg_platform_id,msg_body.app_id,msg_body.instance_id,msg_body.name,msg_body.advertiser_id,msg_body.reason,msg_body.audit_status,msg_body.landing_page,msg_body.titles,msg_body.source,msg_body.cpa_bid,msg_body.budget,msg_body.update_time,msg_body.id)
+    skynet.error(sql)
+    mysqldbx.query(sql)
+    return true
+end
+
+return M

+ 188 - 0
common/dbproxy/tg_zhanghu.lua

@@ -0,0 +1,188 @@
+--账户
+local M = {}
+
+local mysqldbx = require "mysqldbx"
+local tools = require "tools"
+local skynet = require "skynet"
+local httpc = require "http.httpc"
+--page_size  是你想要在每页中显示的记录数。
+--page_number 页数
+--获取所有账户
+function M.getZhangHuList(msg_body)
+    local isok ,key =  tools.checkData({"page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+    local sql = string.format("SELECT * FROM advertiser ORDER BY id LIMIT %d OFFSET %d", page_size, offset)
+    local isok,res;
+    res = mysqldbx.query(sql)
+    if #res <= 0 then
+        return true ,{}
+    end
+    return true, res
+end
+
+function M.getTotal()
+    local sql = "SELECT COUNT(*) AS total FROM advertiser"
+    local res = mysqldbx.query(sql)
+    return true,res[1]
+end
+
+function M.setZhanghuOfMain(msg_body)
+    local isok ,key =  tools.checkData({"id_list","main_id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local current_time = os.date("%Y-%m-%d %H:%M:%S")
+    msg_body.update_time = current_time
+    for i = 1, #msg_body.id_list, 1 do
+        local id = msg_body.id_list[i]
+        local sql = string.format("UPDATE `advertiser` SET main_id = %d  WHERE id = %d ",
+        msg_body.main_id,id)
+        skynet.error(sql)
+        mysqldbx.query(sql)
+    end
+    return true,{}
+end
+
+function M.searchZhanghu(msg_body)
+    local isok ,key =  tools.checkData({"advertiser_id"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("SELECT * FROM advertiser  WHERE advertiser_id = '%s'  LIMIT 1 ", tostring(msg_body.advertiser_id))
+    local res;
+    res = mysqldbx.query(sql)
+    local info = {}
+    if #res>0 then
+        info = res[1]
+    end
+    return true,info
+end
+
+function M.searchName(msg_body)
+    local isok ,key =  tools.checkData({"content","page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+
+    local sql = string.format(" SELECT COUNT(*) AS total FROM advertiser  advertiser_name LIKE '%%%s%%' ",  msg_body.content)
+    local total = mysqldbx.query(sql)
+
+    sql = string.format("SELECT * FROM advertiser WHERE advertiser_name LIKE '%%%s%%'  ORDER BY id LIMIT %d OFFSET %d ", msg_body.content, page_size, offset)
+    local res;
+    res = mysqldbx.query(sql)
+    return true,res,total[1].total
+end
+
+function M.switch(msg_body)
+    local isok ,key =  tools.checkData({"id_list","status"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+
+    for i = 1, #msg_body.id_list, 1 do
+        local id = msg_body.id_list[i]
+        local sql = string.format("UPDATE `advertiser` SET status = %d  WHERE id = %d ",
+        msg_body.status,id)
+        local res;
+        res = mysqldbx.query(sql)
+    end
+    return true,{}
+end
+function M.mainFilter(msg_body)
+    local isok ,key =  tools.checkData({"main_id","page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+
+    local sql = string.format(" SELECT COUNT(*) AS total FROM advertiser  WHERE main_id = %d ",  msg_body.main_id)
+    local total = mysqldbx.query(sql)
+   
+    sql = string.format("SELECT * FROM advertiser  WHERE main_id = %d  ORDER BY id LIMIT %d OFFSET %d ", msg_body.main_id, page_size, offset)
+    local res;
+    res = mysqldbx.query(sql)
+    return true,res,total[1].total
+end
+
+function M.search(msg_body)
+    local isok ,key =  tools.checkData({"content","page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+    
+    local sql = string.format("SELECT COUNT(*) AS total  FROM advertiser WHERE (advertiser_name LIKE CONCAT( '%%%s%%')) OR (advertiser_id LIKE CONCAT('%%%s%%')) ", msg_body.content,msg_body.content)
+    local total = mysqldbx.query(sql)
+    sql = string.format("SELECT * FROM advertiser WHERE (advertiser_name LIKE CONCAT( '%%%s%%')) OR (advertiser_id LIKE CONCAT('%%%s%%')) ORDER BY id LIMIT %d OFFSET %d", msg_body.content, msg_body.content, page_size, offset)
+    local res;
+    res = mysqldbx.query(sql)
+    return true,res,total[1].total
+end
+
+function M.search_info_by_id(msg_body)
+    local isok ,key =  tools.checkData({"query_list"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local temp = {}
+    for i = 1, #msg_body.query_list, 1 do
+        local zhang_hu_id = msg_body.query_list[i].zhang_hu_id..""
+        local key = msg_body.query_list[i].id
+        local sql = string.format("SELECT * FROM advertiser WHERE advertiser_id = '%s' LIMIT 1",zhang_hu_id)
+        local res = mysqldbx.query(sql)
+        if #res >0 then
+            temp[key] = res[1]
+        end
+    end
+    return true,temp
+end
+
+function M.update_zhanghu(msg_body)
+    httpc.dns() -- set dns server
+    httpc.timeout = 100 -- set timeout 1 second
+    local status, body = httpc.get('https://clipvideoup.s6kuwan.com/adoce/advertiser/sync_center_advertiser','',{})
+    if status == 200 then
+        return true,{}
+    else
+        return false,{}
+    end
+    return true,{}
+end
+function searchZhanghuName(name,id)
+    local sql = string.format("SELECT * FROM advertiser WHERE advertiser_name LIKE '%%%s%%'", name)
+    local res;
+    res = mysqldbx.query(sql)
+    local id_list = {}
+    for i = 1, #res, 1 do
+        table.insert(id_list,i,res[i].id)
+    end
+    if #id_list> 0 then
+        M.setZhanghuOfMain({id_list=id_list,main_id=id})
+    end
+end
+function M.init()
+    local sql = string.format("select * from `tg_main` ")
+    local isok,res;
+    res = mysqldbx.query(sql)
+    if #res > 0 then
+        tools.dump(res)
+        for i = 1, #res, 1 do
+            local name = res[i].main_name
+            searchZhanghuName(name,res[i].id)
+        end
+    end
+    return true,{}
+end
+return M

+ 1598 - 0
common/preload/functions.lua

@@ -0,0 +1,1598 @@
+--[[
+
+Copyright (c) 2011-2014 chukong-inc.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+]]
+
+--[[--
+
+提供一组常用函数,以及对 Lua 标准库的扩展
+
+]]
+
+--[[--
+
+输出格式化字符串
+
+~~~ lua
+
+printf("The value = %d", 100)
+
+~~~
+
+@param string fmt 输出格式
+@param [mixed ...] 更多参数
+
+]]
+function printf(fmt, ...)
+    print(string.format(tostring(fmt), ...))
+end
+
+local skynet = require "skynet"
+local cjson  = require "cjson"
+
+function table.empty(tlb)
+    local t = tlb or {}
+    for k, v in pairs(tlb) do
+        return false
+    end
+
+    return true
+end
+
+function table.array(array)
+    return setmetatable(array, cjson.empty_array_mt)
+end
+
+function table.dumpdebug(value, desciption, nesting)
+    if type(nesting) ~= "number" then nesting = 3 end
+
+    local lookupTable = {}
+    local result = {}
+
+    local function _v(v)
+        if type(v) == "string" then
+            v = "\"" .. v .. "\""
+        end
+        return tostring(v)
+    end
+
+    local traceback = string.split(debug.traceback("", 2), "\n")
+    if not ngx then
+        skynet.error("dump from: " .. string.trim(traceback[3]))
+    else
+        ngx.log(ngx.DEBUG,"dump from: " .. string.trim(traceback[3]))
+    end
+
+    local function _dump(value, desciption, indent, nest, keylen)
+        desciption = desciption or "<var>"
+        spc = ""
+        if type(keylen) == "number" then
+            spc = string.rep(" ", keylen - string.len(_v(desciption)))
+        end
+        if type(value) ~= "table" then
+            result[#result +1 ] = string.format("%s%s%s = %s", indent, _v(desciption), spc, _v(value))
+        elseif lookupTable[value] then
+            result[#result +1 ] = string.format("%s%s%s = *REF*", indent, desciption, spc)
+        else
+            lookupTable[value] = true
+            if nest > nesting then
+                result[#result +1 ] = string.format("%s%s = *MAX NESTING*", indent, desciption)
+            else
+                result[#result +1 ] = string.format("%s%s = {", indent, _v(desciption))
+                local indent2 = indent.."    "
+                local keys = {}
+                local keylen = 0
+                local values = {}
+                for k, v in pairs(value) do
+                    keys[#keys + 1] = k
+                    local vk = _v(k)
+                    local vkl = string.len(vk)
+                    if vkl > keylen then keylen = vkl end
+                    values[k] = v
+                end
+                table.sort(keys, function(a, b)
+                    if type(a) == "number" and type(b) == "number" then
+                        return a < b
+                    else
+                        return tostring(a) < tostring(b)
+                    end
+                end)
+                for i, k in ipairs(keys) do
+                    _dump(values[k], k, indent2, nest + 1, keylen)
+                end
+                result[#result +1] = string.format("%s}", indent)
+            end
+        end
+    end
+    _dump(value, desciption, "- ", 1)
+
+    for i, line in ipairs(result) do
+        if not ngx then
+            skynet.error(line)
+        else
+            ngx.log(ngx.DEBUG,line)
+        end
+    end
+end
+
+string.split = function(s, p)
+
+    local rt= {}
+    string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end )
+    return rt
+
+end
+
+--[[--
+
+检查并尝试转换为数值,如果无法转换则返回 0
+
+@param mixed value 要检查的值
+@param [integer base] 进制,默认为十进制
+
+@return number
+
+]]
+function checknumber(value, base)
+    return tonumber(value, base) or 0
+end
+
+--[[--
+
+检查并尝试转换为整数,如果无法转换则返回 0
+
+@param mixed value 要检查的值
+
+@return integer
+
+]]
+function checkint(value)
+    return math.round(checknumber(value))
+end
+
+--[[--
+
+检查并尝试转换为布尔值,除了 nil 和 false,其他任何值都会返回 true
+
+@param mixed value 要检查的值
+
+@return boolean
+
+]]
+function checkbool(value)
+    return (value ~= nil and value ~= false)
+end
+
+--[[--
+
+检查值是否是一个表格,如果不是则返回一个空表格
+
+@param mixed value 要检查的值
+
+@return table
+
+]]
+function checktable(value)
+    if type(value) ~= "table" then value = {} end
+    return value
+end
+
+--[[--
+
+如果表格中指定 key 的值为 nil,或者输入值不是表格,返回 false,否则返回 true
+
+@param table hashtable 要检查的表格
+@param mixed key 要检查的键名
+
+@return boolean
+
+]]
+function isset(hashtable, key)
+    local t = type(hashtable)
+    return (t == "table" or t == "userdata") and hashtable[key] ~= nil
+end
+
+--[[--
+
+深度克隆一个值
+
+~~~ lua
+
+-- 下面的代码,t2 是 t1 的引用,修改 t2 的属性时,t1 的内容也会发生变化
+local t1 = {a = 1, b = 2}
+local t2 = t1
+t2.b = 3    -- t1 = {a = 1, b = 3} <-- t1.b 发生变化
+
+-- clone() 返回 t1 的副本,修改 t2 不会影响 t1
+local t1 = {a = 1, b = 2}
+local t2 = clone(t1)
+t2.b = 3    -- t1 = {a = 1, b = 2} <-- t1.b 不受影响
+
+~~~
+
+@param mixed object 要克隆的值
+
+@return mixed
+
+]]
+function clone(object)
+    local lookup_table = {}
+    local function _copy(object)
+        if type(object) ~= "table" then
+            return object
+        elseif lookup_table[object] then
+            return lookup_table[object]
+        end
+        local new_table = {}
+        lookup_table[object] = new_table
+        for key, value in pairs(object) do
+            new_table[_copy(key)] = _copy(value)
+        end
+        return setmetatable(new_table, getmetatable(object))
+    end
+    return _copy(object)
+end
+
+--[[--
+
+创建一个类
+
+~~~ lua
+
+-- 定义名为 Shape 的基础类
+local Shape = class("Shape")
+
+-- ctor() 是类的构造函数,在调用 Shape.new() 创建 Shape 对象实例时会自动执行
+function Shape:ctor(shapeName)
+    self.shapeName = shapeName
+    printf("Shape:ctor(%s)", self.shapeName)
+end
+
+-- 为 Shape 定义个名为 draw() 的方法
+function Shape:draw()
+    printf("draw %s", self.shapeName)
+end
+
+--
+
+-- Circle 是 Shape 的继承类
+local Circle = class("Circle", Shape)
+
+function Circle:ctor()
+    -- 如果继承类覆盖了 ctor() 构造函数,那么必须手动调用父类构造函数
+    -- 类名.super 可以访问指定类的父类
+    Circle.super.ctor(self, "circle")
+    self.radius = 100
+end
+
+function Circle:setRadius(radius)
+    self.radius = radius
+end
+
+-- 覆盖父类的同名方法
+function Circle:draw()
+    printf("draw %s, raidus = %0.2f", self.shapeName, self.raidus)
+end
+
+--
+
+local Rectangle = class("Rectangle", Shape)
+
+function Rectangle:ctor()
+    Rectangle.super.ctor(self, "rectangle")
+end
+
+--
+
+local circle = Circle.new()             -- 输出: Shape:ctor(circle)
+circle:setRaidus(200)
+circle:draw()                           -- 输出: draw circle, radius = 200.00
+
+local rectangle = Rectangle.new()       -- 输出: Shape:ctor(rectangle)
+rectangle:draw()                        -- 输出: draw rectangle
+
+~~~
+
+### 高级用法
+
+class() 除了定义纯 Lua 类之外,还可以从 C++ 对象继承类。
+
+比如需要创建一个工具栏,并在添加按钮时自动排列已有的按钮,那么我们可以使用如下的代码:
+
+~~~ lua
+
+-- 从 CCNode 对象派生 Toolbar 类,该类具有 CCNode 的所有属性和行为
+local Toolbar = class("Toolbar", function()
+    return display.newNode() -- 返回一个 CCNode 对象
+end)
+
+-- 构造函数
+function Toolbar:ctor()
+    self.buttons = {} -- 用一个 table 来记录所有的按钮
+end
+
+-- 添加一个按钮,并且自动设置按钮位置
+function Toolbar:addButton(button)
+    -- 将按钮对象加入 table
+    self.buttons[#self.buttons + 1] = button
+
+    -- 添加按钮对象到 CCNode 中,以便显示该按钮
+    -- 因为 Toolbar 是从 CCNode 继承的,所以可以使用 addChild() 方法
+    self:addChild(button)
+
+    -- 按照按钮数量,调整所有按钮的位置
+    local x = 0
+    for _, button in ipairs(self.buttons) do
+        button:setPosition(x, 0)
+        -- 依次排列按钮,每个按钮之间间隔 10 点
+        x = x + button:getContentSize().width + 10
+    end
+end
+
+~~~
+
+class() 的这种用法让我们可以在 C++ 对象基础上任意扩展行为。
+
+既然是继承,自然就可以覆盖 C++ 对象的方法:
+
+~~~ lua
+
+function Toolbar:setPosition(x, y)
+    -- 由于在 Toolbar 继承类中覆盖了 CCNode 对象的 setPosition() 方法
+    -- 所以我们要用以下形式才能调用到 CCNode 原本的 setPosition() 方法
+    getmetatable(self).setPosition(self, x, y)
+
+    printf("x = %0.2f, y = %0.2f", x, y)
+end
+
+~~~
+
+**注意:** Lua 继承类覆盖的方法并不能从 C++ 调用到。也就是说通过 C++ 代码调用这个 CCNode 对象的 setPosition() 方法时,并不会执行我们在 Lua 中定义的 Toolbar:setPosition() 方法。
+
+@param string classname 类名
+@param [mixed super] 父类或者创建对象实例的函数
+
+@return table
+
+]]
+function class(classname, super)
+    local superType = type(super)
+    local cls
+
+    if superType ~= "function" and superType ~= "table" then
+        superType = nil
+        super = nil
+    end
+
+    if superType == "function" or (super and super.__ctype == 1) then
+        -- inherited from native C++ Object
+        cls = {}
+
+        if superType == "table" then
+            -- copy fields from super
+            for k,v in pairs(super) do cls[k] = v end
+            cls.__create = super.__create
+            cls.super    = super
+        else
+            cls.__create = super
+            cls.ctor = function() end
+        end
+
+        cls.__cname = classname
+        cls.__ctype = 1
+
+        function cls.new(...)
+            local instance = cls.__create(...)
+            -- copy fields from class to native object
+            for k,v in pairs(cls) do instance[k] = v end
+            instance.class = cls
+            instance:ctor(...)
+            return instance
+        end
+
+    else
+        -- inherited from Lua Object
+        if super then
+            cls = {}
+            setmetatable(cls, {__index = super})
+            cls.super = super
+        else
+            cls = {ctor = function() end}
+        end
+
+        cls.__cname = classname
+        cls.__ctype = 2 -- lua
+        cls.__index = cls
+
+        function cls.new(...)
+            local instance = setmetatable({}, cls)
+            instance.class = cls
+            instance:ctor(...)
+            return instance
+        end
+    end
+
+    return cls
+end
+
+-- 提供假名以避免和 moonscript 发生冲突
+function quick_class(classname, super)
+  return class(classname, super)
+end
+
+
+--[[--
+
+如果对象是指定类或其子类的实例,返回 true,否则返回 false
+
+~~~ lua
+
+local Animal = class("Animal")
+local Duck = class("Duck", Animal)
+
+print(iskindof(Duck.new(), "Animal")) -- 输出 true
+
+~~~
+
+@param mixed obj 要检查的对象
+@param string classname 类名
+
+@return boolean
+
+]]
+function iskindof(obj, classname)
+    local t = type(obj)
+    local mt
+    if t == "table" then
+        mt = getmetatable(obj)
+    elseif t == "userdata" then
+        mt = tolua.getpeer(obj)
+    end
+
+    while mt do
+        if mt.__cname == classname then
+            return true
+        end
+        mt = mt.super
+    end
+
+    return false
+end
+
+--[[--
+
+载入一个模块
+
+import() 与 require() 功能相同,但具有一定程度的自动化特性。
+
+假设我们有如下的目录结构:
+
+~~~
+
+app/
+app/classes/
+app/classes/MyClass.lua
+app/classes/MyClassBase.lua
+app/classes/data/Data1.lua
+app/classes/data/Data2.lua
+
+~~~
+
+MyClass 中需要载入 MyClassBase 和 MyClassData。如果用 require(),MyClass 内的代码如下:
+
+~~~ lua
+
+local MyClassBase = require("app.classes.MyClassBase")
+local MyClass = class("MyClass", MyClassBase)
+
+local Data1 = require("app.classes.data.Data1")
+local Data2 = require("app.classes.data.Data2")
+
+~~~
+
+假如我们将 MyClass 及其相关文件换一个目录存放,那么就必须修改 MyClass 中的 require() 命令,否则将找不到模块文件。
+
+而使用 import(),我们只需要如下写:
+
+~~~ lua
+
+local MyClassBase = import(".MyClassBase")
+local MyClass = class("MyClass", MyClassBase)
+
+local Data1 = import(".data.Data1")
+local Data2 = import(".data.Data2")
+
+~~~
+
+当在模块名前面有一个"." 时,import() 会从当前模块所在目录中查找其他模块。因此 MyClass 及其相关文件不管存放到什么目录里,我们都不再需要修改 MyClass 中的 import() 命令。这在开发一些重复使用的功能组件时,会非常方便。
+
+我们可以在模块名前添加多个"." ,这样 import() 会从更上层的目录开始查找模块。
+
+~
+
+不过 import() 只有在模块级别调用(也就是没有将 import() 写在任何函数中)时,才能够自动得到当前模块名。如果需要在函数中调用 import(),那么就需要指定当前模块名:
+
+~~~ lua
+
+# MyClass.lua
+
+# 这里的 ... 是隐藏参数,包含了当前模块的名字,所以最好将这行代码写在模块的第一行
+local CURRENT_MODULE_NAME = ...
+
+local function testLoad()
+    local MyClassBase = import(".MyClassBase", CURRENT_MODULE_NAME)
+    # 更多代码
+end
+
+~~~
+
+@param string moduleName 要载入的模块的名字
+@param [string currentModuleName] 当前模块名
+
+@return module
+
+]]
+function import(moduleName, currentModuleName)
+    local currentModuleNameParts
+    local moduleFullName = moduleName
+    local offset = 1
+
+    while true do
+        if string.byte(moduleName, offset) ~= 46 then -- .
+            moduleFullName = string.sub(moduleName, offset)
+            if currentModuleNameParts and #currentModuleNameParts > 0 then
+                moduleFullName = table.concat(currentModuleNameParts, ".") .. "." .. moduleFullName
+            end
+            break
+        end
+        offset = offset + 1
+
+        if not currentModuleNameParts then
+            if not currentModuleName then
+                local n,v = debug.getlocal(3, 1)
+                currentModuleName = v
+            end
+
+            currentModuleNameParts = string.split(currentModuleName, ".")
+        end
+        table.remove(currentModuleNameParts, #currentModuleNameParts)
+    end
+
+    return require(moduleFullName)
+end
+
+--[[--
+
+将 Lua 对象及其方法包装为一个匿名函数
+
+在 quick-cocos2d-x 中,许多功能需要传入一个 Lua 函数做参数,然后在特定事件发生时就会调用传入的函数。例如触摸事件、帧事件等等。
+
+~~~ lua
+
+local MyScene = class("MyScene", function()
+    return display.newScene("MyScene")
+end)
+
+function MyScene:ctor()
+    self.frameTimeCount = 0
+    -- 注册帧事件
+    self:addEventListener(cc.ENTER_FRAME_EVENT, self.onEnterFrame)
+end
+
+function MyScene:onEnterFrame(dt)
+    self.frameTimeCount = self.frameTimeCount + dt
+end
+
+~~~
+
+上述代码执行时将出错,报告"Invalid self" ,这就是因为 C++ 无法识别 Lua 对象方法。因此在调用我们传入的 self.onEnterFrame 方法时没有提供正确的参数。
+
+要让上述的代码正常工作,就需要使用 handler() 进行一下包装:
+
+~~~ lua
+
+function MyScene:ctor()
+    self.frameTimeCount = 0
+    -- 注册帧事件
+    self:addEventListener(cc.ENTER_FRAME_EVENT, handler(self, self.onEnterFrame))
+end
+
+~~~
+
+实际上,除了 C++ 回调 Lua 函数之外,在其他所有需要回调的地方都可以使用 handler()。
+
+@param mixed obj Lua 对象
+@param function method 对象方法
+
+@return function
+
+]]
+function handler(obj, method)
+    return function(...)
+        return method(obj, ...)
+    end
+end
+
+--[[--
+
+根据系统时间初始化随机数种子,让后续的 math.random() 返回更随机的值
+
+]]
+function math.newrandomseed()
+    local ok, socket = pcall(function()
+        return require("socket")
+    end)
+
+    if ok then
+        -- 如果集成了 socket 模块,则使用 socket.gettime() 获取随机数种子
+        math.randomseed(socket.gettime() * 1000)
+    else
+        math.randomseed(os.time())
+    end
+    math.random()
+    math.random()
+    math.random()
+    math.random()
+end
+
+--[[--
+
+对数值进行四舍五入,如果不是数值则返回 0
+
+@param number value 输入值
+
+@return number
+
+]]
+function math.round(value)
+    return math.floor(value + 0.5)
+end
+
+function math.angle2radian(angle)
+    return angle*math.pi/180
+end
+
+function math.radian2angle(radian)
+    return radian/math.pi*180
+end
+
+--[[--
+
+检查指定的文件或目录是否存在,如果存在返回 true,否则返回 false
+
+可以使用 CCFileUtils:fullPathForFilename() 函数查找特定文件的完整路径,例如:
+
+~~~ lua
+
+local path = CCFileUtils:sharedFileUtils():fullPathForFilename("gamedata.txt")
+if io.exists(path) then
+    ....
+end
+
+~~~
+
+@param string path 要检查的文件或目录的完全路径
+
+@return boolean
+
+]]
+function io.exists(path)
+    local file = io.open(path, "r")
+    if file then
+        io.close(file)
+        return true
+    end
+    return false
+end
+
+--[[--
+
+读取文件内容,返回包含文件内容的字符串,如果失败返回 nil
+
+io.readfile() 会一次性读取整个文件的内容,并返回一个字符串,因此该函数不适宜读取太大的文件。
+
+@param string path 文件完全路径
+
+@return string
+
+]]
+function io.readfile(path)
+    local file = io.open(path, "r")
+    if file then
+        local content = file:read("*a")
+        io.close(file)
+        return content
+    end
+    return nil
+end
+
+--[[--
+
+以字符串内容写入文件,成功返回 true,失败返回 false
+
+"mode 写入模式" 参数决定 io.writefile() 如何写入内容,可用的值如下:
+
+-   "w+" : 覆盖文件已有内容,如果文件不存在则创建新文件
+-   "a+" : 追加内容到文件尾部,如果文件不存在则创建文件
+
+此外,还可以在 "写入模式" 参数最后追加字符 "b" ,表示以二进制方式写入数据,这样可以避免内容写入不完整。
+
+**Android 特别提示:** 在 Android 平台上,文件只能写入存储卡所在路径,assets 和 data 等目录都是无法写入的。
+
+@param string path 文件完全路径
+@param string content 要写入的内容
+@param [string mode] 写入模式,默认值为 "w+b"
+
+@return boolean
+
+]]
+function io.writefile(path, content, mode)
+    mode = mode or "w+b"
+    local file = io.open(path, mode)
+    if file then
+        if file:write(content) == nil then return false end
+        io.close(file)
+        return true
+    else
+        return false
+    end
+end
+
+--[[--
+
+拆分一个路径字符串,返回组成路径的各个部分
+
+~~~ lua
+
+local pathinfo  = io.pathinfo("/var/app/test/abc.png")
+
+-- 结果:
+-- pathinfo.dirname  = "/var/app/test/"
+-- pathinfo.filename = "abc.png"
+-- pathinfo.basename = "abc"
+-- pathinfo.extname  = ".png"
+
+~~~
+
+@param string path 要分拆的路径字符串
+
+@return table
+
+]]
+function io.pathinfo(path)
+    local pos = string.len(path)
+    local extpos = pos + 1
+    while pos > 0 do
+        local b = string.byte(path, pos)
+        if b == 46 then -- 46 = char "."
+            extpos = pos
+        elseif b == 47 then -- 47 = char "/"
+            break
+        end
+        pos = pos - 1
+    end
+
+    local dirname = string.sub(path, 1, pos)
+    local filename = string.sub(path, pos + 1)
+    extpos = extpos - pos
+    local basename = string.sub(filename, 1, extpos - 1)
+    local extname = string.sub(filename, extpos)
+    return {
+        dirname = dirname,
+        filename = filename,
+        basename = basename,
+        extname = extname
+    }
+end
+
+--[[--
+
+返回指定文件的大小,如果失败返回 false
+
+@param string path 文件完全路径
+
+@return integer
+
+]]
+function io.filesize(path)
+    local size = false
+    local file = io.open(path, "r")
+    if file then
+        local current = file:seek()
+        size = file:seek("end")
+        file:seek("set", current)
+        io.close(file)
+    end
+    return size
+end
+
+--[[--
+
+计算表格包含的字段数量
+
+Lua table 的 "#" 操作只对依次排序的数值下标数组有效,table.nums() 则计算 table 中所有不为 nil 的值的个数。
+
+@param table t 要检查的表格
+
+@return integer
+
+]]
+function table.nums(t)
+    local count = 0
+    for k, v in pairs(t) do
+        count = count + 1
+    end
+    return count
+end
+
+--[[--
+
+返回指定表格中的所有键
+
+~~~ lua
+
+local hashtable = {a = 1, b = 2, c = 3}
+local keys = table.keys(hashtable)
+-- keys = {"a", "b", "c"}
+
+~~~
+
+@param table hashtable 要检查的表格
+
+@return table
+
+]]
+function table.keys(hashtable)
+    local keys = {}
+    for k, v in pairs(hashtable) do
+        keys[#keys + 1] = k
+    end
+    return keys
+end
+
+--[[--
+
+返回指定表格中的所有值
+
+~~~ lua
+
+local hashtable = {a = 1, b = 2, c = 3}
+local values = table.values(hashtable)
+-- values = {1, 2, 3}
+
+~~~
+
+@param table hashtable 要检查的表格
+
+@return table
+
+]]
+function table.values(hashtable)
+    local values = {}
+    for k, v in pairs(hashtable) do
+        values[#values + 1] = v
+    end
+    return values
+end
+
+--[[--
+
+将来源表格中所有键及其值复制到目标表格对象中,如果存在同名键,则覆盖其值
+
+~~~ lua
+
+local dest = {a = 1, b = 2}
+local src  = {c = 3, d = 4}
+table.merge(dest, src)
+-- dest = {a = 1, b = 2, c = 3, d = 4}
+
+~~~
+
+@param table dest 目标表格
+@param table src 来源表格
+
+]]
+function table.merge(dest, src)
+    for k, v in pairs(src) do
+        dest[k] = v
+    end
+end
+
+--[[--
+
+在目标表格的指定位置插入来源表格,如果没有指定位置则连接两个表格
+
+~~~ lua
+
+local dest = {1, 2, 3}
+local src  = {4, 5, 6}
+table.insertto(dest, src)
+-- dest = {1, 2, 3, 4, 5, 6}
+
+dest = {1, 2, 3}
+table.insertto(dest, src, 5)
+-- dest = {1, 2, 3, nil, 4, 5, 6}
+
+~~~
+
+@param table dest 目标表格
+@param table src 来源表格
+@param [integer begin] 插入位置
+
+]]
+function table.insertto(dest, src, begin)
+    begin = checkint(begin)
+    if begin <= 0 then
+        begin = #dest + 1
+    end
+
+    local len = #src
+    for i = 0, len - 1 do
+        dest[i + begin] = src[i + 1]
+    end
+end
+
+--[[
+
+从表格中查找指定值,返回其索引,如果没找到返回 false
+
+~~~ lua
+
+local array = {"a", "b", "c"}
+print(table.indexof(array, "b")) -- 输出 2
+
+~~~
+
+@param table array 表格
+@param mixed value 要查找的值
+@param [integer begin] 起始索引值
+
+@return integer
+
+]]
+function table.indexof(array, value, begin)
+    for i = begin or 1, #array do
+        if array[i] == value then return i end
+    end
+    return false
+end
+
+--[[--
+
+从表格中查找指定值,返回其 key,如果没找到返回 nil
+
+~~~ lua
+
+local hashtable = {name = "dualface", comp = "chukong"}
+print(table.keyof(hashtable, "chukong")) -- 输出 comp
+
+~~~
+
+@param table hashtable 表格
+@param mixed value 要查找的值
+
+@return string 该值对应的 key
+
+]]
+function table.keyof(hashtable, value)
+    for k, v in pairs(hashtable) do
+        if v == value then return k end
+    end
+    return nil
+end
+
+--[[--
+
+从表格中删除指定值,返回删除的值的个数
+
+~~~ lua
+
+local array = {"a", "b", "c", "c"}
+print(table.removebyvalue(array, "c", true)) -- 输出 2
+
+~~~
+
+@param table array 表格
+@param mixed value 要删除的值
+@param [boolean removeall] 是否删除所有相同的值
+
+@return integer
+
+]]
+function table.removebyvalue(array, value, removeall)
+    local c, i, max = 0, 1, #array
+    while i <= max do
+        if array[i] == value then
+            table.remove(array, i)
+            c = c + 1
+            i = i - 1
+            max = max - 1
+            if not removeall then break end
+        end
+        i = i + 1
+    end
+    return c
+end
+
+--[[--
+
+对表格中每一个值执行一次指定的函数,并用函数返回值更新表格内容
+
+~~~ lua
+
+local t = {name = "dualface", comp = "chukong"}
+table.map(t, function(v, k)
+    -- 在每一个值前后添加括号
+    return "[" .. v .. "]"
+end)
+
+-- 输出修改后的表格内容
+for k, v in pairs(t) do
+    print(k, v)
+end
+
+-- 输出
+-- name [dualface]
+-- comp [chukong]
+
+~~~
+
+fn 参数指定的函数具有两个参数,并且返回一个值。原型如下:
+
+~~~ lua
+
+function map_function(value, key)
+    return value
+end
+
+~~~
+
+@param table t 表格
+@param function fn 函数
+
+]]
+function table.map(t, fn)
+    for k, v in pairs(t) do
+        t[k] = fn(v, k)
+    end
+end
+
+--[[--
+
+对表格中每一个值执行一次指定的函数,但不改变表格内容
+
+~~~ lua
+
+local t = {name = "dualface", comp = "chukong"}
+table.walk(t, function(v, k)
+    -- 输出每一个值
+    print(v)
+end)
+
+~~~
+
+fn 参数指定的函数具有两个参数,没有返回值。原型如下:
+
+~~~ lua
+
+function map_function(value, key)
+
+end
+
+~~~
+
+@param table t 表格
+@param function fn 函数
+
+]]
+function table.walk(t, fn)
+    for k,v in pairs(t) do
+        fn(v, k)
+    end
+end
+
+--[[--
+
+对表格中每一个值执行一次指定的函数,如果该函数返回 false,则对应的值会从表格中删除
+
+~~~ lua
+
+local t = {name = "dualface", comp = "chukong"}
+table.filter(t, function(v, k)
+    return v ~= "dualface" -- 当值等于 dualface 时过滤掉该值
+end)
+
+-- 输出修改后的表格内容
+for k, v in pairs(t) do
+    print(k, v)
+end
+
+-- 输出
+-- comp chukong
+
+~~~
+
+fn 参数指定的函数具有两个参数,并且返回一个 boolean 值。原型如下:
+
+~~~ lua
+
+function map_function(value, key)
+    return true or false
+end
+
+~~~
+
+@param table t 表格
+@param function fn 函数
+
+]]
+function table.filter(t, fn)
+    for k, v in pairs(t) do
+        if not fn(v, k) then t[k] = nil end
+    end
+end
+
+--[[--
+
+遍历表格,确保其中的值唯一
+
+~~~ lua
+
+local t = {"a", "a", "b", "c"} -- 重复的 a 会被过滤掉
+local n = table.unique(t)
+
+for k, v in pairs(n) do
+    print(v)
+end
+
+-- 输出
+-- a
+-- b
+-- c
+
+~~~
+
+@param table t 表格
+
+@return table 包含所有唯一值的新表格
+
+]]
+function table.unique(t)
+    local check = {}
+    local n = {}
+    for k, v in pairs(t) do
+        if not check[v] then
+            n[k] = v
+            check[v] = true
+        end
+    end
+    return n
+end
+
+-- 随机洗牌
+function table.shuffle(t)
+    local n = #t
+
+    while n >= 2 do
+        -- n is now the last pertinent index
+        local k = math.random(n) -- 1 <= k <= n
+        -- Quick swap
+        t[n], t[k] = t[k], t[n]
+        n = n - 1
+    end
+
+    return t
+end
+
+-- 切片
+function table.slice(t, begin, offset)
+    local res = {}
+
+    -- default values for range
+    local n = #t
+
+    begin = begin or 1
+    if begin < 1 or begin > n then
+        return res
+    end
+
+    offset = offset or n
+    if offset < 0 then
+        offset = n + offset + 1
+    elseif offset > n then
+        offset = n
+    end
+
+    local k = 1
+    for i = begin, begin + offset - 1 do
+        res[k] = t[i]
+        k = k + 1
+    end
+    return res
+end
+
+string._htmlspecialchars_set = {}
+string._htmlspecialchars_set["&"] = "&amp;"
+string._htmlspecialchars_set["\""] = "&quot;"
+string._htmlspecialchars_set["'"] = "&#039;"
+string._htmlspecialchars_set["<"] = "&lt;"
+string._htmlspecialchars_set[">"] = "&gt;"
+
+--[[--
+
+将特殊字符转为 HTML 转义符
+
+~~~ lua
+
+print(string.htmlspecialchars("<ABC>"))
+-- 输出 &lt;ABC&gt;
+
+~~~
+
+@param string input 输入字符串
+
+@return string 转换结果
+
+]]
+function string.htmlspecialchars(input)
+    for k, v in pairs(string._htmlspecialchars_set) do
+        input = string.gsub(input, k, v)
+    end
+    return input
+end
+
+function string.startwith(s,start)
+   return string.sub(s,1,string.len(start))==start
+end
+
+
+
+--[[--
+
+将 HTML 转义符还原为特殊字符,功能与 string.htmlspecialchars() 正好相反
+
+~~~ lua
+
+print(string.restorehtmlspecialchars("&lt;ABC&gt;"))
+-- 输出 <ABC>
+
+~~~
+
+@param string input 输入字符串
+
+@return string 转换结果
+
+]]
+function string.restorehtmlspecialchars(input)
+    for k, v in pairs(string._htmlspecialchars_set) do
+        input = string.gsub(input, v, k)
+    end
+    return input
+end
+
+--[[--
+
+将字符串中的 \n 换行符转换为 HTML 标记
+
+~~~ lua
+
+print(string.nl2br("Hello\nWorld"))
+-- 输出
+-- Hello<br />World
+
+~~~
+
+@param string input 输入字符串
+
+@return string 转换结果
+
+]]
+function string.nl2br(input)
+    return string.gsub(input, "\n", "<br />")
+end
+
+--[[--
+
+将字符串中的特殊字符和 \n 换行符转换为 HTML 转移符和标记
+
+~~~ lua
+
+print(string.nl2br("<Hello>\nWorld"))
+-- 输出
+-- &lt;Hello&gt;<br />World
+
+~~~
+
+@param string input 输入字符串
+
+@return string 转换结果
+
+]]
+function string.text2html(input)
+    input = string.gsub(input, "\t", "    ")
+    input = string.htmlspecialchars(input)
+    input = string.gsub(input, " ", "&nbsp;")
+    input = string.nl2br(input)
+    return input
+end
+
+--[[--
+
+用指定字符或字符串分割输入字符串,返回包含分割结果的数组
+
+~~~ lua
+
+local input = "Hello,World"
+local res = string.split(input, ",")
+-- res = {"Hello", "World"}
+
+local input = "Hello-+-World-+-Quick"
+local res = string.split(input, "-+-")
+-- res = {"Hello", "World", "Quick"}
+
+~~~
+
+@param string input 输入字符串
+@param string delimiter 分割标记字符或字符串
+
+@return array 包含分割结果的数组
+
+]]
+function string.split(input, delimiter)
+    input = tostring(input)
+    delimiter = tostring(delimiter)
+    if (delimiter=='') then return false end
+    local pos,arr = 0, {}
+    -- for each divider found
+    for st,sp in function() return string.find(input, delimiter, pos, true) end do
+        table.insert(arr, string.sub(input, pos, st - 1))
+        pos = sp + 1
+    end
+    table.insert(arr, string.sub(input, pos))
+    return arr
+end
+
+--[[--
+
+去除输入字符串头部的空白字符,返回结果
+
+~~~ lua
+
+local input = "  ABC"
+print(string.ltrim(input))
+-- 输出 ABC,输入字符串前面的两个空格被去掉了
+
+~~~
+
+空白字符包括:
+
+-   空格
+-   制表符 \t
+-   换行符 \n
+-   回到行首符 \r
+
+@param string input 输入字符串
+
+@return string 结果
+
+@see string.rtrim, string.trim
+
+]]
+function string.ltrim(input)
+    return string.gsub(input, "^[ \t\n\r]+", "")
+end
+
+function string.fromhex(str)
+    return (str:gsub('..', function (cc)
+        return string.char(tonumber(cc, 16))
+    end))
+end
+
+function string.tohex(str)
+    return (str:gsub('.', function (c)
+        return string.format('%02X', string.byte(c))
+    end))
+end
+
+--[[--
+
+去除输入字符串尾部的空白字符,返回结果
+
+~~~ lua
+
+local input = "ABC  "
+print(string.ltrim(input))
+-- 输出 ABC,输入字符串最后的两个空格被去掉了
+
+~~~
+
+@param string input 输入字符串
+
+@return string 结果
+
+@see string.ltrim, string.trim
+
+]]
+function string.rtrim(input)
+    return string.gsub(input, "[ \t\n\r]+$", "")
+end
+
+--[[--
+
+去掉字符串首尾的空白字符,返回结果
+
+@param string input 输入字符串
+
+@return string 结果
+
+@see string.ltrim, string.rtrim
+
+]]
+function string.trim(input)
+    input = string.gsub(input, "^[ \t\n\r]+", "")
+    return string.gsub(input, "[ \t\n\r]+$", "")
+end
+
+
+--[[--
+
+将字符串的第一个字符转为大写,返回结果
+
+~~~ lua
+
+local input = "hello"
+print(string.ucfirst(input))
+-- 输出 Hello
+
+~~~
+
+@param string input 输入字符串
+
+@return string 结果
+
+]]
+function string.ucfirst(input)
+    return string.upper(string.sub(input, 1, 1)) .. string.sub(input, 2)
+end
+
+local function urlencodechar(char)
+    return "%" .. string.format("%02X", string.byte(char))
+end
+
+--[[--
+
+将字符串转换为符合 URL 传递要求的格式,并返回转换结果
+
+~~~ lua
+
+local input = "hello world"
+print(string.urlencode(input))
+-- 输出
+-- hello%20world
+
+~~~
+
+@param string input 输入字符串
+
+@return string 转换后的结果
+
+@see string.urldecode
+
+]]
+function string.urlencode(input)
+    -- convert line endings
+    input = string.gsub(tostring(input), "\n", "\r\n")
+    -- escape all characters but alphanumeric, '.' and '-'
+    input = string.gsub(input, "([^%w%.%- ])", urlencodechar)
+    -- convert spaces to "+" symbols
+    return string.gsub(input, " ", "+")
+end
+
+--[[--
+
+将 URL 中的特殊字符还原,并返回结果
+
+~~~ lua
+
+local input = "hello%20world"
+print(string.urldecode(input))
+-- 输出
+-- hello world
+
+~~~
+
+@param string input 输入字符串
+
+@return string 转换后的结果
+
+@see string.urlencode
+
+]]
+function string.urldecode(input)
+    input = string.gsub (input, "+", " ")
+    input = string.gsub (input, "%%(%x%x)", function(h) return string.char(checknumber(h,16)) end)
+    input = string.gsub (input, "\r\n", "\n")
+    return input
+end
+
+--[[--
+
+计算 UTF8 字符串的长度,每一个中文算一个字符
+
+~~~ lua
+
+local input = "你好World"
+print(string.utf8len(input))
+-- 输出 7
+
+~~~
+
+@param string input 输入字符串
+
+@return integer 长度
+
+]]
+function string.utf8len(input)
+    local len  = string.len(input)
+    local left = len
+    local cnt  = 0
+    local arr  = {0, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc}
+    while left ~= 0 do
+        local tmp = string.byte(input, -left)
+        local i   = #arr
+        while arr[i] do
+            if tmp >= arr[i] then
+                left = left - i
+                break
+            end
+            i = i - 1
+        end
+        cnt = cnt + 1
+    end
+    return cnt
+end
+
+--[[--
+
+将数值格式化为包含千分位分隔符的字符串
+
+~~~ lua
+
+print(string.formatnumberthousands(1924235))
+-- 输出 1,924,235
+
+~~~
+
+@param number num 数值
+
+@return string 格式化结果
+
+]]
+function string.formatnumberthousands(num)
+    local formatted = tostring(checknumber(num))
+    local k
+    while true do
+        formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2')
+        if k == 0 then break end
+    end
+    return formatted
+end

+ 334 - 0
common/preload/inspect.lua

@@ -0,0 +1,334 @@
+local inspect ={
+  _VERSION = 'inspect.lua 3.1.0',
+  _URL     = 'http://github.com/kikito/inspect.lua',
+  _DESCRIPTION = 'human-readable representations of tables',
+  _LICENSE = [[
+    MIT LICENSE
+
+    Copyright (c) 2013 Enrique García Cota
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the
+    "Software"), to deal in the Software without restriction, including
+    without limitation the rights to use, copy, modify, merge, publish,
+    distribute, sublicense, and/or sell copies of the Software, and to
+    permit persons to whom the Software is furnished to do so, subject to
+    the following conditions:
+
+    The above copyright notice and this permission notice shall be included
+    in all copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+  ]]
+}
+
+local tostring = tostring
+
+inspect.KEY       = setmetatable({}, {__tostring = function() return 'inspect.KEY' end})
+inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end})
+
+local function rawpairs(t)
+  return next, t, nil
+end
+
+-- Apostrophizes the string if it has quotes, but not aphostrophes
+-- Otherwise, it returns a regular quoted string
+local function smartQuote(str)
+  if str:match('"') and not str:match("'") then
+    return "'" .. str .. "'"
+  end
+  return '"' .. str:gsub('"', '\\"') .. '"'
+end
+
+-- \a => '\\a', \0 => '\\0', 31 => '\31'
+local shortControlCharEscapes = {
+  ["\a"] = "\\a",  ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n",
+  ["\r"] = "\\r",  ["\t"] = "\\t", ["\v"] = "\\v"
+}
+local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031
+for i=0, 31 do
+  local ch = string.char(i)
+  if not shortControlCharEscapes[ch] then
+    shortControlCharEscapes[ch] = "\\"..i
+    longControlCharEscapes[ch]  = string.format("\\%03d", i)
+  end
+end
+
+local function escape(str)
+  return (str:gsub("\\", "\\\\")
+             :gsub("(%c)%f[0-9]", longControlCharEscapes)
+             :gsub("%c", shortControlCharEscapes))
+end
+
+local function isIdentifier(str)
+  return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" )
+end
+
+local function isSequenceKey(k, sequenceLength)
+  return type(k) == 'number'
+     and 1 <= k
+     and k <= sequenceLength
+     and math.floor(k) == k
+end
+
+local defaultTypeOrders = {
+  ['number']   = 1, ['boolean']  = 2, ['string'] = 3, ['table'] = 4,
+  ['function'] = 5, ['userdata'] = 6, ['thread'] = 7
+}
+
+local function sortKeys(a, b)
+  local ta, tb = type(a), type(b)
+
+  -- strings and numbers are sorted numerically/alphabetically
+  if ta == tb and (ta == 'string' or ta == 'number') then return a < b end
+
+  local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb]
+  -- Two default types are compared according to the defaultTypeOrders table
+  if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb]
+  elseif dta     then return true  -- default types before custom ones
+  elseif dtb     then return false -- custom types after default ones
+  end
+
+  -- custom types are sorted out alphabetically
+  return ta < tb
+end
+
+-- For implementation reasons, the behavior of rawlen & # is "undefined" when
+-- tables aren't pure sequences. So we implement our own # operator.
+local function getSequenceLength(t)
+  local len = 1
+  local v = rawget(t,len)
+  while v ~= nil do
+    len = len + 1
+    v = rawget(t,len)
+  end
+  return len - 1
+end
+
+local function getNonSequentialKeys(t)
+  local keys, keysLength = {}, 0
+  local sequenceLength = getSequenceLength(t)
+  for k,_ in rawpairs(t) do
+    if not isSequenceKey(k, sequenceLength) then
+      keysLength = keysLength + 1
+      keys[keysLength] = k
+    end
+  end
+  table.sort(keys, sortKeys)
+  return keys, keysLength, sequenceLength
+end
+
+local function countTableAppearances(t, tableAppearances)
+  tableAppearances = tableAppearances or {}
+
+  if type(t) == 'table' then
+    if not tableAppearances[t] then
+      tableAppearances[t] = 1
+      for k,v in rawpairs(t) do
+        countTableAppearances(k, tableAppearances)
+        countTableAppearances(v, tableAppearances)
+      end
+      countTableAppearances(getmetatable(t), tableAppearances)
+    else
+      tableAppearances[t] = tableAppearances[t] + 1
+    end
+  end
+
+  return tableAppearances
+end
+
+local copySequence = function(s)
+  local copy, len = {}, #s
+  for i=1, len do copy[i] = s[i] end
+  return copy, len
+end
+
+local function makePath(path, ...)
+  local keys = {...}
+  local newPath, len = copySequence(path)
+  for i=1, #keys do
+    newPath[len + i] = keys[i]
+  end
+  return newPath
+end
+
+local function processRecursive(process, item, path, visited)
+  if item == nil then return nil end
+  if visited[item] then return visited[item] end
+
+  local processed = process(item, path)
+  if type(processed) == 'table' then
+    local processedCopy = {}
+    visited[item] = processedCopy
+    local processedKey
+
+    for k,v in rawpairs(processed) do
+      processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited)
+      if processedKey ~= nil then
+        processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited)
+      end
+    end
+
+    local mt  = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited)
+    if type(mt) ~= 'table' then mt = nil end -- ignore not nil/table __metatable field
+    setmetatable(processedCopy, mt)
+    processed = processedCopy
+  end
+  return processed
+end
+
+
+
+-------------------------------------------------------------------
+
+local Inspector = {}
+local Inspector_mt = {__index = Inspector}
+
+function Inspector:puts(...)
+  local args   = {...}
+  local buffer = self.buffer
+  local len    = #buffer
+  for i=1, #args do
+    len = len + 1
+    buffer[len] = args[i]
+  end
+end
+
+function Inspector:down(f)
+  self.level = self.level + 1
+  f()
+  self.level = self.level - 1
+end
+
+function Inspector:tabify()
+  self:puts(self.newline, string.rep(self.indent, self.level))
+end
+
+function Inspector:alreadyVisited(v)
+  return self.ids[v] ~= nil
+end
+
+function Inspector:getId(v)
+  local id = self.ids[v]
+  if not id then
+    local tv = type(v)
+    id              = (self.maxIds[tv] or 0) + 1
+    self.maxIds[tv] = id
+    self.ids[v]     = id
+  end
+  return tostring(id)
+end
+
+function Inspector:putKey(k)
+  if isIdentifier(k) then return self:puts(k) end
+  self:puts("[")
+  self:putValue(k)
+  self:puts("]")
+end
+
+function Inspector:putTable(t)
+  if t == inspect.KEY or t == inspect.METATABLE then
+    self:puts(tostring(t))
+  elseif self:alreadyVisited(t) then
+    self:puts('<table ', self:getId(t), '>')
+  elseif self.level >= self.depth then
+    self:puts('{...}')
+  else
+    if self.tableAppearances[t] > 1 then self:puts('<', self:getId(t), '>') end
+
+    local nonSequentialKeys, nonSequentialKeysLength, sequenceLength = getNonSequentialKeys(t)
+    local mt                = getmetatable(t)
+
+    self:puts('{')
+    self:down(function()
+      local count = 0
+      for i=1, sequenceLength do
+        if count > 0 then self:puts(',') end
+        self:puts(' ')
+        self:putValue(t[i])
+        count = count + 1
+      end
+
+      for i=1, nonSequentialKeysLength do
+        local k = nonSequentialKeys[i]
+        if count > 0 then self:puts(',') end
+        self:tabify()
+        self:putKey(k)
+        self:puts(' = ')
+        self:putValue(t[k])
+        count = count + 1
+      end
+
+      if type(mt) == 'table' then
+        if count > 0 then self:puts(',') end
+        self:tabify()
+        self:puts('<metatable> = ')
+        self:putValue(mt)
+      end
+    end)
+
+    if nonSequentialKeysLength > 0 or type(mt) == 'table' then -- result is multi-lined. Justify closing }
+      self:tabify()
+    elseif sequenceLength > 0 then -- array tables have one extra space before closing }
+      self:puts(' ')
+    end
+
+    self:puts('}')
+  end
+end
+
+function Inspector:putValue(v)
+  local tv = type(v)
+
+  if tv == 'string' then
+    self:puts(smartQuote(escape(v)))
+  elseif tv == 'number' or tv == 'boolean' or tv == 'nil' or
+         tv == 'cdata' or tv == 'ctype' then
+    self:puts(tostring(v))
+  elseif tv == 'table' then
+    self:putTable(v)
+  else
+    self:puts('<', tv, ' ', self:getId(v), '>')
+  end
+end
+
+-------------------------------------------------------------------
+
+function inspect.inspect(root, options)
+  options       = options or {}
+
+  local depth   = options.depth   or math.huge
+  local newline = options.newline or '\n'
+  local indent  = options.indent  or '  '
+  local process = options.process
+
+  if process then
+    root = processRecursive(process, root, {}, {})
+  end
+
+  local inspector = setmetatable({
+    depth            = depth,
+    level            = 0,
+    buffer           = {},
+    ids              = {},
+    maxIds           = {},
+    newline          = newline,
+    indent           = indent,
+    tableAppearances = countTableAppearances(root)
+  }, Inspector_mt)
+
+  inspector:putValue(root)
+
+  return table.concat(inspector.buffer)
+end
+
+setmetatable(inspect, { __call = function(_, ...) return inspect.inspect(...) end })
+
+return inspect
+

+ 41 - 0
common/preload/inspect_api.lua

@@ -0,0 +1,41 @@
+local inspect_lib = require "inspect"
+
+function inspect(value)
+    return inspect_lib(value, {
+    process = function(item, path)
+        if type(item) == "function" then
+            return nil
+        end
+
+        if path[#path] == inspect_lib.METATABLE then
+            return nil
+        end
+
+        return item
+    end,
+    newline = " ",
+    indent = ""
+})
+end
+
+function DUMP(value)
+    return inspect_lib(value, {
+    process = function(item, path)
+        return item
+    end,
+    newline = " ",
+    indent = ""
+})
+end
+
+function TraceBack()
+    for level = 1, math.huge do
+        local info = debug.getinfo(level, "nSl")
+        if not info then break end
+        if info.what == "C" then -- is a C function?
+            DEBUG(level, "C function")
+        else
+            DEBUG(info.name,string.format("%d, [%s] : %d", level, info.short_src, info.currentline))
+        end
+    end
+end

+ 56 - 0
common/preload/logger_api.lua

@@ -0,0 +1,56 @@
+local skynet = require "skynet"
+-- require "skynet.manager"
+
+
+-- 日志级别
+local log_level = {
+  LOG_DEFAULT   = 1,
+  LOG_TRACE     = 1,
+  LOG_DEBUG     = 2,
+  LOG_INFO      = 3,
+  LOG_WARN      = 4,
+  LOG_ERROR     = 5,
+  LOG_FATAL     = 6,
+}
+
+local defaultLevel = log_level.LOG_DEBUG
+local prefix = ""
+function LOG_PREFIX(pre)
+  prefix = "[" .. pre .. "]"
+end
+
+--日志 --
+local function logger(str, level, color)
+  return function (...)
+    if level >= defaultLevel then
+        local info = table.pack(...)
+        info[#info+1] = "\x1b[0m"
+        skynet.error(string.format("%s%s%s", color, prefix, str), table.unpack(info))
+    end
+  end
+end
+
+
+local M = {
+  TRACE = logger("[trace]", log_level.LOG_TRACE, "\x1b[35m"),
+  DEBUG = logger("[debug]", log_level.LOG_DEBUG, "\x1b[32m"),
+  INFO  = logger("[info]", log_level.LOG_INFO, "\x1b[34m"),
+  WARN  = logger("[warning]", log_level.LOG_WARN, "\x1b[33m"),
+  ERROR   = logger("[error]", log_level.LOG_ERROR, "\x1b[31m"),
+  FATAL = logger("[fatal]", log_level.LOG_FATAL,"\x1b[31m")
+}
+
+-- 错误日志 --
+
+setmetatable(M, {
+  __call = function(t)
+    for k, v in pairs(t) do
+      _G[k] = v
+    end
+  end,
+})
+
+M()
+
+return M
+

+ 8 - 0
etc/config.path

@@ -0,0 +1,8 @@
+root = "../../"
+proj_root = "../"
+lualoader = root .. "skynet/lualib/loader.lua"
+
+luaservice = proj_root.."common/?.lua;" .. "../service/?.lua;" .. "../service/?/init.lua;" .. root .. "skynet/service/?.lua;" .. proj_root .. "common/dbproxy/?.lua;" .. proj_root .. "common/dbproxy/mysqldb/?.lua;" .. proj_root .. "common/dbproxy/mongodb/?.lua;" .. proj_root .. "common/dbproxy/redisdb/?.lua;"
+
+lua_path = proj_root .. "common/dbproxy/?.lua;" .. proj_root .. "common/preload/?.lua;" .. "../luaclib_src/lua-protobuf-master/?.lua;" .. "../etc/?.lua;" .. "../msg/?.lua;" .. "../lualib/?.lua;" .. "../lualib/?/init.lua;" .. root .. "lualib/?.lua;" .. root .. "skynet/lualib/?.lua;" .. root .. "skynet/lualib/?/init.lua"
+lua_cpath = "../luaclib_src/lua-protobuf-master/?.so;" .. root .. "luaclib/?.so;" .. root .. "skynet/luaclib/?.so;" .. "../luaclib/?.so;"

+ 17 - 0
etc/config_node1

@@ -0,0 +1,17 @@
+--必须配置
+include "config.path"
+thread = 8                          --启用多少个工作线程
+cpath = root.."skynet/cservice/?.so"    --用C编写的服务模块的位置
+bootstrap = "snlua bootstrap"       --启动的第一个服务
+preload = root .. "jl_tg_config_back/preload.lua" 
+--bootstrap配置项
+start = "main"                      --主程序入口
+harbor = 0                          --不使用主从节点模式
+
+--后台模式
+--daemon = "./jl_tg_config_back.pid"
+logger = "userlog"
+logpath = "."
+logservice = "snlua"
+--节点
+node = "node1"

+ 18 - 0
etc/prodconfig

@@ -0,0 +1,18 @@
+--必须配置
+include "config.path"
+thread = 8                          --启用多少个工作线程
+cpath = root.."skynet/cservice/?.so"    --用C编写的服务模块的位置
+bootstrap = "snlua bootstrap"       --启动的第一个服务
+preload = root .. "jl_tg_config_back/preload.lua" 
+--bootstrap配置项
+start = "main"                      --主程序入口
+harbor = 0                          --不使用主从节点模式
+
+enablessl = true
+--后台模式
+daemon = "./jl_tg_config_back.pid"
+logger = "userlog"
+logpath = "."
+logservice = "snlua"
+--节点
+node = "node1"

+ 223 - 0
log/2024_11_28.log

@@ -0,0 +1,223 @@
+24/11/28 19:18:29:00000017(1732792709.65): ............dump...........
+24/11/28 19:18:29:00000017(1732792709.65):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:18:29:00000017(1732792709.79): ............dump...........
+24/11/28 19:18:29:00000017(1732792709.79):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:18:29:00000017(1732792709.88): ............dump...........
+24/11/28 19:18:29:00000017(1732792709.88):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:18:29:00000017(1732792709.94): ............dump...........
+24/11/28 19:18:29:00000017(1732792709.94):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:18:29:00000017(1732792709.95): ............dump...........
+24/11/28 19:18:29:00000017(1732792709.95):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:20:08:00000017(1732792808.94): ............dump...........
+24/11/28 19:20:08:00000017(1732792808.95):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:20:08:00000017(1732792808.96): ............dump...........
+24/11/28 19:20:08:00000017(1732792808.96):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:20:09:00000017(1732792809.18): ............dump...........
+24/11/28 19:20:09:00000017(1732792809.18):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:20:09:00000017(1732792809.23): ............dump...........
+24/11/28 19:20:09:00000017(1732792809.23):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:20:09:00000017(1732792809.27): ............dump...........
+24/11/28 19:20:09:00000017(1732792809.27):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:20:21:00000017(1732792821.57): ............dump...........
+24/11/28 19:20:21:00000017(1732792821.57):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:20:21:00000017(1732792821.57): ............dump...........
+24/11/28 19:20:21:00000017(1732792821.57):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:20:21:00000017(1732792821.84): ............dump...........
+24/11/28 19:20:21:00000017(1732792821.84):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:20:21:00000017(1732792821.93): ............dump...........
+24/11/28 19:20:21:00000017(1732792821.93):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:20:22:00000017(1732792822.03): ............dump...........
+24/11/28 19:20:22:00000017(1732792822.03):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:23:34:00000017(1732793014.01): ............dump...........
+24/11/28 19:23:34:00000017(1732793014.01):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:23:34:00000017(1732793014.11): ............dump...........
+24/11/28 19:23:34:00000017(1732793014.11):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:23:34:00000017(1732793014.12): ............dump...........
+24/11/28 19:23:34:00000017(1732793014.12):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:23:34:00000017(1732793014.14): ............dump...........
+24/11/28 19:23:34:00000017(1732793014.14):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:23:34:00000017(1732793014.16): ............dump...........
+24/11/28 19:23:34:00000017(1732793014.16):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:24:03:00000017(1732793043.05): ............dump...........
+24/11/28 19:24:03:00000017(1732793043.05):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:24:03:00000017(1732793043.05): ............dump...........
+24/11/28 19:24:03:00000017(1732793043.05):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:24:03:00000017(1732793043.31): ............dump...........
+24/11/28 19:24:03:00000017(1732793043.31):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:24:03:00000017(1732793043.38): ............dump...........
+24/11/28 19:24:03:00000017(1732793043.38):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:24:03:00000017(1732793043.46): ............dump...........
+24/11/28 19:24:03:00000017(1732793043.46):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:24:04:00000017(1732793044.64): ............dump...........
+24/11/28 19:24:04:00000017(1732793044.64):  {"cmd":"tg_zhanghu","fun":"update_zhanghu","data":{}}
+24/11/28 19:24:04:00000017(1732793044.64): lua call [20 to :17 : 0 msgsz = 70] error : ../../skynet/lualib/skynet.lua:988: ../../skynet/lualib/skynet.lua:452: ../../skynet/lualib/skynet/socket.lua:244: bad argument #1 to 'connect' (string expected, got nil)
+stack traceback:
+	[C]: in function 'skynet.socketdriver.connect'
+	../../skynet/lualib/skynet/socket.lua:244: in function 'skynet.socket.open'
+	../../skynet/lualib/http/sockethelper.lua:94: in upvalue 'f'
+	../../skynet/lualib/skynet.lua:402: in function <../../skynet/lualib/skynet.lua:374>
+stack traceback:
+	[C]: in function 'assert'
+	../../skynet/lualib/skynet.lua:988: in function 'skynet.manager.dispatch_message'
+24/11/28 19:24:05:00000017(1732793045.64): ../../skynet/lualib/http/sockethelper.lua:117: attempt to concatenate a nil value (local 'host')
+24/11/28 19:24:05:00000017(1732793045.64): stack traceback:
+	../lualib/service.lua:27: in function 'traceback'
+	../../skynet/lualib/http/sockethelper.lua:117: in function 'http.sockethelper.connect'
+	../../skynet/lualib/http/httpc.lua:84: in upvalue 'connect'
+	../../skynet/lualib/http/httpc.lua:113: in function 'http.httpc.request'
+	(...tail calls...)
+	../common/dbproxy/tg_zhanghu.lua:155: in function 'tg_zhanghu.update_zhanghu'
+	../service/backmgr/init.lua:35: in function 'run'
+	../service/backmgr/init.lua:58: in field '?'
+	../service/backmgr/init.lua:70: in function <../service/backmgr/init.lua:67>
+	[C]: in function 'xpcall'
+	../lualib/service.lua:37: in upvalue 'f'
+	../../skynet/lualib/skynet.lua:402: in function <../../skynet/lualib/skynet.lua:374>
+24/11/28 19:24:21:00000017(1732793061.31): ............dump...........
+24/11/28 19:24:21:00000017(1732793061.31):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:24:21:00000017(1732793061.32): ............dump...........
+24/11/28 19:24:21:00000017(1732793061.32):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:24:21:00000017(1732793061.59): ............dump...........
+24/11/28 19:24:21:00000017(1732793061.59):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:24:21:00000017(1732793061.67): ............dump...........
+24/11/28 19:24:21:00000017(1732793061.67):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:24:21:00000017(1732793061.83): ............dump...........
+24/11/28 19:24:21:00000017(1732793061.83):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:25:02:00000017(1732793102.80): ............dump...........
+24/11/28 19:25:02:00000017(1732793102.80):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:25:03:00000017(1732793103.08): ............dump...........
+24/11/28 19:25:03:00000017(1732793103.08):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:25:03:00000017(1732793103.15): ............dump...........
+24/11/28 19:25:03:00000017(1732793103.15):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:25:03:00000017(1732793103.17): ............dump...........
+24/11/28 19:25:03:00000017(1732793103.17):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:25:03:00000017(1732793103.24): ............dump...........
+24/11/28 19:25:03:00000017(1732793103.24):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:25:16:00000017(1732793116.79): ............dump...........
+24/11/28 19:25:16:00000017(1732793116.79):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:25:16:00000017(1732793116.79): ............dump...........
+24/11/28 19:25:16:00000017(1732793116.79):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:25:17:00000017(1732793117.05): ............dump...........
+24/11/28 19:25:17:00000017(1732793117.05):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:25:17:00000017(1732793117.76): ............dump...........
+24/11/28 19:25:17:00000017(1732793117.76):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:25:17:00000017(1732793117.88): ............dump...........
+24/11/28 19:25:17:00000017(1732793117.88):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:25:44:00000017(1732793144.51): ............dump...........
+24/11/28 19:25:44:00000017(1732793144.51):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:25:44:00000017(1732793144.59): ............dump...........
+24/11/28 19:25:44:00000017(1732793144.59):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:25:44:00000017(1732793144.90): ............dump...........
+24/11/28 19:25:44:00000017(1732793144.90):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:25:45:00000017(1732793145.60): ............dump...........
+24/11/28 19:25:45:00000017(1732793145.60):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:25:45:00000017(1732793145.68): ............dump...........
+24/11/28 19:25:45:00000017(1732793145.68):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:27:16:00000017(1732793236.87): ............dump...........
+24/11/28 19:27:16:00000017(1732793236.87):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:27:16:00000017(1732793236.87): ............dump...........
+24/11/28 19:27:16:00000017(1732793236.87):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:27:16:00000017(1732793236.94): ............dump...........
+24/11/28 19:27:16:00000017(1732793236.94):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:27:17:00000017(1732793237.04): ............dump...........
+24/11/28 19:27:17:00000017(1732793237.04):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:27:19:00000017(1732793239.30): ............dump...........
+24/11/28 19:27:19:00000017(1732793239.30):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:28:42:00000017(1732793322.94): ............dump...........
+24/11/28 19:28:42:00000017(1732793322.94):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:28:43:00000017(1732793323.05): ............dump...........
+24/11/28 19:28:43:00000017(1732793323.05):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:28:43:00000017(1732793323.14): ............dump...........
+24/11/28 19:28:43:00000017(1732793323.14):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:28:43:00000017(1732793323.24): ............dump...........
+24/11/28 19:28:43:00000017(1732793323.24):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:28:43:00000017(1732793323.36): ............dump...........
+24/11/28 19:28:43:00000017(1732793323.36):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:29:04:00000017(1732793344.18): ............dump...........
+24/11/28 19:29:04:00000017(1732793344.18):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:29:04:00000017(1732793344.19): ............dump...........
+24/11/28 19:29:04:00000017(1732793344.19):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:29:04:00000017(1732793344.43): ............dump...........
+24/11/28 19:29:04:00000017(1732793344.43):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:29:04:00000017(1732793344.93): ............dump...........
+24/11/28 19:29:04:00000017(1732793344.93):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:29:05:00000017(1732793345.02): ............dump...........
+24/11/28 19:29:05:00000017(1732793345.02):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:29:26:00000017(1732793366.15): ............dump...........
+24/11/28 19:29:26:00000017(1732793366.15):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:29:26:00000017(1732793366.16): ............dump...........
+24/11/28 19:29:26:00000017(1732793366.16):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:29:26:00000017(1732793366.46): ............dump...........
+24/11/28 19:29:26:00000017(1732793366.46):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:29:26:00000017(1732793366.63): ............dump...........
+24/11/28 19:29:26:00000017(1732793366.63):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:29:26:00000017(1732793366.74): ............dump...........
+24/11/28 19:29:26:00000017(1732793366.74):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:30:03:00000017(1732793403.03): ............dump...........
+24/11/28 19:30:03:00000017(1732793403.03):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:30:03:00000017(1732793403.03): ............dump...........
+24/11/28 19:30:03:00000017(1732793403.03):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:30:04:00000017(1732793404.53): ............dump...........
+24/11/28 19:30:04:00000017(1732793404.53):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:30:04:00000017(1732793404.63): ............dump...........
+24/11/28 19:30:04:00000017(1732793404.63):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:30:04:00000017(1732793404.74): ............dump...........
+24/11/28 19:30:04:00000017(1732793404.74):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:30:21:00000017(1732793421.53): ............dump...........
+24/11/28 19:30:21:00000017(1732793421.53):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:30:21:00000017(1732793421.54): ............dump...........
+24/11/28 19:30:21:00000017(1732793421.54):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:30:22:00000017(1732793422.14): ............dump...........
+24/11/28 19:30:22:00000017(1732793422.14):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:30:23:00000017(1732793423.06): ............dump...........
+24/11/28 19:30:23:00000017(1732793423.06):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:30:23:00000017(1732793423.76): ............dump...........
+24/11/28 19:30:23:00000017(1732793423.76):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:31:30:00000017(1732793490.79): ............dump...........
+24/11/28 19:31:30:00000017(1732793490.79):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:31:30:00000017(1732793490.82): ............dump...........
+24/11/28 19:31:30:00000017(1732793490.82):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:31:31:00000017(1732793491.05): ............dump...........
+24/11/28 19:31:31:00000017(1732793491.05):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:31:31:00000017(1732793491.65): ............dump...........
+24/11/28 19:31:31:00000017(1732793491.65):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:31:31:00000017(1732793491.75): ............dump...........
+24/11/28 19:31:31:00000017(1732793491.75):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:31:58:00000017(1732793518.24): ............dump...........
+24/11/28 19:31:58:00000017(1732793518.24):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:31:58:00000017(1732793518.24): ............dump...........
+24/11/28 19:31:58:00000017(1732793518.24):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:31:58:00000017(1732793518.54): ............dump...........
+24/11/28 19:31:58:00000017(1732793518.54):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:31:58:00000017(1732793518.67): ............dump...........
+24/11/28 19:31:58:00000017(1732793518.67):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:31:58:00000017(1732793518.79): ............dump...........
+24/11/28 19:31:58:00000017(1732793518.79):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:32:12:00000017(1732793532.67): ............dump...........
+24/11/28 19:32:12:00000017(1732793532.67):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:32:12:00000017(1732793532.68): ............dump...........
+24/11/28 19:32:12:00000017(1732793532.68):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:32:12:00000017(1732793532.94): ............dump...........
+24/11/28 19:32:12:00000017(1732793532.94):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:32:13:00000017(1732793533.75): ............dump...........
+24/11/28 19:32:13:00000017(1732793533.75):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:32:15:00000017(1732793535.40): ............dump...........
+24/11/28 19:32:15:00000017(1732793535.40):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}
+24/11/28 19:32:23:00000026(1732793543.77): /admin/modules/framework/amp_conf/htdocs/admin/config.php
+24/11/28 19:32:23:00000026(1732793543.77): 错误访问:
+24/11/28 19:32:23:00000026(1732793543.77): ............dump...........
+24/11/28 19:32:23:00000026(1732793543.77): {
+24/11/28 19:32:23:00000026(1732793543.77):  addr = 127.0.0.1:40874 ,
+24/11/28 19:32:23:00000026(1732793543.77):  address = 10 ,
+24/11/28 19:32:23:00000026(1732793543.77):  id = 144 ,
+24/11/28 19:32:23:00000026(1732793543.77): }
+24/11/28 19:32:39:00000017(1732793559.53): ............dump...........
+24/11/28 19:32:39:00000017(1732793559.53):  {"cmd":"tg_platform","fun":"getPlatformList","data":{}}
+24/11/28 19:32:39:00000017(1732793559.53): ............dump...........
+24/11/28 19:32:39:00000017(1732793559.53):  {"cmd":"db_filter_config","fun":"getConfig","data":{}}
+24/11/28 19:32:39:00000017(1732793559.81): ............dump...........
+24/11/28 19:32:39:00000017(1732793559.81):  {"cmd":"tg_main","fun":"getMainList","data":{}}
+24/11/28 19:32:40:00000017(1732793560.28): ............dump...........
+24/11/28 19:32:40:00000017(1732793560.28):  {"cmd":"tg_zhanghu","fun":"getZhangHuList","data":{"page_number":1,"page_size":20}}
+24/11/28 19:32:40:00000017(1732793560.30): ............dump...........
+24/11/28 19:32:40:00000017(1732793560.30):  {"cmd":"tg_zhanghu","fun":"getTotal","data":{}}

+ 87 - 0
lualib/service.lua

@@ -0,0 +1,87 @@
+local skynet = require "skynet"
+local cluster = require "skynet.cluster"
+
+local M = {
+	--类型和id
+	name = "",
+	id = 0,
+	--回调函数
+	exit = nil,
+	init = nil,
+	--分发方法
+	resp = {},
+}
+
+--[[
+function exit_dispatch()
+	if M.exit then
+		M.exit()
+	end
+	skynet.ret()
+	skynet.exit()
+end
+--]]
+
+function traceback(err)
+	skynet.error(tostring(err))
+	skynet.error(debug.traceback())
+end
+
+local dispatch = function(session, address, cmd, ...)
+	local fun = M.resp[cmd]
+	if not fun then
+		skynet.ret()
+		return
+	end
+	
+	local ret = table.pack(xpcall(fun, traceback, address, ...))
+	local isok = ret[1]
+	
+	if not isok then
+		skynet.ret()
+		return
+	end
+
+	skynet.retpack(table.unpack(ret,2))
+end
+
+function init()
+	skynet.dispatch("lua", dispatch)
+	if M.init then
+		M.init()
+	end
+end
+
+function M.call(node, srv, ...)
+	local mynode = skynet.getenv("node")
+	if node == mynode then
+		return skynet.call(srv, "lua", ...)
+	else
+		return cluster.call(node, srv, ...)
+	end
+end
+
+function M.send(node, srv, ...)
+	local mynode = skynet.getenv("node")
+	if node == mynode then
+		return skynet.send(srv, "lua", ...)
+	else
+		return cluster.send(node, srv, ...)
+	end
+end
+
+function M.start(name, id, ...)
+	M.name = name
+	M.id = tonumber(id)
+	skynet.start(init)
+end
+
+M.resp.exit = function()
+    if M.exit then
+        M.exit()
+    end
+    skynet.ret()
+    skynet.exit()
+end
+
+return M

+ 129 - 0
lualib/tools.lua

@@ -0,0 +1,129 @@
+
+local sockethelper = require "http.sockethelper"
+local skynet = require "skynet"
+local httpd = require "http.httpd"
+local cjson = require "cjson"
+local crypt = require "client.crypt"
+local M = {
+
+}
+local headers = {
+    ['Content-Type'] = 'application/json',
+    ['Access-Control-Allow-Origin'] = '*', -- 这里写允许访问的域名就可以了,允许所有人访问的话就写*
+    ['Access-Control-Allow-Headers'] = 'Origin, X-Requested-With, Content-Type, Accept',
+    ['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS',
+ }
+
+M.read_request = function(id)
+     -- limit request body size to 8192 (you can pass nil to unlimit)
+        -- 一般的业务不需要处理大量上行数据,为了防止攻击,做了一个 8K 限制。这个限制可以去掉。
+    -- local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(id), 8192)
+    local code, url, method, header, body = httpd.read_request(sockethelper.readfunc(id))
+    return {code=code,url=url,method=method,header=header,body=body}
+end
+
+M.response = function(id, ...)
+    local ok, err = httpd.write_response(sockethelper.writefunc(id), ...)
+    if not ok then
+        -- if err == sockethelper.socket_error , that means socket closed.
+        skynet.error(string.format("fd = %d, %s", id, err))
+    end
+end
+
+
+
+--检查工具返回的字段是否缺失
+M.checkData= function(origin,table)
+    for _, field in pairs(origin) do
+        if not table[field] then
+            return false,field
+        end
+    end
+    return true
+end
+
+M.dump = function(res, tab)
+    tab = tab or 0
+    if(tab == 0) then
+        skynet.error("............dump...........")
+    end
+    
+    if type(res) == "table" then
+        skynet.error(string.rep("\t", tab).."{")
+        for k,v in pairs(res) do
+            if type(v) == "table" then
+                skynet.error(k.."=")
+                M.dump(v, tab + 1)
+             else
+                skynet.error(string.rep("\t", tab), k, "=", v, ",")
+            end
+        end
+        skynet.error(string.rep("\t", tab).."}")
+    else
+        skynet.error(string.rep("\t", tab) , res)
+    end
+end
+
+M.getDbResData = function(res)
+    local tab = {}
+    if #res >1 then
+        local i = 1;
+        for k, v in pairs(res) do
+            -- skynet.error("Row " .. k)
+            local tab_1 = {}
+            for field, value in pairs(v) do
+                tab_1[field] = value
+                -- skynet.error(field .. ": " .. value)
+            end
+            tab[i] = tab_1;
+            i=i+1;
+        end
+    else
+        for k, v in pairs(res) do
+            for field, value in pairs(v) do
+                tab[field] = value
+            end
+        end
+    end
+    return tab
+end
+
+M.tokenEncode = function(user_data)
+    return crypt.base64encode(user_data)
+end
+
+M.tokenDecode = function(base_str)
+    return crypt.base64decode(base_str)
+end
+
+M.base64decode = function(base_str)
+    return crypt.base64decode(base_str)
+end
+
+M.base64encode = function(base_str)
+    return crypt.base64encode(base_str)
+end
+
+M.sort_table_by_keys = function(tbl)
+    table.sort(tbl)
+    return tbl
+    -- local keys = {}
+    -- -- 提取所有键
+    -- for key in pairs(tbl) do
+    --     table.insert(keys, key)
+    -- end
+    
+    -- -- 使用table.sort对键进行字典序排序
+    -- table.sort(keys, function(a, b)
+    --     return a < b
+    -- end)
+    
+    -- -- 创建一个新table,根据排序后的键来组织内容
+    -- local sorted_tbl = {}
+    -- for _, key in ipairs(keys) do
+    --     sorted_tbl[key] = tbl[key]
+    -- end
+    
+    -- return sorted_tbl
+end
+return M

+ 13 - 0
preload.lua

@@ -0,0 +1,13 @@
+-- This file will execute before every lua service start
+-- See config
+
+print("PRELOAD", ...)
+PROJ_ROOT="../jl_config_back"
+
+require "logger_api"
+require "inspect_api"
+require "functions"
+
+math.randomseed(tostring(os.time()):reverse():sub(1, 6))
+
+collectgarbage()

+ 169 - 0
service/agent.lua

@@ -0,0 +1,169 @@
+local skynet = require "skynet"
+local socket = require "skynet.socket"
+local cjson = require "cjson"
+local tools = require "tools"
+local websocket = require "http.websocket"
+local mysqldbx = require "mysqldbx"
+local closing = false
+local isRunTask = false --是否在工作
+local isActive = false --是否激活
+local handle = {}
+local M = {}
+local RECV_TASK = {}
+local AGENT_ID = 0
+function handle.connect(id)
+    print("ws connect from: " .. tostring(id))
+end
+
+function handle.handshake(id, header, url)
+    local addr = websocket.addrinfo(id)
+    print("ws handshake from: " .. tostring(id), "url", url, "addr:", addr)
+    print("----header-----")
+    for k,v in pairs(header) do
+        print(k,v)
+    end
+    print("--------------")
+end
+--工人已完成
+function  M.finish_task(id, msg)
+    skynet.error("工人已完成:",cjson.encode(msg['data']))
+    isRunTask = false --等待老板发送新任务
+end
+--工人未完成
+function  M.unfinish_task(id, msg)
+    skynet.error("工人未完成:",msg['data'].error_info)
+    isRunTask = false
+end
+--工人准备工作
+function  M.status_task(id, msg)
+    skynet.error("工人准备工作:",id,msg)
+    AGENT_ID = id
+    isActive = true
+
+    skynet.fork(function()
+        RECV_TASK.updateAppConfig()
+        -- skynet.sleep(200)
+        RECV_TASK.updateFilterConfig()
+        -- skynet.sleep(200)
+        RECV_TASK.updateMainConfig()
+        -- skynet.sleep(200)
+        RECV_TASK.updatePlatformConfig()
+    end)
+
+end
+
+function handle.message(id, msg, type)
+    if msg == "ping" then
+        websocket.write(id,"pong")
+        return
+    end
+    msg = cjson.decode(msg)
+    if M[msg.cmd] then
+        M[msg.cmd](id,msg)
+    else
+        skynet.error("no find:",msg)
+    end
+
+end
+
+function handle.ping(id)
+    print("ws ping from: " .. tostring(id) .. "\n")
+end
+
+function handle.pong(id)
+    print("ws pong from: " .. tostring(id))
+end
+
+function handle.close(id, code, reason)
+    print("ws close from: " .. tostring(id), code, reason)
+    AGENT_ID = 0
+    isRunTask = false
+    isActive = false
+    closing = true
+end
+
+function handle.error(id)
+    print("ws error from: " .. tostring(id))
+end
+
+local connect = function(fd, addr)
+    if closing then
+        return
+    end
+    local protocol = "ws"
+    local ok, err = websocket.accept(fd, handle, protocol, addr)
+    if not ok then
+        skynet.error(err)
+    else
+        print("websocket connect!")
+    end
+end
+
+function RECV_TASK.isActive()
+    return isActive
+end
+
+function RECV_TASK.isRunStak()
+    return isRunTask
+end
+
+function RECV_TASK.startOneTask(msg_body)
+    skynet.error(" 收到老板的任务:",msg_body,AGENT_ID)
+    local body = cjson.decode(msg_body)
+    if AGENT_ID~=0 then
+        isRunTask = true --工人进入工作状态
+        websocket.write(AGENT_ID, cjson.encode({cmd="find_book",dy_url=body.dy_url}))
+    end
+end
+
+
+function RECV_TASK.updateAppConfig(msg_body)
+    -- local body = cjson.decode(msg_body)
+    if AGENT_ID~=0 then
+        isRunTask = true --工人进入工作状态
+        websocket.write(AGENT_ID, cjson.encode({cmd="updateAppConfig"}))
+    end
+end
+
+function RECV_TASK.updatePlatformConfig(msg_body)
+    if AGENT_ID~=0 then
+        isRunTask = true --工人进入工作状态
+        websocket.write(AGENT_ID, cjson.encode({cmd="updatePlatformConfig"}))
+    end
+end
+
+function RECV_TASK.updateMainConfig(msg_body)
+    if AGENT_ID~=0 then
+        isRunTask = true --工人进入工作状态
+        websocket.write(AGENT_ID, cjson.encode({cmd="updateMainConfig"}))
+    end
+end
+
+function RECV_TASK.updateFilterConfig(msg_body)
+    if AGENT_ID~=0 then
+        isRunTask = true --工人进入工作状态
+        websocket.write(AGENT_ID, cjson.encode({cmd="updateFilterConfig"}))
+    end
+end
+
+function RECV_TASK.addMain(msg_body)
+    if AGENT_ID~=0 then
+        isRunTask = true --工人进入工作状态
+        --根据主体匹配,筛选出需要创建推广连接的书
+        websocket.write(AGENT_ID, cjson.encode({cmd="addMain",data=msg_body}))
+    end
+end
+
+local dispatch = function(session, address,id, addr,cmd,...)
+    if(cmd=="connect") then
+        connect(id,addr)
+    else
+        local f = assert(RECV_TASK[cmd], cmd .. " not found")
+        skynet.retpack(f(...))
+    end
+end
+skynet.start(function()
+    skynet.dispatch("lua", dispatch)
+end)
+
+

+ 116 - 0
service/agent_manager.lua

@@ -0,0 +1,116 @@
+local skynet = require "skynet"
+local sockethelper = require "http.sockethelper"
+local socket = require "skynet.socket"
+local runconfig = require "run_config"
+local tools = require "tools"
+local CMD = {}
+local agents = {}
+function traceback(err)
+	skynet.error(tostring(err))
+	skynet.error(debug.traceback())
+end
+local dispatch = function(session, address, cmd, ...)
+    local fun = CMD[cmd]
+	if not fun then
+		skynet.ret()
+		return
+	end
+    local ret = table.pack(xpcall(fun, traceback, address, ...))
+	local isok = ret[1]
+	if not isok then
+		skynet.ret()
+		return
+	end
+	skynet.retpack(table.unpack(ret,2))
+end
+
+function getOneAgent()
+    -- for i = 1, #agents, 1 do
+	-- 	local isActive =  skynet.call(agents[i],"lua",nil,nil,"isActive")
+	-- 	if isActive then
+	-- 		local isRunTask = skynet.call(agents[i],"lua",nil,nil,"isRunStak")
+	-- 		if(isRunTask==false) then
+	-- 			return agents[i]
+	-- 		end
+	-- 	end
+    -- end
+	local isActive =  skynet.call(agents[1],"lua",nil,nil,"isActive")
+	if isActive then
+		return agents[1]
+	end
+    return nil
+end
+--更新筛选配置
+function CMD.updateFilterConfig(_,msg_body) 
+    local agent = getOneAgent()
+    if agent~=nil then
+        skynet.call(agent,"lua",nil,nil,"updateFilterConfig",msg_body)
+    else
+        skynet.error("把任务放到队列")
+    end
+end
+
+--更新主体配置
+function CMD.updateMainConfig(_,msg_body) 
+    local agent = getOneAgent()
+    if agent~=nil then
+        skynet.call(agent,"lua",nil,nil,"updateMainConfig",msg_body)
+    else
+        skynet.error("把任务放到队列")
+    end
+end
+
+
+--更新App配置
+function CMD.updateAppConfig(_,msg_body) 
+    local agent = getOneAgent()
+    if agent~=nil then
+        skynet.call(agent,"lua",nil,nil,"updateAppConfig",msg_body)
+    else
+        skynet.error("把任务放到队列")
+    end
+end
+
+
+--更新平台配置
+function CMD.updatePlatformConfig(_,msg_body) 
+    local agent = getOneAgent()
+    if agent~=nil then
+        skynet.call(agent,"lua",nil,nil,"updatePlatformConfig",msg_body)
+    else
+        skynet.error("把任务放到队列")
+    end
+end
+
+
+--添加主体
+function CMD.addMain(_,msg_body) 
+    local agent = getOneAgent()
+    if agent~=nil then
+        skynet.call(agent,"lua",nil,nil,"addMain",msg_body)
+    else
+        skynet.error("把任务放到队列")
+    end
+end
+--收到一个获取黑岩书的任务
+function CMD.task_get_heiyan_book() 
+    
+end
+
+skynet.start(function()
+	local protocol = "ws" 
+	-- for i= 1, 3 do --开启30个服务用来接收消息
+	-- 	agents[i] = skynet.newservice("agent", "agent", protocol)
+	-- end
+	agents[1] = skynet.newservice("agent", "agent", protocol)
+	local balance = 1
+	local id = socket.listen("0.0.0.0",runconfig.wsProt )
+	socket.start(id , function(id, addr)
+		skynet.send(agents[balance], "lua", id,addr,"connect")
+		balance = balance + 1
+		if balance > #agents then
+			balance = 1
+		end
+	end)
+    skynet.dispatch("lua", dispatch)
+end)

+ 12 - 0
service/backmgr/back_response.lua

@@ -0,0 +1,12 @@
+local skynet = require "skynet"
+local cjson = require "cjson"
+local crypt = require "client.crypt"
+local tools = require "tools"
+local M = {
+
+}
+
+M.response = function()
+    
+end
+return M

+ 224 - 0
service/backmgr/filter_task.lua

@@ -0,0 +1,224 @@
+--最大转化
+local M = {}
+local db
+local mysqldtaskbx = {}
+local mysqldbx = require "mysqldbx"
+require "skynet.manager"
+local mysql = require "skynet.db.mysql"
+local config = require "run_config"
+local tools = require "tools"
+local skynet = require "skynet"
+--获取原始数据总数
+function M.get_origin_total()
+    local sql = "SELECT COUNT(*) AS total FROM origin_data"
+    local res = mysqldbx.query(sql)
+    return true,res[1]
+end
+--获取原始数据
+function M.get_origin(msg_body)
+    local isok ,key =  tools.checkData({"page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+    local sql = string.format("SELECT * FROM origin_data ORDER BY id LIMIT %d OFFSET %d",page_size, offset)
+    local isok,res;
+    res = mysqldbx.query(sql)
+    return true,res
+end
+--获取筛选总数
+function M.get_filter_total()
+    local sql = "SELECT COUNT(*) AS total FROM filter_data"
+    local res = mysqldbx.query(sql)
+    return true,res[1]
+end
+
+
+--获取筛选数据
+function M.get_filter(msg_body)
+    local isok ,key =  tools.checkData({"page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+    local sql = string.format("SELECT * FROM filter_data ORDER BY id LIMIT %d OFFSET %d",page_size, offset)
+    local isok,res;
+    res = mysqldbx.query(sql)
+    return true,res
+end
+
+
+
+--获取书籍总数
+function M.get_book_total()
+    local sql = "SELECT COUNT(*) AS total FROM video_product"
+    local res = mysqldtaskbx.Singleton().query(sql)
+    return true,res[1]
+end
+
+
+--获取书籍
+function M.get_book(msg_body)
+    local isok ,key =  tools.checkData({"page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+    local sql = string.format("SELECT * FROM video_product ORDER BY id LIMIT %d OFFSET %d",page_size, offset)
+    local isok,res;
+    res = mysqldtaskbx.Singleton().query(sql)
+    return true,res
+end
+
+
+
+
+--获取小程序书籍总数
+function M.get_app_book_total()
+    local sql = "SELECT COUNT(*) AS total FROM video_applet_product"
+    local res = mysqldtaskbx.Singleton().query(sql)
+    return true,res[1]
+end
+
+
+--获取小程序书籍
+function M.get_app_book(msg_body)
+    local isok ,key =  tools.checkData({"page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+    local sql = string.format("SELECT * FROM video_applet_product ORDER BY id LIMIT %d OFFSET %d",page_size, offset)
+    local isok,res;
+    res = mysqldtaskbx.Singleton().query(sql)
+    return true,res
+end
+
+--设置小程序书籍状态
+function M.set_app_book_status(msg_body)
+    local isok ,key =  tools.checkData({"id_list","status"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    for i = 1, #msg_body.id_list, 1 do
+        local res,sql,id;
+        id = msg_body.id_list[i]
+        sql = string.format("UPDATE  video_applet_product SET status = %d WHERE id = %d ",msg_body.status,id)
+        res = mysqldtaskbx.Singleton().query(sql)
+    end
+    return true,{}
+end
+
+
+--获取推广数据总数
+function M.get_tui_guang_total()
+    local sql = "SELECT COUNT(*) AS total FROM video_material"
+    local res = mysqldbx.query(sql)
+    return true,res[1]
+end
+
+
+--获取推广数据
+function M.get_tui_guang(msg_body)
+    local isok ,key =  tools.checkData({"page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+    local sql = string.format("SELECT * FROM video_material ORDER BY id LIMIT %d OFFSET %d",page_size, offset)
+    local isok,res;
+    res = mysqldbx.query(sql)
+    return true,res
+end
+--推广增量
+function M.tui_guang_zeng_liang(msg_body)
+    local isok ,key =  tools.checkData({"main_id","quantity","bid_type","id_list"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local idString = table.concat(msg_body.id_list, ",")
+    local sql = string.format("SELECT * FROM video_material WHERE id IN (%s)",idString)
+    local isok,res;
+    res = mysqldbx.query(sql)
+
+    for i = 1, #res, 1 do
+        local id =   res[i].id
+        local material_id = res[i].material_id
+        sql = string.format("UPDATE  video_material SET bl_status = 1 WHERE id =%d ",id)
+        mysqldbx.query(sql)
+
+        sql = string.format("INSERT INTO `task_boost_material_queue` (material_id,main_id,quantity,bid_type)  VALUES (%d,%d,%d,%d)",
+        material_id,msg_body.main_id,msg_body.quantity,msg_body.bid_type)
+        mysqldbx.query(sql)
+
+    end
+    return true,res
+end
+
+
+--获取爆量数据总数
+function M.get_bao_liang_total()
+    local sql = "SELECT COUNT(*) AS total FROM boost_material_history"
+    local res = mysqldbx.query(sql)
+    return true,res[1]
+end
+
+
+--获取爆量数据
+function M.get_bao_liang(msg_body)
+    local isok ,key =  tools.checkData({"page_size","page_number"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local page_size = msg_body.page_size
+    local page_number = msg_body.page_number
+    local offset = (page_number - 1) * page_size
+    local sql = string.format("SELECT * FROM boost_material_history ORDER BY id LIMIT %d OFFSET %d",page_size, offset)
+    local isok,res;
+    res = mysqldbx.query(sql)
+    return true,res
+end
+
+function mysqldtaskbx.start()
+    local function on_connect(db)
+        db:query("set charset utf8mb4");
+    end
+    local conf = config.db_cnf.book_server.mysqldb_task_cnf
+    db = mysql.connect{
+        host=conf.ip,
+        port=conf.port,
+        database=conf.db,
+        user=conf.user,
+        password=conf.password,
+        charset="utf8mb4",
+        max_packet_size = 1024 * 1024,
+        on_connect = on_connect
+    }
+    if not db then
+        error("mysql connect fail")
+    end
+end
+
+
+
+function mysqldtaskbx.Singleton()
+    if db == nil then
+        mysqldtaskbx.start()
+    end
+    return mysqldtaskbx
+end
+function mysqldtaskbx.query(sql)
+    return db:query(sql)
+end
+
+return M

+ 76 - 0
service/backmgr/init.lua

@@ -0,0 +1,76 @@
+local skynet = require "skynet"
+local s = require "service"
+local tools = require "tools"
+local cjson = require "cjson"
+local mysql = require "skynet.db.mysql"
+local back_response = require "back_response"
+local urllib = require "http.url"
+local crypt = require "skynet.crypt"
+local tg_temp_app   = require "tg_temp_app"
+local tg_platform   = require "tg_platform"
+local tg_zhanghu   = require "tg_zhanghu"
+local tg_max_zhuanhua   = require "tg_max_zhuanhua"
+local user   = require "user"
+local tg_app   = require "tg_app"
+local tg_main   = require "tg_main"
+local db_filter_config = require "db_filter_config"
+local push_msg = require "push_msg"
+local filter_task = require "filter_task"
+local status_200 = 200
+local CMD = {
+    
+}
+CMD["tg_temp_app"] = tg_temp_app;
+CMD["tg_platform"] = tg_platform;
+CMD["tg_zhanghu"] = tg_zhanghu;
+CMD["tg_max_zhuanhua"] = tg_max_zhuanhua;
+CMD["tg_app"] = tg_app;
+CMD["user"] = user;
+CMD["tg_main"] = tg_main;
+CMD["db_filter_config"] = db_filter_config;
+CMD["push_msg"] = push_msg;
+CMD["filter_task"] = filter_task;
+function run(target,fun,msg_body,fd)
+    if target~=nil and fun~=nil and target[fun]~=nil then
+        local isok,data,total = target[fun](msg_body)
+        if isok then
+            if data~=nil then
+                if total~=nil then
+                    tools.response(fd,status_200,cjson.encode({code=10000,data=data,total=total}))
+                else
+                    tools.response(fd,status_200,cjson.encode({code=10000,data=data}))
+                end
+               
+            else
+                tools.response(fd,status_200,cjson.encode({code=10000,msg="OK!"}))
+            end
+        else
+            tools.response(fd,status_200,cjson.encode({code=10001,msg=data}))
+        end
+    else
+        return tools.response(fd,status_200,{code=10002,msg="没找到方法!"})
+    end
+end
+
+CMD.api = function(msg_body,fd)
+    if msg_body~=nil and msg_body~="" then
+        if CMD[msg_body['cmd']] then
+            run(CMD[msg_body['cmd']],msg_body['fun'],msg_body['data'],fd)
+        end
+    end
+end
+
+CMD.ws_push_msg = function(msg_body)
+    CMD['push_msg'].push(msg_body.cmd,msg_body.data)
+end
+--接口end
+s.resp.on_recv = function (source, fd, msg_id, msg_body)
+    if CMD[msg_id]~=nil then
+        tools.dump(msg_body)
+        CMD[msg_id](cjson.decode(msg_body),fd)
+    end
+end
+s.init = function()
+  
+end
+s.start(...)

+ 17 - 0
service/backmgr/push_msg.lua

@@ -0,0 +1,17 @@
+--推送消息
+local M = {}
+local agent_manager = nil
+local mysqldbx = require "mysqldbx"
+local tools = require "tools"
+local skynet = require "skynet"
+
+function M.push(cmd,msg_body)
+    if not agent_manager then
+        agent_manager = skynet.queryservice("agent_manager")
+    end
+    skynet.fork(function()
+        skynet.sleep(200)
+        skynet.call(agent_manager,"lua",cmd,msg_body)
+    end)
+end
+return M

+ 24 - 0
service/backmgr/user.lua

@@ -0,0 +1,24 @@
+--用户
+local M = {}
+
+local mysqldbx = require "mysqldbx"
+local tools = require "tools"
+local skynet = require "skynet"
+
+
+function M.Login(msg_body)
+    local isok ,key =  tools.checkData({"account","password"},msg_body)
+    if not isok then
+        return false,string.format("缺少字段: %s.", key)
+    end
+    local sql = string.format("SELECT * FROM admin_user WHERE account = '%s' and password = '%s' ", msg_body.account, msg_body.password)
+    local isok,res;
+    res = mysqldbx.query(sql)
+    if #res <= 0 then
+        return false ,"账号或密码错误!"
+    end
+    return true, {}
+end
+
+
+return M

+ 148 - 0
service/doc/cmd_sql.sql

@@ -0,0 +1,148 @@
+create table novel_tab (  
+	id int not null auto_increment COMMENT '唯一id',
+	book_name  varchar(1024) not null COMMENT '小说名字',
+	book_id  int DEFAULT 0 COMMENT '书id',	
+	appid int DEFAULT 0 COMMENT '小程序id',	
+	create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+	info JSON COMMENT '详情',
+	primary key (id));
+
+create table account_tab (  
+	id int not null auto_increment COMMENT '唯一id',
+	account_id   int DEFAULT 0 COMMENT '账号id',	
+	account_type   int DEFAULT 0 COMMENT '账号类型',	
+	is_open   int DEFAULT 0 COMMENT '是否开启',	
+	create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+	info JSON COMMENT '详情',
+	primary key (id));
+	create table classification_list_tab (  
+	id int not null auto_increment COMMENT '唯一id',
+	create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+	info JSON  COMMENT  '详情',
+	self_id int not NULL,
+	primary key (id));
+
+create table fan_qie_book_tab (
+	id int not null auto_increment COMMENT '唯一id',
+	book_name  varchar(1024) not null COMMENT '小说名字',
+	book_id   varchar(1024) not null COMMENT '书id',	
+	author varchar(1024) not null COMMENT '作者',
+	category varchar(1024) not null COMMENT '分类',
+	chapter_amount int not NULL COMMENT '章节数',
+	latest_update_time varchar(1024) not null COMMENT '更新时间',
+	creation_status int not null COMMENT '书本完结状态,0为已完结,1为连载中',
+	genre int not null COMMENT '体裁(设置定价时,请关注该字段)- 0:长篇网文- 8:短故事- 202:付费短剧',
+	length_type int not null COMMENT '短故事类型(设置定价时,请关注该字段)- 0:多章- 2:整本',
+	info JSON  COMMENT  '详情',
+primary key (id));
+
+
+create table auto_book_link (
+	id int not null auto_increment COMMENT '唯一id',
+	book_name  varchar(1024) DEFAULT "" COMMENT '小说名字',
+	book_id   varchar(1024) DEFAULT "" COMMENT '书id',
+	type   varchar(1024) DEFAULT "" COMMENT '类型',	
+	info JSON  COMMENT  '详情',
+primary key (id));
+
+
+create table tg_platform (
+	id int not null auto_increment COMMENT '唯一id',
+	tg_platform_id int,
+primary key (id));
+
+
+create table admin_user (  
+	id int not null auto_increment COMMENT '唯一id',
+	account   varchar(1024) DEFAULT "" COMMENT '账号',	
+	password   varchar(1024) DEFAULT "" COMMENT '密码',	
+	primary key (id));
+
+create table tg_app (  
+	id int not null auto_increment COMMENT '唯一id',
+	tg_platform_id int not null  COMMENT '平台id',	
+	app_id   varchar(1024) not null COMMENT '小程序ID',	
+	advertiser_id   varchar(1024) not null COMMENT '所属账户ID',	
+	instance_id   varchar(1024) not null COMMENT '资产ID',	
+	name   varchar(1024) not null COMMENT '小程序名称',	
+	create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+	update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+	primary key (id));
+
+create table tg_main (  
+	id int not null auto_increment COMMENT '唯一id',
+	tg_platform_id int not null  COMMENT '平台id',	
+	app_id   varchar(1024) not null COMMENT '小程序ID',	
+	main_name   varchar(1024) not null COMMENT '主体名称',	
+	create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+	update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+	primary key (id));
+
+create table db_filter_config (  
+	id int not null auto_increment COMMENT '唯一id',
+	config_id int   COMMENT '配置id',	
+	config JSON  COMMENT  '配置',
+	primary key (id));
+
+--原始数据
+create table origin_data (  
+	id int not null auto_increment COMMENT '唯一id',
+	video_id  varchar(100)  COMMENT '视频id',	
+	video_link  varchar(300)  COMMENT '视频链接',	
+	title varchar(300)  COMMENT '标题',
+	publish_time TIMESTAMP  COMMENT '发布时间',
+	kepp_num int  COMMENT '收藏数',
+	comment_num int  COMMENT '评论数',
+	like_num int  COMMENT '点赞数',
+	shared_num int  COMMENT '分享数',
+	is_guajian int  COMMENT '是否挂件',
+	guajian_link varchar(1024)  COMMENT '挂件地址',
+	primary key (id));
+
+--筛选数据
+create table filter_data (  
+	id int not null auto_increment COMMENT '唯一id',
+	info JSON  COMMENT  '详情',
+	primary key (id));
+--书籍数据
+create table book_data (  
+	id int not null auto_increment COMMENT '唯一id',
+	info JSON  COMMENT  '详情',
+	primary key (id));
+
+--收集后的数据
+create table collect_data (  
+	id int not null auto_increment COMMENT '唯一id',
+	info JSON  COMMENT  '详情',
+	primary key (id));
+
+CREATE TABLE `filter_data` (
+    `id` int NOT NULL AUTO_INCREMENT COMMENT '唯一id',
+    `video_id` varchar(100) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '视频id',
+    `video_link` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '视频链接',
+    `title` varchar(300) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '标题',
+    `publish_time` timestamp NULL DEFAULT NULL COMMENT '发布时间',
+    `kepp_num` int DEFAULT NULL COMMENT '收藏数',
+    `comment_num` int DEFAULT NULL COMMENT '评论数',
+    `like_num` int DEFAULT NULL COMMENT '点赞数',
+    `shared_num` int DEFAULT NULL COMMENT '分享数',
+    `is_guajian` int DEFAULT NULL COMMENT '是否挂件',
+	`book_id` varchar(300) DEFAULT NULL COMMENT '书id',
+	`book_name` varchar(300)  DEFAULT NULL COMMENT '书名字',
+	`genre`  int   DEFAULT 0 COMMENT '长中短分类',
+	`words`  varchar(300)   DEFAULT '0' COMMENT '字数',
+    `guajian_link` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '挂件地址',
+    `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`)
+) ENGINE = InnoDB AUTO_INCREMENT = 6470 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_general_ci
+
+
+
+create table get_fq_book_tab (  
+	id int not null auto_increment COMMENT '唯一id',
+	book_key  varchar(100)  COMMENT 'key',	
+	book_id  varchar(100)  COMMENT 'book_id',	
+	info JSON  COMMENT  '详情',
+	primary key (id));
+
+

+ 28 - 0
service/http_work/init.lua

@@ -0,0 +1,28 @@
+local skynet = require "skynet"
+-- local httpc = require "http.httpc"
+-- local httpurl = require "http.url"
+-- local dns = require "skynet.dns"
+local httpd = require "http.httpd"
+local sockethelper = require "http.sockethelper"
+local socket = require "skynet.socket"
+local cjson = require "cjson"
+local tools = require "tools"
+
+local dispatch = function(session, address,id, addr,...)
+    socket.start(id)
+    local req= tools.read_request(id)
+    if req.url == nil or #req.url==0 or req.code~=200 or #req.body==0 then
+        skynet.error(req.url)
+        skynet.error("错误访问:")
+        tools.dump({address=address,id=id,addr=addr,other=...})
+        return  tools.response(id, req.code, "error!")
+    end
+    if string.find(req.url, "tg/back/") then
+        local func_list = string.split(req.url ,"/")
+        skynet.send("backmgr","lua","on_recv",id,func_list[#func_list],req.body)
+        return
+    end
+end
+skynet.start(function()
+    skynet.dispatch("lua", dispatch)
+end)

+ 78 - 0
service/main.lua

@@ -0,0 +1,78 @@
+local skynet = require "skynet"
+
+local httpc = require "http.httpc"
+local httpurl = require "http.url"
+local dns = require "skynet.dns"
+local runconfig = require "run_config"
+local socket = require "skynet.socket"
+local httpd = require "http.httpd"
+local sockethelper = require "http.sockethelper"
+local cjson = require "cjson"
+local skynet_manager = require "skynet.manager"
+local function http_test(protocol)
+	--httpc.dns()	-- set dns server
+	httpc.timeout = 100	-- set timeout 1 second
+	print("GET baidu.com")
+	protocol = protocol or "http"
+	local respheader = {}
+	local host = string.format("%s://baidu.com", protocol)
+	print("geting... ".. host)
+	local status, body = httpc.get(host, "/", respheader)
+	print("[header] =====>")
+	for k,v in pairs(respheader) do
+		print(k,v)
+	end
+	print("[body] =====>", status)
+	print(body)
+
+	local respheader = {}
+	local ip = dns.resolve "baidu.com"
+	print(string.format("GET %s (baidu.com)", ip))
+	local status, body = httpc.get(host, "/", respheader, { host = "baidu.com" })
+	print(status)
+end
+
+local function response(id, ...)
+    local ok, err = httpd.write_response(sockethelper.writefunc(id), ...)
+    if not ok then
+        -- if err == sockethelper.socket_error , that means socket closed.
+        skynet.error(string.format("fd = %d, %s", id, err))
+    end
+end
+
+function json_test()
+    local myTable = {name = "John", age = 30, city = "New York"}
+    local jsonStr = cjson.encode(myTable)
+    print(jsonStr)
+    jsonStr = '{"name":"John","age":30,"city":"New York"}'
+    local decodedTable = cjson.decode(jsonStr)
+    print(decodedTable.name)
+    print(decodedTable.age)
+    print(decodedTable.city)
+
+end
+
+skynet.start(function()
+	skynet.uniqueservice("dbproxy", "book_server")
+
+	skynet.uniqueservice("agent_manager", "agent_manager")
+
+	local back_srv = skynet.newservice("backmgr", "backmgr", 0)
+	skynet.name("backmgr", back_srv)
+
+	--接收消息的服务
+	local httpworks = {}
+	local protocol = "http" 
+	for i= 1, 30 do --开启30个服务用来接收消息
+		httpworks[i] = skynet.newservice("http_work", "http_work", protocol)
+	end
+	local http_balance = 1
+	local id = socket.listen("0.0.0.0",runconfig.httpProt )
+	socket.start(id , function(id, addr)
+		skynet.send(httpworks[http_balance], "lua", id,addr)
+		http_balance = http_balance + 1
+		if http_balance > #httpworks then
+			http_balance = 1
+		end
+	end)
+end)

+ 20 - 0
service/tools_work/init.lua

@@ -0,0 +1,20 @@
+local skynet = require "skynet"
+local s = require "service"
+local tools = require "tools"
+local cjson = require "cjson"
+local httpc = require "http.httpc"
+local runconfig = require "run_config"
+
+
+s.resp.on_recv = function (source, fd, msg_id, msg_body)
+    skynet.error("接收一条工具消息 ",msg_id)
+    local func = string.gsub(msg_id, "/tools/", "")
+    if s.resp[func] ~=nil then
+        return s.resp[func](fd,msg_body)
+    end
+    return tools.response(fd,200,string.format("接口 %s 不存在",func))
+end
+
+
+
+s.start(...)

+ 62 - 0
service/userlog.lua

@@ -0,0 +1,62 @@
+local skynet = require "skynet"
+require "skynet.manager"
+local fd=nil
+local fname=nil
+local logfolder =nil
+
+skynet.register_protocol {
+    name = "text",
+    id = skynet.PTYPE_TEXT,
+    unpack = skynet.tostring,
+    dispatch = function(_, address, msg)
+        if not logfolder then
+            return
+        end
+        local now=os.date("*t",os.time())
+        local s=""..now.year..now.month..now.day
+        local foldername = string.format("%d_%02d_%02d.log",now.year,now.month,now.day)
+
+        local logpath=logfolder..foldername
+        if (not fname) or logpath~=fname then
+            if fd then
+                fd:close()
+                fd=nil
+            end
+            fname = logpath
+        end
+
+        if not fd then
+            fd=io.open(logpath,"a+")
+        end
+
+        if fd then
+            local content = string.format("%s:%08x(%.2f): %s",os.date("%y/%m/%d %H:%M:%S"), address, skynet.time(), msg..'\r\n')
+            print(content)
+            fd:write(content)
+            fd:flush()
+        else
+            --print(fname)
+        end
+    end
+
+}
+
+skynet.register_protocol {
+    name = "SYSTEM",
+    id = skynet.PTYPE_SYSTEM,
+    unpack = function(...) return ... end,
+    dispatch = function()
+        if not fd then
+            fd:close()
+            fname=nil
+        end
+    end
+
+}
+
+skynet.start(function()
+    skynet.error("PROJ_ROOT::",PROJ_ROOT)
+    logfolder ="../".."/log/"
+    local err=os.execute("mkdir "..logfolder)
+    skynet.register ".logger"
+end)