SSE and NodeJS Express - javascript

Cannot get SSE events to file in browser.
This the server code (express):
app.all('/callme', function(req, res){
res.writeHead(200, {
'Connection': 'keep-alive',
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache'
});
setInterval(function(){
console.log('writing');
res.write((new Date()).toString() + '\n');
}, 1000);
})
This the client code:
var source = new EventSource('/events');
source.onmessage = function(e) {
document.body.innerHTML += e.data + '<br>';
};
I use this same server code using XHR on the client and it works. The server appears to be sending the data correctly, but not getting fired in the browser..
I've already read JavaScript EventSource SSE not firing in browser Doesn't seem to apply here, as I'm not running anti-virus that would affect it.

It looks like the formatting on your event isn't correct
You want it formatted like this
res.write("id: " + Date.now() + "\ndata: " + message + "\n\n");
Also, check out this
node-easysse and easysse-client

Related

Using server-side events (SSE) to push updates to web client using Javascript

I'm trying to use server-side events (SSE) in Javascript and Node.JS to push updates to a web client.
To keep things simple, I have a function which will generate the time every second:
setTimeout(function time() {
sendEvent('time', + new Date);
setTimeout(time, uptimeTimeout);
}, 1000);
The sendEvent function puts together the event in the expected format and sends it to the client.
var clientRes;
var lastMessageId = 0;
function sendEvent(event, message) {
message = JSON.stringify(message);
++lastMessageId;
sendSSE(clientRes, lastMessageId, event, message);
}
The clientRes value comes from the server function to handle the route from the base URL.
app.use('/', function (req, res) {
clientRes = res;
...
}
What I want to achieve at the client UI is a simple page which shows:
> <h1>The current time is {event.data}</h1>
where I derive the current time from the latest message data received from the server.
I have created an index.html file to have the client listen for these server-sent messages:
<!DOCTYPE html>
<html>
<body>
<h1>Getting server updates</h1>
<div id="result"></div>
<script>
if(typeof(EventSource) !== "undefined") {
console.log("Event source is supported");
var source = new EventSource("localhost:3000");
source.onmessage = function(event) {
document.getElementById("result").innerHTML += "=>" + event.data + "<br>";
};
} else {
console.log("Event source not supported");
document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events...";
}
evtSource.addEventListener("time", function(event) {
const newElement = document.createElement("li");
const time = JSON.parse(event.data).time;
console.log("Time listener found time " + time);
newElement.innerHTML = "ping at " + time;
eventList.appendChild(newElement);
});
</script>
</body>
</html>
If I respond to a GET request with this index.html, I don't see any of the time messages.
That is, this server code does not work:
app.use("/", function(request, response) {
response.sendFile(__dirname + "/index.html");
clientRes = response;
});
However if I don't respond with the index.html file and allow the server to push timestamps to the client, they to show up in the browser:
event: time
id: 104
data: 1587943717153
event: time
id: 105
data: 1587943727161
...
Here's is where I'm stuck.
It appears I have successfully gotten the server to push new timestamps every second.
And the browser is seeing them and displaying the text.
But the arrival of the message from the server is not triggering the listener and the message is not being rendered based on the index.html.
Most of the examples I've seen for use of SSE involves a PHP data source. I need for the server to both generate the data and to provide the HTML to display it.
I've been successful in one or the other, but not both at the same time.
I figured out what I was missing.
I did not specify the endpoints correctly.
For the root endpoint, the server code needs to deliver the index.html file.
app.use("/", function(request, response) {
console.log("In root handler");
response.sendFile(__dirname + "/index.html");
});
Index.html contains the script that creates the event source:
var source = new EventSource("http://localhost:3000/time");
But the URL that gets passed in as the input to the EventSource constructor must be a different endpoint (not root). It needs to be the endpoint that generates the timestamps.
So in the server, the handler for the /time endpoint is the one which pushes the data.
app.use('/time', function (req, res) {
res.writeHead(200, {
'content-type': 'text/event-stream',
'cache-control': 'no-cache',
'connection': 'keep-alive'
});
// Save the response
clientRes = res;
});

How to display image from node.js server to jsp page?

Is there someone can help me or give me a tutorial on how I can display the base64 string from Node.Js to JSP/HTML img tag?
Im passing base64 string to this Node.Js server from Java application.
var net = require('net');
var HOST = '127.0.0.1';
var PORT = 6969;
var cl = require('./client.js');
net.createServer(function(sock) {
console.log('CONNECTED: ' + sock.remoteAddress +':'+ sock.remotePort);
sock.on('data', function(data) {
sock.write(data);
var client = new cl.client(data);
});
sock.on('close', function(data) {
console.log('CLOSED: ' + sock.remoteAddress +' '+ sock.remotePort);
});
process.on('uncaughtException', function (err) {
console.error(err.stack);
console.log("Node NOT Exiting...");
});
}).listen(PORT, HOST);
console.log('Server listening on ' + HOST +':'+ PORT);
Does the Base64 string start with data:image/jpeg;base64(the type may be different).
If so, you can set the src attribute of img tag with it.
<img src="data:image/jpeg;base64XXXXXXXXX">
If the base64 string that you are passing already has data:image/[image type];base64 prefix then you can just set it in the image source you don't need to do anything special.
Or just have a method to check it and add the prefix if you don't have it.
function setBase64ToImage(baseString){
// data:image/[image type];base64
if(baseString.substring(0,4) != "data"){
baseString = "data:image/png;base64," + baseString;
}
return baseString;
}
and in your HTML img src tag
<img src=setBase64ToImage(data)>
If your question is how to pass data from node.js to the html file then you should use a template like ejs or something to make it easy.
https://github.com/tj/ejs or look at this question which anwers how to pass data from node to html.
Variables between Node.js Server and Client

Session is not open when connecting to autobahn js

I'm having trouble while developing chat-like feature to my socket server.
First let me give you a little bit of my code:
document.conn = new ab.Session('ws://127.0.0.1:8090',
function () {
console.log('AB:Connected!');
conn.subscribe('room_1', function (topic, data) {
console.log('New message published to room "' + topic + '" : ' + data.content + ' by:' );
console.log(data);
});
},
function () {
console.warn('WebSocket connection closed');
},
{'skipSubprotocolCheck': true}
);
Currently it's attached to document just to try it out, the error I'm getting is as follows:
"Session not open"
I'm a bit confused about this error and it's origin, should I somehow define the connection?
do you start your socket server through cmd.exe ?
you need to use this command to start the server:
php c://wamp64/www/yourproject/bin/push-server.php

Convert Console output from Node to a webpage?

I wrote a piece of code that allows me search for all tweets hash tagged hello.
var stream = T.stream('statuses/filter', { track: 'hello', stall_warnings: true });
var counter = 0;
if (stream) {
console.log('connected!');
};
stream.on('tweet', function (tweet) {
console.log('tweet: '+ tweet.text);
console.log('by:' + ' #' + tweet.user.screen_name);
console.log('date:'+ ' ' + tweet.created_at + ' | ' + counter);
counter++;
});
How do I go about redirecting this so that I can create a web page that looks like a Twitter stream data, or something of the sort? Maybe using AngularJS.
You will have to create a web server first, try express.
then you can use something like sockets.io to communicate from the server to your client web page.
then on the webpage you must handle the messages to display them (angular, or maybe just jQuery) - basically on tweet you will send a message from your server to the client web page through socket.io, then your dront end javascript will get the message, parse it and decide how to display it.
Have a look at Sails.js, it's basically express with sockets integrated and a few more things
edit
say you export your server in server.js,
var http = require('./server.js');
var io = require('socket.io')(http);
stream.on('tweet', function (tweet) {
io.sockets.emit("new tweet", {
text: tweet.text,
by: tweet.user.screen_name,
date: tweet.created_at,
counter: counter++;
});
});
require('socket.io')(http) starts the "socket manager" on your server (and also publishes the js client side code for it), so clients can connect to your server through sockets.
io.sockets.emit will send a message to all connected clients.
on your web page you must have something like this
<div id="tweets"></div>
<script src="/your/js/jquery.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on("new tweet", function(tweet) {
$('#tweets').append('tweet: ' + tweet.text + '<br>');
$('#tweets').append('by:' + ' #' + tweet.by + '<br>');
$('#tweets').append('date:'+ ' ' + tweet.date + ' | ' + tweet.counter + '<br>');
});
</script>
the library /socket.io/socket.io.js was published by that require('socket.io')(http) from earlier, so we can use it on our clients.
the call io() basically connects to the server, and returns a handle to that connection (socket), we use that to receive all messages from the server, and on each message you can write the contents to the page anyway you want.
With socket.io you can broadcast events from the server to the client, in this case you could do something like this :
stream.on('tweet', function (tweet) {
io.sockets.emit("new tweet", tweet);
counter++;
});
And you could receive that event on the client-side like this :
var socket = io();
socket.on("new tweet", function(tweet){
//Do something with the tweet
});
This is a very basic and generic example, for more information you can look at the official documentation here.

Syntax error for cross domain messaging

below is my code. I am trying to receive data from a website using cross-domain messaging. When I click the runit button, I keep getting the following error: "Uncaught SyntaxError: An invalid or illegal string was specified." Please help me identify the problem, I am at a loss.
html code:
<html>
<script language="JavaScript">
function runit() {
alert("here");
// Get the iframe window object
var client = document.getElementById('client');
// Create the data string to be passed to the OPS JavaScript
var data = "{'url' : 'http://ops.epo.org/3.0/rest-services/published-data/publication/epodoc/EP1000000/biblio', " + "'method' : 'GET', " + "'requestHeaders' : {'Origin': 'ops.epo.org', 'Accept': 'application/json' } " + "}";
alert(data);
// Use the postMessage() method in order to send the data to the
// iframe object
client.contentWindow.postMessage(data, 'ops.epo.org');
}
// Add event listener for your window
window.addEventListener("message", receiveMessage, false);
// Method handling window events
function receiveMessage(event) {
alert("here");
// Check origin of the event!
if (event.origin == "http://ops.epo.org") {
var dataJSON = eval('(' + event.data + ')');
// work with data / display data
alert(dataJSON);
}
else {
alert("Got message from unknown source.");
}
}
</script>
<body>
<input type="button" onclick="runit()" value="runit"></input>
<iframe width=100 height=100 id="client" src="http://ops.epo.org/3.0/xss/crosssitescript.html" />
</body>
</html>
EDIT:
I tried double quotes for the data string, and JSON.stringify, and it didn't work:
var data = JSON.stringify('{"url" : "http://ops.epo.org/3.0/rest-services/published-data/publication/epodoc/EP1000000/biblio", ' + '"method" : "GET", ' + '"requestHeaders" : {"Origin": "ops.epo.org", "Accept": "application/json" } ' + '}');
You have to pass the protocol of the targetOrigin when you call postMessage:
client.contentWindow.postMessage(data, 'http://ops.epo.org');
This also works, but may have security implications:
client.contentWindow.postMessage(data, '*');
I peeked at the documentation for what you're trying to do, and there's also the option to use JSONP. Why not just use that, since it's simpler and probably better supported?

Categories