Ok, so I have my server.js
var express = require("express"),
app = express(),
bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(express.static(__dirname + '/'));
app.post('/message', function(req, res) {
var jsonData = req.body;
if (jsonData.hasOwnProperty('phone1')) {
console.log("Phone 1 is connected to", jsonData.phone1.connection,
"and has a downlink speed of", jsonData.phone1.dl, "Mbps");
} else
if (jsonData.hasOwnProperty('phone2')) {
console.log("Phone 2 is connected to", jsonData.phone2.connection,
"and has a downlink speed of", jsonData.phone2.dl, "Mbps");
}
});
var port = 1337;
app.listen(port);
console.log("Running at Port " + port);
and as you see I want to do stuff when the server gets something posted on /message. I can console.log stuff yes, but I want to change things on the web page this server is serving. The POST requests are coming from another server. This server only presents them.
How can I do that without having to update the page?
I'm also using AngularJS on the client side, so any way for the client side to pick up the JSON data would be nice.
I hope to present the data in my Highcharts gauges and charts but a simple text update on a page element (e.g. <p id="example">) will do just fine for an answer to this question.
I know I can get jquery to node but I still lack the window element to manipulate the presented data. NW.js might do exactly what I want, I haven't still tried it though, but I suspect there might be another solution to this problem.
If you want to push new content to the client (opposite flow to the client requesting data from the server), WebSockets are an option (see http://socket.io/ for a common library).
Alternatively, you could setup long polling on the client side. This is using JavaScript to periodically 'poll' the server for information using setInterval or a similar approach.
Since I only need to send data from the server to the client, I ended up with Server Sent Events (SSE) and my code looks like this on the server side:
var mypage;
app.get('/connect', function(req, res){
res.writeHead(200, {
'Connection': 'keep-alive',
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache'
});
mypage = res;
});
app.post('/message', function(req, res) {
if (mypage !== undefined) {
mypage.write('data: '+ JSON.stringify( req.body ) +'\n\n');
}
});
and on the client side:
$(function () {
var server = new EventSource('/connect'),
point1 = $("#gauge1").highcharts().series[0].points[0],
point2 = $("#gauge2").highcharts().series[0].points[0];
server.onmessage = function(e) {
var jsonData = JSON.parse(e.data);
if (jsonData.hasOwnProperty('phone1')) {
point1.update(parseInt(jsonData.phone1.dl));
if (jsonData.phone1.connection === "3G") {
/* extra functionality */
} else {
/* extra functionality */
}
} else
if (jsonData.hasOwnProperty('phone2')) {
point2.update(parseInt(jsonData.phone2.dl));
if (jsonData.phone2.connection === "3G") {
/* extra functionality */
} else {
/* extra functionality */
}
}
};
});
I got extra help from my other question regarding the data formatting of SSE
Node Webkit was not the answer to my problem, since it doesn't run on the browser.
I still have some problems with receiving many posts. I'm generating every 0.5s a post message but I keep receiving 5 messages then nothing for 2 minutes then again 5 messages. I don't know why that's happening, but it's not part of this problem so I'll post another question about that.
Related
I'm must say I'm very new to back end development,
I'm currently working on an exercise project of making a fake money poker website. I use Node.js socket.io/express-session/passport
At first, I mainly used express with a HTTP server listening on one port. Averagely Like this:
const express = require("express")
const app = express()
app.get('/home',connectEnsureLogin.ensureLoggedIn("/loginPage"),function(req, res) {
//console.log(req.user.username+": sessionId: "+req.sessionID);
return res.sendFile( __dirname+"/website/index.html");
}
);
const PORT = process.env.PORT || 5000;
app.listen(PORT, () => console.log("Poker site Server started on ${PORT})")
The website wasn't working very fast. When a client joined a poker table they needed to ask the server every second for new updates on the state of the game so that was a lot of HTTP requests coming into my server. So I decided without much theoretical certitude that it seemed like a good idea: To have the server use socket.io sockets to hand info for clients that are in poker tables, but when they are not in poker tables and are just browsing the site I use a HTTP server to handle their request. Code wise I feel I haven't really managed to do this correctly. My code with Express, express-session, and passport combined makes sure only to hand information to users authenticated. But since The socket.io servers seem totally separate from all the express code, they don't share the same authentication functionality as the express code. So I need to somehow link my express and socket.io code so I can check if a client is authenticated before handing him any info via sockets. here is the system I'm currently using I didn't put all my code but I tried to summarize the essential parts:
const express = require('express');
const app = express();
//i creat the http server that is somehow linked with my express app when this server is listening
//it will call express handling methods.
const http = require('http').Server(app);
const io = require('socket.io')(http);
const path = require("path");
const passport = require("passport");
const connectEnsureLogin = require('connect-ensure-login');
const AccountInfo = require("./AccountInfo").AcccountInfo;
const expressSession = require('express-session')({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
});
//passport setup
passport.use(AccountInfo.createStrategy());
passport.serializeUser(AccountInfo.serializeUser());
passport.deserializeUser(AccountInfo.deserializeUser());
//body parser
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
//Sessions
app.use(expressSession);
//!!!!here is where I connect socket.io with the sessions i found this in another forum.
// thanks to this code I can access the session that a client is using when their socket connects.
io.use(function(socket, next) {
expressSession(socket.request, socket.request.res, next);
});
//so when a clients socket connects i save his socket.id to his session.
io.on('connection',function(socket) {
console.log(`socket.io connected: ${socket.id}`);
// save socket.io socket in the session
socket.request.session.socketio = socket.id;
socket.request.session.save();
});
//once the clients socket is connected directly after the clients sends a HTTP "PUT" request
//and this code answers it.
app.post('/Table/ConnectSocketToTable',Utilities.ensureLoggedIn(),function(req, res)
{
//I retrieve the socket using the socket.id I had saved in the session.
let socket = io.sockets.sockets.get(req.session.socketio);
let player = GetPlayerFromAnyTable(req.user.username);
if(player==null)//the player can't be in two tables at once
{
//since now we are in an express callback, express made sure that the client is indeed
//authenticated with the middle-ware: "Utilities.ensureLoggedIn()" also just before I made sure
//the client is not in another table. So we are good to go we can now link the socket to the table
//and have the client receive all the info about the state of his table
socket.join("table-"+req.session.passport.table);
req.user.socket = socket;
let table = GetTable(req.session.passport.table);
table.sitPlayer(req.user);
}
else
{
//the player is already connected so we just update his socket to a new one
player.requestUnseat=false;
player.account.socket =io.sockets.sockets.get(req.session.socketio);
}
socket.on('chatMessage', function(data,time) {
socket.to("table-"+req.session.passport.table).emit("chatMessage",req.user.username,data,time);
console.log(`send chat message : ${data}`);
});
socket.on('disconnect', function() {
GetTable(req.session.passport.table).requestUnsitUsername(req.user.username);
console.log(req.user.username +" was disconnected so now requesting unsit");
});
console.log("the socket of "+req.user.username+" has being connected to table-"+req.session.passport.table);
return res.sendStatus(200);
});
So for me, the way I'm doing this seems pretty bad since "app.post('/Table/ConnectSocketToTable'...)" and "io.on('connection',...)" are two different request listening functions I feel I should probably just do everything in one.
So should I do all the checks in the "io.on('connection',...)" function and somehow manage to make sure the client is authenticated within the callback of io.on('connection',callback) ?
or should I find a way to make the socket connection happen in the initial HTTP call the client uses to join a table, which is what I initially wanted?
But really I'm kinda lost because I'm telling myself maybe I don't even need Express anymore and I should just use socket.io for everything. I seem to clearly lack the general understanding that would allow me to know what approach I should be going for so any help is welcome. I started doing this self-made exercise to get into server-side development but also if there is any other recommended exercise to start up with back-end development I'm definitely interested in hearing about it.
From random testing I found out how to authenticate to my express session from the socket code you don't actually have to do it in the callback of io.on('connection',callback) you just need to add a few more middleware functions like this:
//connecting express sessions
io.use(function(socket, next) {
expressSession(socket.request, socket.request.res, next);
});
//connecting passport
io.use(function(socket, next) {
passport.initialize()(socket.request, socket.request.res, next);
});
//connecting passport sessions
io.use(function(socket, next) {
passport.session()(socket.request, socket.request.res, next);
});
//check if client is authenticated returns error if authentication failed
io.use((socket, next) => {
console.log("started socket Connection");
if(!socket.request.isAuthenticated&&socket.request.isAuthenticated())
{
socket.request.session.socketio = socket.id;
socket.request.session.save();
console.log("table "+socket.request.session.passport.table);
console.log("user.username "+socket.request.user.username);
console.log(`is authentificated`);
next();
}
else
{
console.log(`failed socket connection`);
next(new Error("unauthorized"));
}
});```
So this is a very odd question and I don't expect any one to really have an answer to this, but I'm here to try and see if anyone has experienced the same issue.
The issue that I'm noticing is that our application seems to be sending duplicate emails. For example, I can send a report from our application, and it will send that email once, and then it looks like another one gets sent exactly a minute later.
I'm using nodemailer to send the emails from our applications server, and our default email that we use in our office is Outlook v16.0.12130.20272 using IMAP. These emails are being sent by our noreply email which I believe is being hosted through GoDaddy.
I've sent test emails myself and looked in the network tab to see if it might be a timeout issue, but the response completes with a 200 OK status and the timing shows up as completed as well. Also when I console log the response it only occurs once, which makes me believe that it is actually only sending one email. There must be something happening in between when the host sends the email, and when our recipients actually receive them, but I'm not quite sure.
Here is the server.js file. This is where the smtp request is being made.
var nodemailer = require("nodemailer");
const path = require('path');
const express = require('express');
const http = require('http');
const fs = require('fs');
const socketIO = require('socket.io');
const bodyParser = require('body-parser')
import env from '../env.config.json';
const PORT = require('../env.config.json').SERVER.PORT;
const publicPath = path.join(__dirname, '../public');
import api from './routers/api-routing';
//---------------------------------------------------------------------------
var smtpTransport = nodemailer.createTransport({
service: env.EMAIL.SERVICE,
host: env.EMAIL.HOST,
auth: {
user:env.EMAIL.AUTH.USER,
pass:env.EMAIL.AUTH.PASS
}
});
var mailCounter = 0;
var numPeople = 0;
var app = express();
var server = http.createServer(app);
const port = PORT || 3000;
app.use(express.static(publicPath));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true}));
const io = socketIO(server);
app.use('/api', api(app, io));
// require('./routers/api-routing')(app, io);
//$.get("/send", { to: to, subject: subject).value, text: 'html' }, function (data) { });
app.get('*', function (request, response) {
if (request.get('x-auth')) console.log("x-auth: ", request.get('x-auth'));
const proto = request.get('X-Forwarded-Proto');
if (proto) {
if (proto === 'http') response.redirect(301, "https://ourdomain.com".concat(request.url));
}
response.sendFile(path.resolve(__dirname, '../', 'public', 'index.html'))
if ((request.url).substring(0, 5) == "/send") {
var mailOptions = {
to: request.query.to,
bcc: request.query.bcc,
subject: request.query.subject,
text: request.query.text
}
//console.log(mailOptions); Read up on NodeMailer for details.
smtpTransport.sendMail({ //email options
from: "COMPANY <noreply#ouremail.com>", // sender address. Must be the same as authenticated user if using Gmail.
to: mailOptions.to,
bcc: "COMPANY <noreply#ouremail.com>", // sending to itself
subject: mailOptions.subject, // subject
html: mailOptions.text, // body
}, function (error, response) { //callback
if (error) {
console.log(error);
} else {
console.log("Message sent");
//console.log("Amount of people getting this email: " + response.accepted.length);
}
smtpTransport.close(); // shut down the connection pool, no more messages. Comment this line out to continue sending emails.
});
}
});
io.on('connection', (socket) => {
require('./middleware/sockets')(socket);
});
server.listen(port, () => {
console.log(`Server is up on port ${port}.`);
});
This is the part of our env.config.file that pertains to the emails.
"EMAIL": {
"SERVICE": "Godaddy",
"HOST": "smtp.gmail.com",
"AUTH": {
"USER": "noreply#ouremail.com",
"PASS": "OURPASS"
}
}
If anyone has any ideas or suggestions, I would be very appreciative, thanks!
Your email is being sent on any request sent to your server so if you access it via a browser, the browser will send two requests, one for the path requested and one for the favicon.ico and you're also sending an email when /favicon.ico is requested.
This can happen because you're route handler is configured as:
app.get('*', ...);
That means you're attempting to send an email for every single incoming http request regardless of path.
So, if you go to your host with a browser at http://yourdomain/, it will first request / and then the browser will request /favicon.ico, causing you to then send a second email.
My suggestion is to change from this:
app.get('*', ...);
to this:
app.get('/', ...);
or, even more specific such as:
app.get('/sendemail', ...);
So, you are only sending the email on one specific path request and it will not send the email no other requests such as the favicon. You probably want to add a generic express 404 handler for any other routes.
Note: In a REST design, you would probably send an email with a POST request, not a GET request. A GET would retrieve a resource in a read-only kind of way that does not change any state so it wouldn't have a side effect of sending an email. Note: this isn't related to your problem at all, just a comment about a typical REST design.
After some time I have finally figured out the reason for this behavior. The issue is partially related to what jfriend00 had posted. I ended up making a separate route handler for the emails themselves so that it didn't interfere with the main route handler. The problem is that every request will still go through that route since it is looking for any request indicated by the * and if a person is on the http route making the request instead of https, then it creates a second request or in my case a second email.
You can see that happening in this line here:
if (proto) {
if (proto === 'http') response.redirect(301, "https://ourdomain.com".concat(request.url));
}
The actual fix for this was to create a separate route handler for the emails themselves and then configure my nginx server to reroute to https if a person was going to the http route of the application instead. After this, we have not experienced anymore duplicate emails.
Another way of doing it would be to remove the ```*```` route handler completely and setup the other routes separately. Hopefully this will help somebody in the near future.
This is my first post on stackoverflow so pls forgive me if I'm making post taht already existis. I'm kinda new into HTML and .js, "know basics guy".
I have a mobile app on tablet that has kisok mode browser and I'm using it to connect to my NodeJS Server on RPI (works). I have a lot of HTML's and .js files already in my project.
What I'm trying to find out:
Is it possible to make new seperate HTML or .js file that would do something like remote control with my tablet to server. Example - When I click a button taht same button is clicked on browser on RPI beacuse I have another seperate display on RPI that show same thing and I would use my tablet only as a getter of HTML (so I can show it on tablet) and input method for RPI. (simultaneously on both display but use tablet as input)
Or update all existing HTML and .js on server side (harder way, if this thing is even posbile to do)
Thank you very much for further help!
EXtra edit - code
Here is the server side code!
//var app = require('http').createServer(handler);
//var express = require("express")();
var express = require("express");
//var app = require("express")();
var app = express();
var http = require("http").Server(app);
var path = require("path");
//var io = require('socket.io')(app);
var io = require('socket.io')(http);
var SerialPort = require('serialport');
//previous was app.listen(3000);
http.listen(3000);
//Enabling CORS - for specific localhost port
app.use(function (req, res, next){
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
function handler(req, res){
console.log(req, res);
}
var serialPort = new SerialPort.SerialPort("/dev/ttyAMA0", {
baudrate: 9600,
dataBits: 8,
parity: "none",
stopBits: 1,
flowControl: false
});
var counter = 0;
serialPort.on("open", function () {
console.log("open");
var service = new Service();
serialPort.on("data", function (data) {
var hexData = data.toString('hex');
console.log(data, hexData);
io.emit('hit', data);
});
});
io.on('connection', function(socket){
console.log('Connected');
//nsmrcek - custom code for accepting data from client side
socket.on("message1",function(data){
});
socket.on("message2",function(data){
});
socket.on("message3",function(data){
});
socket.on("message4", function(data){
});
socket.on("message5", function(data){
});
});
app.use(express.static(path.join(__dirname, '/')));
//app.use('/js', express.static(path.join(__dirname,
app.get("/home",function(req,res,next){
//res.send("OK");
//if fails path incorrect
res.sendFile(path.join(__dirname + "/index.html"));
//res.render("index.html");
});
function Service() {
this.mapCodeToHit = function (data) {
"data send from little homemade CPU board via serial port to RPI server" }
I hope this is enough code so You can instruct me where to put more code to simulate click on evry other client while clicking button on one of the clients (alawys 2 clients)
If you created a websocket connection that ran through your server and pushed the updated state of the button to the connected clients this would certainly be possible. I can't give a detailed answer without seeing your code but you could start with the socket.io docs here and ask more questions as you get started.
http://socket.io/
I am new with node and I am trying to print the results to the console and eventually display them in HTML. I have tried invoking the function as a var that I would later use in HTML but this didn't work. Some similar example code:
var app = require('express')();
var x = require('x-ray')();
app.get('/', function(req, res) {
res.send(x('http://google.com', 'title').write());
})
Thanks!
I don't know much about the "x-ray" library, but I presume the problem is with that since it has to asynchronously make a request before it can return the response data. The documentation says that if you don't set a path as an argument to the write function it returns a readable stream, so try this:
app.get('/', function(req, res) {
var stream = x('http://google.com', 'title').write(),
responseString = '';
stream.on('data', function(chunk) {
responseString += chunk;
});
stream.on('end', function() {
res.send(responseString);
});
});
You also need to start the server listening on a particular port (3000 in the example below):
const PORT = 3000;
app.listen(PORT, function() {
console.log("Server is listening on port " + PORT + ".");
}); // the callback function simply runs once the server starts
Now open your browser and navigate to 127.0.0.1:3000 or localhost:3000, and you'll see "Google" appear!
ALSO: If you want to use the response data in a full HTML page (rather than just sending the string on its own), you may want to explore further how to do this in Express with Jade (or similar) templates. And the code at the moment scrapes Google every time someone makes a request to the appropriate route of your server; if you only want to scrape Google once, and then use the same string again and again in your server's responses, you may want to think about how to implement this (it's easy!).
So I have built a html form to interact with Slack. Currently my js code looks like this.
$("#submitemail").click(function(){
$.post(
"https://openpgh.slack.com/services/hooks/incoming-webhook?token=MY_SECRET_TOKEN",
JSON.stringify({'text':'invite request from: '+$("#email").val(),'username':'Slack Inviter','icon_emoji':':raising_hand:'})
).success(function(){
$("#email").val("");
});
});
if anyone were to just copy this right out of my html file they could just run a console command and change the JSON and bombard my slack group with massive amounts of nonsense until they hit the API call limit.
What I am wondering is if I could store this in my index.js (I am using a node.js template) as a var and then call it in the html.
Any options or advice is greatly appreciated I am very new to this.
My structure is:
Slack App
|_node_modules
| |_express
|_public
| |_index.html
| |_node.svg (idk what this does)
|_.gitignore
|_app.json
|_index.js
|_package.json
|_procfile
|_README.md
the code for my index.js is just
var express = require('express');
var app = express();
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
app.listen(app.get('port'), function() {
console.log("Node app is running at localhost:" + app.get('port'))
});
I can throw in my full html if you want its just a basic modal w/ a button to click to execute the form and pull the email.
Disclaimer: this code is untested
You would basically do something like this:
index.js (commented to explain what i added):
var express = require('express');
// install request module
var request = require('request');
var app = express();
// make a new route that you can call from the client side
app.get('/getSlackData', function(req, res) {
//variable to hold your response from slack
var slackResponse;
//make the request to slack
var slackUrl = "https://openpgh.slack.com/services/hooks/incoming-webhook?token=MY_SECRET_TOKEN""
request(slackUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
slackReponse = response;
} else {
console.log(error);
});
return slackResponse;
});
app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
app.listen(app.get('port'), function() {
console.log("Node app is running at localhost:" + app.get('port'))
});
So we added a new route, that is basically an API you can call from the client side, it will return the JSON object that you got from Slack. You can pretty much leave your client side code the same, just change the route you're calling:
$("#submitemail").click(function(){
$.post("/getSlackData",
JSON.stringify({'text':'invite request from:'+$("#email").val(),'username':'Slack Inviter','icon_emoji':':raising_hand:'})
).success(function(){
$("#email").val("");
});
});
I hope I understood your question correctly, this should at least get you pointed in the right direction.