-- 网关agent local skynet = require "skynet" local code = require "code" local nodeUtil = require("utils.nodeUtil") local protobufUtil = require("utils.protobufUtil") local CMD = {} local GATE, WATCHDOG local mapFd = {} -- MAP, key fd; value {uid=uid, heart=0} local mapUid2Session = {} -- MAP, key uid; value session -- 断开非活跃链接 local function l_start_fd_heart_bit() skynet.fork( function(...) while true do for fd, v in pairs(mapFd) do if skynet_time() - v.heart >= 60 then skynet.send(WATCHDOG, "lua", "close", fd, "overTime") end end skynet.sleep(200) -- 20s end end ) end local function l_request(fd, protoname, args, ...) local fdInfo = mapFd[fd] if fdInfo == nil or fdInfo.uid == nil then -- fd未绑定玩家 return end local uid = fdInfo.uid local session = mapUid2Session[uid] if not session then return end -- 修改fd心跳时间 fdInfo.heart = skynet_time() -- 转发给游戏服 args.uid = args.uid or uid nodeUtil:send_to_node(session.gameNode, session.gameAgent, "c2s_forward", uid, protoname, args, ...) end local function l_dispath_msg(fd, msg) -- 解析协议 local ok, protoname, args, response, session = pcall(protobufUtil.parse_protobuf_data, msg) if not ok then return log.error("decode sproto faild") end l_request(fd, protoname, args, session) end -- 获取玩家fd local function l_get_user_fd(uid) if uid == nil then return end local session = mapUid2Session[uid] if session then return session.fd end end skynet.register_protocol { name = "client", id = skynet.PTYPE_CLIENT, unpack = skynet.tostring, dispatch = function(fd, address, msg) skynet.ignoreret() l_dispath_msg(fd, msg) end } -- from watchdog function CMD.login(uid, fd) GATE = GATE or skynet.queryservice("srvGate") WATCHDOG = WATCHDOG or skynet.queryservice("wsWatchdog") local session = mapUid2Session[uid] if session then if session.fd then mapFd[fd] = nil end session.fd = fd else -- 分配游戏服节点/agent local gameNode, gameAgent = nodeUtil:user_dispatch_game_node_and_agent(uid) session = { fd = fd, uid = uid, gateNode = skynet.getenv("nodeName"), gateAgent = skynet.self(), gameNode = gameNode, gameAgent = gameAgent } end local fdInfo = {uid = uid, heart = skynet_time()} mapFd[fd] = fdInfo mapUid2Session[uid] = session -- 通知gameAgent 玩家登陆 local ok = nodeUtil:call_to_game_agent(session.gameNode, session.gameAgent, "login", uid, session) if not ok then log.error("uid:%s send game to login error", uid) return false end -- 接收客户端协议 _, ok = pcall(skynet.call, GATE, "lua", "fd_band_agent", fd) if not ok then log.error("uid:%s send gate to fd_band_agent", tostring(uid)) return false end nodeUtil:user_master_band_node(uid) return true end -- from watchdog function CMD.logout(uid) local session = mapUid2Session[uid] if not session then return end local fd = session.fd if fd then mapFd[fd] = nil end session.fd = nil -- 玩家登出 nodeUtil:call_to_game_agent(session.gameNode, session.gameAgent, "logout", uid, session) nodeUtil:user_master_unband_node(uid) if uid then mapUid2Session[uid] = nil end end -- 向玩家发消息 function CMD.s2c(uid, name, msg) local fd = l_get_user_fd(uid) if fd == nil then return end -- log.proto("push uid=%s, name=%s, msg=%s", uid, name, tostring(msg)) local data = protobufUtil.pack_push_msg(name, msg) skynet.send(GATE, "lua", "send_to_client", fd, data) end -- 回应客户端请求 function CMD.c2s_response(uid, name, msg, session, ud) local fd = l_get_user_fd(uid) if fd == nil then return end if is_empty(name) or msg == nil then return end local data = protobufUtil.pack_response_msg(name, msg, session) if data == nil then msg = {code = code.INNER_SERVER_ERROR} data = protobufUtil.pack_response_msg(name, msg, session) end skynet.send(GATE, "lua", "send_to_client", fd, data) end -- 踢玩家 function CMD.kick(uid, msg) local fd = l_get_user_fd(uid) if fd == nil then return end -- 通知玩家被踢 local data = protobufUtil.pack_push_msg("on_server_code", msg) skynet.send(GATE, "lua", "send_to_client", fd, data) -- 关闭链接 skynet.send(WATCHDOG, "lua", "close", fd, "kick") end function CMD.recycle() skynet.exit() end function CMD.update_proto() end skynet.start( function() skynet.dispatch( "lua", function(session, address, command, ...) local f = CMD[command] if session > 0 then skynet.ret(skynet.pack(f(...))) else f(...) end end ) -- 心跳监听 l_start_fd_heart_bit() end )