socket.io Updating all the open pages - html

I am trying to create a chat website, something like a discord clone. I am using socket.io to connect my front end and back-end but I cant figure out how to make it that when someone enters a message that message to be displayed on all currently open browser pages
Server.js (My server file I use):
const express = require("express");
const app = express();
const http = require("http").Server(app);
const port = 4000;
const io = require("socket.io")(http);
app.get("/", (req, res) => {
res.sendFile("ChatRoom.html", {"root": __dirname});
});
io.on("connection", (socket) => {
console.log("A user has connected");
socket.on("messageSend", (data) =>{
console.log(data);
io.emit("chatUpdate", data);
});
});
http.listen(port, () => {
console.log("Server.js listening on port " + port );
});
And my Javascript code in the HTML file:
var socket = io();
document.addEventListener('keydown', InputText);
function InputText(e)
{
//Checks if the pressed button is Enter and if the input box is empty
if( e.keyCode == 13 && document.getElementById("chat_input").value != "")
{
//Gets the div which the message will be ridden to
var parent = document.getElementById("chat");
//Current date to be used when displaying the exact time of sending the
messgae
let d = new Date()//.getTimezoneOffset();
//Getting the properties of the input
var value = document.getElementById("chat_input");
//Telling the server that a message has been sent - function
emitter(parent, value.value, d);
//Setting the text box back to blank
value.value = "";
}
}
//Function
function emitter(holder, text, date){
socket.emit("messageSend", text);
socket.once("chatUpdate", (message) => {
var z = document.createElement("p");
z.innerText = date.getHours() +":"+ date.getMinutes() + " | " +
message;
z.style = 'border-top: 1px solid Black;border-bottom: 1px solid
Black;font-size:20px; margin: 0;padding: 10px;';
holder.appendChild(z);
});
}

Once you have emitted the message you need to be listening for it in the client, if the action you are trying to achieve is sending the message to another user that has the socket currently open on their window. Because you are sending it to a user not the server, so you would need to be connecting to the socket so it's very possible your socket might need to be defined more like this.
var socket = io.connect('Your:/url/of/windowlocation/whileonsocket/here')
Hope this helps!

Related

file chooser for download appears only after closing node.js

I have a very simple node.js app which successfully processes a file (from formidable form) but the download of the result file fails. The download html
<p><input type="text" value = "tx-AllSerums.xlsx"><br>
<a href="/transformed/tx-AllSerums.xlsx"
download="All Serums.xlsx">Download transformed file</a>
</p>
The result files are written to the directory structure from where I run node (the 'transformed' dir is in the dir in which I run node).
When I click on the above href I get console output but no file save dialog. (Should the server even get this event?)
When I kill the node server, up pops the file save dialog. Of course the save fails: Network error.
I'm currently running everything on my workstation: Ubuntu 18.04; Chrome 70.0.3538.77, node v10.13.0
I've found that the file save dialog does appear but a very long time after the click. But the server is still up and the save operation still fails: Network error.
Adding res.end() to the block catching the download click gets the dialog up immediately. Now I successfully download a zero length file. Oddly I find that encouraging.
var formidable = require('formidable');
var util = require("util");
var http = require('http');
var url = require('url');
var fs = require('fs');
var java = require("java");
var proc = require("process");
java.classpath.push("/home/u0138544/fake/prep-1.jar");
java.classpath.push("/home/u0138544/fake/SRTDependancies-1.jar");
console.log(proc.cwd());
http.createServer(function (req, res) {
txName = "";
if (req.url == '/fileupload' && req.method.toLowerCase() == 'post') {
var form = formidable.IncomingForm();
form.keepExtensions = true;
var excelFilePath;
var origName;
form.parse(req , function (err, fields, files) {
excelFilePath = files.filetoupload.path;
console.log("upload " + excelFilePath);
origName = files.filetoupload.name;
txName = "tx-" + origName.replace(/\s/g, "");
console.log( "txname = " + txName);
//just for formatter
var clz = "edu.utah.camplab.xlsx.SampleReportTransformer";
var tx = java.newInstanceSync(clz);
java.callMethodSync(tx, "run", excelFilePath, "./transformed/" + txName);
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<p>');
res.write('<input type="text" value = "' + txName +'"><br>');
res.write('Download transformed file</p>');
return res.end();
});
}
else if (req.url.includes('transformed') &&
req.method.toLowerCase() == 'get') {
console.log("download attribute doesn't work")
res.end();
}
else {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload" label="Pick a file"><br>');
res.write('<input type="submit">');
res.write('</form>');
return res.end();
}
}).listen(15080);

Parse TCP JSON Stream and emit each object via Socket.io

I am working with a data feed that sends a JSON stream over a TCP socket and I'm using node.js/socket.io to emit the stream to a browser client.
Everything is working except I need each JSON object to emitted as a separate message from the socket.io server. In the client the messages are received like this:
//Message 1:
{"type":"TYPE_1","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
//Message 2:
{"type":"TYPE_2","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
{"type":"TYPE_3","odds":[{"eventId":"foo","odds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
//Message 3:
{"type":"TYPE_4","odds":[{"eventId":"foo","od
//Message 4:
ds":[{"oddId":foo,"oddType":"LIVE","source":"foo"}]}]}
The data feed docs state: "All messages sending to your application will form a JSON stream (no delimiter between messages), so you may need a decoder that support JSON stream."
So the stream is strictly correct but I need each object as separate message.
I have looked at https://www.npmjs.com/package/JSONStream and others but am very new to nodejs and socketio and am not sure how to implement them in to the server.
Have also read How can I parse the first JSON object on a stream in JS, nodejs JSON.parse(data_from_TCP_socket), http://www.sebastianseilund.com/json-socket-sending-json-over-tcp-in-node.js-using-sockets.
I think it's something to do with buffer chunk lengths and them being too big so the messages get split but that could be wrong! I'm guessing I need a delimiter check that balances brackets but not sure how to go about it or if the right approach.
My Server Script:
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var net = require('net');
var port = 8992; // Datafeed port
var host = '127.0.0.1'; // Datafeed IP address
//Whenever someone connects this gets executed
io.on('connection', function(socket){
console.log('A user connected to me the server');
//Whenever someone disconnects this piece of code executed
socket.on('disconnect', function () {
console.log('A user disconnected');
});
});
//Create a TCP socket to read data from datafeed
var socket = net.createConnection(port, host);
socket.on('error', function(error) {
console.log("Error Connecting");
});
socket.on('connect', function(connect) {
console.log('connection established');
socket.write('{"type":"SUBSCRIBE"}');
});
socket.on('data', function(data) {
//console.log('DATA ' + socket.remoteAddress + ': ' + data);
var data = data.toString();
io.sockets.emit('event', JSON.stringify(data));
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
My Client:
<!DOCTYPE html>
<html>
<head><title>Hello world</title></head>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script>
var socket = io.connect('http://localhost:3000');
</script>
<body>
<form action="">
<input id="m" autocomplete="off" /><button>Send</button>
</form>
<ul id="messages"></ul>
<script>
socket.on('event', function(data){
var t = JSON.parse(data.toString('utf8'));
$('#messages').prepend($('<li>').text(t));
console.log('Got event from Server:', t);
});
</script>
</body>
</html>
Any help or guidance would be amazing as really struggling with this.
A common delimiter to use is a newline character (\n). If you have that appended to your JSON messages it will be very easy to parse the messages. For example:
var sockBuf = '';
socket.setEncoding('utf8');
socket.on('data', function(data) {
sockBuf += data;
var i;
var l = 0;
while ((i = sockBuf.indexOf('\n', l)) !== -1) {
io.sockets.emit('event', sockBuf.slice(l, i));
l = i + 1;
}
if (l)
sockBuf = sockBuf.slice(l);
});
or a more efficient, but slightly less simple solution:
var sockBuf = '';
socket.setEncoding('utf8');
socket.on('data', function(data) {
var i = data.indexOf('\n');
if (i === -1) {
sockBuf += data;
return;
}
io.sockets.emit('event', sockBuf + data.slice(0, i));
var l = i + 1;
while ((i = data.indexOf('\n', l)) !== -1) {
io.sockets.emit('event', data.slice(l, i));
l = i + 1;
}
sockBuf = data.slice(l);
});

Res.write is not working when continuously sending UDP packet

//Sending UDP message to TFTP server
//dgram modeule to create UDP socket
var express= require('express'), fs= require('fs'),path = require('path'),util = require('util'),dgram= require('dgram'),client= dgram.createSocket('udp4'),bodyParser = require('body-parser'),app = express(), ejs = require('ejs');
var plotly = require('plotly')("Patidar", "ku0sisuxfm")
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json())
app.use(express.static('public'));
//Reading in the html file for input page
app.get('/', function(req, res){
var html = fs.readFileSync('index2.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
//reading in html file for output page
app.get('/output', function(req, res){
var html = fs.readFileSync('index4.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(html);
});
//Recieving UDP message
app.post('/output', function(req, res){
var once= req.body.submit;
if (once == "Once") {
//Define the host and port values of UDP
var HOST= req.body.ip;
var PORT= req.body.port;
//Reading in the user's command, converting to hex
var message = new Buffer(req.body.number, 'hex');
//Sends packets to TFTP
client.send(message, 0, message.length, PORT, HOST, function (err, bytes) {
if (err) throw err;
});
//Recieving message back and printing it out to webpage
client.on('message', function (message) {
fs.readFile('index3.html', 'utf-8', function(err, content) {
if (err) {
res.end('error occurred');
return;
}
var temp = message.toString(); //here you assign temp variable with needed value
var renderedHtml = ejs.render(content, {temp:temp, host: HOST, port: PORT}); //get redered HTML code
res.end(renderedHtml);
//var data = [{x:[req.body.number], y:[temp], type: 'scatter'}];
//var layout = {fileopt : "overwrite", filename : "simple-node-example"};
//plotly.plot(data, layout, function (err, msg) {
//if (err) return console.log(err);
//console.log(msg);
//});
});
});
}
if (once == "continuous") {
var timesRun = 0;
var requestLoop = setInterval(function(){
timesRun += 1;
if(timesRun === 5){
clearInterval(requestLoop);
}
//Define the host and port values of UDP
var HOST= req.body.ip;
var PORT= req.body.port;
//Reading in the user's command, converting to hex
var message = new Buffer(req.body.number, 'hex');
//Sends packets to TFTP
client.send(message, 0, message.length, PORT, HOST, function (err, bytes) {
if (err) throw err;
});
//Recieving message back and printing it out to webpage
client.on('message', function (message) {
fs.readFile('index3.html', 'utf-8', function(err, content) {
if (err) {
res.end('error occurred');
return;
}
var temp = message.toString(); //here you assign temp variable with needed value
var renderedHtml = ejs.render(content, {temp:temp, host: HOST, port: PORT}); //get redered HTML code
res.write(renderedHtml);
//var data = [{x:[req.body.number], y:[temp], type: 'scatter'}];
//var layout = {fileopt : "overwrite", filename : "simple-node-example"};
//plotly.plot(data, layout, function (err, msg) {
//if (err) return console.log(err);
//console.log(msg);
//});
});
});
}, 10000);
}
});
//Setting up listening server
app.listen(3000, "192.168.0.136");
console.log('Listening at 192.168.0.136:3000');
I have two button, one button sends the UDP packet once, while a continuous button sends the same UDP packets every 10 seconds. However, when this button is pressed, res.write is repeating the entire output again. Look at the attached pic to see output[![enter image description here][1]][1]
After putting your code into an auto-code-formatter to make it readable, I can see that you are doing this:
client.on('message', function (message) { ...
inside of your app.post() handler. That means that every time your post handler is called, you add yet another client.on('message', ...) event handler. So, after it's called the 2nd time, you have two event handlers, after it's called the 3rd time, you have three and so on.
So, as soon as you have these duplicate, each will get called and you will get duplicate actions applied.
Your choices are to either:
Use .once() for the event handler so it is automatically removed after it fires.
Remove it manually after it fires or when you are done with it.
Add it once outside your app.post() handler so you never add duplicates.
Restructure the way your code works so it doesn't have this type of issue. For example, you have two different handlers for the same incoming message. This is a sign of very stateful code which is more complex to write properly. A better design that isn't stateful in that way would be simpler.

Node.js HTTPS Request for Quandl API

I am using IBM Bluemix to make a web service for a school project.
My project needs to request JSON data from two APIs, for use in the project.
The first one is a http.request, which I executed just fine. For the second one, however, I need a https.request - and that is where the trouble comes from.
I don't know how to get a JSON through a https request. I've been trying to adapt the code for the http one, but my efforts have rendered useless.
How can I request a JSON via https?
Here is my .jsfile:
// Hello.
//
// This is JSHint, a tool that helps to detect errors and potential
// problems in your JavaScript code.
//
// To start, simply enter some JavaScript anywhere on this page. Your
// report will appear on the right side.
//
// Additionally, you can toggle specific options in the Configure
// menu.
function main() {
return 'Hello, World!';
}
main();/*eslint-env node*/
//------------------------------------------------------------------------------
// node.js starter application for Bluemix
//------------------------------------------------------------------------------
// HTTP request - duas alternativas
var http = require('http');
var request = require('request');
//HTTPS request
var https = require('https');
var https = require('https');
var fs = require('fs');
// cfenv provides access to your Cloud Foundry environment
// for more info, see: https://www.npmjs.com/package/cfenv
var cfenv = require('cfenv');
//chama o express, que abre o servidor
var express = require('express');
// create a new express server
var app = express();
// serve the files out of ./public as our main files
app.use(express.static(__dirname + '/public'));
// get the app environment from Cloud Foundry
var appEnv = cfenv.getAppEnv();
// start server on the specified port and binding host
app.listen(appEnv.port, '0.0.0.0', function() {
// print a message when the server starts listening
console.log("server starting on " + appEnv.url);
});
app.get('/home1', function (req,res) {
http.get('http://developers.agenciaideias.com.br/cotacoes/json', function (res2) {
var body = '';
res2.on('data', function (chunk) {
body += chunk;
});
res2.on('end', function () {
var json = JSON.parse(body);
var CotacaoDolar = json["dolar"]["cotacao"];
var VariacaoDolar = json["dolar"]["variacao"];
var CotacaoEuro = json["euro"]["cotacao"];
var VariacaoEuro = json["euro"]["variacao"];
var Atualizacao = json["atualizacao"];
obj=req.query;
DolarUsuario=obj['dolar'];
RealUsuario=Number(obj['dolar'])*CotacaoDolar;
EuroUsuario=obj['euro'];
RealUsuario2=Number(obj['euro'])*CotacaoEuro;
Oi=1*VariacaoDolar;
Oi2=1*VariacaoEuro;
if (VariacaoDolar<0) {
recomend= "Recomenda-se, portanto, comprar dólares.";
}
else if (VariacaoDolar=0){
recomend="";
}
else {
recomend="Recomenda-se, portanto, vender dólares.";
}
if (VariacaoEuro<0) {
recomend2= "Recomenda-se, portanto, comprar euros.";
}
else if (VariacaoEuro=0){
recomend2="";
}
else {
recomend2="Recomenda-se,portanto, vender euros.";
}
res.render('cotacao_response.jade', {
'CotacaoDolar':CotacaoDolar,
'VariacaoDolar':VariacaoDolar,
'Atualizacao':Atualizacao,
'RealUsuario':RealUsuario,
'DolarUsuario':DolarUsuario,
'CotacaoEuro':CotacaoEuro,
'VariacaoEuro':VariacaoEuro,
'RealUsuario2':RealUsuario2,
'recomend':recomend,
'recomend2':recomend2,
'Oi':Oi,
'Oi2':Oi2
});
app.get('/home2', function (req,res) {
https.get('https://www.quandl.com/api/v3/datasets/BCB/432.json?api_key=YOUR_API_KEY', function (res3) {
var body = '';
res3.on('data', function (chunk) {
body += chunk;
});
res3.on('end', function () {
var x=json.dataset.data[0][1];
console.log("My JSON is "+x); });
});
});
});
});
});
Your https.get should work as set up. There were a few other issues with your code that caused it to break, which I'm outlining below with explanations:
1. Potentially incorrect nesting of the /home2 route
Your declaration of the /home2 route was inside the declaration of your /home1 route. It is likely that you meant it to be outside. I've fixed this (and also fixed some indentation) in the code below.
2. json is undefined in the /home2 route's https.get callback
The variable json is not defined before use in the https.get callback function. You will need a line similar to the one you have in the http.get callback: var json = JSON.parse(body);.
Here's the fixed code for the routes
app.get('/home1', function (req,res) {
http.get('http://developers.agenciaideias.com.br/cotacoes/json', function (res2) {
var body = '';
res2.on('data', function (chunk) {
body += chunk;
});
res2.on('end', function () {
var json = JSON.parse(body);
var CotacaoDolar = json["dolar"]["cotacao"];
var VariacaoDolar = json["dolar"]["variacao"];
var CotacaoEuro = json["euro"]["cotacao"];
var VariacaoEuro = json["euro"]["variacao"];
var Atualizacao = json["atualizacao"];
obj=req.query;
DolarUsuario=obj['dolar'];
RealUsuario=Number(obj['dolar'])*CotacaoDolar;
EuroUsuario=obj['euro'];
RealUsuario2=Number(obj['euro'])*CotacaoEuro;
Oi=1*VariacaoDolar;
Oi2=1*VariacaoEuro;
if (VariacaoDolar<0) {
recomend= "Recomenda-se, portanto, comprar dólares.";
}
else if (VariacaoDolar=0){
recomend="";
}
else {
recomend="Recomenda-se, portanto, vender dólares.";
}
if (VariacaoEuro<0) {
recomend2= "Recomenda-se, portanto, comprar euros.";
}
else if (VariacaoEuro=0){
recomend2="";
}
else {
recomend2="Recomenda-se,portanto, vender euros.";
}
res.render('cotacao_response.jade', {
'CotacaoDolar':CotacaoDolar,
'VariacaoDolar':VariacaoDolar,
'Atualizacao':Atualizacao,
'RealUsuario':RealUsuario,
'DolarUsuario':DolarUsuario,
'CotacaoEuro':CotacaoEuro,
'VariacaoEuro':VariacaoEuro,
'RealUsuario2':RealUsuario2,
'recomend':recomend,
'recomend2':recomend2,
'Oi':Oi,
'Oi2':Oi2
});
});
});
});
app.get('/home2', function (req,res) {
https.get('https://www.quandl.com/api/v3/datasets/BCB/432.json?api_key=YOUR_API_KEY', function (res3) {
var body = '';
res3.on('data', function (chunk) {
body += chunk;
});
res3.on('end', function () {
var json = JSON.parse(body);
var x=json.dataset.data[0][1];
console.log("My JSON is "+x);
res.send('done https: JSON result: '+x);
});
});
});
Final note
You added your API key in the https URL. I would recommend changing the key, if sensitive information is involved.
The HTTPS server and client API is almost identical to the HTTP API.In fact, the client API is the same, and the HTTPS server only differs in that it needs a certificate file.
Starting the server
To start the HTTPS server, you need to read the private key and certificate. Note that readFileSync is used in this case, since blocking to read the certificates when the server starts is acceptable:
// HTTPS
var https = require('https');
// read in the private key and certificate
var pk = fs.readFileSync('./privatekey.pem');
var pc = fs.readFileSync('./certificate.pem');
var opts = { key: pk, cert: pc };
// create the secure server
var serv = https.createServer(opts, function(req, res) {
console.log(req);
res.end();
});
// listen on port 443
serv.listen(443, '0.0.0.0');
Note that on Linux, you may need to run the server with higher privileges to bind to port 443. Other than needing to read a private key and certificate, the HTTPS server works like the HTTP server.

Call socket.io from dgram socket udp4

I'm having some problems with a small aplications that I'm developing.
I have an Arduino with a temperature sensor, I wanted to send the values to a nodejs service, and show it to a webpage. I wanted to use socket.io, but I'm just able to use UDP connection from arduino to server (ethernet). Just to keep the sensor value refreshed, seems that I have to call a io socket from the UDP service, but I can't.
My socket.io that works when I call it from a webpage.
var io = require('socket.io').listen(3000);
io.sockets.on('connection', function (socket) {
socket.on('message', function (message) {
console.log("Got message: " + message);
io.sockets.emit('SensorList', { 'temperature': temp });
});
});
This is the UDP service that reads the arduino packets:
var dgram = require("dgram");
var server = dgram.createSocket("udp4");
var fs = require('fs');
**var io = require('socket.io');**
var crlf = new Buffer(2);
crlf[0] = 0xD; //CR - Carriage return character
crlf[1] = 0xA; //LF - Line feed character
server.on("message", function (msg, rinfo) { //every time new data arrives do this:
console.log("server got: " + msg.readUInt16LE(0) + " from " + rinfo.address + ":" + rinfo.port); // you can comment this line out
**var socket = io.connect('http://localhost:3000');
socket.on('connect', function () {
socket.send(msg.readUInt16LE(0));
});**
});
server.on("listening", function () {
var address = server.address();
console.log("server listening " + address.address + ":" + address.port);
});
server.bind(6000); //listen to udp traffic on port 6000
The error is:
var socket = io.connect('http://localhostit.is:3000'); ^
TypeError: Object # has no method 'connect'
at Socket. (/Users/xfr/Documents/nodejs/temp1/app2.js:15:19)
at Socket.EventEmitter.emit (events.js:98:17)
at UDP.onMessage (dgram.js:437:8)
If I erase all the io part, I'm able to see the values in console.
If there is another way to mix 2 services in one.. tell me some clues and I'll do the search.
Thanks.
Made it!
2 in 1...
var http = require('http'),
dgram = require('dgram'),
socketio = require('socket.io');
var fs = require('fs');
var app = http.createServer(),
io = socketio.listen(app),
socket = dgram.createSocket('udp4');
var crlf = new Buffer(2);
crlf[0] = 0xD; //CR - Carriage return character
crlf[1] = 0xA; //LF - Line feed character
socket.on('message', function(content, rinfo) {
console.log('got message', content.readUInt16LE(0), 'from', rinfo.address, rinfo.port);
io.sockets.emit('udp message', content.readUInt16LE(0));
});
socket.bind(6000);
app.listen(8000);
On the webpage side:
src="socket.io.min.js"
src="jquery.min.js"
<script>
var socket = io.connect('http://local_host.com:8000');
socket.on('udp message', function(msg) {
console.log(msg) ;
temperature = msg/100;
$('#temperature h1').html(temperature+'°C');
});
</script>
bind/listen newbie issues.