The WebSocket plugin enables real-time bidirectional communication between clients and the Rusty Beam server. It provides automatic subscription to document changes and broadcasts live updates when content is modified through the selector-handler plugin.
This plugin implements the WebSocket protocol (RFC 6455) and integrates with Rusty Beam's selector-based architecture to provide real-time updates. When a WebSocket connects to a document URL, it automatically subscribes to all changes for that document. When the document is modified using HTTP requests with CSS selectors, all WebSocket clients connected to that URL receive immediate notifications in the StreamItem format.
To add the WebSocket plugin to your pipeline:
<table itemscope itemtype="https://rustybeam.net/schema/Plugin">
<tbody>
<tr>
<td>Library</td>
<td itemprop="library">file://./plugins/librusty_beam_websocket.so</td>
</tr>
</tbody>
</table>
The WebSocket plugin currently has no configuration parameters. All settings are handled automatically.
Parameter | Type | Required | Default | Description |
---|---|---|---|---|
No configuration parameters required |
Recommended pipeline order:
# Test WebSocket upgrade
curl -i -N \
-H "Connection: Upgrade" \
-H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==" \
-H "Sec-WebSocket-Version: 13" \
http://localhost:3000/document.html
# Expected response:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
// Connect to WebSocket for the current page
const ws = new WebSocket(`ws://localhost:3000${window.location.pathname}`);
ws.onopen = function() {
console.log('WebSocket connected');
};
ws.onmessage = function(event) {
// Parse the StreamItem
const parser = new DOMParser();
const doc = parser.parseFromString(event.data, 'text/html');
const streamItem = doc.querySelector('[itemtype="https://rustybeam.net/schema/StreamItem"]');
if (streamItem) {
const method = streamItem.querySelector('[itemprop="method"]').textContent;
const url = streamItem.querySelector('[itemprop="url"]').textContent;
const selector = streamItem.querySelector('[itemprop="selector"]').textContent;
const content = streamItem.querySelector('[itemprop="content"]').innerHTML;
console.log(`${method} ${url} ${selector}:`, content);
// Apply the update to the current page if it matches
if (url === window.location.pathname) {
const target = document.querySelector(selector);
if (target) {
target.outerHTML = content;
}
}
}
};
import websocket
from bs4 import BeautifulSoup
def on_message(ws, message):
print(f"Received: {message}")
# Parse StreamItem
soup = BeautifulSoup(message, 'html.parser')
stream_item = soup.find(attrs={'itemtype': 'https://rustybeam.net/schema/StreamItem'})
if stream_item:
method = stream_item.find(attrs={'itemprop': 'method'}).text
url = stream_item.find(attrs={'itemprop': 'url'}).text
selector = stream_item.find(attrs={'itemprop': 'selector'}).text
content = stream_item.find(attrs={'itemprop': 'content'}).decode_contents()
print(f"{method} {url} {selector}: {content}")
def on_open(ws):
print("WebSocket connected - automatically subscribed to document changes")
ws = websocket.WebSocketApp("ws://localhost:3000/blog/post.html",
on_open=on_open,
on_message=on_message)
ws.run_forever()
Updates are triggered when content is modified using the selector-handler plugin:
# This will broadcast to all WebSocket clients connected to /document.html
curl -X PUT \
-H "Range: selector=#content" \
-d '<div id="content">Updated content</div>' \
http://localhost:3000/document.html
Updates are broadcast in the StreamItem microdata format:
<div itemscope itemtype="https://rustybeam.net/schema/StreamItem">
<span itemprop="method">PUT</span>
<span itemprop="url">/document.html</span>
<span itemprop="selector">#content</span>
<div itemprop="content">
<div id="content">Updated content</div>
</div>
</div>
The WebSocket plugin uses a simple connection-based subscription model:
ws://host:port/document.html
/document.html
No explicit subscription messages are required - the subscription is based on the URL path of the WebSocket connection.
The WebSocket plugin relies on metadata set by the selector-handler plugin. When selector-handler successfully applies a change, it sets:
applied_selector
- The CSS selector that was usedselected_content
- The updated HTML contentWebSocket connections respect the same authorization rules as HTTP requests. Clients must be authorized to access the document URL they're connecting to.
WebSocket upgrade requests are logged like any other HTTP request. The connection upgrade shows as a 101 status code in access logs.
Issue | Possible Cause | Solution |
---|---|---|
Connection fails with 404 | WebSocket plugin not in pipeline | Ensure WebSocket plugin is loaded before file-handler |
No updates received | Connected to wrong URL or no updates occurring | Verify WebSocket connects to the same URL being updated |
Connection closes immediately | Authorization failure | Check authorization rules for the document URL |
Invalid upgrade response | Missing WebSocket headers | Ensure client sends all required WebSocket headers |
Enable verbose mode to see WebSocket activity:
./rusty-beam -v config.html
This will show: