summaryrefslogtreecommitdiff
path: root/client.lua
blob: 1bf49525b1f45b0f15d5ea01097dc5eee267f55f (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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
local enet = require("enet")
local socket = require("socket")
local util = require("util")
local common = require("common")

local client = {}

local function create_client(secret)
    local clt = {}
    clt.host = enet.host_create()
    clt.secret = secret
    return clt
end

local function connect(clt, addr)
    clt.server = clt.host:connect(addr)
    clt.server_req = socket.gettime()
    clt.status = "wait_server"
end

function client.join(invite, match_addr)
    local invite_dec = util.base64_dec(invite)
    if not invite_dec then
        return nil, "invalid_invite"
    end

    local game_id = invite_dec:sub(1, common.gameid_len)
    local secret = invite_dec:sub(common.gameid_len+1)

    local clt = create_client(secret)
    clt.match = clt.host:connect(match_addr or common.default_match_addr)
    util.send(clt.match, { type = "match_join", game_id = game_id })
    clt.match_req = socket.gettime()
    clt.game_id = game_id
    clt.status = "wait_match"
    return clt
end

function client.connect(addr, secret)
    local clt = create_client(secret)
    connect(clt, addr)
    return clt
end

local function handle_match(clt, pkt)
    if pkt.type == "client_join" then
        if type(pkt.peer_addr) ~= "string" then
            print("[client] client_join: invalid peer_addr")
            return
        end
        connect(clt, pkt.peer_addr)
    elseif pkt.type == "client_join_fail" then
        clt.status = "fail_match"
    end
end

local function handle_server(clt, pkt)
    if pkt.type == "client_hi" then
        clt.status = "active"
    elseif pkt.type == "client_reject" then
        clt.status = "fail_server"
    elseif pkt.type == "client_info" then
        clt.info = pkt
    elseif pkt.type == "client_player" then
        clt.player = pkt.name
    elseif pkt.type == "client_player_fail" then
        clt.player_error = pkt.error
    end
end

function client.update(clt)
    local event = clt.host:service(20)
    while event do
        if event.type == "receive" then
            local pkt = util.json_dec(event.data)
            if pkt then
                if event.peer == clt.match and clt.status == "wait_match" then
                    handle_match(clt, pkt)
                    clt.match:disconnect()
                    clt.match = nil
                elseif event.peer == clt.server then
                    handle_server(clt, pkt)
                end
            end
        elseif event.type == "connect" then
            if event.peer == clt.match and clt.status == "wait_match" then
                util.send(clt.match, { type = "match_join", game_id = util.base64_enc(clt.game_id) })
            elseif event.peer == clt.server and clt.status == "wait_server" then
                util.send(clt.server, { type = "server_hi", secret = util.base64_enc(clt.secret) })
            else
                event.peer:disconnect_now()
            end
            print("[client] connect " .. tostring(event.peer))
        elseif event.type == "disconnect" then
            print("[client] disconnect " .. tostring(event.peer))
            if event.peer == clt.server and clt.status == "active" then
                clt.status = "disco"
            end
        end
        event = clt.host:service()
    end
end

function client.status(clt)
    if clt.status == "wait_match" and clt.match_req+3 < socket.gettime() then
        clt.status = "timeout_match"
    elseif clt.status == "wait_server" and clt.server_req+5 < socket.gettime() then
        clt.status = "timeout_server"
    end

    return clt.status
end

function client.select_player(clt, name, create)
    util.send(clt.server, {
        type = "server_player",
        name = name,
        create = create,
    })
end

function client.close(clt)
    if clt.match then clt.match:disconnect() end
    if clt.server then clt.server:disconnect() end
    clt.host:flush()
    clt.host:destroy()
end

return client