Server-Sent Events

new topic     » topic index » view thread      » older message » newer message

Server-Sent Events


I haven’t seen much discussion here about Server-Sent Events, which is not surprising given that the number of people doing CGI processing seems to be fairly small. There’s but one mention of this, by acEduardo in this thead .

I’ve been playing with this, successfully, to drive progress bars, and to populate log sections on web pages. I’m posting the results in case anyone else has a need for this function.

First, a few words on what it is. A short chronology, which many can skip.

  • The first web pages were completely static. You entered a url, and back came a web page. Embedded in that page would be hyperlinks, images, video, sound … but a page was a page.
  • With the development of CGI functionality, the ability to create the page on the fly allowed for the model in common use, including the page on which you’re reading this now, whereby the url included attributes describing how the page should be constructed. This typically involved looking up a database, and assembling the page with static elements and constructed elements based on processing the database results. As well as the base url, additional query options are sent as part of a GET or POST.
  • One problem with this is that as page sizes got larger, the overhead in asking for and receiving a huge page to make a minor change became cumbersome. Javascript came to the rescue, with the AJAX function. Javascript is of course a programming language embedded in the HTML of the web page. An AJAX request is one that is made, to a url, on behalf of just one element of the page. This request will also involve query components.
    • A good example of AJAX is when you start filling in a form field, and based on what you have typed the field is populated (or a drop-down is populated) with suggestions. After each keystroke, an AJAX request is sent which returns all appropriate words starting with that (or those) characters.
  • In all of this the communications were initiated by the browser. The server could respond to any kind of request, but could never initiate a communication. To implement online chat, for example, in which case both parties send messages via a server, it’s necessary for the server to advise client B that there is a new message from client A. The traditional way has been by way of polling. Every interval the client page would, with an AJAX request, ask the server if there were any new data. This is certainly better than refreshing an entire page every few seconds, but the constant polling has its own undesirable overhead.
  • That’s where Server-Set Events come in. A Javascript object is created that initiates a listener. When the server has something to say, it sends data to the listener, which has a function attached to it which will (perhaps after processing) put the new information somewhere on the web page. It might be the latest chat message. Or an updated stock ticker.

Implementation

Javascript


This is example code, updating a progress bar (“test”) as well as final status in a field (“Result3”). Changing the value in “test” will update the length of the progress bar.

 
{view:"button", id:"test_progress", value:"Test Progress", type:"form", autowidth:true, 
     click: function(){ 
                                var source = new EventSource("./find_fix_tables.eui?action=test_progress"); 
				source.onmessage = function(event) { 
			        .setValue(event.data * 1)}; // turn string into number 
 
			        source.onopen = function(event) { 
				          console.log("OPEN socket"); 
				          $ $("test").show(); 
				          $ $("Result3").setHTML("Processing")} 
 
				source.onerror = function(event) { 
				          console.log("ERROR - CLOSING socket"); 
					  source.close();  
					  $ $("test").hide(); 
					  $ $("Result3").setHTML("Completed")} 
			         } 
}, 
// I have had to write '$ $("test")' because if the two dollar signs are adjacent the 
// forum formatting code strips each such item out. 

Euphoria


Here is the server code. For testing, it’s just a loop counting from 1 to 100, advising the client on each iteration.

Notes:

  • The no-cache header, recommended in all the documentation for Server-Set Events, prevents this from working. It’s commented out.
  • The usual Content-Type header, such as ‘text/html’, ’application/json’ etc. is now ‘text/event-stream’. This must be followed by two blank lines. With normal text headers, you need *at least* two, and can have more. In this case however you need *exactly* two.
  • The data must be in the format ‘data:your_data’. In this case the loop counter is used, so the result is, form example ‘data: 5’. The Javascript receiver will parse only lines with ‘data: …’ and use the value of 5.
  • Most CGI scripts written in Euphoria have the headers and final ‘puts()’ at the end of the program. The program then terminates. That serves to send the output to Apache or other web server. In this case, there is no termination, so it’s necessary to insert a flush() statement to ensure that the data are sent to Apache.
--******************************************** 
--*      function test_progress()            * 
--******************************************** 
function test_progress() 
--puts(1,"Cache-Control: no-cache") -- This header would prevent the function from working. 
puts(1,"Content-Type: text/event-stream\n\n") 
for i = 1 to 100 do 
		sleep(0.1) 
		puts(1, sprintf("data: %d \n\n", i)) -- must have the two newlines 
		flush(1) 
end for 
puts(1, "Status: 415 OK") 
return {"Finished test"} 
end function 

That’s it. It works. I’m happy to answer any questions or provide any help.

Craig

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu