-- 网关agent local skynet = require "skynet" local protoUtil = require("utils.protoUtil") local nodeUtil = require("utils.nodeUtil") 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, ptype, protoname, args, session, ud = pcall(protoUtil.decode_c2s_req_ex, protoUtil, msg) if not ok then return log.error("decode sproto faild") end if ptype ~= "REQUEST" then return log.error("This example doesn't support request client") end l_request(fd, protoname, args, session, ud) 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("wsSprotoWatchdog") 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) log.info("login uid[%s] gameNode[%s] gameAgent[%s]", tostring(uid), tostring(gameNode), tostring(gameAgent)) if is_empty(gameNode) or is_empty(gameAgent) then return false end 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 rs = protoUtil:encode_s2c_req(name, msg) skynet.send(GATE, "lua", "send_to_client", fd, rs) end -- 向所有玩家发消息 function CMD.s2c_broadcast(name, msg) local rs = protoUtil:encode_s2c_req(name, msg) for fd, _ in pairs(mapFd) do skynet.send(GATE, "lua", "send_to_client", fd, rs) end end -- 回应客户端请求 function CMD.c2s_response(uid, name, msg, session, ud) local fd = l_get_user_fd(uid) if fd == nil then return end -- log.proto("response uid=%s, name=%s, msg=%s", uid, name, tostring(msg)) local rs = protoUtil:encode_c2s_rsp_ex(name, msg, session, ud) skynet.send(GATE, "lua", "send_to_client", fd, rs) end -- 踢玩家 function CMD.kick(uid, msg) local fd = l_get_user_fd(uid) if fd == nil then return end -- 通知玩家被踢 local rs = protoUtil:encode_s2c_req("on_server_code", msg) skynet.send(GATE, "lua", "send_to_client", fd, rs) -- 关闭链接 skynet.send(WATCHDOG, "lua", "close", fd, "kick") end function CMD.recycle() skynet.exit() end function CMD.update_proto() protoUtil:update() end skynet.start( function() skynet.dispatch( "lua", function(session, address, command, ...) local f = CMD[command] if f == nil then log.error("agent command[%s] not found", tostring(command)) end if session > 0 then skynet.ret(skynet.pack(f(...))) else f(...) end end ) -- 心跳监听 l_start_fd_heart_bit() end )