Showcases modern real-time communication patterns between the server and web clients. This example demonstrates using 'WebResponse.SetContentEventStream' to maintain persistent HTTP connections and the 'WebServerSentEvent' class to broadcast live data updates to multiple subscribers using a name-based channel pattern.
<?pas
var mode := WebRequest.QueryField['mode'];
if mode = 'stream' then begin
// 1. SSE Endpoint
// Establish the connection on 'my_channel'
WebResponse.SetContentEventStream('my_channel');
// The connection is now kept open by the server automatically
end else if mode = 'broadcast' then begin
// 2. Event Trigger
// Broadcast an event to all listeners on 'my_channel'
var evt := new WebServerSentEvent;
evt.Name := 'ping'; // Event name (client listens for 'ping' or 'message')
evt.Data.Add('Server time: ' + FormatDateTime('hh:nn:ss.z', Now));
evt.Post('my_channel');
Print('Broadcasted to ' + IntToStr(WebServerSentEvents.Connections('my_channel').Length) + ' clients.');
end else begin
// 3. Client UI (HTML + JS)
Print(#'
<h3>Server-Sent Events Demo</h3>
<p>This page connects to the server and listens for real-time events.</p>
<div class="mb-3">
<button id="btn-ping" class="btn btn-primary">Broadcast Event</button>
<span id="status" class="ms-2 text-muted">Connecting...</span>
</div>
<div id="log" class="border rounded p-2 bg-body-tertiary" style="height: 200px; overflow-y: auto; font-family: monospace;"></div>
<script>
const log = document.getElementById("log");
const status = document.getElementById("status");
// Connect to the SSE stream
const evtSource = new EventSource("?mode=stream");
evtSource.onopen = function() {
status.textContent = "Connected (Listening on my_channel)";
status.className = "ms-2 text-success";
};
evtSource.onerror = function() {
status.textContent = "Disconnected";
status.className = "ms-2 text-danger";
};
// Listen for specific event name "ping"
evtSource.addEventListener("ping", function(e) {
const line = document.createElement("div");
line.textContent = "Received: " + e.data;
log.prepend(line);
});
// Button to trigger broadcast
document.getElementById("btn-ping").onclick = function() {
fetch("?mode=broadcast")
.then(r => r.text())
.then(msg => {
const line = document.createElement("div");
line.style.color = "gray";
line.textContent = "Log: " + msg;
log.prepend(line);
});
};
</script>
');
end;
?>
<h3>Server-Sent Events Demo</h3>
<p>This page connects to the server and listens for real-time events.</p>
<div class="mb-3">
<button id="btn-ping" class="btn btn-primary">Broadcast Event</button>
<span id="status" class="ms-2 text-muted">Connecting...</span>
</div>
<div id="log" class="border rounded p-2 bg-body-tertiary" style="height: 200px; overflow-y: auto; font-family: monospace;"></div>
<script>
const log = document.getElementById("log");
const status = document.getElementById("status");
// Connect to the SSE stream
const evtSource = new EventSource("?mode=stream");
evtSource.onopen = function() {
status.textContent = "Connected (Listening on my_channel)";
status.className = "ms-2 text-success";
};
evtSource.onerror = function() {
status.textContent = "Disconnected";
status.className = "ms-2 text-danger";
};
// Listen for specific event name "ping"
evtSource.addEventListener("ping", function(e) {
const line = document.createElement("div");
line.textContent = "Received: " + e.data;
log.prepend(line);
});
// Button to trigger broadcast
document.getElementById("btn-ping").onclick = function() {
fetch("?mode=broadcast")
.then(r => r.text())
.then(msg => {
const line = document.createElement("div");
line.style.color = "gray";
line.textContent = "Log: " + msg;
log.prepend(line);
});
};
</script>