local enet = require("enet") local socket = require("socket") local util = require("util") local common = require("common") local server = {} function server.create(match_addr) local srv = {} srv.host = enet.host_create() srv.secret = util.rand_string(common.secret_len) srv.clients = {} srv.match = srv.host:connect(match_addr or common.default_match_addr) srv.match_req = socket.gettime() return srv end local function handle_match(srv, pkt) if pkt.type == "server_match" then local game_id = type(pkt.game_id) == "string" and util.base64_dec(pkt.game_id) if not game_id then print("[server] server_match: invalid game_id") return end if srv.game_id then print("[server] server_match: received while game already running") return end srv.game_id = game_id srv.invite = util.base64_enc(srv.game_id .. srv.secret) elseif pkt.type == "server_join" then if type(pkt.peer_addr) ~= "string" then print("[server] server_join: invalid peer_addr") return end srv.host:connect(pkt.peer_addr) end end local function handle_client(srv, peer, pkt) if pkt.type == "server_hi" then local secret = type(pkt.secret) == "string" and util.base64_dec(pkt.secret) if not secret then print("[server] server_hi: invalid secret") return end if srv.clients[peer] then print("[server] server_hi: client already connected") return end if secret == srv.secret then print("[server] auth success " .. tostring(peer)) srv.clients[peer] = { peer = peer } peer:send(util.json_enc({ type = "client_hi" })) else print("[server] auth failure " .. tostring(peer)) peer:send(util.json_enc({ type = "client_reject" })) peer:disconnect_later() end end end function server.update(srv) local event = srv.host:service(20) while event do if event.type == "receive" then local pkt = util.json_dec(event.data) if pkt then if event.peer == srv.match then handle_match(srv, pkt) else handle_client(srv, event.peer, pkt) end end elseif event.type == "connect" then if event.peer == srv.match then srv.match:send(util.json_enc({ type = "match_register" })) end print("[server] connect " .. tostring(event.peer)) elseif event.type == "disconnect" then print("[server] disconnect " .. tostring(event.peer)) if event.peer == srv.match then -- TODO else srv.clients[event.peer] = nil end end event = srv.host:service() end end function server.match_status(srv) if srv.game_id then return "active", srv.invite elseif srv.match_req + 3 >= socket.gettime() then return "wait" else return "fail" end end function server.close(srv) srv.host:destroy() end return server