WatsonWebsocket

repository·main·Indexed 43 days ago

https://github.com/jchristn/watsonwebsocket

A .NET library for building WebSocket client and server applications with high-level abstractions for connection management and message exchange. It provides classes like WatsonWsServer and WatsonWsClient, supporting SSL, custom HTTP headers, and browser-based connections. Note: This library is deprecated and its functionality is being integrated into Watson Webserver.

Tokens
4.8K
Snippets
16
Records
19
Agent score
54%

What's inside WatsonWebsocket

  1. Enable SSL in WatsonWebsocket

    main

    SSL is supported via the constructors for both WatsonWsServer and WatsonWsClient. Pass a bool value to the constructor to enable SSL.

    Note: WatsonWebsocket uses HTTPS/SSL and relies on the certificates present in your operating system's certificate store. For Windows-specific SSL configuration, refer to the Watson Webserver wiki.

  2. Configure access from outside localhost

    main

    By default, listening on 127.0.0.1 or localhost restricts access to the local machine. To allow external access, follow these requirements:

    • Hostname Matching: Specify the exact DNS hostname in the WatsonWsServer constructor. The incoming HTTP HOST header must match this value.
    • Wildcard Listening: To listen on multiple hostnames/IPs, use * or +. This requires running the application as an Administrator.
    • Privileged Ports: To use ports below 1024, you must run as Administrator.
    • Firewall: Open the specific TCP port in your firewall.
    • URL ACLs (Windows): You may need to register URL bindings using netsh.
      • Check existing: netsh http show urlacl
      • Add new: netsh http add urlacl url=http://[hostname]:[port]/ user=everyone listen=yes
    • SSL: If using SSL, certificates must be installed in the OS certificate store.
  3. Connect to WatsonWsServer using a Browser

    main

    You can connect to a WatsonWsServer using standard JavaScript WebSocket APIs. Ensure the server is started with a URI-based constructor (e.g., new WatsonWsServer("http://localhost:9000/")) to support browser-based connections.

    // Server side (C#)
    server = new WatsonWsServer("http://localhost:9000/");
    server.Start();
    // Client side (Browser JS)
    let socket = new WebSocket("ws://localhost:9000/test/");
    socket.onopen = function () { console.log("success"); };
    socket.onmessage = function (msg) { console.log(msg.data); };
    socket.onclose = function () { console.log("closed"); };
    // wait a moment
    socket.send("Hello, world!");
  4. Implement a WatsonWsServer

    main

    To create a websocket server, instantiate WatsonWsServer. The constructor accepts an IP address (or hostname), a port, and a bool to enable or disable SSL. You can subscribe to ClientConnected, ClientDisconnected, and MessageReceived events to handle lifecycle and data events.

    Note: In v4.0.x, clients are identified by a Guid in ClientMetadata, and Send* methods now require a guid instead of an IpPort.

    using WatsonWebsocket;
    
    WatsonWsServer server = new WatsonWsServer("[ip]", port, true|false);
    server.ClientConnected += ClientConnected;
    server.ClientDisconnected += ClientDisconnected;
    server.MessageReceived += MessageReceived; 
    server.Start();
    
    static void ClientConnected(object sender, ConnectionEventArgs args) 
    {
        Console.WriteLine("Client connected: " + args.Client.ToString());
    }
    
    static void ClientDisconnected(object sender, DisconnectionEventArgs args) 
    {
        Console.WriteLine("Client disconnected: " + args.Client.ToString());
    }
    
    static void MessageReceived(object sender, MessageReceivedEventArgs args) 
    {
        Console.WriteLine("Message received from " + args.Client.ToString() + ": " + Encoding.UTF8.GetString(args.Data));
    }
  5. Implement a WatsonWsClient

    main

    To create a websocket client, instantiate WatsonWsClient. The constructor accepts the server's IP address, the port, and a bool to enable or disable SSL. Subscribe to ServerConnected, ServerDisconnected, and MessageReceived events to handle the connection lifecycle and incoming messages.

    using WatsonWebsocket;
    
    WatsonWsClient client = new WatsonWsClient("[server ip]", [server port], true|false);
    client.ServerConnected += ServerConnected;
    client.ServerDisconnected += ServerDisconnected;
    client.MessageReceived += MessageReceived; 
    client.Start(); 
    
    static void MessageReceived(object sender, MessageReceivedEventArgs args) 
    {
        Console.WriteLine("Message from server: " + Encoding.UTF8.GetString(args.Data));
    }
    
    static void ServerConnected(object sender, EventArgs args) 
    {
        Console.WriteLine("Server connected");
    }
    
    static void ServerDisconnected(object sender, EventArgs args) 
    {
        Console.WriteLine("Server disconnected");
    }
  6. Send messages with WatsonWsClient

    main

    The WatsonWsClient provides methods for both asynchronous fire-and-forget messaging and synchronous request-response patterns.

    Asynchronous Messaging

    • SendAsync(string text): Sends a text message to the server. Returns a Task<bool> indicating success.
    • SendAsync(byte[] data): Sends binary data to the server. Returns a Task<bool> indicating success.

    Synchronous (Wait-for-Response) Messaging

    • SendAndWaitAsync(string text): Sends text and awaits a response from the server. Returns the response as a string.
    • SendAndWaitAsync(byte[] data): Sends binary data and awaits a response. Returns the response as a byte[] (or a collection of bytes).
    // Fire and forget text
    bool success = await _client.SendAsync("Hello Server");
    
    // Fire and forget bytes
    await _client.SendAsync(Encoding.UTF8.GetBytes(myByteArray));
    
    // Send text and wait for response
    string response = await _client.SendAndWaitAsync("Ping");
    
    // Send bytes and wait for response
    byte[] responseBytes = await _client.SendAndWaitAsync(Encoding.UTF8.GetBytes("BinaryPing"));
  7. Initialize WatsonWsClient with custom HTTP headers

    main

    To include custom HTTP headers in the websocket handshake, use the StartWithTimeoutAsync method. This method accepts a NameValueCollection containing your custom headers.

    Note: You must provide the headers during the connection startup phase.

    using System.Collections.Specialized;
    
    // Create your headers
    NameValueCollection headers = new NameValueCollection();
    headers.Add("Custom-Header", "HeaderValue");
    
    // Start the client with headers
    // The timeout is specified in seconds
    await _Client.StartWithTimeoutAsync(30, headers);
  8. Initialize and use WatsonWsClient

    main

    The WatsonWsClient is the primary class used to connect to a Watson server. You can initialize it using a Uri object, specifying either ws:// or wss:// depending on whether SSL is required.

    Key Lifecycle Methods

    • StartWithTimeoutAsync(int timeout): Starts the client connection with a specified timeout (in seconds).
    • Stop(): Closes the connection.
    • Dispose(): Disposes of the client and its resources.

    Connection Properties

    • Connected: A boolean indicating if the client is currently connected to the server.
    • AcceptInvalidCertificates: A boolean to allow connections even if the server's SSL certificate is invalid.

    Event Handlers

    Subscribe to these events to react to connection changes and incoming data:

    • ServerConnected: Triggered when a connection is successfully established.
    • ServerDisconnected: Triggered when the connection is lost or closed.
    • MessageReceived: Triggered when a message is received from the server. Use the MessageReceivedEventArgs to access the data and the message type.
    // Initialize using a URI
    var client = new WatsonWsClient(new Uri("wss://localhost:9000"));
    
    // Configure SSL behavior
    client.AcceptInvalidCertificates = true;
    
    // Subscribe to events
    client.ServerConnected += (sender, args) => Console.WriteLine("Connected!");
    client.MessageReceived += (sender, args) => {
        string msg = Encoding.UTF8.GetString(args.Data.Array, 0, args.Data.Count);
        Console.WriteLine($"{args.MessageType}: {msg}");
    };
    
    // Start the connection
    await client.StartWithTimeoutAsync(30);
  9. Manage Clients and Send Messages with WatsonWsServer

    main

    Once the server is running, you can interact with connected clients using their unique Guid.

    Key Operations:

    • List Clients: Use ListClients() to retrieve a collection of ClientMetadata objects representing all currently connected clients.
    • Send Data: Use SendAsync(Guid clientGuid, byte[] data) or SendAsync(Guid clientGuid, string text) to send messages to a specific client. This method returns a Task<bool> indicating success.
    • Disconnect Client: Use DisconnectClient(Guid clientGuid) to force a specific client to disconnect.
    • Server Statistics: Access Stats to retrieve server performance and connection metrics.
    // List all clients
    var clients = server.ListClients();
    foreach (var client in clients) {
        Console.WriteLine(client.ToString());
    }
    
    // Send a text message to a specific client
    Guid targetGuid = Guid.Parse("...");
    bool success = await server.SendAsync(targetGuid, "Hello Client!");
    
    // Force a client to disconnect
    server.DisconnectClient(targetGuid);
  10. Configure SSL and certificate validation

    main

    When connecting via wss://, you can control whether the client accepts invalid SSL certificates by setting the AcceptInvalidCertificates property on the WatsonWsClient instance.

    var client = new WatsonWsClient(new Uri("wss://localhost:9000"));
    client.AcceptInvalidCertificates = true; // Set to true to bypass certificate validation
  11. Initialize and Configure WatsonWsServer

    main

    To set up a WebSocket server, instantiate WatsonWsServer with the desired IP address, port, and SSL preference. You can also initialize it using a list of hostnames or a Uri object.

    Key configuration properties include:

    • AcceptInvalidCertificates: A boolean to allow invalid SSL certificates.
    • Logger: A delegate (e.g., Console.WriteLine) to handle logging.
    • HttpHandler: A delegate to handle non-WebSocket HTTP requests received by the server.

    Common events to subscribe to:

    • ClientConnected: Fired when a new client connects. Provides ConnectionEventArgs containing the Client and the HttpRequest.
    • ClientDisconnected: Fired when a client disconnects. Provides DisconnectionEventArgs.
    • MessageReceived: Fired when a message is received. Provides MessageReceivedEventArgs containing the message type and data.
    // Basic initialization
    var server = new WatsonWsServer("localhost", 9000, false);
    server.AcceptInvalidCertificates = true;
    server.Logger = Console.WriteLine;
    
    // Event subscriptions
    server.ClientConnected += (sender, args) => {
        Console.WriteLine($"Client connected: {args.Client.Guid}");
    };
    
    server.MessageReceived += (sender, args) => {
        string msg = Encoding.UTF8.GetString(args.Data.Array, 0, args.Data.Count);
        Console.WriteLine($"Received: {msg}");
    };
    
    // Start the server
    await server.StartAsync();