Blame view

src/services/agent_queued.lua 3.69 KB
5e6af9d6   zhouhaihai   排队功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  -- 排队系统
  
  require "ProtocolCode"
  require "shared.init"
  require "utils.init"
  require "GlobalVar"
  require "RedisKeys"
  require "skynet.manager"
  
  local queue = require "skynet.queue"
  local netpack = require "skynet.netpack"
  local socket = require "skynet.socket"
  local xxtea = require "xxtea"
  
  skynet = require "skynet"
  
  local MAX_COUNT = tonumber(skynet.getenv("max_queue"))
  -- 心跳定时间隔
  local HEART_TIMER_INTERVAL 		= 30
  local HEART_TIMEOUT_COUNT_MAX 	= 3
5e6af9d6   zhouhaihai   排队功能
21
22
23
24
25
26
27
28
29
  
  local CMD = {}
  local f2u = {}
  local u2i = {}	-- {idx, fd, {lastHeart, timeOutCount, nextCheck}}
  local idx2u = {}
  local curIdx = 0  -- 下一个即将进入游戏的玩家索引
  local nextIdx = 0  -- 新加的位置
  
  
5e6af9d6   zhouhaihai   排队功能
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
  local function getRank(uid)
  	local info = u2i[uid]
  	if not info then return -1 end
  	return (info[1] + MAX_COUNT - curIdx) % MAX_COUNT + 1
  end
  
  
  function SendPacket(actionCode, bin, client_fd)
  	if #bin > 0 then bin = xxtea.encrypt(bin, XXTEA_KEY) end
  	local head = string.pack("H", actionCode)
  	return socket.write(client_fd, netpack.pack(head .. bin))
  end
  
  local function checkQueue(fd)
  	if not f2u[fd] then return end
  	local info = u2i[f2u[fd]]
  	if info then
  		info[3][1] = skynet.timex()
  	end
  	local rank = getRank(f2u[fd])
  	SendPacket(actionCodes.Sys_checkQueue, MsgPack.pack({rank = rank}), fd)
  end
  
  
  skynet.register_protocol {
  	name = "client",
  	id = skynet.PTYPE_CLIENT,
  	unpack = function (msg, sz)
  		local data = skynet.tostring(msg, sz)
  		local cmd = string.unpack("H", string.sub(data, 1, 2))
  		return cmd, string.sub(data, 3)
  	end,
  	dispatch = function(session, address, cmd, data)
  		skynet.ignoreret()
e24d1abd   zhouhaihai   修改 排队
64
65
66
  		if cmd == actionCodes.Sys_checkQueue then
  			checkQueue(session)
  		end
5e6af9d6   zhouhaihai   排队功能
67
68
69
  	end
  }
  
5e6af9d6   zhouhaihai   排队功能
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  function CMD.push(uid, fd)
  	uid = tostring(uid)
  	if u2i[uid] then -- 存在]
  		local oldfd = u2i[uid][2]
  		if  oldfd and oldfd ~= fd then 
  			-- 踢掉老的
  			SendPacket(actionCodes.Sys_maintainNotice, MsgPack.pack({body = "server_accountOccupied", iskey = true}), oldfd)
  			skynet.timeout(10, function ()
  				skynet.call(gate_serv, "lua", "kick", oldfd)
  			end)
  			f2u[oldfd] = nil
  		end
  		u2i[uid][2] = fd
  		f2u[fd] = uid
  		u2i[uid][3] = {skynet.timex(), 0, skynet.timex() + HEART_TIMER_INTERVAL}
  	else -- 新排队的用户
  		if nextIdx == curIdx and next(idx2u) then -- 满了
  			return 
  		end
  		u2i[uid] = {nextIdx, fd, {skynet.timex(), 0, skynet.timex() + HEART_TIMER_INTERVAL}}
  		f2u[fd] = uid
  		idx2u[nextIdx] = uid
  		nextIdx = (nextIdx + 1) % MAX_COUNT
  	end
  	skynet.call(gate_serv, "lua", "forward", fd, 0, skynet.self())
  
  	return getRank(uid)
  end
  
  function CMD.pop()
  	while true do
  		local uid = idx2u[curIdx]
  		if not uid then return end  -- 空的
  		local info = u2i[uid]
  		if not info then
  			idx2u[curIdx] = nil
  		else
  			if info[2] then
  				-- 找到合适的了
  				u2i[uid] = nil
  				idx2u[curIdx] = nil
  				f2u[info[2]] = nil
  
  				curIdx = (curIdx + 1) % MAX_COUNT
  				return uid, info[2]
  			else
  				idx2u[curIdx] = nil
  				u2i[uid] = nil
  			end
  		end
  		curIdx = (curIdx + 1) % MAX_COUNT
  	end
  end
  
e24d1abd   zhouhaihai   修改 排队
124
  
5e6af9d6   zhouhaihai   排队功能
125
126
127
128
129
130
131
132
133
  -- 下线了
  function CMD.socket_close(fd)
  	local uid = f2u[fd]
  	if not uid then return end
  	f2u[fd] = nil
  	local info = u2i[uid]
  	info[2] = nil
  end
  
e24d1abd   zhouhaihai   修改 排队
134
  function CMD.handle_timeout()
5e6af9d6   zhouhaihai   排队功能
135
136
137
138
139
140
141
142
143
144
145
146
147
  	local now = skynet.timex()
  	for uid, info in pairs(u2i) do
  		if info[2] and info[3] and now >= info[3][3] then --存在fd 检查心跳
  			if info[3][1] -  now > HEART_TIMER_INTERVAL or now - info[3][1] > HEART_TIMER_INTERVAL then
  				info[3][2] = info[3][2] + 1
  				info[3][3] = now + HEART_TIMER_INTERVAL
  				if info[3][2] >= HEART_TIMEOUT_COUNT_MAX then
  					skynet.error("timeout! then queued will closed", info[2], uid)
  					skynet.call(gate_serv, "lua", "kick", info[2])
  				end
  			end
  		end
  	end
5e6af9d6   zhouhaihai   排队功能
148
149
  end
  
e24d1abd   zhouhaihai   修改 排队
150
151
152
  function CMD.count()
  	return (nextIdx + MAX_COUNT - curIdx) % MAX_COUNT
  end
5e6af9d6   zhouhaihai   排队功能
153
  
e24d1abd   zhouhaihai   修改 排队
154
  return CMD