Initiate data transfers from Server => Client? - node.js

i want to build a server app in node/express which receives requests from one client and sends information to another client, maybe somehow similar to this:
var express = require('express');
var app = express();
var IP_client1 = "10.1.2.3";
var IP_client2 = "10.1.2.4";
//get information from client1
app.get('/client1',function(req,res){
res.send('OK, will send it to client2");
//==> How to send to client2 from here?
});
//get information from client2
app.get('/client2',function(req,res){
res.send('OK, will send it to client1");
//==> How to send to client1 from here?
});
//==> How to send data to client1 or/and client2 from here?
app.listen(3000);
I know how to handle requests from clients to the server, but how could i simply set up a transfer of data from the server to another arbitrary client?
I went through a lot of tutorials, but no one covers this!

Yes, websockets (sockets.io) is what allows free communication through communication channels (sockets).
The tutorial here
https://socket.io/get-started/chat/
showed me what to do, but unfortunately there seems to be a little bug (or missing detail) in the clients html file!?
It needs:
var socket = io.connect('http://local.host:port');
to make it running! Very annoying!
Anyway, i have a better feeling now, and i can step forward to the next problem!

Related

long-running applications and socket.io

I have a web application that accepts an input from the client (browser) and calls an application at the server side with the input. The problem is that the application will run for a long time (about 20s). In order to not block the client (browser) and show the progress to the user, my server side POST function returns immediately and feeds the user
input to the application. Once the application computed the result, I send the result to the client using socket.io. Another twist to the scenario is that the application can not be repeatedly launched and closed (will cause some problem with CUDA) so the whole server side runs just one instance of the application. A sketch of my server-side code looks like the following. Embedded in the code are the three questions that I have searched through the Internet and tried various solutions but could not work out. Any help on them is really appreciated. If this is not the right place to ask, I would be thankful to any feedback about where to ask this question.
var express = require('express');
const{ spawn }= require('child_process');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var darknet = spawn('./darknet', other arguments...) ;
io.on('connection', function(socket){
app.socket = socket;
console.log('A connection has been established');
})
darknet.stdout.on('data',(data) =>{
// This function is called once darknet finished computation and wrote the result to the stdout
// Question 1: now need to send the data back to the client but have no access to any socket here?
})
io.on('connection', function(socket){
//Question 2: how to store this socket so that I can use it in a solution to the Question 1? Can I use session? */
//Question 3: I observed that once the client side refreshed its page (for example, uploaded an image), the previous socket will be closed and a new socket will be established. How do I make sure that I send the output from the application to the right socket since the original one may be invalid when the output is ready to be sent?
})
app.post('/predict', function (req,res){
darknet.stdin.write(user_input+'\n');
res.render();
})

Using Node, Express, (and Socket.io?) to update a page every 1 second

I am a bit new to Node.js and Express, and am currently working on a page where I would like to generate and send messages (from the server) to the client page every 1 second (1250ms, actually). When a user visits the site, I would like the latest message to be broadcasted, with new messages coming in every second after. In other words, every user would see the same message at the same time on the web page, regardless of when they connected to the server.
I have done some searching and have unfortunately have not had any luck playing with code samples online. Here is a ROUGH IDEA to explain:
app.js
'use strict';
var express = require('express');
var app = express();
var http = require( "http" ).createServer( app );
var io = require( "socket.io" )( http );
app.get('/', function (req, res) {
res.sendFile(__dirname + '/public/index.html');
});
http.listen(3000, function(){
/* someFunction to generate new LATESTMESSAGE every 1s */
io.on('connection', function (socket) {
socket.emit('news', { messages: LATESTEMESSAGE })
});
});
I assume I would need to send the message via socket.io from the function that generates the LATESTMESSAGE (every 1s when message is generated, send via socket?)? If that is the case, I am unfamiliar with how I would require socket.io in a page that is NOT the app.js (this function would probably be a class, in its own js file), as socket.io requires app and express (see code above).
I appreciate the help! I have spent a good amount of time pondering this today and would appreciate any direction or assistance. Please let me know if I have not supplied enough information.
p.s. the code above definitely would not accomplish what is needed. just a rough outline to show what i am attempting to accomplish
What you're doing looks like half-duplex communication i.e. Only the server sends data to the client, and not the other way around. Socket.io is full duplex communication, i.e. Server and client send data to each other. So technically what would be best for your requirements is Server Sent Events (SSE) using EventStream. Socket.io might be slightly excessive.
Having said that, what you want is to write a Middleware, to which you pass the application. Please take a look at https://expressjs.com/en/guide/using-middleware.html
Basically, your io would be passed in to the middleware functions, so they'd have access to Socket. And the middleware functions in turn would be imported into your app.js.

How to inform a NodeJS server of something using PHP?

I'd like to add a live functionality to a PHP based forum - new posts would be automatically shown to users as soon as they are created.
What I find a bit confusing is the interaction between the PHP code and NodeJS+socket.io.
How would I go about informing the NodeJS server about new posts and have the server inform the clients that are watching the thread in which the post was posted?
Edit
Tried the following code, and it seems to work, my only question is whether this is considered a good solution, as it looks kind of messy to me.
I use socket.io to listen on port 81 to clients, and the server running om port 82 is only intended to be used by the forum - when a new post is created, a PHP script sends a POST request to localhost on port 82, along with the data.
Is this ok?
var io = require('socket.io').listen(81);
io.sockets.on('connection', function(socket) {
socket.on('init', function(threadid) {
socket.join(threadid);
});
});
var forumserver = require('http').createServer(function(req, res) {
if (res.socket.remoteAddress == '127.0.0.1' && req.method == 'POST') {
req.on('data', function(chunk) {
data = JSON.parse(chunk.toString());
io.sockets.in(data.threadid).emit('new-post', data.content);
});
}
res.end();
}).listen(82);
Your solution of a HTTP server running on a special port is exactly the solution I ended up with when faced with a similar problem. The PHP app simply uses curl to POST to the Node server, which then pushes a message out to socket.io.
However, your HTTP server implementation is broken. The data event is a Stream event; Streams do not emit messages, they emit chunks of data. In other words, the request entity data may be split up and emitted in two chunks.
If the data event emitted a partial chunk of data, JSON.parse would almost assuredly throw an exception, and your Node server would crash.
You either need to manually buffer data, or (my recommendation) use a more robust framework for your HTTP server like Express:
var express = require('express'), forumserver = express();
forumserver.use(express.bodyParser()); // handles buffering and parsing of the
// request entity for you
forumserver.post('/post/:threadid', function(req, res) {
io.sockets.in(req.params.threadid).emit('new-post', req.body.content);
res.send(204); // HTTP 204 No Content (empty response)
});
forumserver.listen(82);
PHP simply needs to post to http​://localhost:82/post/1234 with an entity body containing content. (JSON, URL-encoded, or multipart-encoded entities are acceptable.) Make sure your firewall blocks port 82 on your public interface.
Regarding the PHP code / forum's interaction with Node.JS, you probably need to create an API endpoint of sorts that can listen for changes made to the forum. Depending on your forum software, you would want to hook into the process of creating a new post and perform the API callback to Node.js at this time.
Socket.io out of the box is geared towards visitors of the site being connected on the frontend via Javascript. Upon the Node server receiving notification of a new post update, it would then notify connected clients of this new post and its details, at which point it would probably add new HTML to the DOM of the page the visitor is viewing.
You may want to arrange the Socket.io part of things so that users only subscribe to specific events being emitted by them being in a specific room such as "subforum123" so that they only receive notifications of applicable posts.

Creating a Socket IO channels from client side

I'm new to Nodejs and Socketio. I want to do something like the following.
-> Create a socket.io/node.js server that listens to channels specified by the web browser.
-> server side script pushes messeges to specific channels.
(I already have a server created and here is the code. This just sends out two messeges. action and messege to all the connected clients)
//start code
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, url = require('url')
app.listen(8080);
function handler (req, res) {
// parse URL
var requestURL = url.parse(req.url, true);
// if there is a message, send it
if(requestURL.query.message)
sendMessage(decodeURI(requestURL.query.action), decodeURI(requestURL.query.message));
// end the response
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end("");
}
function sendMessage(action, message) {
io.sockets.emit('notification', {'action': action, 'message' : message});
}
So basically Socket.io server doesn't have any channels defined inside them. But they are defined by the client (js in browser) and messeges are sent to the specific channels by a server side script (like php using cURL)
Sorry if this questions has been asked before, I did search and couldnt find anything helpful.
I am bit confused about your question. By channels, do you mean socket.io rooms?
https://github.com/LearnBoost/socket.io/wiki/Rooms
Rooms are groups of clients and it is possible to send message to all clients in room by using following command:
io.sockets.in('room').emit('event_name', data)
It is important to realize that rooms are server side thing. So, if you want to send message to a room from client, you must send message (or request) to server and pass room name.
Also, it is bit unusual that your handler function is exposed as HTTP endpoint. If your clients already have socket.io connections, than it is easier to send it as socket.io message.
If this does not answer you question, can you post also your client side code? Maybe it will help to understand me what are you trying to achieve.

Generating socket.io at Server side as Rest request

There is a way to manage the socket.io creation at Server Side?, Currently, I couldn't found any doc, Only found in relation with the socket is created per request from a client "io.connect(server)".
The current flow work OK:
Set Socket.io (at Node.js) at SERVER:PORT
Client connect to SERVER
using io.connect(SERVER:PORT)
I wonder if it is possible ? Trying to do:
Set Socket.io (at Node.js) at SERVER:PORT
Recieved a POST (REST) - Server side
Create/Open Socket.io a server side.
At response of Post send the id?
the clien open a socke.io
Sent to client socket.id to client as
So Far, looking in deep on the code and doc, I found that socket.io support namespaces, so I used this in order to manage client connection id.
at server.js
var app = express();
var server = require('http').createServer(app),
io = require('socket.io').listen(server,{ log: false });
// Rest New Process
function generateNameSpaceWs (responce, request) {
io.of("/" + id).on('connection', handler);
response.send(id);
}
app.post("/newWS", function (res, req) {
return generateNameSpaceWs(res, req);
}
at Client.js
function makeWS(){
var ws, c = new XMLHttpRequest();
c.open("GET", url, false);
c.send();
if (c.status == 200){
id = JSON.parse(c.responseText);
ws = new io.connect("server/" + id)
}
So far you are doing right, if I understand your question correctly, you are trying to authenticate connection via POST, so that user can only connect to server via socket if server responds to ID. This is a roundabout way. Use the socket instead of POST.
Socket server has to be running already, and accepts connection via io.sockets.on('connection'), at server you can choose whether to accept it or reject it ,do socket.disconnect('unauthorized') to close connection from server.
I would you suggest you do this :
Set Socket.io (at Node.js) at SERVER:PORT
Client connect to SERVER using io.connect(SERVER:PORT)
Send what you are sending in POST over socket.
Authenticate/Process on io.sockets.on('connection', function(socket) at server.
Close socket if unathorized.
Send back ID data to client.
This doesn't seem possible -- while the official documentation for socket.io is lacking, the documentation for the net module indicates that the only way to create a socket is to initiate it server side.
However, you can still achieve the desired effect by creating an id for the socket on the server to associate with the socket. That is,
Set Socket.io (at Node.js) at SERVER:PORT
Recieved POST (REST) - Server side
Create id (Note:This could be done before step 2)
At response of Post send the id!
Client connect to SERVER
using io.connect(SERVER:PORT)
The client sends the id to the server using something like
socket.emit("set_id",id)
The server recieves the id and associates it with the socket using something like
socket.on("set_id",function(id){
socket.set("id",id)
}
Now you can reference the socket using the id that you created!
Good luck!

Resources