I've created client and server of node with socket.io. server is executing 4 get requests of news feed and fetched the data. These data is sent to the client with socket.io.
client is displaying news feed on the occurrence of specific socket.io event.
This works well for once. Here is the code and working fiddle
server.js
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, fs = require('fs')
, redis = require("redis");
var http = require("http");
// initialize the container for our data
var data = "";
var nfs = [
"http://economictimes.feedsportal.com/c/33041/f/534037/index.rss",
"http://www.timesonline.co.uk/tol/feeds/rss/uknews.xml",
"http://www.independent.co.uk/news/business/rss",
"http://www.dailymail.co.uk/money/index.rss"
];
//setInterval(function() {
for(var i=0; i<nfs.length; i++){
//console.log(nfs[i]);
http.get(nfs[i], function (http_res) {
// this event fires many times, each time collecting another piece of the response
http_res.on("data", function (chunk) {
// append this chunk to our growing `data` var
data += chunk;
});
// this event fires *one* time, after all the `data` events/chunks have been gathered
http_res.on("end", function () {
// you can use res.send instead of console.log to output via express
console.log("data received");
});
});
}
//}, 30000);
app.listen(8080);
function handler (req, res) {
fs.readFile(__dirname + '/client.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
});
}
io.on('connection', function (socket) {
//setInterval(function() {
socket.emit('news', data);
/*socket.on('my other event', function (data) {
console.log(data);
});*/
//}, 5000);
});
client.html
<html>
<head>
<script src="https://cdn.socket.io/socket.io-1.2.1.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
//socket io client
var socket = io.connect('http://localhost:8080');
//on connetion, updates connection state and sends subscribe request
socket.on('connect', function(data){
setStatus('connected');
socket.emit('subscribe', {channel:'notif'});
});
//when reconnection is attempted, updates status
socket.on('reconnecting', function(data){
setStatus('reconnecting');
});
//on new message adds a new message to display
socket.on('news', function (data) {
console.log(data);
//socket.emit('my other event', { my: 'data' });
addMessage(data);
});
/*socket.on('news', function (data) {
debugger;
socket.emit('my other event', { my: 'data' }
var msg = "";
if (data) {
msg = data;
}
addMessage(msg);
});*/
//updates status to the status div
function setStatus(msg) {
$('#status').html('Connection Status : ' + msg);
}
//adds message to messages div
function addMessage(msg) {
//debugger;
var $xml = $(msg);
var html = '';
$xml.find("item").each(function() {
var $item = $(this);
html += '<li>' +
'<h3><a href ="' + $item.find("link").text() + '" target="_new">' +
$item.find("title").text() + '</a></h3> ' +
'<p>' + $item.find("description").text() + '</p>' +
// '<p>' + $item.attr("c:date") + '</p>' +
'</li>';
});
$('#result').prepend(html);
}
</script>
</head>
<body>
<div id="status"></div><br><br>
<ul id="result"></ul>
</body>
</html>
What I understand about socket.io is that we don't need long server polling and so how do server come to know that news is added to the respected news feed.
How do I update the client with newly added news when news is added to the news feed rss ???
Update
Ok so from all the responses I get the point that it is not possible for socket.io to know that new entry has been added. So, how do I know (which tools/libraries do require to know that new entry has beed added and update the client as well) ???
Retrieving the messages from the news feeds are completely independent of socket.io unless the news feeds implement sockets on their end and your server becomes their client. So you will have to continue to poll them with http requests to know whether they have updated data.
In order to notify your clients of the update you would just emit the news event. Presumably you would have logic on the server to make sure you are only sending events which have not previously be sent.
There is no way for "node" to know when a new entry is added to the news feed. You will have to poll the news service like you are doing now. This really has nothing to do with Node or Socket.io unless I completely misunderstand what you are asking.
Related
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;
});
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
I am atempting to build a chatroom with NodeJS and Socket.io and I have gotten so far as to get the users input and send it to the Node server but that's all I want to be able to display it up in a div
Client-side script
var socket = io();
$('form').submit(function(e) {
e.preventDefault();
// gets the value from the message text feild and sets it as the message var
var message = {
text: $('#chat-box-div-txtinpt').val()
}
if (message.text.trim().length !== 0) {
socket.emit('chat-message', message);
}
$('#chat-box-div-txtinpt').focus();
document.getElementById('chat-box-div-txtinpt').value='';
});
Server-side script
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res) {
res.sendfile('index.html');
});
http.listen(3000, function() {
console.log('listening on *:3000');
});
io.on('connection', function (socket) {
console.log('a user connected');
socket.on('disconnect', function () {
console.log('user disconected');
});
socket.on('chat-message', function (message) {
console.log('message: ' + message.text);
});
});
Here is the site
It appears you're using jQuery, so for this line: document.getElementById('chat-box-div-txtinpt').value=''; you could just do $('#chat-box-div-txtinpt').val('');
to answer your question: you could just do $('#chatlog-display-div').append(message.text)
Your code would end up looking something like this
$('form').submit(function(e) {
e.preventDefault();
//gets the value from the message text feild and sets it as the message var
var message = {
text : $('#chat-box-div-txtinpt').val()
}
if (message.text.trim().length !== 0) {
socket.emit('chat-message', message);
//append the message to the chatlog-display-div
$('#chatlog-display-div').append(message.text);
}
//clear the value of the txtinput after you focus it.
$('#chat-box-div-txtinpt').focus().val('');
});
please mark as accepted answer if you feel this adequately solves the issue.
To send messages to everyone from the server use emit() from io
on server
socket.on('chat-message', function (message) {
console.log('message : ' + message.text);
io.emit("chat-message",message);
});
on client
socket.on('chat-message',function(message){
//add message to the chat window
});
If you do not want the person sending the message to get the chat-message emit then use broadcast.emit() from the socket that sent it
//server
socket.on('chat-message', function (message) {
console.log('message : ' + message.text);
//excludes "socket" from getting the emit
socket.broadcast.emit("chat-message",message);
});
To actually put the message in the div just use any of jQuery's various methods html()/text()/append()
//client
socket.on('chat-message', function (message) {
jQuery(".chat-window").append('<div>'+message.text+'</div>');
});
You could simple .append the text to "chatlog-display-div" with a templet if you use ES6 could be something like
$('form').submit(function(e) {
e.preventDefault();
//gets the value from the message text feild and sets it as the message var
var message = {
text : $('#chat-box-div-txtinpt').val()
}
if (message.text.trim().length !== 0) {
socket.emit('chat-message', message);
document.getElementById('chatlog-display-div').append('<divclass="message-style" > ${message.text}</div>')
}
$('#chat-box-div-txtinpt').focus();
document.getElementById('chat-box-div-txtinpt').value='';
});
I have tried several variations of trying to emit to all users connected to a particular /namespace, but have had no luck. I could be misunderstanding how sockets work.
But what I have right now is two browsers open on different pages. When a user connects to pageA, that user is now part of '/users' namespace. When a user connects to pageB, that user is now part of '/valets' namespace.
I have a .emit() on pageA that sends to server.js. I listen for it with .on(), and then try to run .emit() but to only the users in '/valets' namespace.
I am able to see in my terminal "listening for request valet" and the console.log(data) part.
I believe my problem is the usr_nsp.of('/valets').emit("incoming-request",{data:data}); portion. The other commented lines are what I have tried so far. They all give me an error: is not a function.
server.js
var app = require('http').createServer();
var io = require('socket.io')(app);
app.listen(3000, function(){
console.log('listening on port 3000');
});
var redis = require('socket.io/node_modules/redis');
// create custom namespace for Users
var room_number;
var usr_nsp = io.of('/users');
usr_nsp.on('connection', function(socket){
console.log('user has connected to /users namespace');
socket.on('request-valet', function(data){
console.log("listening for request valet");
console.log(data);
room_number = data.room_number;
socket.join(room_number);
// usr_nsp.broadcast.of('/valets').emit("incoming-request",{repark:data});
// usr_nsp.of('/valets').broadcast.emit("incoming-request",{repark:data});
// io.of('/valets').emit("incoming-request",{repark:data});
// socket.of('/valets').emit("incoming-request",{repark:data});
usr_nsp.of('/valets').emit("incoming-request",{repark:data});
});
});
var valet_nsp = io.of('/valets');
valet_nsp.on('connection', function(socket){
console.log('valet has connected to /valets namespace');
// var room_number;
socket.on('join-room', function(data){
// assign valet to room
room_number = data.room_number;
socket.join(room_number);
//valet_nsp.sockets.in(room_number).emit("request-accepted",{current_pos:current_pos})
});
socket.on('set-valet-starting-position', function(data){
//var valet_starting_pos = data.starting_position;
valet_nsp.sockets.in(room_number).emit('activate-directions-service', {repark:data});
})
socket.on('get-new-location', function(data){
// send the updated location only to User
// maybe use .broadcast??
valet_nsp.sockets.in(room_number).emit("update-valet-location", {current_pos:data});
});
});
pageB.html (sockets portion)
socket.on('incoming-request', function(data){
console.log("incoming request");
alert("incoming request");
// use data to display on html screen
});
The namespace handle you created is used to emit to users in that particular namespace. This should thus work:
var users = io.of('/users'),
valets = io.of('/valets');
users.on('connection', function(socket) {
socket.on('request-valet', function(data) {
valets.emit('incoming-request', { repark : data });
});
});
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.