This functionality is not present at the moment in WebSharper.Owin.WebSocket, but it is easy enough to implement using an F# MailboxProcessor.

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
type GlobalNotification = string // or whatever you need to broadcast to all clients.

/// The agent that stores currently running websocket connections:

type ConnectionsAgentMessage =
    | ClientConnected of (GlobalNotification -> Async<unit>) * AsyncReplyChannel<System.Guid>
    | ClientDisconnected of System.Guid
    | Broadcast of GlobalNotification

let ConnectionsAgent = MailboxProcessor<ConnectionsAgentMessage>.Start(fun inbox ->
    let rec loop connections = async {
        let! message = inbox.Receive()
        match message with
        | ClientConnected (onNotification, chan) ->
            let id = System.Guid.NewGuid()
            chan.Reply id
            return! loop (Map.add id onNotification connections)
        | ClientDisconnected id ->
            return! loop (Map.remove id connections)
        | Broadcast notification ->
            // Using Async.Start here instead of awaiting with do!
            // because we don't want to delay this agent while broadcasting the notification.
            do connections
                |> Seq.map (fun (KeyValue(_, f)) -> async {
                    try return! f notification
                    with e ->
                        // Maybe the client disconnected in the meantime, or something.
                        // You may want to log the error.
                        ()
                })
                |> Async.Parallel
                |> Async.Ignore
                |> Async.Start
            return! loop connections
    }
    loop Map.empty
)

/// The websocket client:

open WebSharper.Owin.WebSocket
open WebSharper.Owin.WebSocket.Server

let WebSocketAgent : Agent<_, _> =
    fun client ->
        let notify x = client.PostAsync x // or whatever you want to do when receiving a notification.
        let connectionId = ConnectionsAgent.PostAndReply (fun chan -> ClientConnected(notify, chan))
        function
        | Close -> ConnectionsAgent.Post (ClientDisconnected connectionId)
        | Error e -> () // Your error handling here
        | Message m -> () // Your incoming message handling here

/// And then, to broadcast a notification, just do:

ConnectionsAgent.Post (Broadcast notification)
By on 1/26/2016 12:44 AM ()

Nice solution, works like a dream! Thank you! :)

By on 1/26/2016 1:07 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper