Secure WebSockets

Establish secure, bi-directional WebSocket connections from BrightScript

The BrightScript language supports secure WebSocket connections. This enables apps, for example, to receive real-time entitlement notifications that grant customers immediate access to content they have purchased, update the app UI based on real-time data received from a backend system, and send real-time analytics and other data to a backend system without repeatedly creating and terminating network connections.

The components that enable secure WebSockets in BrightScript are as follows:

  • roWebSocket. Establishes WebSocket connections to remote WebSocket server URLs and performs bi-directional communication according to the WebSocket protocol.
  • roWebSocketEvent. Delivers asynchronous WebSocket event notifications to your app.

WebSocket examples

Asynchronous event-driven execution

Use an event-driven approach and perform WebSocket operations asynchronously. To do this, set a message port on an roWebSocket instance and handle WebSocket events with roWebSocketEvent objects.

' Test execution routine using asynchronous event driven logic.
function TextEchoTest(ws_url as String)as Boolean
    'Sets event constants like: m.OpenEvent = 1, m.ClosedEvent = 2, …
	SetWSEventConstants(m)
	m.port = createObject("roMessagePort")
    m.websocket = createObject("roWebSocket")
    m.websocket.setMessagePort(m.port)    
    
    m.websocket.SetUrl(ws_url)
	m.echoText = "Test echo message. Please reply!"
	m.echoReceived = False
	m.replyTimeout = 5000 ' we will wait for 5s for echo reply.
    print "Opening connection..."
    m.websocket.Open()
    ' Run the event loop to handle WebSocket events.
    runWSEventLoop(m.port, handleWebSocketEvent)
    
    ' Reporting the test result.
    return m.echoReceived
end function

' Event loop helper receiving WS events and passing them to the
' provided WS event handler.
' The WS event handler should return True for the last event to let the loop
' finish.
sub runWSEventLoop(port as Object, eventHandler as Dynamic)
    while(true)
        msg = wait(0, port)
        msgType = type(msg)
        if msgType = "roWebSocketEvent"
            if eventHandler(msg)
                return
            end if
        end if
    end while
end sub

' Dispatching WS events to specific event handlers.
function handleWebSocketEvent(msg as Object) as Boolean
    TraceWSEvent(msg)
    event = msg.GetType()
    if event = m.OpenedEvent ' =1
        return OnOpened(msg)
    else if event = m.ClosedEvent ' =2
        return OnClosed(msg)
    else if event = m.TimerEvent ' =9
        return OnTimer(msg)
    else if event = m.TextReceivedEvent ' =5
        return OnTextReceived(msg)
    end if
    return false
end function

function OnOpened(msg as Object) as Boolean    
    'Sending our Echo text message    
    m.websocket.Send(m.echoText)
    ' Setting one-shot timer for max reply time.
    m.websocket.SetTimer("Echo reply timer", m.replyTimeout, true)
    return false 'Not the last event for our event loop.
end function 
   
function OnTimer(msg as Object) as Boolean
    print "Echo reply timeout ocurred." 
    ' Closing our WebSocket.
    print "Closing connection..."
    m.websocket.Close()
    return false 'Not the last event for our event loop.
end function

function OnClosed(msg as Object) as Boolean
    print "Connection closed."    
    return true 'Finally, it is the last event for our event loop!
end function

function OnTextReceived(msg as Object) as Boolean
    print "Text received."
    if msg.GetInfo().Text = m.echoText
        m.echoReceived = True
    end if    
    ' Closing our WebSocket.
    print "Closing connection..."
    m.websocket.Close()
    return false 'Not the last event for our event loop.
end function

Synchronous execution

Although an asynchronous event-driven approach is recommended for WebSocket operations, a synchronous step-by-step method is sometimes easier — especially when the WebSocket client knows how the server behaves. In this case, run the synchronous operations in a task that runs in parallel with the main UI task. Waiting for WebSocket events in a blocking, step-by-step manner then does not block the UI task.

A mixed approach can also be useful, where some WebSocket operations are done in a blocking, step-by-step synchronous way (for example, a setup step) and the remaining operations are done in an asynchronous, event-driven, non-blocking manner.

The roWebSocket interface provides methods (for example, Open(), Send(), and Close()) that block for client-initiated operations. You can implement waiting for server messages using WebSocket events and helper functions.

' Test execution routine using synchronous event driven logic.
function TextEchoTestSync(ws_url as String)as Boolean
	'Sets event constants like: m.OpenEvent = 1, m.ClosedEvent = 2, …
	SetWSEventConstants(m)

	m.port = createObject("roMessagePort")
    m.websocket = createObject("roWebSocket")
    m.websocket.setMessagePort(m.port)    
    m.websocket.SetUrl(ws_url)
	m.echoText = "Test echo message. Please reply!"
	m.echoReceived = False
	m.replyTimeout = 5000 ' we will wait for 5s for echo reply.
	
	'Opening WebSocket connection will wait for 2s for opening.
    print "Opening connection..."
    if !m.websocket.Open(2000)
		print "Failed to open connection."
		return False
	end if
    print "Websocket is ready."
    ' print Open info.
    print "open_info="; m.websocket.GetOpenInfo()
    
    ' Sending our Echo text message.
    m.websocket.Send(m.echoText)    
    ' Waiting for the 'text received' event up to the reply timeout.
    msg = waitForWSEvent(m.port, m.TextReceivedEvent, m.replyTimeout)
    if msg <> invalid
        m.echoReceived = msg.GetInfo().Text = m.echoText
    end if
    
    ' Closing our WebSocket
    print "Closing connection..."
    m.websocket.Close()
    print "Connection closed."
    ' Reporting the test result.
    return m.echoReceived
end function

' Helper function waiting for a certain WS event.
function waitForWSEvent(port as Object, event as Integer, timeout = 0 as Integer, socket_id = -1 as Integer) as Object
    while(true)
        msg = wait(timeout, port)
        if msg = invalid
            return msg
        end if
        msgType = type(msg)
        if msgType = "roWebSocketEvent"
            e = msg.GetType()
            socket_match = True
            if socket_id > 0 and socket_id <> msg.GetSocketId()
                ' Not event from the socket we want.
                socket_match = false
            end if
            if socket_match
                if e = event
                    return msg
                else if e = 2 ' Close event
                    ' if WebSocket was closed we will not get our event, so we need to stop waiting.
                    exit while
                end if
            end if
        end if
    end while
    return Invalid
end function

Did this page help you?