local M = {} local clients = {} local socket_client_mapping = {} local activerooms = {} local ping_interval = 6 M.ping_interval = ping_interval local debug_mode = true local function debug(...) if debug_mode then print(...) end end local json = require("dkjson") local db = require("messagelog") local room_metatable = { __index = { join = function(self, client) self.users[client] = 1 debug("client joined &"..self.name) end, leave = function(self, client) self.users[client] = nil debug("client left &"..self.name) end, } } local client_metatable = { __index = { onmessage = function(self, m) local msg = json.decode(m) debug("client sent message ",m) if not msg or not type(msg.data) == "table" or not type(msg.type) == "string" then return end local data = msg.data if msg.type == "ping" then self:reply(msg, { data = { time = msg.data.time } }) if not self.joined then self.joined = true try(self.room):join(self) end end end, disconnect = function(self) if self.joined then activerooms[self.room]:leave(self) end clients[self] = nil end, send_event = function(self, tbl) local s = json.encode(tbl) self.s:send(s) end, reply = function(self, original, reply) reply.id = original.id reply.type = original.type .. "-reply" local s = json.encode(reply) self.s:send(s) end, ping = function(self) self:send_event { type = "ping-event", data = { time = os.time(), next = os.time() + 6, } } end, } } local function try_room(r) if activerooms[r] then return activerooms[r] end local res = { users = {}, name = r, } setmetatable(res, room_metatable) activerooms[r] = res return res end function M.getclient(s) return socket_client_mapping[s] end function M.onsocket(s, room) local client = { s = s, room = room, joined = false, last_ping_time = os.time(), } setmetatable(client,client_metatable) socket_client_mapping[s] = client clients[client] = 1 end function M.onclose(s) local client = M.getclient(s) if not client then return end client:disconnect() socket_client_mapping[s] = nil end function M.onmessage(s,m) local client = M.getclient(s) client:onmessage(m) end function M.last_ping(s) local client = M.getclient(s) return client.last_ping_time end function M.ping(s) local client = M.getclient(s) client:ping() end return M