summaryrefslogtreecommitdiff
path: root/server.lua
blob: 5d1ddd40ef2ec88a55845ebc676f73d06b5ef1b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
64
65
66
67
68
69
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
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