Overview
Examples
Screenshots
Comparisons
Applications
Download
Documentation
Tutorials
Bazaar
Status & Roadmap
FAQ
Authors & License
Forums
Funding Ultimate++
Search on this site
Search in forums












SourceForge.net Logo
Home » Extra libraries, Code snippets, applications etc. » U++ users applications in progress and useful code snippets, including reference examples! » Server Sent Events Example
Server Sent Events Example [message #60546] Sun, 21 April 2024 20:03 Go to next message
omari is currently offline  omari
Messages: 265
Registered: March 2010
Experienced Member
Server-Sent Events (SSE) is a technology that enables a server to push real-time updates to a web application over an HTTP connection. Unlike traditional request-response mechanisms where the client initiates communication, SSE allows the server to initiate data transmission to the client once the client establishes a connection.

main.cpp:
#include <Core/Core.h>

using namespace Upp;

struct MySocket {
	TcpSocket socket;
	bool initialized = false;
};
class SSEServer
{
	private:
		TcpSocket server;
		Array<MySocket> clients;
		Mutex mx;
		
		bool end = false;
		Thread th;
		
		int port;
	
		bool accept()
		{
			if(end) return false;
			
			mx.Enter();
			clients.Add();
			mx.Leave();
			MySocket& client = clients.Top();
			bool ret = false;
			DUMP(clients.GetCount());
			if(client.socket.Accept(server)) {

				HttpHeader h;
				h.Read(client.socket);
				
				bool authorized = true;
				//  authenticate the user using h.f2 (/token)

				if(authorized) {
					client.socket.Put("HTTP/1.1 200 OK\r\n"                 //Standard HTTP header line
				      "Content-Type: text/event-stream\r\n"          //This is the only allowed MIME type for SSE
	                  "Transfer-Encoding: chunked\r\n"               //Chunked encoding lets it know when an event is done without knowing packet boundaries.
					  "Access-Control-Allow-Origin: *\r\n"           //Because the HTML comes from a file, not this server, we have to allow access
				      "\r\n");
				      
				      ret = true;
				      client.initialized = true;
				}
				else {
					client.socket.Put("HTTP/1.1 401 Unauthorized\r\n"                 //Standard HTTP header line
				      "\r\n");
				     ret = false;
				}
			}

			if(ret == false) {
				mx.Enter();
				clients.Remove(clients.GetCount() - 1);
				mx.Leave();
			}
			
			return ret;                                   //End of header indicator
		}

		void WriteChunk(const String& str)
		{

			String out;
			out << FormatIntHex(str.GetCount()) << "\r\n"  << str << "\r\n";
			mx.Enter();
			for(auto& c:clients) {
				if(!c.socket.IsEof() && !c.socket.IsError()) {
					c.socket.Put(out);
				}
			}
			
			for(int i = clients.GetCount(); i > 0 ; i--) {
				MySocket& c = clients[ i - 1 ];
				
				if(c.initialized && ( c.socket.IsEof() || c.socket.IsError())) {
					clients.Remove(i-1);
				}
			}
			mx.Leave();
		}

	public:

		SSEServer(int Port = 6500): port(Port)
		{
			server.Listen(port, 5);
		}
		
		~SSEServer()
		{
			mx.Enter();
			for(auto&client: clients) client.socket.Close();
			mx.Leave();
			server.Close();
		}
		
		void Start() {
			Cout() << "Listn at port " << port << "\n";
			end = false;
			th.Run([&] {while(!end){accept(); Sleep(1);}});
		}

		void Stop() {
			end = true;
			TcpSocket soc;
			soc.Connect("localhost", port);
			soc.Connect("localhost", port);
			soc.Connect("localhost", port);
			th.Wait();
		}
		
		void WriteData(String d) { WriteData(~d); }
		void WriteData(const char* data) {
			//Build up an event in server-send-event format. The message consists of
			//one or more fields of the form:
			//field: value\n
			//Followed by an empty line.
			//
			//The main tag is "data:" which carries the data payload.
			//See https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
			//for more info (e.g. different message types and dispatch)
			String msg;
			
			if(Upp::Random(10)>5)
				msg << "event: " << "custom" << "\n"; // Send same msgs as 'custom' event instead  of 'message' (the default).
		
			msg << "data: " << data << "\r\n";
			msg << "\r\n";  //Empty field ends the message.
	
			//Send the message data using chunked encoding
			WriteChunk(msg);
				
		}
};

CONSOLE_APP_MAIN
{
	SSEServer sse;
	bool end = false;
	Thread th;
	th.Start([&] {
		while(!end){
		Time t = GetSysTime();
		String s ;
		s << t;
		sse.WriteData(s);
		Sleep(1000);
		}
	});
	
	sse.Start();
	Cout() << "Press enter to terminate\n" ;
	ReadStdIn();
	end = true;
	sse.Stop();
	th.Wait();
}



index.html:
<!DOCTYPE html>
<html>
<head>  <meta charset="UTF-8"> </head>
<body>

<h1>Getting server updates</h1>
<div id="result"></div>

<script>
if(typeof(EventSource) !== "undefined") {
    var source = new EventSource("http://127.0.0.1:6500/token");
    source.onmessage = function(event) {
        document.getElementById("result").innerHTML += "Data: " + event.data + "<br>";
		// console.log(event);
    };
	
    source.addEventListener("custom", function(event) {
        document.getElementById("result").innerHTML += "Custom: " + event.data + "<br>";
		// console.log(event);
    });

    source.onerror = function(event) {
        document.getElementById("result").innerHTML += "Connection failed<br>";
    };
} else {
    document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
</script>

</body>
</html>



regards
omari.
Re: Server Sent Events Example [message #60547 is a reply to message #60546] Mon, 22 April 2024 20:30 Go to previous message
zsolt is currently offline  zsolt
Messages: 697
Registered: December 2005
Location: Budapest, Hungary
Contributor
I didn't know, this is so simple. Thank you.
Previous Topic: wxWidgets Grid sizers like Ctrl
Goto Forum:
  


Current Time: Sat May 04 00:00:31 CEST 2024

Total time taken to generate the page: 0.02203 seconds