Skip to content

SSE Server-Side Real-time Push

Overview

HttpServer has built-in SSE (Server-Sent Events) support, enabling server-to-client real-time message push. Suitable for:

  • Real-time notifications
  • Online chat
  • Data monitoring
  • Progress push

Client Request

Client connects using cSSEClient:

vb
Private WithEvents SSE As cSSEClient

Private Sub Connect()
    Set SSE = New cSSEClient
    SSE.Connect "http://localhost:8080/events"
End Sub

Private Sub SSE_OnMessage(EventName As String, Data As String, Id As String)
    Debug.Print "Received: " & EventName & " = " & Data
End Sub

Server Implementation

Basic Push

vb
' Push message in controller
Public Sub Events(ctx As cHttpServerContext)
    ' Use SendPack for quick send
    ctx.SSE.SendPack "message", "Hello World", ctx.ClientInfo.hSocket

    ' Send JSON data
    Dim data As New Dictionary
    data("time") = Now
    data("status") = "ok"
    ctx.SSE.SendPack "data", Json.Encode(data), ctx.ClientInfo.hSocket

    ' Use Data + Send for custom data structure
    ctx.SSE.Data.Add "type", "alert"
    ctx.SSE.Data.Add "message", "System maintenance notice"
    ctx.SSE.Send ctx.ClientInfo.hSocket
End Sub

Broadcast Message

vb
' cNotificationController.cls

' Send to all connections (omit hSocket for broadcast)
Public Sub Broadcast(ctx As cHttpServerContext)
    Dim msg As String
    msg = ctx.Request.Form("message")

    ' Broadcast to all SSE clients
    ctx.SSE.SendPack "notification", msg

    ctx.Response.Json Nothing, 0, "Broadcast sent"
End Sub

' Send to specific user
Public Sub SendToUser(ctx As cHttpServerContext)
    Dim userId As String, msg As String
    userId = ctx.Request.Form("user_id")
    msg = ctx.Request.Form("message")

    ' Chain call to send to specific user
    ctx.SSE.ToUser(userId).SendPack "private", msg
    ctx.Response.Json Nothing, 0, "Sent"
End Sub

Real-time Data Stream

Note: SSE is an event-driven model, not suitable for Do While polling loops in controllers. Use a timer (e.g., cTimer) to periodically push data instead of blocking loops.

vb
' cMonitorController.cls
' Push triggered by timer (recommended approach)
Public Sub PushStats(ctx As cHttpServerContext)
    ' Collect system data
    Dim data As New Dictionary
    data("cpu") = GetCPUUsage()
    data("memory") = GetMemoryUsage()
    data("time") = Now

    ' Push to all online SSE clients
    ctx.SSE.SendPack "stats", Json.Encode(data)
End Sub

Progress Push

vb
' cTaskController.cls
' Push progress triggered by timer or callback
Public Sub PushProgress(ctx As cHttpServerContext)
    Dim taskId As String
    taskId = ctx.Request.Form("task_id")
    Dim percent As Long
    percent = CLng(ctx.Request.Form("percent"))

    Dim progress As New Dictionary
    progress("percent") = percent
    progress("task_id") = taskId

    ' Push to requesting client
    ctx.SSE.SendPack "progress", Json.Encode(progress), ctx.ClientInfo.hSocket
End Sub

Public Sub PushComplete(ctx As cHttpServerContext)
    ctx.SSE.SendPack "complete", "{\"status\":\"done\"}", ctx.ClientInfo.hSocket
End Sub

Complete Chat Example

vb
' ========== Server ==========

' cChatController.cls
Option Explicit

' GET /chat/stream
Public Sub Stream(ctx As cHttpServerContext)
    ' Check login
    If Not ctx.Session.Exists("user_id") Then
        ctx.Response.State401 "Please login first"
        Exit Sub
    End If

    ' Register to chat room (SSE connection managed by framework, no manual headers needed)
    Dim userId As String, username As String
    userId = ctx.Session("user_id")
    username = ctx.Session("username")

    ' Bind user (can push by username later)
    ctx.SSE.BindUser ctx.ClientInfo.hSocket, userId

    ' Send welcome message
    ctx.SSE.SendPack "system", "{\"msg\":\"Welcome " & username & " to the chat room\"}", ctx.ClientInfo.hSocket
End Sub

' POST /chat/send
Public Sub SendMsg(ctx As cHttpServerContext)
    Dim msg As String
    msg = ctx.Request.Form("message")

    Dim username As String
    username = ctx.Session("username")

    ' Broadcast to all users (omit hSocket for broadcast)
    Dim data As String
    data = "{\"user\":\"" & username & "\",\"msg\":\"" & msg & "\"}"

    ctx.SSE.SendPack "message", data

    ctx.Response.Json Nothing, 0, "Sent"
End Sub

' ========== Client ==========

Private WithEvents SSE As cSSEClient

Private Sub JoinChat()
    Set SSE = New cSSEClient
    SSE.Connect "http://localhost:8080/chat/stream"
End Sub

Private Sub SendMessage(msg As String)
    Dim http As New cHttpClient
    http.RequestDataForm("message") = msg
    http.SendPost "http://localhost:8080/chat/send"
End Sub

Private Sub SSE_OnMessage(EventName As String, Data As String, Id As String)
    Select Case EventName
        Case "system"
            ' Show system message
            ShowSystemMessage Data
        Case "message"
            ' Show chat message
            ShowChatMessage Data
    End Select
End Sub

Server API Reference

Start

Start SSE service, bind path and event handler.

Note: Start is a method of the cSSE class, only called during service startup. It cannot be called via ctx.SSE (cSSEContext) in controllers.

vb
Public Function Start(Optional MatchPath As String, Optional EventsHandler As Object) As Boolean

Parameters:

  • MatchPath - Request path to match (empty matches all)
  • EventsHandler - Event handler object, must implement OnConnect(Context) and OnClose(Context) methods

Example:

vb
' Start SSE, listen on /events path
Set SSE = New cSSE
SSE.Start "/events", Me  ' Me implements OnConnect/OnClose

' In event handler
Public Sub OnConnect(ctx As cHttpServerContext)
    Debug.Print "SSE client connected: " & ctx.ClientInfo.IP
End Sub

Public Sub OnClose(ctx As cHttpServerContext)
    Debug.Print "SSE client disconnected: " & ctx.ClientInfo.IP
End Sub

Send / SendPack

Send message to SSE client.

vb
' Custom data send
Public Function Send(Optional ByVal hSocket As Long) As Boolean

' Quick pack send (action + content format)
Public Function SendPack(Action As String, Content As Variant, Optional hSocket As Long) As Boolean

Description: Send uses the shared Data dictionary to build message body, SendPack auto-wraps {"action":..., "content":...} format. Both support specifying hSocket to send to a specific client, or omit (target set by ToUser/ToGroup chain).

Send Reentry Safety: The Send method snapshots the shared Data to a local variable before encoding, so even if reentry calls are triggered during sending, data corruption will not occur.

Example:

vb
' Use Send for custom data
SSE.Data.Add "type", "alert"
SSE.Data.Add "message", "System maintenance notice"
SSE.Send hSocket

' Use SendPack for quick send
SSE.SendPack "notification", "You have a new message", hSocket

' Chain call to send to specific user
SSE.ToUser("admin").SendPack "private", "Welcome back"

CloseClient

Close specified SSE client connection.

vb
Public Function CloseClient(Optional ByVal hSocket As Long) As Boolean

Description: Whether called via parameter or ToUser chain, performs complete cleanup:

  1. Trigger OnClose user event
  2. Clear SSE context references
  3. Remove from Clients dictionary
  4. Clean up user/group mappings
  5. Close Socket connection, triggering cClientCallback's complete cleanup flow

Example:

vb
' Close specified client
SSE.CloseClient hSocket

' Chain close specified user
SSE.ToUser("admin").CloseClient

BindUser / GetUser / GetClientByUser

Manage user-to-Socket mapping.

vb
Public Function BindUser(ByVal hSocket As Long, ByVal User As String) As Boolean
Public Function GetUser(ByVal hSocket As Long) As String
Public Function GetClientByUser(ByVal User As String) As Long

Example:

vb
' Bind user
SSE.BindUser hSocket, "user_123"

' Find socket by username
Dim sock As Long
sock = SSE.GetClientByUser("user_123")

' Find username by socket
Dim user As String
user = SSE.GetUser(hSocket)

ToUser / ToGroup

Chain call to specify send target.

vb
Public Function ToUser(ByVal User As String) As cSSEContext
Public Function ToGroup(ByVal Name As String) As cSSEContext

Description: Returns cSSEContext itself while setting the internal target hSocket. Subsequent calls to Send/SendPack/CloseClient don't need to pass hSocket.

Example:

vb
' Send to specific user
ctx.SSE.ToUser("admin").SendPack "msg", "Hello Admin"

' Close specific user connection
ctx.SSE.ToUser("admin").CloseClient

ClientCount

Current online SSE client count (read-only).

vb
Public Property Get ClientCount() As Long

Example:

vb
Debug.Print "Online SSE clients: " & SSE.ClientCount

Last Updated: 2026-06-13

VB6 and LOGO copyright of Microsoft Corporation