# How ChocolateLMLite Uses WebSocket Broadcasting for Real-Time Updates

> Discover how ChocolateLMLite leverages WebSocket broadcasting with a static Broadcaster façade for seamless real-time UI updates. Learn about JSON message propagation to connected clients.

- Repository: [Segment (gpsnmeajp)/chocolatelmlite](https://github.com/gpsnmeajp/chocolatelmlite)
- Tags: how-to-guide
- Published: 2026-03-02

---

**ChocolateLMLite implements WebSocket broadcasting through a static Broadcaster façade that decouples application logic from socket management, enabling real-time UI updates via JSON message propagation to all connected clients.**

ChocolateLMLite is an open-source C# application that delivers instant UI synchronization between server-side events and browser clients. According to the gpsnmeajp/chocolatelmlite source code, the project implements **WebSocket broadcasting for real-time updates** through a clean separation of concerns, isolating socket handling in a dedicated WebServer class while exposing a simple static API via the Broadcaster component.

## Core Architecture Components

The broadcasting system relies on three coordinated components that isolate networking complexity from business logic.

### The WebServer Class

Located in [`src/WebServer.cs`](https://github.com/gpsnmeajp/chocolatelmlite/blob/main/src/WebServer.cs), this class manages the actual WebSocket connections. It maintains a thread-safe collection of active clients and handles JSON serialization using `System.Text.Json` with camelCase naming policies.

### The Broadcaster Façade

The [`src/Broadcaster.cs`](https://github.com/gpsnmeajp/chocolatelmlite/blob/main/src/Broadcaster.cs) file defines a static class that acts as a dispatch proxy. It stores a delegate reference to the WebServer's broadcast method, allowing any part of the application to push messages without referencing socket APIs directly.

### Frontend Integration

Browser clients connect via standard WebSocket APIs defined in files like [`static/js/gametalk.js`](https://github.com/gpsnmeajp/chocolatelmlite/blob/main/static/js/gametalk.js). These scripts parse incoming JSON payloads and update the DOM immediately upon receiving server events.

## Implementing the Broadcast Façade (src/Broadcaster.cs)

The Broadcaster class eliminates tight coupling between application logic and network infrastructure. It accepts a `Func<Dictionary<string, object>, Task>` delegate during initialization, which it invokes whenever the application needs to broadcast.

```csharp
// src/Broadcaster.cs
public static class Broadcaster
{
    static Func<Dictionary<string, object>, Task>? broadcastAction;

    // Called once at startup – registers the concrete Web‑Socket push method.
    public static void Initialize(Func<Dictionary<string, object>, Task> action)
        => broadcastAction = action;

    // Any component calls this to push a message to all clients.
    public static async Task Broadcast(Dictionary<string, object> message)
    {
        if (broadcastAction != null)
            await broadcastAction.Invoke(message);
    }
}

```

By accepting a delegate rather than a concrete server instance, the design supports testing scenarios where the broadcast action can be replaced with a mock implementation.

## WebSocket Server Broadcasting Logic (src/WebServer.cs)

The WebServer class handles connection management and message distribution. It stores active sockets in a `List<WebSocket>` protected by a `lock` statement to ensure thread safety during concurrent access.

When broadcasting, the server creates a snapshot of the client list to avoid holding locks during network I/O. It serializes the `Dictionary<string, object>` payload to JSON using `JsonSerializerOptions` configured with `PropertyNamingPolicy.CamelCase`.

```csharp
// src/WebServer.cs (excerpt)
public class WebServer
{
    private readonly List<WebSocket> _clients = new();   // thread‑safe via lock
    private readonly JsonSerializerOptions _jsonOpts = new() 
    { 
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase 
    };

    // Called by Broadcaster – sends JSON to every connected client.
    public async Task Broadcast(Dictionary<string, object> payload)
    {
        var json = JsonSerializer.Serialize(payload, _jsonOpts);
        var buffer = Encoding.UTF8.GetBytes(json);
        var segment = new ArraySegment<byte>(buffer);

        List<WebSocket> snapshot;
        lock (_clients) snapshot = _clients.ToList();   // copy to avoid locking during I/O

        foreach (var ws in snapshot)
        {
            if (ws.State == WebSocketState.Open)
                await ws.SendAsync(
                    segment, 
                    WebSocketMessageType.Text, 
                    true, 
                    CancellationToken.None);
        }
    }
}

```

This implementation ensures that slow clients or network latency do not block the broadcast loop for other recipients.

## Application Startup and Registration (src/Program.cs)

The application entry point wires the Broadcaster to the WebServer instance. During startup, the server instantiates `WebServer`, then registers its `Broadcast` method with the static façade.

```csharp
// src/Program.cs (excerpt)
var server = new WebServer(/* config */);
Broadcaster.Initialize(server.Broadcast);   // ← registers the broadcast delegate
await server.StartAsync();                 // starts the HTTP/Web‑Socket listener

```

Once initialized, any component throughout the codebase can call `Broadcaster.Broadcast()` to trigger real-time updates without knowing which clients are connected or how serialization occurs.

## Handling Real-Time Updates in the Browser (static/js/gametalk.js)

Client-side JavaScript establishes a WebSocket connection to the backend endpoint (typically `/ws`). The event listener parses incoming JSON and routes messages based on type fields, updating chat bubbles or status indicators without page reloads.

```javascript
// static/js/gametalk.js (excerpt)
const socket = new WebSocket(
    `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/ws`
);

socket.addEventListener('message', event => {
    const msg = JSON.parse(event.data);
    switch (msg.type) {
        case 'chat':
            renderChatBubble(msg.author, msg.content);
            break;
        case 'status':
            updateStatusBar(msg.status);
            break;
    }
});

```

This architecture enables instantaneous UI reflection of server-side events such as LLM responses, persona switches, or system status changes.

## Summary

- **ChocolateLMLite** uses a delegate-based façade pattern to separate WebSocket broadcasting from application logic.
- The **`Broadcaster`** class in [`src/Broadcaster.cs`](https://github.com/gpsnmeajp/chocolatelmlite/blob/main/src/Broadcaster.cs) provides a static API that accepts `Dictionary<string, object>` messages and forwards them to a registered delegate.
- **`WebServer`** in [`src/WebServer.cs`](https://github.com/gpsnmeajp/chocolatelmlite/blob/main/src/WebServer.cs) manages thread-safe client lists using `lock` statements and broadcasts JSON using `System.Text.Json` with camelCase serialization.
- **Startup initialization** in [`src/Program.cs`](https://github.com/gpsnmeajp/chocolatelmlite/blob/main/src/Program.cs) connects the Broadcaster to the WebServer via `Broadcaster.Initialize(server.Broadcast)`.
- Browser clients in [`static/js/gametalk.js`](https://github.com/gpsnmeajp/chocolatelmlite/blob/main/static/js/gametalk.js) consume WebSocket messages to update the DOM in real time without HTTP polling.

## Frequently Asked Questions

### How does ChocolateLMLite ensure thread safety during WebSocket broadcasting?

The `WebServer` class maintains a `List<WebSocket>` field that is accessed exclusively within `lock (_clients)` blocks. When broadcasting, it creates a snapshot copy of the list to iterate over, preventing modification exceptions while allowing the main collection to accept new connections or removals during transmission.

### What data format does ChocolateLMLite use for real-time messages?

The system uses `Dictionary<string, object>` payloads internally, which `WebServer.Broadcast` serializes to JSON using `System.Text.Json.JsonSerializer`. The serializer options specify `PropertyNamingPolicy.CamelCase`, ensuring consistent lowercase property names in the transmitted JSON.

### Can the Broadcaster be tested without an active WebSocket server?

Yes. Because `Broadcaster.Initialize` accepts a `Func<Dictionary<string, object>, Task>` delegate rather than a concrete type, unit tests can inject mock implementations that capture messages or write to logs instead of transmitting over network sockets. This design decouples message generation from transport concerns.

### Which frontend files handle WebSocket connections in ChocolateLMLite?

The primary client-side WebSocket logic resides in [`static/js/gametalk.js`](https://github.com/gpsnmeajp/chocolatelmlite/blob/main/static/js/gametalk.js), which creates the WebSocket instance, attaches `message` event listeners, and parses JSON payloads to update chat interfaces and status displays dynamically.