GithubHelp home page GithubHelp logo

marfusios / websocket-client Goto Github PK

View Code? Open in Web Editor NEW
673.0 20.0 126.0 563 KB

🔧 .NET/C# websocket client library

License: MIT License

C# 88.95% HTML 6.09% CSS 3.36% JavaScript 1.61%
websocket websockets client dotnet-core dotnet-standard websocket-client websockets-client

websocket-client's Introduction

Logo

Websocket .NET client NuGet version Nuget downloads

This is a wrapper over native C# class ClientWebSocket with built-in reconnection and error handling.

Releases and breaking changes

License:

MIT

Features

  • installation via NuGet (Websocket.Client)
  • targeting .NET Standard 2.0 (.NET Core, Linux/MacOS compatible) + Standard 2.1, .NET 5 and .NET 6
  • reactive extensions (Rx.NET)
  • integrated logging abstraction (LibLog)
  • using Channels for high performance sending queue

Usage

var exitEvent = new ManualResetEvent(false);
var url = new Uri("wss://xxx");

using (var client = new WebsocketClient(url))
{
    client.ReconnectTimeout = TimeSpan.FromSeconds(30);
    client.ReconnectionHappened.Subscribe(info =>
        Log.Information($"Reconnection happened, type: {info.Type}"));

    client.MessageReceived.Subscribe(msg => Log.Information($"Message received: {msg}"));
    client.Start();

    Task.Run(() => client.Send("{ message }"));

    exitEvent.WaitOne();
}

More usage examples:

  • integration tests (link)
  • console sample (link)
  • .net framework sample (link)
  • blazor sample (link)

Pull Requests are welcome!

Advanced configuration

To set some advanced configurations, which are available on the native ClientWebSocket class, you have to provide the factory method as a second parameter to WebsocketClient. That factory method will be called on every reconnection to get a new instance of the ClientWebSocket.

var factory = new Func<ClientWebSocket>(() => new ClientWebSocket
{
    Options =
    {
        KeepAliveInterval = TimeSpan.FromSeconds(5),
        Proxy = ...
        ClientCertificates = ...
    }
});

var client = new WebsocketClient(url, factory);
client.Start();

Also, you can access the current native class via client.NativeClient. But use it with caution, on every reconnection there will be a new instance.

Change URL on the fly

It is possible to change the remote server URL dynamically. Example:

client.Url = new Uri("wss://my_new_url");;
await client.Reconnect();

Reconnecting

A built-in reconnection invokes after 1 minute (default) of not receiving any messages from the server. It is possible to configure that timeout via communicator.ReconnectTimeout. In addition, a stream ReconnectionHappened sends information about the type of reconnection. However, if you are subscribed to low-rate channels, you will likely encounter that timeout - higher it to a few minutes or implement ping-pong interaction on your own every few seconds.

In the case of a remote server outage, there is a built-in functionality that slows down reconnection requests (could be configured via client.ErrorReconnectTimeout, the default is 1 minute).

Usually, websocket servers do not keep a persistent connection between reconnections. Every new connection creates a new session. Because of that, you most likely need to resubscribe to channels/groups/topics inside ReconnectionHappened stream.

client.ReconnectionHappened.Subscribe(info => {
    client.Send("{type: subscribe, topic: xyz}")
});

Multi-threading

Observables from Reactive Extensions are single threaded by default. It means that your code inside subscriptions is called synchronously and as soon as the message comes from websocket API. It brings a great advantage of not to worry about synchronization, but if your code takes a longer time to execute it will block the receiving method, buffer the messages and may end up losing messages. For that reason consider to handle messages on the other thread and unblock receiving thread as soon as possible. I've prepared a few examples for you:

Default behavior

Every subscription code is called on a main websocket thread. Every subscription is synchronized together. No parallel execution. It will block the receiving thread.

client
    .MessageReceived
    .Where(msg => msg.Text != null)
    .Where(msg => msg.Text.StartsWith("{"))
    .Subscribe(obj => { code1 });

client
    .MessageReceived
    .Where(msg => msg.Text != null)
    .Where(msg => msg.Text.StartsWith("["))
    .Subscribe(arr => { code2 });

// 'code1' and 'code2' are called in a correct order, according to websocket flow
// ----- code1 ----- code1 ----- ----- code1
// ----- ----- code2 ----- code2 code2 -----

Parallel subscriptions

Every single subscription code is called on a separate thread. Every single subscription is synchronized, but different subscriptions are called in parallel.

client
    .MessageReceived
    .Where(msg => msg.Text != null)
    .Where(msg => msg.Text.StartsWith("{"))
    .ObserveOn(TaskPoolScheduler.Default)
    .Subscribe(obj => { code1 });

client
    .MessageReceived
    .Where(msg => msg.Text != null)
    .Where(msg => msg.Text.StartsWith("["))
    .ObserveOn(TaskPoolScheduler.Default)
    .Subscribe(arr => { code2 });

// 'code1' and 'code2' are called in parallel, do not follow websocket flow
// ----- code1 ----- code1 ----- code1 -----
// ----- code2 code2 ----- code2 code2 code2

Parallel subscriptions with synchronization

In case you want to run your subscription code on the separate thread but still want to follow websocket flow through every subscription, use synchronization with gates:

private static readonly object GATE1 = new object();
client
    .MessageReceived
    .Where(msg => msg.Text != null)
    .Where(msg => msg.Text.StartsWith("{"))
    .ObserveOn(TaskPoolScheduler.Default)
    .Synchronize(GATE1)
    .Subscribe(obj => { code1 });

client
    .MessageReceived
    .Where(msg => msg.Text != null)
    .Where(msg => msg.Text.StartsWith("["))
    .ObserveOn(TaskPoolScheduler.Default)
    .Synchronize(GATE1)
    .Subscribe(arr => { code2 });

// 'code1' and 'code2' are called concurrently and follow websocket flow
// ----- code1 ----- code1 ----- ----- code1
// ----- ----- code2 ----- code2 code2 ----

Async/Await integration

Using async/await in your subscribe methods is a bit tricky. Subscribe from Rx.NET doesn't await tasks, so it won't block stream execution and cause sometimes undesired concurrency. For example:

client
    .MessageReceived
    .Subscribe(async msg => {
        // do smth 1
        await Task.Delay(5000); // waits 5 sec, could be HTTP call or something else
        // do smth 2
    });

That await Task.Delay won't block stream and subscribe method will be called multiple times concurrently. If you want to buffer messages and process them one-by-one, then use this:

client
    .MessageReceived
    .Select(msg => Observable.FromAsync(async () => {
        // do smth 1
        await Task.Delay(5000); // waits 5 sec, could be HTTP call or something else
        // do smth 2
    }))
    .Concat() // executes sequentially
    .Subscribe();

If you want to process them concurrently (avoid synchronization), then use this

client
    .MessageReceived
    .Select(msg => Observable.FromAsync(async () => {
        // do smth 1
        await Task.Delay(5000); // waits 5 sec, could be HTTP call or something else
        // do smth 2
    }))
    .Merge() // executes concurrently
    // .Merge(4) you can limit concurrency with a parameter
    // .Merge(1) is same as .Concat() (sequentially)
    // .Merge(0) is invalid (throws exception)
    .Subscribe();

More info on Github issue.

Don't worry about websocket connection, those sequential execution via .Concat() or .Merge(1) has no effect on receiving messages. It won't affect receiving thread, only buffers messages inside MessageReceived stream.

But beware of producer-consumer problem when the consumer will be too slow. Here is a StackOverflow issue with an example how to ignore/discard buffered messages and always process only the last one.

Available for help

I do consulting, please don't hesitate to contact me if you need a paid help
(web, nostr, [email protected])

websocket-client's People

Contributors

1fabi0 avatar brucecarson avatar circle2096 avatar densidenko avatar dependabot[bot] avatar drauch avatar emanuel-v-r avatar ibigbug avatar jacquelinecasey avatar jasonwei512 avatar k-karuna avatar marfusios avatar odonno avatar sahb1239 avatar viveksg avatar zigmundl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

websocket-client's Issues

no support for events?

Hi,

Any reason you aren't raising an event on error/connect/disconnect/reconnect?

thanks

IWebsocketClient missing Send overload with byte[] payload

Hi

Is there a reason IWebsocketClient does not have Send/SendInstant(byte[])?

Not having it means the client needs to be wrapped up in order to allow mocking in unit tests.

Thanks for a nice, simple, clean almost unit testable library :-)

Cheers

Dave

Custom headers

Hi. First of all - thank you for your work.

I wanted to ask - can i set custom HTTP headers with your lib? Like "Sec-WebSocket-Extensions" for example.

Auth, Origin, Sec-WebSocket-Protocol Support?

I was experimenting with this last night and I could not find any method for supporting of authentication (basic auth) nor how to set the origin or sub protocol. Are these websocket attributes not supported?

Adding PreReconnection handler

Hello,
I think it would be cool, if there is some kind of preReconnection handler, which is always triggered just before a reconnect happens. That way you should be able to control, whether a reconnect happens and in what way.

For example / User story:

  • If the connection mistakenly disconnected by the server, I don't want to reconnect, since the error should be handled server side.
  • If a reconnection happens, I want to send some kind of "welcome-back/reconnected"-message to restore the state where the previous connection has been before.

What do you think?

Throwing Exception to reconnect even the Websocket got closed

I closed the websocket after performing some task but in logs file this exception is coming again and again even the websocket connection is closed. Any why why it is throwing this exception.

Exception while connecting. Waiting 60 sec before next reconnection try. Error: 'Cannot access a disposed object.
Object name: 'System.Net.WebSockets.ClientWebSocket'.'] [Exception :System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.Net.WebSockets.ClientWebSocket'.
at System.Net.WebSockets.ClientWebSocket.ConnectAsync(Uri uri, CancellationToken cancellationToken)
at Websocket.Client.WebsocketClient.<>c__DisplayClass65_0.<b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Websocket.Client.WebsocketClient.d__68.MoveNext()

this is code i am using to connect
ClientWebSocket clientWebSocket = new ClientWebSocket();

            // Create the factory with Native Object of Client Websocket
            var factory = new Func<ClientWebSocket>(() => clientWebSocket);
            // Init client object with URI and Factory object
            _client = new WebsocketClient(new Uri("wss//:xxxxxxxxxxxxxxxxxxxxxxxx), factory);
            // Reconnect time set to 30 seconds -> Will reconect if it fails due to network issue
            _client.ReconnectTimeout = TimeSpan.FromSeconds(30);

            // Subscribe over Reconnection and it will print in the console about reconection
            _client.ReconnectionHappened.Subscribe(ReconnectionOccured);

            // Message received will be posted to Receive Method 
            _client.MessageReceived.Subscribe(Receive);

            // Let's connect to WSS
            _client.Start();

Pause main thread until specific message is received

I need to send a (varying) number of requests, to which I eventually get responses, but I need to somehow pause the main thread until I have got all those responses. The service I am querying sends sequence numbers so I can identify the responses, but I'm really not sure how to best achieve this with the MessageReceived observable...

Are there any best practice to wait for specific responses?

Thanks!

Disposed WebsocketClients

I was wondering, is there a technical reason for not invoking the OnCompleted method on the WebsocketClient's subjects?

The reason I'm asking is that I'm actually sometimes disposing of older sockets for new one and I've noticed the MessageReceived stream never gets OnCompleted invoked. This last bit prevents the automatic unsubscription and the amount of streams just keeps rising.

It's not a complex issue (one-liner fix) but I'm wondering if I could be missing some reason.

PS: Hi, thanks for sharing the library. It's great and makes using Websockets even more fun/intuitive.

Add an ability to set infinite reconnect timeout (disable reconnection)

Hi!

Awesome lib, thanks! May I ask the authors for the feature which adds an ability to disable reconnection? For example, by adding the property TimeSpan ReconnectTimeout and supporting System.Threading.Timeout.InfiniteTimeSpan?

var client = new WebsocketClient(uri)
{
    ReconnectTimeout= System.Threading.Timeout.InfiniteTimeSpan // this coud disable reconnect
};

Closes on it's own all the time for no reason.

You are lacking experience at coding. You made it all the way to 3.1.32 with shit code? With all the time I've spent trying to figure out why your client just keeps disconnecting I would have been done writing my own lib.

Lacks more Options for Advanced Configuration.

I want to add more headers other than the current because the WebSocket server forced me to do so but this websocket client doesn't implement.

I think it would be better if the Options from here

var factory = new Func<ClientWebSocket>(() => new ClientWebSocket
{
    Options =
    {
        KeepAliveInterval = TimeSpan.FromSeconds(5),
        Proxy = ...
        ClientCertificates = ...
    }
});

is flexible.
I think that's better like if it's a Dictionary.

NuGet package versioning and GitHub releases

Hello!

First of all, thanks for the awesome work on this library!

I noticed that the NuGet package versioning is different from the git versioning. Wouldn't it be better if the changes in git were versioned with additional minor and patch versions so that it is clear exactly which version of the library is installed?

Sending ping message and receive a pong message

Hey

I have a question/problem/bug-ish. I am using your lib to connect to a wss service and I followed your simple console example. It Since this is a low rate channel, the lib reconnects to the server as there hasn't been any messages coming through. But, since I use

var factory = new Func<ClientWebSocket>(() => new ClientWebSocket
{
   Options =
   {
      KeepAliveInterval = TimeSpan.FromSeconds(30)
   }
});

and as I can see that my code pings the websocket server, and get a pong response, I kinda expected websocket-client to not trying to reconnect after the default 60 seconds because of no messages.
What are yout thoughts about this?

[Question] Client blocks UI Thread

I'm trying to run the client inside of a WPF-Application. Somehow I can't get it to start without blocking the UI Thread.

Already calling new WebsocketClient(uri, factory) opens a connection to the server and blocks the UI. Is this intended? Should the connection not be opened on Start()?

Messages received before Start finished

Hi,
I think this is not intended behavior. When you create a client, subscribe to a message observable and then await Start (or StartOrFail) method, you might receive one or more messages before Start has finished.
This is especially annoying since protocols like Socket.IO send handshake immediately after connection and you cannot respond to it, because the socket is not ready yet.

Here is an example code on how to simulate this behavior:

using (IWebsocketClient client = new WebsocketClient(new Uri("wss://streamer.cryptocompare.com/socket.io/?EIO=3&transport=websocket")))
{
    Stopwatch sw = Stopwatch.StartNew();
    string received = null;
    var receivedEvent = new ManualResetEvent(false);

    client.MessageReceived.Subscribe(msg =>
    {
        sw.Stop();
        receivedEvent.Set();
    });

    await client.StartOrFail();
    Assert.True(sw.IsRunning);
    sw.Stop();

    receivedEvent.WaitOne(TimeSpan.FromSeconds(30));

    Assert.NotNull(received);
}

How to connect with custom header cookie

Hi all,
i didn't find it in the document, but can i add the cookie like this

WebSocket = new WebsocketClient(new Uri(url))
{
headers.Add("Cookie","my cookie");
};

Thanks!

StackTrace of exceptions doesn't reach the log

Hi!

I'm using SlackConnector for my Slack-Bot to talk to Slack. It uses WebsocketClient internally to do the actual communication.

In your WebsocketClient class you log connection errors like so:

WebsocketClient.Logger.Error(websocketClient1.L("Exception while connecting. " + string.Format("Reconnecting canceled by user, exiting. Error: '{0}'", (object) ex.Message)));

As you can see, you omit the actual exception and just add the exception message to the log message. This prevents me from seeing stack traces in my logs, so I don't know which SlackConnector component actually faced the problem.

Is it possible to improve the situation and pass along the exception to all Logger.Error calls?

Best regards,
D.R.

Improper conditional subscription examples

In the main ReadMe there is the following example

client
    .MessageReceived
    .Where(msg => msg.StartsWith("{"))
    .Subscribe(obj => { code1 });

In the above msg is not a string but a ResponseMessage so it does not have a StartsWith method.
Should be msg.Text.StartsWith

Maybe add a comment saying it needs a null check or check MessageType to make sure it is text. I haven't seen what happens when a single websocket sends both text and binary so can't comment too much on this.

Custom Reconnect behavior

I'm trying to build a client for Azure bot framework's DirectLine channel.

When reconnecting, the chat client has to request a new websocket url based on a watermark from the last message received. Then, the websocket client needs to reconnect to that updated url. That way the chat can smoothly continue from the last received message.

However, currently the websocket client already reconnects before I have the chance to set the updated url.

Can you implement e.g. a delegate that is executed before the Reconnect() is done?

Reference: https://docs.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-reconnect-to-conversation?view=azure-bot-service-4.0

Multi connections

I'm trying to make different connections to serveral websocket servers
But after starting the first one all the thread get blocked and I didnt succeed in moving it to another thread successfully any ideas how to be done?

Handling when unable to connect

I cannot find an event that is triggered when the client is unable to connect. In the event it is is unable to connect it keeps waiting for the connection to happen

Please update NuGet dependencies to newest

Hello,

I spend a lot of time investigating why web sockets didn't work properly in Release mode of my app.
The reason was in replacing System.Runtime.CompilerServices.Unsafe.dll by newest version used in other packages.

Regards,
IvanGit

How to detect an connection failure?

Hello,
could you please add more error handling examples to the documentation? For instance, how can I detect if the server is not available. There should be some kind of Exception or something when calling start(), saying that connection attempt wasn't successful.

Instead it seems, that nothing happens.

Thanks in advance.

Server Certificate Validation

Hi

I'm wondering if anyone here understands how to achieve validating the servers certificate with this client?

I've tried to add a ServicePointManager.ServerCertificateValidationCallback to my code but it gets ignored and I can't find a way to set the ServerCertificateValidationCallback on HttpClient (if it has one) but still use this library.

Any ideas would be appreciated, thanks.

Cheers

Dave

Supporting unit testing websockets with TestHost

Hello,

In order to unit test my client implementation I would like to use the TestHost class provided by ASP.NET Core.

The Testhost class however returns a TestHost.WebSocketClient which has a method ConnectAsync which returns a WebSocket. Since the websocket client requires that the type should be ClientWebSocket (which inherits from WebSocket).

I can see the only major blocker for changing to WebSocket is the connection and reconnection logic. This could possible be fixed by updating the factory method to handle connection. For example (line 19 in WebsocketClient):

Func<Uri, Task<WebSocket>> clientFactory = null

The default implementation would be (the CancellationToken would need to be updated):

_clientFactory = clientFactory ?? (async (uri) =>
{
    var client = new ClientWebSocket
    {
        Options = { KeepAliveInterval = new TimeSpan(0, 0, 5, 0) }
    };
    await client.ConnectAsync(uri, CancellationToken.None).ConfigureAwait(false);
    return client;
}); 

This is however only part of the solution and will be a breaking change for the existing websocket client.

Are you willing to accept a PR to support this? Including a unit test with TestHost.

Sincerely,
Søren

Outstanding SendAsync call

Hello,

Unfortunately, I can't reproduce my problem but I sometimes get the following error:

Error: There is already one outstanding 'SendAsync' call for this WebSocket instance. ReceiveAsync and SendAsync can be called simultaneously, but at most one outstanding operation for each of them is allowed at the same time.

This seems to be also the cause of another error happening later during execution of my app:

Error: Cannot access a disposed object. Object name: 'System.Net.WebSockets.ClientWebSocket'.

Can you confirm, that the first error disposes of the ClientWebSocket and that will lead to the second error?

I use the following snippet to send my messages (and never use SendInstant):
public void SendCommand(JObject command) { client.Send(command.ToString); }

Do you have any idea, why there might be an outstanding send?

Thank you,
Cheers,

Connection and disconnection and issues

Hi,
I have an issue with constant disconnection and reconnection from wss server, every time it reconnects it disconnects immediately. This is the code (.netCore hosted service):

public async Task StartAsync(CancellationToken cancellationToken)
{
    try
    {
        var url = new Uri(wssServer);
        var factory = new Func<ClientWebSocket>(() => new ClientWebSocket
        {
            Options =
            {
                KeepAliveInterval = TimeSpan.FromSeconds(5),
                Credentials = new NetworkCredential(username, password)
            }
        });
        _wssClient = new WebsocketClient(url, factory);
        _wssClient.ReconnectTimeout = null;

        _wssClient.DisconnectionHappened.Subscribe(async type =>
        {
            await _logger.Write($"Disconnected at {DateTime.UtcNow}. Type: {JsonConvert.SerializeObject(type)}");
            await Task.Delay(60 * 1000);
            await ReconnectToWSS();
        });

        _wssClient.MessageReceived.Subscribe(async msg => await OnMessage(msg.Text));

        new Task(async () => await ConnectToWSS()).Start();
    }
    catch (Exception ex)
    {
        await _logger.WriteException(ex);
    }
}

public async Task StopAsync(CancellationToken cancellationToken)
{
    try
    {
        await _wssClient.StopOrFail(WebSocketCloseStatus.NormalClosure, "Stream closing.");
    }
    catch(Exception e)
    {
        await _logger.WriteException(e);
    }

    await _logger.Write($"Stopped at {DateTime.UtcNow}.");
    _wssClient.Dispose();
}

private async Task ReconnectToWSS()
{
    try
    {
        await _wssClient.ReconnectOrFail();
        _logger.Write($"Reconnected at {DateTime.UtcNow}");
    }
    catch(Exception e)
    {
        await _logger.WriteException(e);
        await Task.Delay(60 * 1000);
        await ReconnectToWSS();
    }
}

private async Task ConnectToWSS()
{
    try 
    {
        await _wssClient.StartOrFail();
        await _logger.Write($"Connected at {DateTime.UtcNow}.");
    }
    catch(Exception e)
    {
        await _logger.WriteException(e);
        await Task.Delay(60 * 1000);
        await ConnectToWSS();
    }
}

and it logs this every minute

Reconnected at 01/27/2020 08:51:28

Disconnected at 01/27/2020 08:51:28. Type: {"Type":4,"CloseStatus":null,"CloseStatusDescription":null,"SubProtocol":null,"Exception":null,"CancelReconnection":false,"CancelClosing":false}

Most unusual thing is the disconnection type 4

//
// Summary:
//     Type used when disconnection was requested by user
ByUser = 4,

Thanks in advance for any help!

No way to terminate the connection with custom close codes, or get the status code of a server-triggered close handshake

I know that the client will automatically close and "clean up" when disposed, but being unable to close and send custom close codes hides important functionality from ClientWebSocket which itself does support sending close codes out of the box.

This makes it impossible to use the client in any scenario where you'd like to send custom error codes to the server (for which a reserved range exists in RFC6455 itself).

Thanks for a great package though, makes it really easy to get started chatting over the protocol!

Edit

Additionally there's no way to get the optional 2-byte status code that servers may send when closing connections (RFC section 5.1.1) when subscribing to DisconnectionHappened.

Compression support

Hi! Thank you for your great work.

Is there any chance to use this client with compression?
I need to work with server that uses: "Sec-WebSocket-Extensions", "permessage-deflate; client_max_window_bits".
And when compressed (big) message arrives - websocket drops an exception like:
"The Buffer type '386' is invalid. Valid Buffer types are : 'Close', 'BinaryFragment', 'BinaryMessage', 'UTF8Fragment', 'UTF8Message'"

Disconnect Type NoMessageRecive

I have this code:


var factory = new Func<ClientWebSocket>(() => new ClientWebSocket
            {
                Options =
                {
                     KeepAliveInterval = TimeSpan.FromSeconds(20)
                }
            });
WebSocket = new WebsocketClient(WebsocketUri, factory);
            WebSocket.DisconnectionHappened.Subscribe((info) =>
            {
                if (info.Type == DisconnectionType.ByServer)
                {
                    info.CancelClosing = true;
                    Console.WriteLine("Tried to close connection, blocked!");
                }
                else
                    Console.WriteLine($"Disconnect! Type: {info.Type.ToString()} | {info.CloseStatusDescription}");
            });
            WebSocket.ReconnectTimeout = TimeSpan.FromSeconds(5);
            WebSocket.ErrorReconnectTimeout = TimeSpan.FromSeconds(5);
            WebSocket.ReconnectionHappened.Subscribe(info =>
                Console.WriteLine($"Reconnection happened | type: {info.Type}"));

            WebSocket.MessageReceived.Subscribe(msg =>
            {
                HandleResponse(msg.Text);
            });

            await WebSocket.Start();

I have a timer that every 10 seconds sending '2' for the server to keep the connection alive
I have no idea why its keep disconnecting with NoMessageRecive reason with no explantion.
Is NoMessageRecive is on my end or on the server?

edit:
after NoMessageRecive I get Error immedietly

Websocket.Client DLL is not Signed with a Strong Name Key

Hello,

I use Websocket.Client from NuGet in my application. Because my application is signed I get the error while Websocket.Client dll loading:

Could not load file or assembly 'Websocket.Client, Version=4.1.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. A strongly-named assembly is required. (Exception from HRESULT: 0x80131044)

Could you sign the assembly in NuGet package? Thank you.

Expose more events to handle error scenarios

Hi,

I was wondering whether it would be possible to expose more events so that clients can handle situations like when a message is not sent by socket.

To be specific for example this code

try
{
    await SendInternalSynchronized(message).ConfigureAwait(false);
}
catch (Exception e)
{
    Logger.Error(L($"Failed to send binary message: '{message}'. Error: {e.Message}"));
}

just logs the exceptions which is good, but there is no way for a user to know that this message was not sent. A use case for this might be to react on such error with send retry or some other procedure.

Do you think implementing something like this would make sense? There are more places where I think this might be useful like message not being sent because socket is not connected (perhaps put the message back into the channel?).

I was thinking about implementing something like BitmexClientStreams class in your repository here: bitmex-client-websocket to make it more manageable and cleaner in terms of API.

If you are interested I would create PR for this. Good job on the library so far btw!

SSL certificates

Hi! I was wondering if I can specify SSL certificate pem files (cert and key). I need this feature in order to connect to some WebSocket servers.

Change Authentication Header on Reconnect

Hi, great library.
I'm sending an authentication header when connecting. I'm adding the header in the factory in the connect and it works fine.
I'm worried that at recconect, if the header is expired i need a new one, but i can't do it, i'm trying to change the header in the NativeClient property in the reconnect event handler but it doesn't work as the web socket is already initiated.
Is there a way to do this?

If not I will have to manage the reconnection manually.

Thanks!

Example for use in class library

Hi,
Could you show a short example for using this properly in a client library?
I would like to add more exchanges.

I have it working in console app, but when when using in library I get errors and can’t run (pub key natural error)

Thanks if you can.

Reconnect

Hello. I'm connected to exchange wss.

ws.MessageReceived.Subscribe(msg => OnMessage(msg.Text)); ws.ReconnectionHappened.Subscribe(type => OnReconnect(type));

All other settings are default, reconnection is enabled etc.

After some time, about 4-5 hrs, I get reconnection function triggered with type "Lost".
OnReconnect function triggers new subscriptions to exchange channels.

OnReconnect(type){ ws.Send(subscribtion_message); }

But I do not receive any messages after.
I have a thread that ticks every minute and watches time of received msgs and if it is not updating in OnMessage method then it forces reconnect.
ws.Reconnect();
It is said that it closes socket and I expect it to be as a new client.

My log looks like this:
Lost
ByUser
ByUser
...

It never reconnects with resuming subscriptions.
If I restart my program it immediately connects, subscribes and works as supposed.

My local tests run fine. If I close tcp connection the program restores it and resubscribes to channels.

What could be wrong?

Support reconnection only when connection is closed

Hello,

Would it be possible for you to support only reconnection the client when the actual connection is closed?

With other words LastChance should be configurable to only reconnect if _client.State != WebSocketState.Open.

Sincerely,
Søren

Test OnClose_ShouldWorkCorrectly don't pass

Hi,

just cloned your repo, compiled and tryed to run tests. There I see the test 'OnClose_ShouldWorkCorrectly' didn't pass.

VS 2019, netstandard2.0, Microsoft.NET.Sdk

Could you please look into this?

Regards Gerd

Library bundling...

More of a question but I do find it odd. Unlike everything else I use when I build a project with this library I end up with 100+ additional files/libraries dependencies that have to be packaged as well. Most other libraries don't pull them all into the build unless required as part of external packages.

Is this purposeful?

Doesn't load new data on ubuntu

When I run my code on windows it works well, but when I run the same code on linux it loads only first bunch of data and then do nothing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.