how to use socket.io in controller file - javascript

I am using Node.JS Express and socket.io.
So my idea was to emit the message directly from my controller’s insert-method. In my server.js file, iam creating the socket.io object and try to make it accessible for other modules:
My server.js is like this
require('rootpath')();
var express = require('express');
var app = express();
var cors = require('cors');
var bodyParser = require('body-parser');
var expressJwt = require('express-jwt');
var config = require('config.json');
var mongoose = require('mongoose');
mongoose.connect(config.connectionString);
var db = mongoose.connection;
db.on('error',console.error.bind(console,'Connection error'));
db.on('open',function(){
console.log('connected');
});
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// use JWT auth to secure the api, the token can be passed in the authorization header or querystring
app.use(expressJwt({
secret: config.secret,
getToken: function (req) {
if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
return req.headers.authorization.split(' ')[1];
} else if (req.query && req.query.token) {
return req.query.token;
}
return null;
}
}).unless({
path: [
'/users/authenticate',
'/users/register',
'/users',
'/chats','/chats/sendMessage',
'/rooms','/rooms/create',
'/chats/connection',
'/chats/add-message'
]
}));
// routes
app.use('/users', require('./controllers/users.controller'));
app.use('/chats', require('./controllers/chats.controller'));
app.use('/rooms', require('./controllers/rooms.controller'));
var http = require('http').Server(app);
var io = require('socket.io')(http);
io.on('connection', (socket) => {
console.log('The user is connected');
socket.on('new-message', (message,userInfo) => {
console.log(userInfo);
console.log(message);
io.emit('message', {type:'new-message', text: message});
});
socket.on('disconnect', function(){
console.log('The user is disconnected');
});
socket.on('add-message', (message,userInfo) => {
console.log(userInfo);
console.log(message);
io.emit('message', {type:'new-message', text: message});
});
socket.on('add-record', (record) => {
io.emit('getrecord', {type:'new-record', text: record});
});
});
// start server
var port = process.env.NODE_ENV === 'production' ? 80 : 4000;
var server = http.listen(port, function () {
console.log('Server listening on port ' + port);
});
Client - Data received
Emit welcome message on connection
how can i use this below socket connection in chat.controller.js
io.on('connection', (socket) => {
console.log('The user is connected');
socket.on('new-message', (message,userInfo) => {
console.log(userInfo);
console.log(message);
io.emit('message', {type:'new-message', text: message});
});
socket.on('disconnect', function(){
console.log('The user is disconnected');
});
socket.on('add-message', (message,userInfo) => {
console.log(userInfo);
console.log(message);
io.emit('message', {type:'new-message', text: message});
});
socket.on('add-record', (record) => {
io.emit('getrecord', {type:'new-record', text: record});
});
});
and i am creating controller file like this
chats.controller.js
var config = require('config.json');
var express = require('express');
var router = express.Router();
var userService = require('../services/user.service');
var chatService = require('../services/chat.service');
// routes
router.post('/sendMessage', send);
router.get('/', getAll);
module.exports = router;
function send(req, res) {
chatService.sendMessage(req.body)
.then(function () {
res.sendStatus(200);
})
.catch(function (err) {
res.status(400).send(err);
});
}
function getAll(req, res) {
chatService.getAllMessage()
.then(function (chats) {
res.send(chats);
})
.catch(function (err) {
res.status(400).send(err);
});
}
function getCurrent(req, res) {
userService.getById(req.user.sub)
.then(function (user) {
if (user) {
res.send(user);
} else {
res.sendStatus(404);
}
})
.catch(function (err) {
res.status(400).send(err);
});
}
function update(req, res) {
userService.update(req.params._id, req.body)
.then(function () {
res.sendStatus(200);
})
.catch(function (err) {
res.status(400).send(err);
});
}
function _delete(req, res) {
userService.delete(req.params._id)
.then(function () {
res.sendStatus(200);
})
.catch(function (err) {
res.status(400).send(err);
});
}
And also i have created one service file
name is chat.service.js
var config = require('config.json');
var _ = require('lodash');
var jwt = require('jsonwebtoken');
var bcrypt = require('bcryptjs');
var Q = require('q');
var mongoose = require('mongoose');
var Chat = require('../model/chat');
var service = {};
service.sendMessage = sendMessage;
service.getAllMessage = getAllMessage;
module.exports = service;
function sendMessage(userParam) {
var deferred = Q.defer();
var chat = new Chat({
room_id:userParam.from_id,
from_id:userParam.from_id,
to_id:userParam.to_id,
chatrp_id:userParam.chatrp_id,
message:userParam.message
});
chat.save(function (err,doc) {
if (err) deferred.reject(err.name + ': ' + err.message);
deferred.resolve();
})
return deferred.promise;
}
function getAllMessage() {
var deferred = Q.defer();
Chat.find({},function (err, response) {
if (err) deferred.reject(err.name + ': ' + err.message);
// return users (without hashed passwords)
response = _.map(response, function (res) {
return _.omit(res, 'hash');
});
deferred.resolve(response);
});
return deferred.promise;
}
But is is neither giving me an error or not working.
Can anyone please help, how can I export that in a separate file so that client and server code can be separated?
Thanks in advance for helping.

This how I got this to work.
Steps are as follows:
1) I created a utils folder, inside which I created a file named socket.js
utils/socket.js
const Server = require('socket.io');
const io = new Server();
var Socket = {
emit: function (event, data) {
console.log(event, data);
io.sockets.emit(event, data);
}
};
io.on("connection", function (socket) {
console.log("A user connected");
});
exports.Socket = Socket;
exports.io = io;
2) Then in my server(app.js) I did this
app.js
const app = express();
const server = http.createServer(app);
const { io } = require("./utils/socket");
io.attach(server);
module.exports = app;
3)After this 2 steps, In your controller file or any other file(s) where you need to emit an event, you can then just do this:
const { Socket } = require("../../utils/socket");
Socket.emit("newMessage", {
message: "hello from controller"
});

To emit messages from your controllers, the controllers need to have access to the original socket.io instance.
So, in chats.controller.js I would do like this:
module.exports = function(io){
return {
function: getAll(req, res){
// here you now have access to socket.io.
// you can either do:
io.emit('new-message',{
// new message object
});
// or you can include your chat service the same way
// that this file is included and call the appropriate function
},
}
};
To use this controller, just do
const someController = require('./path/to/chats.controller.js')(io);
You can do exactly the same in your service file.

Related

The content-type is not JSON compatible

With the following code Im trying to create a accessToken with the simple-oauth2 library in node.
I have the server.js and the app.js files. The problem is that every time I try to call the getToken method it returns the following error The content-type is not JSON compatible. Im calling the /token endpoint with postman where the request´s Content-Type is set to application/json.
Has anyone encountered this problem before?
server.js
'use strict';
const app = require('express')()
const bodyParser = require('body-parser')
app.use(bodyParser.json())
const port = 3000;
module.exports = (cb) => {
app.listen(port, (err) => {
if (err) return console.error(err);
console.log(`Express server listening at http://localhost:${port}`);
return cb({
app
});
});
};
app.js
const createApplication = require('./server');
const simpleOauthModule = require('simple-oauth2');
require('dotenv').config()
const credentials = {
client: {
id: process.env.CLIENT_ID,
secret: process.env.CLIENT_SECRET
},
auth: {
tokenHost: 'http://localhost:3000/test'
}
};
createApplication(({ app }) => {
app.post('/token', async (req, res) => {
const oauth2 = simpleOauthModule.create(credentials);
var contype = req.headers['content-type']; // <-- application/json
const tokenConfig = {
username: "test",
password: "1234"
};
try {
const result = await oauth2.ownerPassword.getToken(tokenConfig); //Error occuress
const accessToken = oauth2.accessToken.create(result);
console.log('Access Token: ', accessToken);
} catch (error) {
console.log('Access Token Error', error.message);
}
});
app.post('/test', async (req, res) => {
});
});

Getting null value while sending the data into mssql using node js

It would be great if anyone can help me out. I am new to node.js, and I am trying to send the data into MSSQL database for my initial project, and as per project requirement I was not able to use any other DB other than MSSQL, and I am getting error value into DB while I execute the insert query. I tried to figure out the error more than a day but end up with nothing. Could anyone help me to fix this error.?
Thanks in advance.
// Server.js
var express = require('express');
var app = express();
var port = process.env.port || 3000;
var bodyParser = require('body-parser');
// create application/x-www-form-urlencoded parser
app.use(bodyParser.urlencoded({ extended: true }));
// create application/json parser
app.use(bodyParser.json());
var ProductController = require('./Controller/ProductController')();
app.use("/app/Data", ProductController)
app.listen(port, function () {
var datetime = new Date();
var message = "Server runnning on Port:- " + port + "Started at :- " + datetime;
console.log(message);
});
// App.js
var express = require('express');
var router = express.Router();
var sql = require("mssql");
var conn = require("../connection/connect")();
var routes = function () {
router.route('/')
.get(function (req, res) {
conn.connect().then(function () {
var sqlQuery = "SELECT * FROM ArduinoSensor";
var req = new sql.Request(conn);
req.query(sqlQuery).then(function (recordset) {
res.json(recordset.recordset);
conn.close();
})
.catch(function (err) {
conn.close();
res.status(400).send("Error while Receive Data");
});
})
.catch(function (err) {
conn.close();
res.status(400).send("Error");
});
});
router.route('/')
.post(function (req, res) {
conn.connect().then(function () {
var transaction = new sql.Transaction(conn);
transaction.begin().then(function () {
var request = new sql.Request(transaction);
request.input("start_time", sql.VarChar(50), req.body.start_time)
request.input("end_time", sql.VarChar(50), req.body.end_time)
request.input("length_time", sql.VarChar(50), req.body.length_time)
request.execute("Usp_InsertSensor").then(function () {
transaction.commit().then(function (recordSet) {
conn.close();
res.status(200).send(req.body);
}).catch(function (err) {
conn.close();
res.status(400).send("Error while inserting data");
});
}).catch(function (err) {
conn.close();
res.status(400).send("Error while inserting data");
});
}).catch(function (err) {
conn.close();
res.status(400).send("Error while inserting data");
});
}).catch(function (err) {
conn.close();
res.status(400).send("Error while inserting data");
});
});
return router;
};
module.exports = routes;
PS:- I have attached the outcome of the coding
Outcome of the image

No response from node js (mongoose)

I send request from React with:
export const loadItems = () => async dispatch => {
await axios
.get("http://localhost:8000/api/users")
.then(response => {
console.log(response.users);
dispatch(dataLoaded(response.users));
})
.catch(err => {
dispatch(dataLoadFailed(err));
});
};
But there is no response, and the server does not take request, here is my server app code:
server.js
// a lot of requires
const todoRoutes = require("./routes/serverRoute");
const url = "mongodb://localhost:27017/taskManager";
const app = express();
mongoose.Promise = global.Promise;
mongoose.connect(
url,
{ useNewUrlParser: true },
function(err) {
if (err) {
console.log(err);
} else console.log("Database connected");
}
);
app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "/public/index.html"));
});
// cors allow
app.use("/api", todoRoutes);
app.listen(8000, () => {
console.log("API started");
});
And this is a controller I use, it's all good with Schema and DB, I checked with output to console from the node, users is defined and contains data
const mongoose = require("mongoose");
const User = require("../models/UserModel");
module.exports = {
getUsers(req, res) {
User.find().exec((err, users) => {
if (err) {
console.log(err);
return res.send({ err });
} else {
console.log(users);
return res.send({ users });
}
});
}
};
And this is my router:
module.exports = router => {
router.get('/users', userController.getUsers);
}
Ok, I got it on my own. Problem was here:
router.get('/users', userController.getUsers);
It supposed to be like this:
router.get('/users', userController.getUsers());

Best practise to define a PostgreSQL database connection variable globally in a node.js web application?

I am creating a node and express REST application with a PostgreSQL database.
My question is how to define the connection variable globally in a minimalist express application (for a Hello World example)?
I have the following file structure with the following key files included.
{PROJECT_ROOT}\bin\www
{PROJECT_ROOT}\app.js
{PROJECT_ROOT}\routes\index.js
{PROJECT_ROOT}\db\db.js
{PROJECT_ROOT}\db\location.js
{PROJECT_ROOT}\OTHER FILES
The db.js should contain definition of a variable for a connection to the PostgreSQL database globally. This variable should be shared by other modules whenever necessay so that duplicated connections should be avoided.
db.js
var promise = require('bluebird');
/**
*Use dotenv to read .env vars into Node
*/
require('dotenv').config();
const options = {
// Initialization Options
promiseLib: promise,
connect(client, dc, useCount) {
const cp = client.connectionParameters;
console.log('Connected to database:', cp.database);
}
};
const pgp = require('pg-promise')(options);
const connectionString = process.env.PG_CONN_STR;
const db = pgp(connectionString);
module.exports = {
pgp, db
};
location.js defines the business logic to manipulate the gcur_point_location table.
var db_global = require('./db');
var db = db_global.db;
// add query functions
module.exports = {
getAllLocations: getAllLocations,
getLocation: getLocation,
createLocation: createLocation,
updateLocation: updateLocation,
removeLocation: removeLocation
};
function getAllLocations(req, res, next) {
db.any('select * from gcur_point_location')
.then(function (data) {
res.status(200)
.json({
status: 'success',
data: data,
message: 'Retrieved ALL GCUR Point Locations'
});
})
.catch(function (err) {
return next(err);
});
}
function getLocation(req, res, next) {
var locationId = parseInt(req.params.id);
db.one('select * from gcur_point_location where locationid = $1', locationId)
.then(function (data) {
res.status(200)
.json({
status: 'success',
data: data,
message: 'Retrieved ONE Location by Id'
});
})
.catch(function (err) {
return next(err);
});
}
function createLocation(req, res, next) {
req.body.age = parseInt(req.body.age);
db.none('insert into gcur_point_location(locationname, locationstatus, lng, lat)' +
'values(${locationname}, ${locationstatus}, ${lng}, ${lat})',
req.body)
.then(function () {
res.status(200)
.json({
status: 'success',
message: 'Inserted one Location'
});
})
.catch(function (err) {
return next(err);
});
}
function updateLocation(req, res, next) {
db.none('update gcur_point_location set locationname=$1, locationstatus=$2, lng=$3, lat=$4 where locationid=$5',
[req.body.locationname, req.body.locationstatus, parseFloat(req.body.lng),
parseFloat(req.body.lat), parseInt(req.params.id)])
.then(function () {
res.status(200)
.json({
status: 'success',
message: 'Updated Location'
});
})
.catch(function (err) {
return next(err);
});
}
function removeLocation(req, res, next) {
var locationId = parseInt(req.params.id);
db.result('delete from gcur_point_location where locationid=$1', locationId)
.then(function (result) {
/* jshint ignore:start */
res.status(200)
.json({
status: 'success',
message: `Removed ${result.rowCount} Location`
});
/* jshint ignore:end */
})
.catch(function (err) {
return next(err);
});
}
Likewise, munipulation of different tables will be defined in individual js files. All of them will require the db.js.
routes/index.js
var express = require('express');
var router = express.Router();
var db = require('../db/location');
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.get('/api/locations', db.getAllLocations);
router.get('/api/location/:id', db.getLocation);
router.post('/api/location', db.createLocation);
router.put('/api/location/:id', db.updateLocation);
router.delete('/api/location/:id', db.removeLocation);
module.exports = router;
app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/users', usersRouter);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
I would like to have some ideas about whether the above code is a good or a bad practise or any potential failure?
Most of the code makes sense to me, though I would implement your own ORM and model layers, so you can remove some of the code for PSQL queries and follow MVC design pattern. If all you are building is an express api server, then you do not need the View portion.
I usually have a file called ORM, which has something similar to the following:
var orm = {
all: function(tableInput, cb) {
var queryString = "SELECT * FROM " + tableInput + ";";
connection.query(queryString, function(err, result) {
if (err) {
throw err;
}
cb(result);
});
},
create: function(table, cols, vals, cb) {
var queryString = "INSERT INTO " + table;
queryString += " (";
queryString += cols.toString();
queryString += ") ";
queryString += "VALUES (";
queryString += printQuestionMarks(vals.length);
queryString += ") ";
console.log(queryString);
connection.query(queryString, vals, function(err, result) {
if (err) {
throw err;
}
cb(result);
});
},
// An example of objColVals would be {name: panther, sleepy: true}
update: function(table, objColVals, condition, cb) {
var queryString = "UPDATE " + table;
queryString += " SET ";
queryString += objToSql(objColVals);
queryString += " WHERE ";
queryString += condition;
console.log(queryString);
connection.query(queryString, function(err, result) {
if (err) {
throw err;
}
cb(result);
});
}
};
// Export the orm object for the model (cat.js).
module.exports = orm;
Then I define a model file for each table you have in psql as following:
// Import the ORM to create functions that will interact with the database.
var orm = require("../config/orm.js");
var cat = {
all: function(cb) {
orm.all("cats", function(res) {
cb(res);
});
},
// The variables cols and vals are arrays.
create: function(cols, vals, cb) {
orm.create("cats", cols, vals, function(res) {
cb(res);
});
},
update: function(objColVals, condition, cb) {
orm.update("cats", objColVals, condition, function(res) {
cb(res);
});
}
};
// Export the database functions for the controller (catsController.js).
module.exports = cat;
A controller:
var express = require("express");
var router = express.Router();
// Import the model (cat.js) to use its database functions.
var cat = require("../models/cat.js");
// Create all our routes and set up logic within those routes where required.
router.get("/", function(req, res) {
cat.all(function(data) {
var hbsObject = {
cats: data
};
console.log(hbsObject);
res.render("index", hbsObject);
});
});
router.post("/api/cats", function(req, res) {
cat.create(["name", "sleepy"], [req.body.name, req.body.sleepy], function(result) {
// Send back the ID of the new quote
res.json({ id: result.insertId });
});
});
router.put("/api/cats/:id", function(req, res) {
var condition = "id = " + req.params.id;
console.log("condition", condition);
cat.update(
{
sleepy: req.body.sleepy
},
condition,
function(result) {
if (result.changedRows === 0) {
// If no rows were changed, then the ID must not exist, so 404
return res.status(404).end();
}
res.status(200).end();
}
);
});
// Export routes for server.js to use.
module.exports = router;
This follows MVC design pattern which is very easy to read and understand. So my whole folder structure would look something like this:
Best practices for structuring a database layer with pg-promise are shown in pg-promise-demo.
For a complete, real-world example of using that approach, see LISK database layer.

400 Error when attempting to send PDF through NodeMailer Mailgun Transport

I'm working on a simple webhook in Express to send a PDF through Mailgun on a certain event. However, whenever I try to send it, I get this error: { [Error: 'from' parameter is missing] statusCode: 400 }. I've tested it with simple .txt files and it works fine, so I'm assuming it has something to do with the PDF attachment. My code is here:
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');
var PDFDocument = require('pdfkit');
var mg = require('nodemailer-mailgun-transport');
var fs = require('fs');
app.use(bodyParser.json());
app.post('/', function(req, res) {
generatePDF(req.body.line_items);
if (req.body.line_items) {
sendMail();
res.send('OK');
}
});
app.listen(3030, function() {
console.log('test app listening on port 3030');
});
function generatePDF(lineItems) {
var doc = new PDFDocument();
var writeStream = fs.createWriteStream('mailer/output.pdf');
doc.pipe(writeStream);
for (item in lineItems) {
for (key in item) {
doc.text(item[key]);
}
}
console.log("doc: " + doc);
doc.end();
}
function sendMail() {
var auth = {
auth: {
api_key: 'my-key',
domain: 'my-domain'
}
}
var transporter = nodemailer.createTransport(mg(auth));
var mailOptions = {
from: 'my-email',
to: 'their-email',
subject: 'test',
html: '<b>this is a test</b>',
attachments: [
{
filename: 'output.pdf',
path: 'mailer/output.pdf',
content: 'output mailer'
}
],
}
transporter.sendMail(mailOptions, function(error, info){
console.log('mail sent');
if (error) {
return console.error(error)
}
console.log('success!', info);
})
}
Any help would be much appreciated!
Forgot to post my solution, but here it is belatedly for future people running into this problem. The writeStream wasn't completing before I was sending it, and nodemailer was getting very confused, so I inserted a condition that the PDF (or whatever document) finish writing before it's sent.
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');
var PDFDocument = require('pdfkit');
var mg = require('nodemailer-mailgun-transport');
var fs = require('fs');
var idStorage = [];
app.use(bodyParser.json());
app.post('/', function(req, res) {
var JSON = req.body;
console.log(idStorage);
if (req.body.line_items) {
res.sendStatus(200);
generatePDF(JSON);
}
});
app.listen(3030, function() {
console.log('example app listening on port 3030');
});
function generatePDF(JSON) {
//create doc and doc variables
var doc = new PDFDocument();
var writeStream = fs.createWriteStream('mailer/output.pdf');
doc.pipe(writeStream);
//write whatever you want to the PDF
doc.save();
//wait for the PDF to finish writing before you send it.
writeStream.on('finish', function() {
sendMail(JSON);
});
}
doc.end();
}
}
function sendMail(JSON) {
var auth = {
auth: {
api_key: 'key',
domain: 'domain.com'
}
}
var transporter = nodemailer.createTransport(mg(auth));
var mailOptions = {
from: 'me',
to: 'you',
subject: JSON.id,
html: '<b>Test</b>',
attachments: [
{
filename: 'output.pdf',
path: 'mailer/output.pdf'
}
],
}
transporter.sendMail(mailOptions, function(error, info){
console.log('mail sent');
if (error) {
return console.error(error)
}
console.log('success!', info);
})
}
}

Categories

Resources