How to: Server-Sent Events with Indy HTTP Server (part 2)

In this second part, a server application uses the Indy HTTP server to provide a HTML page which uses SSE to update its content with data sent from the server.

Part 2: the basic demo application, some client data added

Ingredient #1: the HTML page with JavaScript

The script now reads two data items from the ping event:

  • the time stamp, now sent from the server in proper ISO 8601 format
  • the peer data, which is the remote ip address and port number
<!DOCTYPE html>
<html>
	<head>
		<title>SSE example</title>
	</head>
	<body>
		<script>
		const evtSource = new EventSource("sse");
		
		evtSource.addEventListener("ping", (event) => {
  const newElement = document.createElement("li");
  const eventList = document.getElementById("list");
  const time = JSON.parse(event.data).time;
  const peer = JSON.parse(event.data).peer;
  newElement.textContent = `ping at ${time} from ${peer}`;
  eventList.appendChild(newElement);
});

		</script>
		<ul id="list">

		</ul>
	</body>
</html>

The code is based on the article Using server-sent events on MDN

https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

Ingredient #2: server side code

The TIdHTTPServer subclass now contains a private method to provide client-specific data in the /sse resource.

  function TMySSEServer.BuildContentText(AContext: TIdContext): string;
  begin
    Result := '';
    repeat
      Result := Result + 'event: ping' + #13 +
        Format('data: {"time": "%s", "peer": "%s:%d"}',
        [DateToISO8601(Now, False), AContext.Binding.PeerIP,
        AContext.Binding.PeerPort]) + #13#13;
      Sleep(100);
    until Random < 0.8;
  end; 

The DoCommandGet method uses the BuildContentText function to provide the event data:

  procedure TMySSEServer.DoCommandGet(AContext: TIdContext;
    ARequestInfo: TIdHTTPRequestInfo;
    AResponseInfo: TIdHTTPResponseInfo);
  begin
    if ARequestInfo.Document = '/sse' then
    begin
      AResponseInfo.ContentType := 'text/event-stream';
      AResponseInfo.CacheControl := 'no-store';
      AResponseInfo.ContentText := BuildContentText(AContext);
    end
    else
    begin
      AResponseInfo.ContentType := 'text/html';
      AResponseInfo.ContentStream :=
        TFileStream.Create('index.html', fmOpenRead);
    end;
    AResponseInfo.CharSet := 'UTF-8';
  end;

Output

When the browser navigates to http://localhost, the server will provide the HTML and the embedded JavaScript will start reading data from the address http://localhost/sse and receive one or more events.

The ping event, which the server sends to the browser, now includes the server time in ISO 8601 format and the peer IP address and port.

Next part

In the next part, the data stream will be sent continuously.

How to: Server-Sent Events with Indy HTTP Server (part 1)

In this article, a server application uses the Indy HTTP server to provide a HTML page which uses SSE to update its content with data sent from the server.

Server-Sent Events (SSE) is a server push technology enabling a client to receive automatic updates from a server via an HTTP connection, and describes how servers can initiate data transmission towards clients once an initial client connection has been established.

Server-sent events, https://en.wikipedia.org/w/index.php?title=Server-sent_events&oldid=1093881969 (last visited Sept. 17, 2022).

Part 1: a very basic demo application

Ingredient #1: a HTML page with Javascript

<!DOCTYPE html>
<html>
	<head>
	<title>SSE example</title>
	</head>
	<body>
	<script>
	const evtSource = new EventSource("sse");
		
	evtSource.addEventListener("ping", (event) => {
	  const newElement = document.createElement("li");
	  const eventList = document.getElementById("list");
	  const time = JSON.parse(event.data).time;
	  newElement.textContent = `ping at ${time}`;
	  eventList.appendChild(newElement);
	});
	</script>
	<ul id="list">
	</ul>
	</body>
</html>

The code is based on the article Using server-sent events on MDN

https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events

Ingredient #2: server side code

In the example application, a TIdHTTPServer subclass is used to deliver the HTML document when a browser accesses it.

Note that the server has to keep connections alive, so the Server property KeepAlive must be set to true:

  procedure Test;
  begin
    Server := TMySSEServer.Create;
    try
      Server.KeepAlive := True;
      Server.Startup;
      ReadLn;
    finally
      Server.Free;
    end;
  end;

The DoCommandGet method is overriden and looks like this:

  procedure TMySSEServer.DoCommandGet(AContext: TIdContext;
    ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
  var
    S: TStream;
    C: string;
  begin
    if ARequestInfo.Document = '/sse' then
    begin
       AResponseInfo.ContentType := 'text/event-stream';
       AResponseInfo.CacheControl := 'no-store';
       AResponseInfo.CharSet := 'UTF-8';
      
         C := 'event: ping' + #13
           + Format('data: {"time": "%d"}', [GetTickCount]) 
           + #13#13;

       AResponseInfo.ContentText := C;
       AResponseInfo.ResponseNo := 200;
    end
    else
    begin
      S := TFileStream.Create('index.html', fmOpenRead);
      AResponseInfo.ContentType := 'text/html';
      AResponseInfo.ContentStream := S;
      AResponseInfo.ResponseNo := 200;
    end;
  end;

Output

When the browser navigates to http://localhost, the server will provide the HTML and the embedded JavaScript will start reading data from the address http://localhost/sse (and receive only one event). As specified in the HTML spec for EventSource, the client will retry after some seconds:

Each EventSource object has the following associated with it:
– A reconnection time, in milliseconds. This must initially be an implementation-defined value, probably in the region of a few seconds.

HTML – 9.2 Server-sent events (https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events)

Note: this is just the first step. In the next part, we will implement a continuos data stream.

Habari Client libraries release 2022.08

Habarisoft released new versions of its native STOMP client libraries for Delphi / Object Pascal for integration with popular open source message brokers:

Release notes: https://www.habarisoft.com/release_notes.html

Further resources and demo applications

Home page: https://www.habarisoft.com/

About Habari Client libraries

habari_logo_2016Habari Stomp Client libraries enable Object Pascal applications to take advantage of message broker / message queue technology – which is distributed, loosely coupled, reliable and asynchronous – to build integrated systems, using peer-to-peer and publish-subscribe communication models.

Habari Client libraries release 2022.08

Habarisoft released new versions of its native STOMP client libraries for Delphi / Object Pascal for integration with popular open source message brokers:

Release notes: https://www.habarisoft.com/release_notes.html

This version is the first which makes uses of Generics, supported by Delphi 2009 / Free Pascal 3.2.0 and newer. It also supports repeated header entries as specified in STOMP 1.2 specification: Repeated Header Entries.

The version for ActiveMQ includes a small example for using Stomp with TomEE+ (Jakarta EE 9.1) (see this blog article). The version for Eclipse OpenMQ includes a small example for using Stomp with Payara 5 (Jakarta EE 9.1). The examples are in the demo-broker folder.

The Chat example has been updated to improve its exception handling.

Full Release notes can be found at https://www.habarisoft.com/release_notes.html

Further resources and demo applications

Home page: https://www.habarisoft.com/

About Habari Client libraries

habari_logo_2016Habari Stomp Client libraries enable Object Pascal applications to take advantage of message broker / message queue technology – which is distributed, loosely coupled, reliable and asynchronous – to build integrated systems, using peer-to-peer and publish-subscribe communication models.

How to: send messages from Apache TomEE+ 9 to Delphi / Free Pascal applications

Apache TomEE is a Jakarta EE certified application server, based on the popular Apache Tomcat. If you need to send messages from Apache TomEE to Delphi / Free Pascal applications, walk through this article for a short demonstration of message exchange using Habari Client for ActiveMQ.

No additional configuration is required, this example has been designed to run on a standard distribution of TomEE and ActiveMQ.

Read the full article: https://habarisoft.wordpress.com/2022/07/03/how-to-send-messages-from-apache-tomee-9-to-delphi-free-pascal-applications/

ScroogeXHTML for Object Pascal 8.2 released

ScroogeXHTML for Object Pascal is a library which supports a subset of the Rich Text Format (RTF) standard. It converts RTF to HTML5 and XHTML stand-alone documents, or to fragments which can be embedded in other documents. The library is compatible with Delphi 2009+ and Free Pascal 3.2.0. The 8.2 release includes small improvements in the core library and documentation about the new post process API. The installer is now digitally signed.

Resources

Other platforms

ScroogeXHTML is also available for the Java platform.

scrooge_portrait_logo_2016

Habari Client libraries release 2022.06

Habarisoft released new versions of its native STOMP client libraries for Delphi / Object Pascal for integration with popular open source message brokers:

Release notes: https://www.habarisoft.com/release_notes.html

Further resources and demo applications

Home page: https://www.habarisoft.com/

About Habari Client libraries

habari_logo_2016Habari Stomp Client libraries enable Object Pascal applications to take advantage of message broker / message queue technology – which is distributed, loosely coupled, reliable and asynchronous – to build integrated systems, using peer-to-peer and publish-subscribe communication models.

ScroogeXHTML Server Deployment License anniversary discount

To celebrate its 25. foundation anniversary, Habarisoft increased the special discount for ScroogeXHTML Server Deployment licenses:
* old discount: 25%
* new discount: 50%

Order links and editions overview can be found at https://www.scroogexhtml.com/#order and at https://www.scroogexhtml.com/object_pascal.html#order
Single Developer License and Server Deployment License terms are explained at https://www.scroogexhtml.com/scroogexhtml_license.html

Conditions: the discount is only valid for purchases together with one ore more ScroogeXHTML Single Developer Licenses. License purchases are not refundable. The special discount is only valid for a limited time and can not be combined with other discounts (except volume discounts) and promotions.

The discount is valid both for the Java and the Delphi / Pascal version of ScroogeXHTML.
 

Habari Client libraries release 2022.02

Habarisoft released version 2022.02 of its Object Pascal STOMP client libraries for Delphi and Free Pascal integration with popular free open source message brokers.

Further resources and demo applications

Home page: https://www.habarisoft.com/

Release notes: https://www.habarisoft.com/release_notes.html

About Habari Client libraries

habari_logo_2016Habari Stomp Client libraries enable Object Pascal applications to take advantage of message broker / message queue technology – which is distributed, loosely coupled, reliable and asynchronous – to build integrated systems, using peer-to-peer and publish-subscribe communication models.

Habari Client libraries release 2021.12

Habarisoft released version 2021.12 of its Object Pascal STOMP client libraries for Delphi and Free Pascal integration with popular free open source message brokers.

Further resources and demo applications

Home page: https://www.habarisoft.com/

Release notes: https://www.habarisoft.com/release_notes.html

About Habari Client libraries

habari_logo_2016Habari Stomp Client libraries enable Object Pascal applications to take advantage of message broker / message queue technology – which is distributed, loosely coupled, reliable and asynchronous – to build integrated systems, using peer-to-peer and publish-subscribe communication models.