All Projects → 1iveowl → WebsocketClientLite.PCL

1iveowl / WebsocketClientLite.PCL

Licence: MIT License
websocket Client Lite PCL - Xaramrin

Programming Languages

C#
18002 projects
powershell
5483 projects

Projects that are alternatives of or similar to WebsocketClientLite.PCL

purescript-outwatch
A functional and reactive UI framework based on Rx and VirtualDom
Stars: ✭ 33 (+50%)
Mutual labels:  reactivex, rx
Ubiety.Xmpp.Core
XMPP library for .NET Core
Stars: ✭ 32 (+45.45%)
Mutual labels:  netcore2, netstandard20
rx-reason
Reactive programming library for ReasonML/OCaml
Stars: ✭ 49 (+122.73%)
Mutual labels:  reactivex, rx
DotNetGraph
Create GraphViz DOT graph with .NET / C#
Stars: ✭ 57 (+159.09%)
Mutual labels:  netstandard, netstandard20
google-calendar-slack-status
Automatically sync your Google Calendar events to your Slack status
Stars: ✭ 33 (+50%)
Mutual labels:  slack, slack-api
KuttSharp
🔪 .NET Package for kutt.it url shortener
Stars: ✭ 29 (+31.82%)
Mutual labels:  netstandard, netstandard20
ObjectRepository
EscapeTeams In-Memory Object Database
Stars: ✭ 23 (+4.55%)
Mutual labels:  netcore2, netstandard20
aspnetcore-authentication-apikey
Easy to use and very light weight Microsoft style API Key Authentication Implementation for ASP.NET Core. It can be setup so that it can accept API Key in Header, Authorization Header, QueryParams or HeaderOrQueryParams.
Stars: ✭ 215 (+877.27%)
Mutual labels:  netstandard, netstandard20
slack-web-api
Simple, convenient, and configurable HTTP client for making requests to Slack’s Web API. Deno port of @slack/web-api
Stars: ✭ 16 (-27.27%)
Mutual labels:  slack, slack-api
vscode-chat
Chat with your team while you collaborate over code using VS Live Share
Stars: ✭ 496 (+2154.55%)
Mutual labels:  slack, slack-api
rx
Reactive Extensions for D Programming Language
Stars: ✭ 52 (+136.36%)
Mutual labels:  reactivex, rx
rxkotlin-jdbc
Fluent RxJava JDBC extension functions for Kotlin
Stars: ✭ 27 (+22.73%)
Mutual labels:  reactivex, rx
Pharmacist
Builds observables from events.
Stars: ✭ 221 (+904.55%)
Mutual labels:  reactivex, rx
Vortice.Vulkan
Cross platform .NET bindings for Vulkan, VMA, SPIRV-Cross and shaderc
Stars: ✭ 172 (+681.82%)
Mutual labels:  netstandard, netstandard20
XamarinFormsPinView
PIN keyboard for Xamarin.Forms.
Stars: ✭ 83 (+277.27%)
Mutual labels:  netstandard, netstandard20
Math-Expression-Evaluator
A C# library for parsing mathemitical expressions with support for parentheses and variables.
Stars: ✭ 97 (+340.91%)
Mutual labels:  netstandard, netstandard20
Vortice.Mathematics
Cross platform .NET math library.
Stars: ✭ 46 (+109.09%)
Mutual labels:  netstandard, netstandard20
flutter-form-with-validation-BLOC
This form and validation functions are created by using the BLOC pattern with RxDart instead of using StatefulWidget
Stars: ✭ 63 (+186.36%)
Mutual labels:  reactivex, rx
Rx.Http
A reactive way to make HTTP Request in .NET Core 🚀
Stars: ✭ 62 (+181.82%)
Mutual labels:  reactivex, rx
dienstplan
Slack bot app for duty rotations
Stars: ✭ 14 (-36.36%)
Mutual labels:  slack, slack-api

Websocket Client Lite (Rx)

NuGet Badge

.NET Standard

Please star this project if you find it useful. Thank you.

A Light Weight Cross Platform Websocket Client

This library is a ground-up implementation of the Websocket specification (RFC 6544). The implementation does not rely on the build-in Websocket libraries in .NET and UWP etc.

The library allows developers to establish secure wss websocket connections to websocket servers that have self-signing certificates, expired certificates etc. This capability should be used with care, but is useful for testing environments, closed local networks, IoT set-ups etc. To utilize the relaxed security settings set this ConnectAsync parameter: ignoreServerCertificateErrors: true.

This project utilizes Reactive Extensions. Although this has an added learning curve it is an added learning curve worth while persuing, as it IMHO makes creating a library like this much more elegant compared to using call-back or events etc.

New in version 6.3

  • Fixed bug related to connecting to IPv6 enpoints.
  • Updated System.Reactive to v5.0.0.
  • Successfully tested with .NET 5.0.
  • Updated Readme.

New in version 6.1.

Updates, stability and fundamental improvements to the library. See examples below for changes in usage.

New in version 6.0.

Simplifications and no longer relies on SocketLite but utilizes the cross platform capabilities of .NET Standard 2.0 and .NET Core 2.1+.

New in version 5.0.

From hereon only .NET Standard 2.0 and later are supported.

Usage

The library is easy to use, as illustated with the examples below.

Example WebSocket Client:

class Program
{

    const string AllowedChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";


    static async Task Main(string[] args)
    {

        var outerCancellationSource = new CancellationTokenSource();

        await StartWebSocketAsyncWithRetry(outerCancellationSource);

        System.Console.WriteLine("Waiting...");
        System.Console.ReadKey();
        outerCancellationSource.Cancel();
    }

    private static async Task StartWebSocketAsyncWithRetry(CancellationTokenSource outerCancellationTokenSource)
    {
        while (!outerCancellationTokenSource.IsCancellationRequested)
        {
            var innerCancellationSource = new CancellationTokenSource();

            await StartWebSocketAsync(innerCancellationSource);

            while (!innerCancellationSource.IsCancellationRequested)
            {
                await Task.Delay(TimeSpan.FromSeconds(10), innerCancellationSource.Token);
            }

            // Wait 5 seconds before trying again
            await Task.Delay(TimeSpan.FromSeconds(5), outerCancellationTokenSource.Token);
        }
    }

    private static async Task StartWebSocketAsync(CancellationTokenSource innerCancellationTokenSource)
    {
        using (var websocketClient = new MessageWebSocketRx
        {
            IgnoreServerCertificateErrors = true,
            Headers = new Dictionary<string, string> { { "Pragma", "no-cache" }, { "Cache-Control", "no-cache" } },
            TlsProtocolType = SslProtocols.Tls12
             
        })
        {
            System.Console.WriteLine("Start");

            var disposableWebsocketStatus = websocketClient.ConnectionStatusObservable.Subscribe(
                s =>
                {
                    System.Console.WriteLine(s.ToString());
                    if (s == ConnectionStatus.Disconnected
                    || s == ConnectionStatus.Aborted
                    || s == ConnectionStatus.ConnectionFailed)
                    {
                        innerCancellationTokenSource.Cancel();
                    }
                },
                ex =>
                {
                    Console.WriteLine($"Connection status error: {ex}.");
                    innerCancellationTokenSource.Cancel();
                },
                () =>
                {
                    Console.WriteLine($"Connection status completed.");
                    innerCancellationTokenSource.Cancel();
                });
            
            var disposableMessageReceiver = websocketClient.MessageReceiverObservable.Subscribe(
               msg =>
               {
                   Console.WriteLine($"Reply from test server: {msg}");
               },
               ex =>
               {
                   Console.WriteLine(ex.Message);
                   innerCancellationTokenSource.Cancel();
               },
               () =>
               {
                   System.Console.WriteLine($"Message listener subscription Completed");
                   innerCancellationTokenSource.Cancel();
               });

            
            await websocketClient.ConnectAsync(
                new Uri("wss://echo.websocket.org"));
            try
            {
                System.Console.WriteLine("Sending: Test Single Frame");
                await websocketClient.SendTextAsync("Test Single Frame");

                await websocketClient.SendTextAsync("Test Single Frame again");

                await websocketClient.SendTextAsync(TestString(65538, 65550));

                var strArray = new[] { "Test ", "multiple ", "frames" };

                await websocketClient.SendTextAsync(strArray);

                await websocketClient.SendTextMultiFrameAsync("Start ", FrameType.FirstOfMultipleFrames);
                await Task.Delay(TimeSpan.FromMilliseconds(200));
                await websocketClient.SendTextMultiFrameAsync("Continue... #1 ", FrameType.Continuation);
                await Task.Delay(TimeSpan.FromMilliseconds(300));
                await websocketClient.SendTextMultiFrameAsync("Continue... #2 ", FrameType.Continuation);
                await Task.Delay(TimeSpan.FromMilliseconds(150));
                await websocketClient.SendTextMultiFrameAsync("Continue... #3 ", FrameType.Continuation);
                await Task.Delay(TimeSpan.FromMilliseconds(400));
                await websocketClient.SendTextMultiFrameAsync("Stop.", FrameType.LastInMultipleFrames);

                await websocketClient.DisconnectAsync();

                disposableMessageReceiver.Dispose();
                disposableWebsocketStatus.Dispose();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                innerCancellationTokenSource.Cancel();
            }
        }
    }

    private static string TestString(int minlength, int maxlength)
    {

        var rng = new Random();

        return RandomStrings(AllowedChars, minlength, maxlength, 25, rng);
    }

    private static string RandomStrings(
        string allowedChars,
        int minLength,
        int maxLength,
        int count,
        Random rng)
    {
        var chars = new char[maxLength];
        var setLength = allowedChars.Length;

        var length = rng.Next(minLength, maxLength + 1);

        for (var i = 0; i < length; ++i)
        {
            chars[i] = allowedChars[rng.Next(setLength)];
        }

        return new string(chars, 0, length);
    }

Alternative Constructor (Advanced)

It is also possible to pass you own managed TcpClient to the WebsocketClientLite. The TcpClient should not be connected. Connection will be maanged by the library. However, this enables you to defined Socket Options etc. to the TcpClient.

Use:

MessageWebSocketRx(tcpClient)

Working With Slack (And maybe also other Websocket server implementations)

The RFC 6455 section defining how ping/pong works seems to be ambigious on the question of whether or not a pong should include the byte defining the length of "Application Data" in the special case when the length is just zero.

When testing against websocket.org the byte is expected and should have the value: 0 (zero). However when used with the slack.rtm api the byte should not be there and if it is, the slack websocket server will disconnect.

To manage this byte-issue the following property can be set to true, in which case the byte with the zero value will NOT be added to the pong. For instance like this:

var websocketClient = new MessageWebSocketRx()
websocketClient.ExcludeZeroApplicationDataInPong = true;

To futher complicate matters the slack.rtm api also seems to requires a ping at the Slack application layer too. A simplified implementation of this could look like this:

while (true)
{
    await Task.Delay(TimeSpan.FromSeconds(30));
    await _webSocket.SendTextAsync("{\"id\": 1234, // ID, see \"sending messages\" above\"type\": \"ping\",...}");
}

For details read the Ping and Pong section of the slack.rtm api documentation

Monitoring Status

Monitoring connection status is easy:

var websocketLoggerSubscriber = websocketClient.ConnectionStatusObservable.Subscribe(
    status =>
    {
        // Insert code here for logging or handling connection status
        System.Console.WriteLine(status.ToString());
    });

References:

The following documentation was utilized when writting this library:

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].