aboutsummaryrefslogtreecommitdiff
path: root/lib/client/sharder/shard.ml
blob: 7be4aad886d8129edd0df62f53cda085dddcde97 (plain) (blame)
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
open Lwt.Infix
open Websocket

type t = {
    send: (Frame.t -> unit Lwt.t);
    id: int;
    total_shards: int;
    hb_interval: int;
    session_id: string;
    seq: int;
    token: string;
}

let init ?(hb_interval=42500) ?(session_id="") ?(seq=0) ~send ~id ~total_shards ~token () =
    { send; id; total_shards; hb_interval; session_id; seq; token; }

let push_frame shard frame =
    shard.send frame

let process_frame shard frame =
    let json = frame |> Yojson.Basic.from_string in
    match json with
    | `Assoc [("s", `Int _s); ("d", _d); ("t", `String _t); ("op", `Int op);] -> begin
        match op |> Opcode.from_int with
        | DISPATCH -> () (* dispatch t d  Need to write the dispatcher and other ops *)
        | HEARTBEAT -> ()
        | IDENTIFY -> ()
        | STATUS_UPDATE -> ()
        | VOICE_STATE_UPDATE -> ()
        | RESUME -> ()
        | RECONNECT -> ()
        | REQUEST_GUILD_MEMBERS -> ()
        | INVALID_SESSION -> ()
        | HELLO -> ()
        | HEARTBEAT_ACK -> ()
        |> ignore;
        (* { shard with seq = s; } *)
    end
    | _ -> shard

let wrap_payload d op =
    `Assoc [
        ("op", `Int op);
        ("d", d)
    ]

let create_frame content =
    Frame.create ~content ()

let identify ?(threshold=250) shard=
    let p = wrap_payload (`Assoc [
        ("token", `String shard.token);
        ("properties", `Assoc [
            ("$os", `String Sys.os_type);
            ("$browser", `String "animus");
            ("$device", `String "animus");
        ]);
        ("large_threshold", `Int threshold);
        ("shard", `List [`Int shard.id; `Int shard.total_shards]);
    ]) (Opcode.to_int IDENTIFY) in
    push_frame shard (Yojson.Basic.to_string p |> create_frame)

let resume shard =
    let p = wrap_payload (`Assoc [
        ("token", `String shard.token);
        ("session_id", `String shard.session_id);
        ("seq", `Int shard.seq);
    ]) (Opcode.to_int RESUME) in
    push_frame shard (Yojson.Basic.to_string p |> create_frame)

let heartbeat shard =
    let p = wrap_payload (`Int shard.seq) (Opcode.to_int HEARTBEAT) in
    push_frame shard (Yojson.Basic.to_string p |> create_frame)

let connect ~_options ~uri ~id ~total ~token () =
    let url = uri |> Uri.to_string in
    let ip = Ipaddr.V4 Ipaddr.V4.any in
    let client = Websocket.Connected_Client.create
    Websocket_lwt.with_connection (`TLS (`Hostname url, `IP ip, `Port 443)) uri (* Maybe use upgrade_connection? *)
    >|= fun (recv, send) ->
    init ~send ~id ~token ~total_shards:total ()