aboutsummaryrefslogtreecommitdiff
path: root/lib/client
diff options
context:
space:
mode:
Diffstat (limited to 'lib/client')
-rw-r--r--lib/client/client.ml85
-rw-r--r--lib/client/sharder.ml483
-rw-r--r--lib/client/sharder.mli138
3 files changed, 557 insertions, 149 deletions
diff --git a/lib/client/client.ml b/lib/client/client.ml
index b1f6f25..e07e348 100644
--- a/lib/client/client.ml
+++ b/lib/client/client.ml
@@ -1,5 +1,80 @@
-let notify t data =
- Yojson.Basic.pretty_print Format.std_formatter @@ `Assoc data;
- print_newline ();
- print_endline t;
- () \ No newline at end of file
+open Async
+
+type t = {
+ sharder: Sharder.t Ivar.t;
+ (* events: (Events.t, Core_kernel.write) Bvar.t list; *)
+ mutable handler: Sharder.handler;
+ token: string;
+}
+
+let make ?handler token =
+ let handler = match handler with
+ | Some h -> h
+ | None -> begin
+ Sharder.{
+ ready = None;
+ resumed = None;
+ channel_create = None;
+ channel_delete = None;
+ channel_update = None;
+ channel_pins_update = None;
+ guild_create = None;
+ guild_delete = None;
+ guild_update = None;
+ guild_ban_add = None;
+ guild_ban_remove = None;
+ guild_emojis_update = None;
+ guild_integrations_update = None;
+ guild_member_add = None;
+ guild_member_remove = None;
+ guild_member_update = None;
+ guild_members_chunk = None;
+ guild_role_create = None;
+ guild_role_delete = None;
+ guild_role_update = None;
+ message_create = None;
+ message_delete = None;
+ message_update = None;
+ message_delete_bulk = None;
+ message_reaction_add = None;
+ message_reaction_remove = None;
+ message_reaction_remove_all = None;
+ presence_update = None;
+ typing_start = None;
+ user_update = None;
+ voice_state_update = None;
+ voice_server_update = None;
+ webhooks_update = None;
+ }
+ end in
+ {
+ sharder = Ivar.create ();
+ handler;
+ token;
+ }
+
+let start ?count client =
+ Sharder.start ?count ~handler:client.handler client.token
+ >>| fun sharder ->
+ Ivar.fill_if_empty client.sharder sharder;
+ client
+
+let on ev client fn =
+ match ev with
+ | "MESSAGE_CREATE" -> client.handler <- { client.handler with message_create = Some(fn) }
+ | _ -> ()
+
+let set_status client status =
+ Ivar.read client.sharder
+ >>= fun sharder ->
+ Sharder.set_status sharder status
+
+let set_status_with client f =
+ Ivar.read client.sharder
+ >>= fun sharder ->
+ Sharder.set_status_with sharder f
+
+let request_guild_members ~guild ?query ?limit client =
+ Ivar.read client.sharder
+ >>= fun sharder ->
+ Sharder.request_guild_members ~guild ?query ?limit sharder \ No newline at end of file
diff --git a/lib/client/sharder.ml b/lib/client/sharder.ml
index 18d1da0..652358f 100644
--- a/lib/client/sharder.ml
+++ b/lib/client/sharder.ml
@@ -1,51 +1,77 @@
-open Lwt.Infix
-open Websocket
+open Async
+open Core
+open Websocket_async
exception Invalid_Payload
-exception Invalid_Shards
-type data = {
- shards: int list;
- token: string;
- url: string;
+type handler = {
+ ready: (Yojson.Basic.json -> unit) option;
+ resumed: (Yojson.Basic.json -> unit) option;
+ channel_create: (Yojson.Basic.json -> unit) option;
+ channel_delete: (Yojson.Basic.json -> unit) option;
+ channel_update: (Yojson.Basic.json -> unit) option;
+ channel_pins_update: (Yojson.Basic.json -> unit) option;
+ guild_create: (Yojson.Basic.json -> unit) option;
+ guild_delete: (Yojson.Basic.json -> unit) option;
+ guild_update: (Yojson.Basic.json -> unit) option;
+ guild_ban_add: (Yojson.Basic.json -> unit) option;
+ guild_ban_remove: (Yojson.Basic.json -> unit) option;
+ guild_emojis_update: (Yojson.Basic.json -> unit) option;
+ guild_integrations_update: (Yojson.Basic.json -> unit) option;
+ guild_member_add: (Yojson.Basic.json -> unit) option;
+ guild_member_remove: (Yojson.Basic.json -> unit) option;
+ guild_member_update: (Yojson.Basic.json -> unit) option;
+ guild_members_chunk: (Yojson.Basic.json -> unit) option; (* Not sure if this should be exposed *)
+ guild_role_create: (Yojson.Basic.json -> unit) option;
+ guild_role_delete: (Yojson.Basic.json -> unit) option;
+ guild_role_update: (Yojson.Basic.json -> unit) option;
+ message_create: (Yojson.Basic.json -> unit) option;
+ message_delete: (Yojson.Basic.json -> unit) option;
+ message_update: (Yojson.Basic.json -> unit) option;
+ message_delete_bulk: (Yojson.Basic.json -> unit) option;
+ message_reaction_add: (Yojson.Basic.json -> unit) option;
+ message_reaction_remove: (Yojson.Basic.json -> unit) option;
+ message_reaction_remove_all: (Yojson.Basic.json -> unit) option;
+ presence_update: (Yojson.Basic.json -> unit) option;
+ typing_start: (Yojson.Basic.json -> unit) option;
+ user_update: (Yojson.Basic.json -> unit) option;
+ voice_state_update: (Yojson.Basic.json -> unit) option;
+ voice_server_update: (Yojson.Basic.json -> unit) option;
+ webhooks_update: (Yojson.Basic.json -> unit) option;
}
module Shard = struct
type t = {
- mutable hb: Lwt_engine.event option;
+ mutable hb: unit Ivar.t option;
mutable seq: int;
mutable session: string option;
+ mutable handler: handler;
token: string;
- shard: int list;
- send: Frame.t -> unit Lwt.t;
- recv: unit -> Frame.t Lwt.t;
- ready: unit Lwt.t;
+ shard: int * int;
+ write: string Pipe.Writer.t;
+ read: string Pipe.Reader.t;
+ ready: unit Ivar.t;
}
- let id_rt = Lwt_mutex.create ()
+ let identify_lock = Mutex.create ()
- let parse (frame : Frame.t) =
- frame.content
- |> Yojson.Basic.from_string
+ let parse frame =
+ match frame with
+ | `Ok s -> Yojson.Basic.from_string s
+ | `Eof -> raise Invalid_Payload
- let encode term =
- let content = term |> Yojson.Basic.to_string in
- Frame.create ~content ()
-
- let push_frame ?payload shard (ev : Opcode.t) =
+ let push_frame ?payload shard ev =
print_endline @@ "Pushing frame. OP: " ^ Opcode.to_string @@ ev;
let content = match payload with
- | None -> None
+ | None -> ""
| Some p ->
- Some (Yojson.Basic.to_string @@ `Assoc [
+ Yojson.Basic.to_string @@ `Assoc [
("op", `Int (Opcode.to_int ev));
("d", p);
- ])
+ ]
in
- let frame = Frame.create ?content () in
- print_endline @@ Frame.show frame;
- shard.send frame
- >|= fun () ->
+ Pipe.write shard.write content
+ >>| fun () ->
shard
let heartbeat shard =
@@ -59,24 +85,184 @@ module Shard = struct
] in
push_frame ~payload shard HEARTBEAT
- let dispatch shard payload resolver =
- let t = List.assoc "t" payload
- |> Yojson.Basic.Util.to_string in
- let seq = List.assoc "s" payload
- |> Yojson.Basic.Util.to_int in
- let data = List.assoc "d" payload
- |> Yojson.Basic.Util.to_assoc in
+ let dispatch shard payload =
+ let module J = Yojson.Basic.Util in
+ let seq = J.(member "s" payload |> to_int) in
shard.seq <- seq;
+ let t = J.(member "t" payload |> to_string) in
+ let data = J.member "d" payload in
let _ = match t with
- | "READY" ->
- Lwt.wakeup resolver ();
- let session = List.assoc "session_id" data
- |> Yojson.Basic.Util.to_string in
+ | "READY" -> begin
+ Ivar.fill_if_empty shard.ready ();
+ let session = J.(member "session_id" data |> to_string) in
shard.session <- Some session;
+ match shard.handler.ready with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "RESUMED" -> begin
+ match shard.handler.resumed with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "CHANNEL_CREATE" -> begin
+ match shard.handler.channel_create with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "CHANNEL_DELETE" -> begin
+ match shard.handler.channel_delete with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "CHANNEL_UPDATE" -> begin
+ match shard.handler.channel_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "CHANNEL_PINS_UPDATE" -> begin
+ match shard.handler.channel_pins_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_CREATE" -> begin
+ match shard.handler.guild_create with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_DELETE" -> begin
+ match shard.handler.guild_delete with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_UPDATE" -> begin
+ match shard.handler.guild_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_BAN_ADD" -> begin
+ match shard.handler.guild_ban_add with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_BAN_REMOVE" -> begin
+ match shard.handler.guild_ban_remove with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_EMOJIS_UPDATE" -> begin
+ match shard.handler.guild_emojis_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_INTEGRATIONS_UPDATE" -> begin
+ match shard.handler.guild_integrations_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_MEMBER_ADD" -> begin
+ match shard.handler.guild_member_add with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_MEMBER_REMOVE" -> begin
+ match shard.handler.guild_member_remove with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_MEMBER_UPDATE" -> begin
+ match shard.handler.guild_member_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_MEMBERS_CHUNK" -> begin
+ match shard.handler.guild_members_chunk with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_ROLE_CREATE" -> begin
+ match shard.handler.guild_role_create with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_ROLE_DELETE" -> begin
+ match shard.handler.guild_role_delete with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "GUILD_ROLE_UPDATE" -> begin
+ match shard.handler.guild_role_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "MESSAGE_CREATE" -> begin
+ match shard.handler.message_create with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "MESSAGE_DELETE" -> begin
+ match shard.handler.message_delete with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "MESSAGE_UPDATE" -> begin
+ match shard.handler.message_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "MESSAGE_DELETE_BULK" -> begin
+ match shard.handler.message_delete_bulk with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "MESSAGE_REACTION_ADD" -> begin
+ match shard.handler.message_reaction_add with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "MESSAGE_REACTION_REMOVE" -> begin
+ match shard.handler.message_reaction_remove with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "MESSAGE_REACTION_REMOVE_ALL" -> begin
+ match shard.handler.message_reaction_remove_all with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "PRESENCE_UPDATE" -> begin
+ match shard.handler.presence_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "TYPING_START" -> begin
+ match shard.handler.typing_start with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "USER_UPDATE" -> begin
+ match shard.handler.user_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "VOICE_STATE_UPDATE" -> begin
+ match shard.handler.voice_state_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "VOICE_SERVER_UPDATE" -> begin
+ match shard.handler.voice_server_update with
+ | Some f -> f data
+ | None -> ()
+ end
+ | "WEBHOOKS_UPDATE" -> begin
+ match shard.handler.webhooks_update with
+ | Some f -> f data
+ | None -> ()
+ end
| _ -> ()
in
- Client.notify t data;
- Lwt.return shard
+ return shard
let set_status shard status =
let payload = match status with
@@ -102,7 +288,8 @@ module Shard = struct
]
| _ -> raise Invalid_Payload
in
- shard.ready >|= fun _ -> push_frame ~payload shard STATUS_UPDATE
+ Ivar.read shard.ready >>= fun _ ->
+ push_frame ~payload shard STATUS_UPDATE
let request_guild_members ~guild ?(query="") ?(limit=0) shard =
let payload = `Assoc [
@@ -110,28 +297,28 @@ module Shard = struct
("query", `String query);
("limit", `Int limit);
] in
- shard.ready >|= fun _ -> push_frame ~payload shard REQUEST_GUILD_MEMBERS
-
-
+ Ivar.read shard.ready >>= fun _ ->
+ push_frame ~payload shard REQUEST_GUILD_MEMBERS
let initialize shard data =
- print_endline "Initializing...";
+ let module J = Yojson.Basic.Util in
let hb = match shard.hb with
| None -> begin
- let hb_interval = List.assoc "heartbeat_interval" @@
- Yojson.Basic.Util.to_assoc data
- |> Yojson.Basic.Util.to_int
- in
- Lwt_engine.on_timer
- (Float.of_int hb_interval /. 1000.0)
- true
- (fun _ev -> heartbeat shard |> ignore)
+ let hb_interval = J.(member "heartbeat_interval" data |> to_int) in
+ let finished = Ivar.create () in
+ Clock.every'
+ ~continue_on_error:true
+ ~finished
+ (Core.Time.Span.create ~ms:hb_interval ())
+ (fun () -> heartbeat shard >>= fun _ -> return ());
+ finished
end
| Some s -> s
in
shard.hb <- Some hb;
- Lwt_mutex.lock id_rt
- >>= fun () ->
+ Mutex.lock identify_lock;
+ let (cur, max) = shard.shard in
+ let shards = [`Int cur; `Int max] in
match shard.session with
| None ->
let payload = `Assoc [
@@ -143,7 +330,7 @@ module Shard = struct
]);
("compress", `Bool false); (* TODO add compression handling*)
("large_threshold", `Int 250);
- ("shard", `List (List.map (fun i -> `Int i) shard.shard))
+ ("shard", `List shards);
] in
push_frame ~payload shard IDENTIFY
| Some s ->
@@ -153,119 +340,127 @@ module Shard = struct
("seq", `Int shard.seq)
] in
push_frame ~payload shard RESUME
- >|= fun s ->
- Lwt_engine.on_timer 5.0 false (fun _ -> Lwt_mutex.unlock id_rt)
+ >>| fun s ->
+ Clock.after (Core.Time.Span.create ~sec:5 ())
+ >>| (fun _ -> Mutex.unlock identify_lock)
|> ignore;
s
- let handle_frame shard (term : Yojson.Basic.json) resolver =
- match term with
- | `Assoc term -> begin
- (* Yojson.Basic.pretty_print Format.std_formatter @@ `Assoc term;
- print_newline (); *)
- let op = List.assoc "op" term
- |> Yojson.Basic.Util.to_int
+ let handle_frame shard term =
+ let module J = Yojson.Basic.Util in
+ let op = J.(member "op" term |> to_int)
|> Opcode.from_int
- in
- match op with
- | DISPATCH -> dispatch shard term resolver
- | HEARTBEAT -> heartbeat shard
- | RECONNECT -> print_endline "OP 7"; Lwt.return shard (* TODO reconnect *)
- | INVALID_SESSION -> print_endline "OP 9"; Lwt.return shard (* TODO invalid session *)
- | HELLO -> initialize shard @@ List.assoc "d" term
- | HEARTBEAT_ACK -> Lwt.return shard
- | opcode ->
- print_endline @@ "Invalid Opcode:" ^ Opcode.to_string opcode;
- Lwt.return shard
- end
- | _ ->
- print_endline "Invalid payload";
- Lwt.return shard
+ in
+ match op with
+ | DISPATCH -> dispatch shard term
+ | HEARTBEAT -> heartbeat shard
+ | RECONNECT -> print_endline "OP 7"; return shard (* TODO reconnect *)
+ | INVALID_SESSION -> print_endline "OP 9"; return shard (* TODO invalid session *)
+ | HELLO -> initialize shard @@ J.member "d" term
+ | HEARTBEAT_ACK -> return shard
+ | opcode ->
+ print_endline @@ "Invalid Opcode:" ^ Opcode.to_string opcode;
+ return shard
- let create data =
- let uri = (data.url ^ "?v=6&encoding=json") |> Uri.of_string in
- let http_uri = Uri.with_scheme uri (Some "https") in
- let headers = Http.Base.process_request_headers () in
- Resolver_lwt.resolve_uri ~uri:http_uri Resolver_lwt_unix.system >>= fun endp ->
- let ctx = Conduit_lwt_unix.default_ctx in
- Conduit_lwt_unix.endp_to_client ~ctx endp >>= fun client ->
- Websocket_lwt_unix.with_connection
- ~extra_headers:headers
- client
- uri
- >>= fun (recv, send) ->
- let (ready, ready_resolver) = Lwt.task () in
- let rec recv_forever s = begin
- s.recv ()
- >>= fun frame ->
- let p = parse frame in
- handle_frame s p ready_resolver
- >>= fun s -> recv_forever s
- end in
- let shard = {
- send;
- recv;
- ready;
- hb = None;
- seq = 0;
- shard = data.shards;
- session = None;
- token = data.token;
- } in
- Lwt.return (shard, recv_forever shard)
+ let create ~url ~shards ~token ~handler () =
+ let open Core in
+ let uri = (url ^ "?v=6&encoding=json") |> Uri.of_string in
+ let extra_headers = Http.Base.process_request_headers () in
+ let host = Option.value_exn ~message:"no host in uri" Uri.(host uri) in
+ let port =
+ match Uri.port uri, Uri_services.tcp_port_of_uri uri with
+ | Some p, _ -> p
+ | None, Some p -> p
+ | _ -> 443 in
+ let scheme = Option.value_exn ~message:"no scheme in uri" Uri.(scheme uri) in
+ let tcp_fun (r,w) =
+ let (read, write) = client_ez
+ ~extra_headers
+ uri r w
+ in
+ let rec ev_loop shard =
+ Pipe.read read
+ >>= fun frame ->
+ handle_frame shard @@ parse frame
+ >>= fun shard ->
+ ev_loop shard
+ in
+ let shard = {
+ read;
+ write;
+ handler;
+ ready = Ivar.create ();
+ hb = None;
+ seq = 0;
+ shard = shards;
+ session = None;
+ token = token;
+ }
+ in
+ ev_loop shard |> ignore;
+ return shard
+ in
+ match Unix.getaddrinfo host (string_of_int port) [] with
+ | [] -> failwithf "DNS resolution failed for %s" host ()
+ | { ai_addr; _ } :: _ ->
+ let addr =
+ match scheme, ai_addr with
+ | _, ADDR_UNIX path -> `Unix_domain_socket path
+ | "https", ADDR_INET (h, p)
+ | "wss", ADDR_INET (h, p) ->
+ let h = Ipaddr_unix.of_inet_addr h in
+ `OpenSSL (h, p, Conduit_async.V2.Ssl.Config.create ())
+ | _, ADDR_INET (h, p) ->
+ let h = Ipaddr_unix.of_inet_addr h in
+ `TCP (h, p)
+ in
+ Conduit_async.V2.connect addr >>= tcp_fun
end
-type 'a t = {
- shards: (Shard.t * 'a Lwt.t) list;
- promise: 'a Lwt.t;
+type t = {
+ shards: Shard.t list;
}
-let start ?count token =
- Http.get_gateway_bot ()
- >|= fun data ->
- let data = Yojson.Basic.Util.to_assoc data in
- let url = List.assoc "url" data
- |> Yojson.Basic.Util.to_string in
+let start ?count ~handler token =
+ let module J = Yojson.Basic.Util in
+ Http.get_gateway_bot () >>= fun data ->
+ let url = J.(member "url" data |> to_string) in
let count = match count with
| Some c -> c
- | None -> List.assoc "shards" data
- |> Yojson.Basic.Util.to_int
+ | None -> J.(member "shards" data |> to_int)
in
- let shard_list = [0; count] in
- let rec gen_shards l accum =
+ let shard_list = (0, count) in
+ let rec gen_shards l a =
match l with
- | [id; total;] when id < total ->
- let shard_data = Lwt_main.run @@ Shard.create {
- url;
- shards = [id; total;];
- token;
- } in
- shard_data :: gen_shards [id+1; total;] accum
- | [_; _;] -> accum
- | _ -> raise Invalid_Shards
+ | (id, total) when id >= total -> return a
+ | (id, total) ->
+ Shard.create ~url ~shards:(id, total) ~token ~handler ()
+ >>= fun shard ->
+ let a = shard :: a in
+ gen_shards (id+1, total) a
in
- let shards = gen_shards shard_list [] in
- let p_list = List.map (fun (_, loop) -> loop) shards in
- let promise = Lwt.choose p_list in
+ gen_shards shard_list []
+ >>| fun shards ->
{
shards;
- promise;
}
let set_status sharder status =
- List.map (fun (shard, _) ->
+ Deferred.all @@ List.map ~f:(fun shard ->
Shard.set_status shard status
) sharder.shards
- |> Lwt.nchoose
let set_status_with sharder f =
- List.map (fun (shard, _) ->
+ Deferred.all @@ List.map ~f:(fun shard ->
Shard.set_status shard @@ f shard
) sharder.shards
- |> Lwt.nchoose
let request_guild_members ~guild ?query ?limit sharder =
- List.map (fun (shard, _) ->
+ Deferred.all @@ List.map ~f:(fun shard ->
Shard.request_guild_members ~guild ?query ?limit shard
) sharder.shards
- |> Lwt.nchoose \ No newline at end of file
+
+let update_handler sharder handler =
+ List.iter ~f:(fun shard ->
+ shard.handler <- handler
+ ) sharder.shards \ No newline at end of file
diff --git a/lib/client/sharder.mli b/lib/client/sharder.mli
new file mode 100644
index 0000000..b49c264
--- /dev/null
+++ b/lib/client/sharder.mli
@@ -0,0 +1,138 @@
+open Async
+
+(**
+Record type for registering event handlers
+*)
+type handler = {
+ ready: (Yojson.Basic.json -> unit) option;
+ resumed: (Yojson.Basic.json -> unit) option;
+ channel_create: (Yojson.Basic.json -> unit) option;
+ channel_delete: (Yojson.Basic.json -> unit) option;
+ channel_update: (Yojson.Basic.json -> unit) option;
+ channel_pins_update: (Yojson.Basic.json -> unit) option;
+ guild_create: (Yojson.Basic.json -> unit) option;
+ guild_delete: (Yojson.Basic.json -> unit) option;
+ guild_update: (Yojson.Basic.json -> unit) option;
+ guild_ban_add: (Yojson.Basic.json -> unit) option;
+ guild_ban_remove: (Yojson.Basic.json -> unit) option;
+ guild_emojis_update: (Yojson.Basic.json -> unit) option;
+ guild_integrations_update: (Yojson.Basic.json -> unit) option;
+ guild_member_add: (Yojson.Basic.json -> unit) option;
+ guild_member_remove: (Yojson.Basic.json -> unit) option;
+ guild_member_update: (Yojson.Basic.json -> unit) option;
+ guild_members_chunk: (Yojson.Basic.json -> unit) option; (* Not sure if this should be exposed *)
+ guild_role_create: (Yojson.Basic.json -> unit) option;
+ guild_role_delete: (Yojson.Basic.json -> unit) option;
+ guild_role_update: (Yojson.Basic.json -> unit) option;
+ message_create: (Yojson.Basic.json -> unit) option;
+ message_delete: (Yojson.Basic.json -> unit) option;
+ message_update: (Yojson.Basic.json -> unit) option;
+ message_delete_bulk: (Yojson.Basic.json -> unit) option;
+ message_reaction_add: (Yojson.Basic.json -> unit) option;
+ message_reaction_remove: (Yojson.Basic.json -> unit) option;
+ message_reaction_remove_all: (Yojson.Basic.json -> unit) option;
+ presence_update: (Yojson.Basic.json -> unit) option;
+ typing_start: (Yojson.Basic.json -> unit) option;
+ user_update: (Yojson.Basic.json -> unit) option;
+ voice_state_update: (Yojson.Basic.json -> unit) option;
+ voice_server_update: (Yojson.Basic.json -> unit) option;
+ webhooks_update: (Yojson.Basic.json -> unit) option;
+}
+
+(**
+Represents a single Shard. Manual creation is discouraged; use Sharder.start instead
+*)
+module Shard : sig
+ type t = {
+ mutable hb: unit Ivar.t option;
+ mutable seq: int;
+ mutable session: string option;
+ mutable handler: handler;
+ token: string;
+ shard: int * int;
+ write: string Pipe.Writer.t;
+ read: string Pipe.Reader.t;
+ ready: unit Ivar.t;
+ }
+
+ val parse :
+ [< `Ok of string | `Eof] ->
+ Yojson.Basic.json
+
+ val push_frame :
+ ?payload:Yojson.Basic.json ->
+ t ->
+ Opcode.t ->
+ t Deferred.t
+
+ val heartbeat :
+ t ->
+ t Deferred.t
+
+ val dispatch :
+ t ->
+ Yojson.Basic.json ->
+ t Deferred.t
+
+ val set_status :
+ t ->
+ Yojson.Basic.json ->
+ t Deferred.t
+
+ val request_guild_members :
+ guild:int ->
+ ?query:string ->
+ ?limit:int ->
+ t ->
+ t Deferred.t
+
+ val initialize :
+ t ->
+ Yojson.Basic.json ->
+ t Deferred.t
+
+ val handle_frame :
+ t ->
+ Yojson.Basic.json ->
+ t Deferred.t
+
+ val create :
+ url:string ->
+ shards:int * int ->
+ token:string ->
+ handler: handler ->
+ unit ->
+ t Deferred.t
+end
+
+type t = {
+ shards: Shard.t list;
+}
+
+val start :
+ ?count:int ->
+ handler:handler ->
+ string ->
+ t Deferred.t
+
+val set_status :
+ t ->
+ Yojson.Basic.json ->
+ Shard.t list Deferred.t
+
+val set_status_with :
+ t ->
+ (Shard.t -> Yojson.Basic.json) ->
+ Shard.t list Deferred.t
+
+val request_guild_members :
+ guild:int ->
+ ?query:string ->
+ ?limit:int ->
+ t ->
+ Shard.t list Deferred.t
+
+val update_handler :
+ t ->
+ handler ->
+ unit \ No newline at end of file