ad_page_contract { Sample page for emulating streaming HTML via SSE (server side events). In this example, the same page is used as the event sink (where the events are displayed) and as an event source (when called with event=true). @author Gustaf Neumann } { {event:boolean false} } set title "Sample HTML streaming page (SSE)" set context $title if {$event} { # # We are called by the event handler from JavaScript # # # Trivial sse writer # proc sse_write {msg} { # SSE needs handling of new-lines in data field; here we send # two messages in this case. In other cases, maybe coding # newline as literally \n and decoding it on the client might # be approproate. ns_write [string cat "data:" [join [split $msg \n] "\ndata:"] "\n\n"] } # # set up SSE return headers and fire a few events # ns_set update [ns_conn outputheaders] Cache-Control no-cache ns_headers 200 text/event-stream foreach i {1 2 3 4} { set HTML "
  • #acs-kernel.common_finish# $i: ...
  • " sse_write [lang::util::localize $HTML] ns_sleep 1s } sse_write "
  • Done
  • " # # We have to tell sse (in JavaScript) to stop reopening the source # (could be done as well in js alone). # sse_write "__CLOSE_SSE__" } else { # # We are called as an ADP page # # # Register the SSE event handler. # template::head::add_script -script [subst { if(typeof(EventSource) !== "undefined") { var sse = new EventSource("[ns_conn url]?event=1"); sse.onmessage = function(event) { if ('__CLOSE_SSE__' == event.data) { sse.close(); // stop retry } else { document.getElementById("result").innerHTML += event.data; } }; } else { document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events..."; } }] ad_return_template }