LiveOrDevTrying / WebsocketsSimple

WebsocketsSimple provides an easy-to-use and customizable Websocket Server and Websocket Client. The server is created using a TcpListener and upgrades a successful connection to a WebSocket. The server and client can be used for non-SSL or SSL connections and authentication (including client and server SSL certification validation) is provided for identifying the clients connected to your server. Both client and server are created in .NET Standard and use async await functionality.
Apache License 2.0
21 stars 2 forks source link

event types in F# #1

Closed thomasd3 closed 2 years ago

thomasd3 commented 2 years ago

The event types for socket message make it difficult to interface with this lib in F#. I'm not sure if this is something in your scope or not though.

LiveOrDevTrying commented 2 years ago

I did not scope this project to work with F# but can modify it. What specifically would you like changed to make it easier to interface with? Ty,

thomasd3 commented 2 years ago

Events in F# implement the IEvent type; there is a custom object for it (simply called 'Event'). I think the only thing that would really benefit from a change is the event types. If you create an empty F# project, import WebsocketsSimple's nuget into it and then try to hook to an event, you'll see how different the types are right away. Apart from this, everything else should be smooth.

LiveOrDevTrying commented 2 years ago

I think I understand - I tried it in F#, is it because the events are returnning a Task instead of void?

thomasd3 commented 2 years ago

Take this F# example:

open WebsocketsSimple.Client
open WebsocketsSimple.Client.Models

let params = ParamsWSClient(
        Port = 1234,
        Uri = "localhost"
    )

let client = new WebsocketClient(params)
client.ConnectionEvent.Add(fun x -> printfn "event!")

The function passed to the ConnectionEvent is a classic F# lambda, which is quite standard, but here is what the compiler will return:

Program.fs(11, 8): [FS1091] The event 'ConnectionEvent' has a non-standard type. If this event is declared in another CLI language, you may need to access this event using the explicit add_ConnectionEvent and remove_ConnectionEvent methods for the event. If this event is declared in F#, make the type of the event an instantiation of either 'IDelegateEvent<_>' or 'IEvent<_,_>'.

So you can try to add the event through add_ConnectionEvent:

client.add_ConnectionEvent (fun x -> printfn "event!")

But that will not work either because now we need the event to match the right type:

  Program.fs(13, 28): [FS0193] Type constraint mismatch. The type 
    ''a -> unit'    
is not compatible with type
    'PHS.Networking.Events.NetworkingEventHandler<Events.Args.WSConnectionClientEventArgs>'

In the end, the non standard event type is making interfacing quite complex. The solution would be to use an event that has the IEvent type since it's pretty much the standard both in C# and F#.

What is the reason behind having a custom event type?

LiveOrDevTrying commented 2 years ago

Ty, I was able to reproduce this. This is happening because the events are a return type of Task. I can fix this in the next update and will post here. But for my understanding, how do I call an async function in F#? I want to make sure everything is fixed for you.

image

thomasd3 commented 2 years ago

In F#, the async functions have to be explicitly executed.

For example:

let f (x: string) =
    async {
        // do some stuff
        return 1
    }

will have the type string->Async, so if you call it, you will get back an Async.

You can build long chains where you have Async types and then execute them all in cascade.

To answer your question, you can force the execution by calling (in F#) Async.RunSynchronously and this will execute the code inside the async block. To execute from C#, you'd have to await the async block.

This post here: http://tomasp.net/blog/csharp-fsharp-async-intro.aspx/ describes the similarities and differences between the async functions in F# in much better terms than I can.

LiveOrDevTrying commented 2 years ago

Ty again for your feedback. I have made this change in Master and packages have been built. Here is it working in F#:

image

Thank you again and please let me know if I can be of any more help. Rob