Group Chat Data Flow & RCWeb Implementation

This document explains how the "Chat" example leverages RCWeb technology to enable real-time symmetric multi-user communication and peer-to-peer file sharing without a backend database.

1. How the Group Chat Works

Unlike Spacewar's Viewer-Controller architecture, the Chat application uses a symmetric peer-to-peer model. All connected users run the same app by loading the same HTML page (chat/index.html) and join the same room. They act as both senders and receivers.

2. Building a Similar App using RCWeb

To recreate this pattern for a new multi-user symmetric app (like a whiteboard, collaborative editor, or group chat), use these features in the RCWeb library:

A. Configure the Server-Side Environment

Your HTML page must configure the rc environment variables. All clients share the same app (e.g. "chat") and room.

<script>
    var rc = {
            "version": "${version}",
            "app": "${app}",
            "room": "${roomId}",
            "client": "${clientId}",
            "commsWebSocket": "${websocket}"
    };
</script>
<script src="/assets/core/comms.js"></script>

B. Symmetric Messaging

Define a global API for other peers to invoke, and use rc.sendFunctionCall to invoke it on other peers. This method automatically serializes arguments for safe execution on the target(s).

var myApp = (function() {
    return {
        // Public API to be executed remotely over RCWeb
        receiveMessage: function(client, text) {
            if (client === rc.client) return; // Skip our own echo
            // Add message to screen...
        },
        sendMessage: function(text) {
            // Predict local change
            // Add message to screen...
            
            // Broadcast execution instructions to other "chat" app peers in the room
            rc.sendFunctionCall("chat", "myApp.receiveMessage", rc.client, text);
        }
    };
})();

C. Implement P2P File Sharing

To serve local Blobs/Files directly to other clients through the RCWeb server proxy, bind to rc.sendFileChunk:

rc.sendFileChunk = function (fileId, start, url) {
    var file = myApp.sharedFiles[fileId];
    if (!file) return;

    var chunkSize = 1000000; // 1MB chunks
    var end = Math.min(file.size, start + chunkSize);
    var chunk = file.slice(start, end);

    var xhr = new XMLHttpRequest();
    xhr.open("PUT", url);
    xhr.setRequestHeader("Content-Type", file.type);
    xhr.setRequestHeader("Content-Range", "bytes=" + start + "-" + (end - 1) + "/" + file.size);
    xhr.send(chunk);
};

// URL format to share with peers:
// "/x-file/" + rc.room + "/" + rc.client + "/" + fileId + "/image.jpg"

D. Track Presence

Listen to network and client events to maintain the shared room state.

rc.onUpdateClients = function (clients) {
    console.log("Currently connected clients:", clients);
    // Cleanup state for clients that left...
};

rc.onUpdateNetworkStatus = function (heading, info) {
    if (rc.connected && !wasConnected) {
        // We just joined, ask peers to sync state!
        wasConnected = true;
    }
};

Summary

Using a symmetric RCWeb setup allows for rapid development of real-time collaborative applications. By using Javascript execution instructions as the transmission payload, you write the syncing logic in the same language and location as your UI logic, bypassing complex backend schemas and APIs. Features like P2P proxying and presence tracking are handled natively by the platform.