Websocket_async
Module Websocket_async
: websocket library for Async
This module implements a websocket client and server library in the spirit of the otherwise similar TCP functions of the Lwt_io
module. The websocket protocol add message framing in addition of simple TCP communication, and this library implement framing and unframing of messages.
module Frame = Websocket.Frame
val client :
?name:string ->
?extra_headers:Cohttp.Header.t ->
?random_string:(int -> string) ->
?initialized:unit Async.Ivar.t ->
app_to_ws:Frame.t Async.Pipe.Reader.t ->
ws_to_app:Frame.t Async.Pipe.Writer.t ->
net_to_ws:Async.Reader.t ->
ws_to_net:Async.Writer.t ->
Uri.t ->
unit Async.Deferred.Or_error.t
val client_ez :
?opcode:Frame.Opcode.t ->
?name:string ->
?extra_headers:Cohttp.Header.t ->
?heartbeat:Core.Time_ns.Span.t ->
?random_string:(int -> string) ->
Uri.t ->
Async.Reader.t ->
Async.Writer.t ->
string Async.Pipe.Reader.t * string Async.Pipe.Writer.t
val server :
?name:string ->
?check_request:(Cohttp.Request.t -> bool Async.Deferred.t) ->
?select_protocol:(string -> string option) ->
reader:Async.Reader.t ->
writer:Async.Writer.t ->
app_to_ws:Frame.t Async.Pipe.Reader.t ->
ws_to_app:Frame.t Async.Pipe.Writer.t ->
unit ->
unit Async.Deferred.Or_error.t
server ?request_cb reader writer app_to_ws
ws_to_app ()
returns a thread that expects a websocket client connected to reader
/writer
and, after performing the handshake, will resp. read outgoing frames from app_to_ws
and write incoming frames to ws_to_app
. The thread is determined if any of reader
, writer
, app_to_ws
, ws_to_app
is closed. If case of an error, app_to_ws
and ws_to_app
will be closed. Upon reception of the client HTTP request, request_cb
will be called with the request as its argument. If request_cb
returns true, the connection will proceed, otherwise, the result is immediately determined to Error Exit
.
val upgrade_connection :
?select_protocol:(string -> string option) ->
?ping_interval:Core.Time_ns.Span.t ->
app_to_ws:Frame.t Async.Pipe.Reader.t ->
ws_to_app:Frame.t Async.Pipe.Writer.t ->
f:(unit -> unit Async.Deferred.t) ->
Cohttp.Request.t ->
Cohttp.Response.t
* (Async.Reader.t ->
Async.Writer.t ->
unit Async.Deferred.t)
upgrade_connection ?select_protocol ?ping_interval
app_to_ws ws_to_app f request
returns a Cohttp_async.Server.response_action
.
Just wrap the return value of this function with `Expert
. You can combine responses both of HTTP `Response
handler and Websocket `Expert
handler.
Your handler will look like this:
let response =
let app_to_ws, ws_write = Pipe.create () in
let ws_read, ws_to_app = Pipe.create () in
Websocket_async.upgrade_connection request ~app_to_ws ~ws_to_app ~f:begin fun () ->
let rec loop () =
let open Websocket in
match%bind Pipe.read ws_read with
| `Eof -> return ()
| `Ok ({ Frame.opcode; content; _ } as frame) ->
let open Frame in
let frame', closed =
match opcode with
| Opcode.Ping -> Some (create ~opcode:Opcode.Pong ~content ()), false
| Opcode.Close ->
(* Immediately echo and pass this last message to the user *)
if String.length content >= 2 then
Some (create ~opcode:Opcode.Close
~content:(String.sub content ~pos:0 ~len:2) ()), true
else
Some (close 100), true
| Opcode.Pong -> None, false
| Opcode.Text
| Opcode.Binary -> Some frame, false
| _ -> Some (close 1002), false
in
begin
match frame' with
| None -> Deferred.unit
| Some frame -> Pipe.write ws_write frame
end >>= fun () ->
if closed
then Deferred.unit
else loop ()
in
loop ()
end
in
return (`Expert response)