Realtime Messages With WebSockets

It's easy to set up WebSockets with Suave.

First, define a function that takes WebSocket and HttpContext typed parameters, and returns a socket computation expression:

open Suave.Sockets open Suave.Sockets.Control open Suave.WebSocket let ws (webSocket : WebSocket) (context: HttpContext) = socket { ... }

Next, use the read and send function to receive and send messages to the clients:

socket { let mutable loop = true while loop do let! msg = webSocket.read() match msg with | (Text, data, true) -> let str = UTF8.toString data let response = sprintf "response to %s" str let byteResponse = response |> System.Text.Encoding.ASCII.GetBytes |> ByteSegment do! webSocket.send Text byteResponse true | (Close, _, _) -> let emptyResponse = [||] |> ByteSegment do! webSocket.send Close emptyResponse true loop <- false | _ -> () }

Then, use the handShake function to fit it in your web server:

let app : WebPart = choose [ path "/websocket" >=> handShake ws GET >=> choose [ path "/" >=> file "index.html"; browseHome ] NOT_FOUND "Found no handlers." ]

The complete example can be found here.

Handling connection errors

By default the socket computation expression handles any errors transparently on both writing and reading from the websocket shutting down the connection.

You may want to add your own additional error handling logic to catch and handle any errors raised when reading and writing from a websocket. Some scenarios where this may be useful:

  • Alerting the rest of the application that a connection is closed.
  • Unsubscribing and/or shutting down processes used by the websocket connection.
  • Custom logging of the error.

Example code can be found here.

namespace Suave
namespace Suave.Sockets
namespace Suave.Sockets.Control
module WebSocket

from Suave
val ws : webSocket:WebSocket -> context:HttpContext -> 'a

Full name: temp.ws
val webSocket : WebSocket
Multiple items
module WebSocket

from Suave

--------------------
type WebSocket =
  new : connection:Connection -> WebSocket
  member read : unit -> Async<Choice<(Opcode * byte [] * bool),Error>>
  member readIntoByteSegment : byteSegmentForLengthFunc:(int -> ByteSegment) -> Async<Choice<(Opcode * ByteSegment * bool),Error>>
  member send : opcode:Opcode -> bs:ByteSegment -> fin:bool -> Async<Choice<unit,Error>>

Full name: Suave.WebSocket.WebSocket

--------------------
new : connection:Connection -> WebSocket
val context : HttpContext
Multiple items
module HttpContext

from Suave.Http

--------------------
type HttpContext =
  {request: HttpRequest;
   runtime: HttpRuntime;
   connection: Connection;
   userState: Map<string,obj>;
   response: HttpResult;}
  member clientIp : trustProxy:bool -> sources:string list -> IPAddress
  member clientPort : trustProxy:bool -> sources:string list -> Port
  member clientProto : trustProxy:bool -> sources:string list -> string
  member clientIpTrustProxy : IPAddress
  member clientPortTrustProxy : Port
  member clientProtoTrustProxy : string
  member isLocal : bool
  static member clientIp_ : Property<HttpContext,IPAddress>
  static member clientPort_ : Property<HttpContext,Port>
  static member clientProto_ : Property<HttpContext,string>
  static member connection_ : Property<HttpContext,Connection>
  static member isLocal_ : Property<HttpContext,bool>
  static member request_ : Property<HttpContext,HttpRequest>
  static member response_ : Property<HttpContext,HttpResult>
  static member runtime_ : Property<HttpContext,HttpRuntime>
  static member userState_ : Property<HttpContext,Map<string,obj>>

Full name: Suave.Http.HttpContext
val socket : SocketMonad

Full name: Suave.Sockets.Control.SocketMonad.socket
val mutable loop : bool
val msg : Opcode * byte [] * bool
union case Opcode.Text: Opcode
val data : byte []
val str : string
module UTF8

from YoLo
val toString : bs:byte [] -> string

Full name: YoLo.UTF8.toString
val response : string
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val byteResponse : System.ArraySegment<byte>
namespace System
namespace System.Text
type Encoding =
  member BodyName : string
  member Clone : unit -> obj
  member CodePage : int
  member DecoderFallback : DecoderFallback with get, set
  member EncoderFallback : EncoderFallback with get, set
  member EncodingName : string
  member Equals : value:obj -> bool
  member GetByteCount : chars:char[] -> int + 3 overloads
  member GetBytes : chars:char[] -> byte[] + 5 overloads
  member GetCharCount : bytes:byte[] -> int + 2 overloads
  ...

Full name: System.Text.Encoding
property System.Text.Encoding.ASCII: System.Text.Encoding
System.Text.Encoding.GetBytes(s: string) : byte []
System.Text.Encoding.GetBytes(chars: char []) : byte []
System.Text.Encoding.GetBytes(chars: char [], index: int, count: int) : byte []
System.Text.Encoding.GetBytes(chars: nativeptr<char>, charCount: int, bytes: nativeptr<byte>, byteCount: int) : int
System.Text.Encoding.GetBytes(s: string, charIndex: int, charCount: int, bytes: byte [], byteIndex: int) : int
System.Text.Encoding.GetBytes(chars: char [], charIndex: int, charCount: int, bytes: byte [], byteIndex: int) : int
type ByteSegment = System.ArraySegment<byte>

Full name: Suave.Sockets.ByteSegment
union case Opcode.Close: Opcode
val emptyResponse : System.ArraySegment<byte>
val app : WebPart

Full name: temp.app
Multiple items
module WebPart

from Suave

--------------------
type WebPart = WebPart<HttpContext>

Full name: Suave.Http.WebPart

--------------------
type WebPart<'a> = 'a -> Async<'a option>

Full name: Suave.WebPart.WebPart<_>
val choose : options:WebPart<'a> list -> WebPart<'a>

Full name: Suave.WebPart.choose
val path : pathAfterDomain:string -> WebPart

Full name: Suave.Filters.path
val handShake : continuation:(WebSocket -> HttpContext -> SocketOp<unit>) -> ctx:HttpContext -> Async<HttpContext option>

Full name: Suave.WebSocket.handShake
val GET : WebPart

Full name: Suave.Filters.GET
val file : fileName:string -> WebPart

Full name: Suave.Files.file
val browseHome : WebPart

Full name: Suave.Files.browseHome
val NOT_FOUND : body:string -> WebPart

Full name: Suave.RequestErrors.NOT_FOUND

results matching ""

    No results matching ""