How emit event name can be dynamic in Node.js? - html

I am trying to create dynamic EventEmitter in Node.js. So , how can the event name can be dynamic.
Code :
var express = require('express'),
app = express(),
server = require('http').createServer(app),
io = require('socket.io').listen(server);
num = "1";
fs = require('fs');
server.listen(4000);
function handler(req,res){
fs.readFile(__dirname + '/index.html',
function(err,data){
res.writeHead(500);
res.end(data);
});
}
app.get('/', function(req, res){
res.sendfile(__dirname + '/index.html');
});
io.sockets.on('connection', function(socket){
socket.on('send message'+num, function(data){
io.sockets.emit('new message'+num, data);
});
});
right now in this example i have given value "1" but i want it to dynamic , so how can i get the dynamic value from a html file. So , that emit event name can be dynamic.
Please let me know , suggest me some solution.

There is rarely a valid reason to use a dynamically created message name and it seriously complicates the life of whoever is trying to listen for those messages (they may not know what message name to listen for). Use one message name and then put the number in the data structure that goes with the message.
sending:
io.sockets.emit('new-message', {data: data, item: num});
receiving:
socket.on('new-message', function(msgData){
if (msgData.item === xx) {
// handle just a particular message number here
}
}

Related

How do I send the data I've got from db from Node.js through routes to front-end JavaScript file?

*I understand there is a lot of code here, but I've been struggling with this problem for a long time with no joy.
Node.js app with Express, MySQL database and EJS templating engine. I'm a total newbie.
I have a javaScript (getScoresData.js) file that returns data from MySQL database and contains code that creates a JavaScript object. This object contains values I need to send to front end (to create a data chart). The code returns the object to console when I run getSCoresData.js file so I know this part is working.
But, I have no idea how to properly implement this code/js file in order to send the object through my routes to the front end. I also don't know where getScoresData.js should actually sit in the project structure or how/if I should modularize the getScoresData.js file.
The structure is..
project/
app/
routes.js
config/
database.js
passport.js
models/
getScoresData.js
public/
scripts/
dataGraph.js
views/
server.js
getScoresData.js below
// db connection
var mysql = require('mysql');
var dbconfig = require('../config/database');
const connection = mysql.createConnection(dbconfig.connection);
//Sql Query
const scoreQuery = "SELECT question1, question2, question3, question4, question5, question6, question7, question8 FROM assessment_score";
//variable to hold score array
var scoreArray;
//returning the sql query
connection.query(scoreQuery, function (err, result) {
if (err) throw err;
//running getData() function
getData(result);
console.log(scoreArray);
// Slicing the array to make 8 categories
var category1 = scoreArray.slice(0,1);
var category2 = scoreArray.slice(2,3);
var category3 = scoreArray.slice(4,5);
var category4 = scoreArray.slice(6,7);
//parsing and accumlating each category score
var cat1Total = totalScore(category1);
var cat2Total = totalScore(category2);
var cat3Total = totalScore(category3);
var cat4Total = totalScore(category4);
//this is the object I want to send to client side to use in the graphData.js file
const categories = {cat1Total, cat2Total, cat3Total, cat4Total}
});
//function to turn sql result into an array of strings
function getData(result) {
Object.keys(result).forEach(function(key) {
const values = result[key];
return scoreArray = Object.values(values);
});
}
// function to parse the strings into numbers and accumulate them
function totalScore(categoryScore){
return categoryScore.reduce((accum,scoreArray) =>
{
const splitValues = scoreArray.split('/');
return {
score:accum.score + parseInt(splitValues[0]),
maxScore:accum.maxScore + parseInt(splitValues[1]),
}
},{score:0,maxScore:0}
);
}
routes.js file
I want to send the data through the /profile route so when users login they will displayed a graph of their score data on their profile.
module.exports = function(app, passport){
app.get('/', function(req, res){
res.render('index.ejs');
});
app.get('/login', function (req, res){
res.render('login.ejs', {message: req.flash('loginMessage')});
});
app.post('/login', passport.authenticate('local-login',{
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
}),
function(req, res){
if(req.body.remember){
req.session.cookie.maxAge = 1000 * 60 * 3;
}else{
req.session.cookie.expires = false;
}
res.redirect('/');
});
app.get('/profile', isLoggedIn, function (req, res) {
res.render('profile.ejs', {user:req.user
})
});
};
function isLoggedIn(req, res, next) {
if(req.isAuthenticated())
return next();
res.redirect('/');
});
dataGraph.js file
- where I want to use the categories object to create the graph
var ctx = document.getElementById("myChart").getContext('2d');
//Where I want to use the data sent through routes
var barTotalCategoryScores = [categories.cat1Total.score, categories.cat2Total.score, categories.cat3Total.score, categories.cat4Total.score];
var labels = ["Java & Design", "Build & Versioning"];
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: barTotalCategoryScores
}
}
});

what's the best way to send a variable using method get with express, mysql and node.js

I'm building a web site using node.js express MySQL and boostrap, when I try to send a variable against method get for to do a query to the database, it's seem doesn't work, because there's no a good render. this is my code:
app.get('/reservaciones/leer/:id', function(req, res) {
var idreservacion = req.params.idreservacion;
crud.get_leer_reservacion(req,idreservacion,function(data_leer){
res.render'../views/leer.html',data:data_leer});
});
});
exports.get_leer_reservacion = function(req,idreservacion,fn){
// here the query
connection.query('select * from reservacion where idreservacion = '"+idreservacion+"'', function(err,rows){
if(err){
throw err;
}
return fn(rows);
});
};
https://drive.google.com/folderview?id=0BxFTEy90zOKAfmJOXzR3NDFLa081NUtEUFU4LWhuN2ZUTDMtVktPeHlYbVUzWW02a2pGWEk&usp=sharing
res.render'../views/leer.html',data:data_leer});
should be:
(outside of app.get:)
app.use('views', '../views');
(inside:)
res.render('leer',{data:data_leer});
If your problem is actually getting the templated data into the page I suggest the ejs npm package and templating system, you would use <%= data => to template in the value
In this code:
app.get('/reservaciones/leer/:id', function(req, res) {
var idreservacion = req.params.idreservacion;
You define a parameter called id, but you retrieve a parameter called idreservacion. Try something like this:
app.get('/reservaciones/leer/:id', function(req, res) {
var idreservacion = req.params.id;

passport send error by json

I'm making an app with express + passport and angularJS; I want to be able to send any errors produced from passport (such as username taken or no email provided) by json so my angularJS app can receive these errors in a json response. More specifically right now I want to have a json response to my signup POST method that outputs any errors. I have tried to do this for myself and I've search all over the web and stack overflow I just cannot work this out!
Here is my users route file in express:
var express = require('express');
var router = express.Router();
var isAuthenticated = require('../config/isAuthenticated');
module.exports = function(passport){
router.get('/loggedin', function(req, res){
res.send(req.isAuthenticated() ? req.user : '0');
});
router.post('/signup', passport.authenticate('local-signup', {
successRedirect : '/',
failureRedirect : '/signup',
failureFlash: true
}));
router.post('/login', passport.authenticate('local-login'), function(req, res){
res.send(req.user);
});
router.post('/signout', function(req,res){
req.logout();
res.json({redirect: '/'});
});
router.get('/authtest', isAuthenticated, function(req, res){
res.render('authtest', {user: req.user});
});
return router;
};
This is my passport signup strategy:
passport.use('local-signup', new LocalStrategy({
usernameField : 'username',
passwordField : 'password',
passReqToCallback : true
},
function(req, username, password, done){
process.nextTick(function(){
User.findOne({'local.username' : username}, function(err, user){
if(err) return done(err);
if (user) { //username already exists
return done(null, false, {message: 'Username already exists'});
} else if(!req.body.email) { //no email address provided
return done(null, false, {message: 'You must provide an email address!'});
} else {
var newUser = new User();
newUser.local.username = username;
newUser.generateHash(password, function(err, hash){
if(err) return done(err);
newUser.local.password = hash;
});
newUser.email = req.body.email;
newUser.servers = [];
newUser.save(function(err){
if(err) throw err;
return done(null, newUser);
});
};
});
});
}
));
I know looking at my code right now it looks like I haven't tried to solve this myself at all but this is just my latest working code; I have been stuck at this for the past few days!
Any help would be greatly appreciated :)
According to the current code of passport this is probably achievable by passing custom callback to handle all results of authentiction yourself. This callback is given after options or instead of those.
passport( "local-signup", { ... }, callbackFn );
or
passport( "local-login", callbackFn );
This callback is used in all resulting situations of trying to authenticae. It is thus invoked on processing errors like this:
callbackFn( err )
If (all configured) authentications have failed it is called with
callbackFn( null, false, challenge(s), status(es) )
On successfully having authenticated user the callback is invoked like so:
callbackFn( null, user, infos )
with infos optionally provided by strategies.
Now comes the bottom-side: In either situation passport.authenticate() skips usual processing but instantly invokes provided callback to care for the rest. This includes processing of any options passed in call for passport.authenticate() like flashing messages, preparing session and request for containing authenticated user etc.
Since options given passport.authenticate() are never passed into callback there is actually no obvious reason to use both.
When I was stumbling over the very same problem (linking passport-service with angular-js POST request) I declined to consider use of callback a proper solution. This callback isn't documented. And it doesn't even look quite useful for it isn't passing req, res and next to pass any actual request in callback. Thus it makes very little sense to use it at all and I'd expect it to vanish soon or to change its behaviour quite much.
So the second approach was about trying to figure out why there is a problem in AngularJS. Passport is sending plain text Unauthorized in response with status code 401. AngularJS is trying to parse this as JSON and produces Syntax error. The text Unauthorized results from passprt ending response very simply by invoking
res.statusCode = 401;
res.end(http.STATUS_CODES[res.statusCode]);
Thus a proper workaround might try to replace
either text in http.STATUS_CODES though this is having impact on processing further requests and thus isn't preferrable
or res.end() by an overloaded method acting differently if res.statusCode is 401.
Due to affecting any current request, only, I tried the latter. Replaced res.end() might be used to send any text you want:
router.post('/login',
function(req, res, next) {
var _end = res.end;
res.end = function() {
if (res.statusCode === 401) {
return _end('{"status":"Unauthorized"}');
}
return _end.apply(this, arguments);
};
next();
},
passport.authenticate('local-login'),
function(req, res) {
res.send(req.user);
}
);
Alternatively the replaced method might add previously missing response header information on content type, for this was actually causing issues in AngularJS processing that response as JSON by default.
router.post('/login',
function(req, res, next) {
var _end = res.end;
res.end = function() {
if (res.statusCode === 401) {
res.set("Content-Type", "text/plain");
}
return _end.apply(this, arguments);
};
next();
},
passport.authenticate('local-login'),
function(req, res) {
res.send(req.user);
}
);
Finally, either approach is really just a workaround. I think passport is in the need for revising this annoying limitation.

Nodejs + Passport + MySQL

I'm trying to figure out how to use nodejs + Passport + MySQL. It seems as though just about every tutorial out there is using mongoDB and I don't want to do that. In fact some quick searches of this type will yield web pages like (http://nodejsrocks.blogspot.com/2012/04/nodejs-expressjs-mysql.html) and a youtube video that is a guy (https://www.youtube.com/watch?v=jGBbMVJx3h0) doing nothing but loging in, and who knows what he is really using, but the page has had 3K + views. I'd hope that some of the developers would look at that and say maybe there is a use for something like a comprehensive non MVC type of thing with MySQL. My reason for this is I am trying to get iOS and Android capabilities only and have no need for a large scaffolding overhead. Just the DB and server side scripting handling the queries and returning JSON objects to the phones.
So, that being said, can someone who has had real experience with this please help me out(And the rest of the world trying to do similar things without any in-depth tutorials, because we aren't using mongoDB and full blown scaffolding).
The tables I have set up for a 'TwitterStrategy' are users(id (PK), username, email, salt, password), and twitterusers(id (PK), name, screenname, location, description, url, img, token, tokensecret).
Here is the code I am trying to get going from a single main.js file. I know this is not best practices, and I plan to clean it up later, but for now, I would like to understand what I am missing and get things working. It would be extremely appreciated if someone can help, and I'm SURE others would find this very useful as well. Thanks.
var http = require('http'),
mysql = require('mysql'),
url = require('url'),
crypto = require('crypto'),
express = require('express'),
flash = require('connect-flash'),
passport = require('passport'),
TwitterStrategy = require('passport-twitter').Strategy;
var db = mysql.createConnection({
host : "****",
user : "****",
password : "****",
port : '****',
database : '****'
});
// Connect the connection to DB and throw error if exists
db.connect(function(err) {
if (err) {
console.error('Error connecting to db');
console.error(err);
return;
}
console.log('Database connected');
});
var TWITTER_CONSUMER_KEY = "****";
var TWITTER_CONSUMER_SECRET = "****";
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: 'http://127.0.0.1:3000/auth/twitter/callback'},
function(accessToken, refreshToken, profile, done) {
//db.query(SELECT ........ FROM ...... WHERE ........, function (err, user){
if (err) {
console.log(err);
}
if (!err && user != null){
done(null, result);
} else {
console.log(result);
}
})
});
}
));
passport.serializeUser(function(user, done) {
console.log('serializeUser: ' + user.id);
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
db.query('SELECT * FROM users WHERE id = ' + id, function(err, result) {
if (err){
console.log(err);
} else {
console.log(result);
}
if (!err) {
done(null, result);
} else {
done(err, null);
}
});
});
var app = express();
app.set(function(){
// app.set('views', __dirname + '/views'); // Definitely for some views which aren't being used here
// app.set('view engine', 'jade'); // Using jade for views, not used
// app.use(express.favicon()); // Not really sure this is important, should be web only
app.use(express.logger('dev')); // Again, not really sure this is important
app.use(express.bodyParser()); // Have no idea what this is used for
app.use(express.methodOverride()); // Same no Fn clue
app.use(express.cookieParser('what the F'));
app.use(express.session());
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
// app.use(app.router); // Here again we are defining our routes in main, so shouldn't need this.
// app.use(express.static(__dirname + '/public'));
});
var server = http.createServer(function(req, res) {
console.log('url: ' + req.url);
var params = url.parse(req.url, true)
var path = params.pathname;
if (path == '/signup') {
console.log("User signing up");
onSignUp(params, res);
} else if (path == '/signin') {
console.log("User signing in");
onSignIn(params, res);
} else if (path == '/auth/twitter'){
passport.authenticate('twitter'),
function(req, res){
console.log('Twitter User Created or Signed In');
}
}
});
//Keep server alive and listening to requests with DB connected also
server.listen(3000);
Am I missing another auth table? What is it that I need to put in the MySQL statement where the dots are so that I can find the user, and what parameters are being passed from the user request to get the query going, i.e. what is this oauth ID I have seen in tutorials that is getting passed from what seems to be the user to twitter for authorization? Also, what should I be expecting from this callback from Twitter? Anyway, I'll be glad to post all of this somewhere for everyone else to look at once I have a solution made so that all of us using MySQL and node don't get left out and have to search google to find something that seems as though it should be readily available, instead of copies of the same exact nodejs + mongoDB + express tutorial (with many that are out of date except for the scotch io, which looks very good if you wanna use mongo...might I add instances over at Amazon run about $279 estimated per month on the low end) that is floating around and being redistributed by nearly anyone with a "tutorial" out there. Thanks again.
Try wrapping strategy function under process.nextTick, e.g.,
passport.use(new TwitterStrategy({
consumerKey: TWITTER_CONSUMER_KEY,
consumerSecret: TWITTER_CONSUMER_SECRET,
callbackURL: 'http://127.0.0.1:3000/auth/twitter/callback'},
function(accessToken, refreshToken, profile, done) {
process.nextTick(function(){
// this is where you put logic to check the profile sent from twitter already in your DB or not,
// its totally up to you whether you keep a separate auth table for it or not
// NB: there will be some unique value in profile that can be used for next references
db.query(SELECT ........ FROM ...... WHERE ........, function (err, user){
if (err) {
console.log(err);
}
if (!err && user != null){
done(null, result);
} else {
console.log(result);
}
})
});
});
}
));
you also have to have a route for accepting the callback, e.g.,
app.get('/auth/twitter/callback', function(req, res, next) {
passport.authenticate('twitter',
{ },
function(err, user) {
// the result you send from the strategy function will be here
// do anything you like with the user send
}
)(req, res, next);
});
Hope it makes things clearer.

Angular Seed project, set index.html by default

I am using the Angular Seed project to build a simple website. When i start the node server and enter the url at localhost:8000, it serves up the directory contents. I would like it to serve up the index.html file but would like to do this without a redirect.
I believe that I need to modify the following function and that I should change the code for the isDirectory check but I'm not sure if that is the correct way to go about doing this. Any suggestions would be appreciated.
StaticServlet.prototype.handleRequest = function(req, res) {
var self = this;
var path = ('./' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
return String.fromCharCode(parseInt(hex, 16));
});
var parts = path.split('/');
if (parts[parts.length-1].charAt(0) === '.')
return self.sendForbidden_(req, res, path);
fs.stat(path, function(err, stat) {
if (err)
return self.sendMissing_(req, res, path);
if (stat.isDirectory())
return self.sendDirectory_(req, res, path);
return self.sendFile_(req, res, path);
});
}
Update #1
I have two screenshots to clarify. The first image is what I currently get, the second image is what I want.
What I Get
What I Want
Update #2
Using the link to Restify below I found the following example which is exactly what I needed.
var server = restify.createServer();
var io = socketio.listen(server);
server.get('/', function indexHTML(req, res, next) {
fs.readFile(__dirname + '/index.html', function (err, data) {
if (err) {
next(err);
return;
}
res.setHeader('Content-Type', 'text/html');
res.writeHead(200);
res.end(data);
next();
});
io.sockets.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
server.listen(8080, function () {
console.log('socket.io server listening at %s', server.url);
});
The angular-seed project is a starting point for the client, but not really for the server side.
They included a simple web-server node script without dependencies. This way you don't need npm or other modules.
For the server side you can use node with connect/express or any other web server/language.
You just need to make rest services and serve some static html.
Since you have already installed Node restify may be something for you.
Update: I created a basic sample for using the angular-seed with restify:
https://github.com/roelandmoors/restify-angular-seed