Overview

Server-Sent Events (SSE)

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.

Source Code

<?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;
?>

Result

<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>
On this page