123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- local skynet = require "skynet"
- -- local socket = require "skynet.socket"
- -- local sprotoloader = require "sprotoloader"
- local logger = require "logger"
- local timer = require "timer"
- local player = require "model.player"
- local cjson = require "cjson"
- -- local JsSProto = require "JsSProto"
- local websocket = require "http.websocket"
- local traceback = debug.traceback
- local skynet_retpack = skynet.retpack
- local skynet_call = skynet.call
- local skynet_send = skynet.send
- local string_pack = string.pack
- local string_format = string.format
- local websocket_write = websocket.write
- local trace = logger.trace
- local warn = logger.warn
- local handle_request = player.request
- local handle_response = player.response
- local handle_command = player.command
- local handle_disconnect = player.disconnect
- local pbSproto = require "pbSproto"
- local cjson_decode = cjson.decode -- 解码
- local cjson_encode = cjson.encode -- 编码
- -- local mydispatch = JsSProto.decode
- -- local mypack = JsSProto.encode
- local mydispatch = pbSproto.decode
- local mypack = pbSproto.encode
- local fd
- -- local host = sprotoloader.load(1):host( "package")
- -- local pack = host:attach(sprotoloader.load(2))
- local abandon
- local watchdog
- local protocol
- local window = 0
- local tracker = {}
- local function write(data)
- return websocket_write(fd, data, "binary")
- end
- local function send(pname, args, callback)
- return write(mypack(pname, args))
- end
- local function kick(reason, ...)
- if abandon then return end
- if reason then
- logger.error(reason, ...)
- end
- abandon = true
- skynet_call(watchdog, "lua", "close", fd)
- end
- local kill_timer
- local function throw_exception(type, brief, linger)
- assert(type)
- brief = brief or "unknown"
- if abandon then
- return
- end
- -- send('exception', { type=type, brief=brief })
- send('exception_nty', { errno=brief })
- linger = linger or 500
- kill_timer = timer(linger, function()
- kick("exception: { type=%s, brief=%s }", type, brief)
- end)
- end
- local function dispatch_request(pname, args, response)
- if abandon then
- trace("drop a request message: %s", pname)
- return
- end
- local r = handle_request(pname, args)
- if response and r then
- write(response(r))
- end
- end
- local function dispatch_response(session, args)
- local ctx = assert(tracker[session])
- local pname = assert(ctx.pname)
- local callback = assert(ctx.callback)
- tracker[session] = nil
- if abandon then
- trace("drop a response message: %s", pname)
- return
- end
- handle_response(pname, args, callback)
- end
- skynet.register_protocol {
- name = "client",
- id = skynet.PTYPE_CLIENT,
- unpack = function (msg, sz)
- return mydispatch(msg, sz)
- end,
- dispatch = function(_, _, type, pname, ...)
- skynet.ignoreret()
- local f = (type == "REQUEST") and dispatch_request
- if f then
- local ok, msg = xpcall(f, traceback, pname, ...)
- if not ok then
- kick("pname: %s, err: %s", pname, msg)
- end
- end
- end
- }
- local CMD = {}
- function CMD.start(ctx)
- local args = assert(ctx.args)
- local gate = assert(ctx.gate)
- local ipaddr = assert(ctx.ipaddr)
- fd = assert(ctx.fd)
- watchdog = assert(ctx.watchdog)
- protocol = ctx.protocol
- websocket.forward(fd, protocol, ipaddr)
- local resp = player.start({
- args = args,
- ipaddr = ipaddr,
- send = send,
- kick = kick,
- throw_exception = throw_exception,
- pbSproto = pbSproto,
- })
- skynet_call(gate, "lua", "forward", fd)
- local skynet_sleep = skynet.sleep
- skynet.fork(function()
- collectgarbage "collect"
- while true do
- skynet_sleep(60*100)
- local kb, bytes = collectgarbage "count"
- if kb >= 4096 then
- logger.trace("内存超过4M,将启动垃圾回收")
- collectgarbage "collect"
- end
- end
- end)
- return resp
- end
- local suspend = nil
- local dispose = nil
- local function coroutine_yield()
- local co = coroutine.running()
- suspend = suspend or {}
- table.insert(suspend, co)
- skynet.wait(co)
- if dispose then
- dispose()
- end
- end
- local function coroutine_resume()
- suspend = suspend or {}
- local ref = 0
- for _, co in ipairs(suspend) do
- ref = ref + 1
- skynet.wakeup(co)
- end
- if ref > 0 then
- local co = coroutine.running()
- dispose = function()
- ref = ref - 1
- if ref == 0 then
- skynet.wakeup(co)
- end
- end
- skynet.wait(co)
- end
- end
- function CMD.disconnect()
- -- todo: do something before exit
- -- skynet.sleep(1000)
- if kill_timer then
- kill_timer()
- end
- handle_disconnect()
- websocket.clear_pool(fd)
- coroutine_resume()
- skynet.exit()
- end
- -- Reference: watchdog.command.hotfix
- function CMD.exit()
- skynet.exit()
- end
- -- Reference: usercenter.command.maintain
- function CMD.maintain(...)
- local args=select(1, ...)
- local key
- if select("#",...)==0 then
- key=STD_ERR.SERVER_START_MAINTENANCE --"服务器开始维护"
- else
- key=args
- end
- throw_exception("maintain",key, 300)
- coroutine_yield()
- end
- -- Reference: usercenter.command.login
- function CMD.multilogin()
- throw_exception("multilogin", STD_ERR.ACCOUNT_LOGGING_ANOTHER_DEVICE, 100) --"帐号正在其它设备登录"
- coroutine_yield()
- end
- function CMD.broad_cast_msg(pname, args)
- assert(pname)
- trace("CMD.broad_cast_msg: %s", pname)
- send(pname, args or {})
- end
- function CMD.kick(reason, ...)
- -- send('exception',{ type="kick", brief=reason })
- kick(reason, ...)
- end
- skynet.start(function()
- logger.label("<Agent>")
- skynet.dispatch("lua", function(session,_, cmd, ...)
- trace("handle command: '%s'", cmd)
- local f = CMD[cmd]
- if f then
- if session == 0 then
- f(...)
- else
- skynet_retpack(f(...))
- end
- else
- handle_command(session,cmd, ...)
- end
- end)
- end)
|