I have created a socket server as shown below.
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io')(server, {cors:{origin:'*'}})
const mongoose= require("mongoose")
const port = process.env.PORT || 4002;
server.listen(port, ()=>{
console.log(`Listening on port ${port}......`)
})
onlineUsers = [];
const addNewUser = (userId, socketId)=>{
!onlineUsers.some((user)=>user.userId === userId) &&
onlineUsers.push({userId,socketId})
}
const removeUser= (socketId) =>{
onlineUsers = onlineUsers.filter((user)=> user.socketId!==socketId)
}
const getUser = (userId)=>{
return onlineUsers.find(user=>user.userId ===userId)
}
io.on("connection", (socket=> {
console.log("User connected:", socket.id);
socket.on("disconnect",()=>{
removeUser(socket.id)
})
socket.on("newUser",(userId)=>{
addNewUser(userId, socket.id)
})
export function handleMessaging (userId,clientID,messageId )
{
const receiver = getUser(userId);
if(receiver)
{
io.to(receiver.socketId).emit("sendMessage", {data:"working properly"});
return true;
}
else return false
}
}));
I want to export the function handle messaging so that I can use it inside the API like (shown below) to see if a user is online and if yes, send a message.
But as someone new to programming, I can't figure out how to export handle messaging the proper way. I tried to use export but its telling me "Modifiers cannot appear here".
router.post('/:companyId' async (req, res) => {
const {userId,clientId,messageId} = req.body
handleMessaging (userId,clientID,messageId )
{
//do xyz
}
}
Related
How to connect new mongodb v5 to nodejs
const express = require('express');
const app = express();
const { MongoClient } = require('mongodb');
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);
async function main() {
await client.connect();
}
const collection = client.db('internfeb').collection('dashboard');
const port = process.env.PORT || 7710;
app.get('/health',async(req,res) => {
const output = []
const cursor = collection.find({});
for await (const doc of cursor) {
output.push(doc)
}
cursor.closed;
res.send(output)
})
app.post('/addUser',async(req,res) => {
await collection.insertOne(req.body)
res.send('Data Added')
})
app.listen(port,() => {
main()
console.log(`Running on thr port ${port}`)
})
You should initialize collection after the client has connected:
const express = require('express');
const app = express();
const { MongoClient } = require('mongodb');
const url = 'mongodb://localhost:27017';
const client = new MongoClient(url);
let collection;
async function main() {
try {
await client.connect();
collection = client.db('internfeb').collection('dashboard');
} catch (err) {
console.log(err);
process.exit(1);
}
}
const port = process.env.PORT || 7710;
app.get('/health', async (req, res) => {
const output = [];
const cursor = collection.find({});
for await (const doc of cursor) {
output.push(doc);
}
cursor.closed;
res.send(output);
});
app.post('/addUser', async (req, res) => {
await collection.insertOne(req.body);
res.send('Data Added');
});
app.listen(port, () => {
main();
console.log(`Running on thr port ${port}`);
});
I'm a new learner express.js I want to test simple post and get operations with tdd mechanism. I created the test, route, index and db files but when I try to test POST method it gives me this error.
This is my routes/task.js
const express = require('express');
const router = express.Router();
router.post("/api/task", async (req,res) => {
try {
const task = await new Task(req.body).save();
res.send(task);
} catch (error) {
res.send(error);
}
})
This is my test/task.js
let chai = require("chai");
const chaiHttp = require("chai-http");
const { send } = require("process");
let server = require("../index");
//Assertion Style
chai.should();
chai.use(chaiHttp);
describe('Tasks API', () => {
/**
* Test the POST Route
*/
describe('POST /api/task', () => {
it("It should POST a new task", () => {
const task = {task: "Wake Up"};
chai.request(server)
.post("/api/task")
.send(task)
.end((err, response) => {
response.should.have.status(201);
response.body.should.be.a('string');
response.body.should.have.property('id');
response.body.should.have.property('task');
response.body.should.have.property('task').eq("Wake Up");
response.body.length.should.be.eq(1);
done();
});
});
});
});
This is my db.js
var sqlite3 = require('sqlite3').verbose()
const DBSOURCE = "db.sqlite"
let db = new sqlite3.Database(DBSOURCE, (err) => {
if (err) {
// Cannot open database
console.error(err.message)
throw err
}else{
console.log('Connected to the SQLite database.')
db.run(`CREATE TABLE IF NOT EXISTS todo (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task text
)`,
(err) => {
if (err) {
// Table already created
console.log(err);
}
});
}
});
module.exports = db
And this is my index.js
const connection = require('./db');
const express = require('express');
const app = express();
const cors = require("cors");
const port = process.env.PORT || 8080;
app.use(express.json());
app.use(cors());
app.get('/', (req, res) => {
res.send('Hello World');
});
app.post('/api/task', (req, res) => {
res.status(201).send(req);
});
app.listen(port, () => console.log(`Listening on port ${port}...`));
module.exports = app;
The thing that I try to do is building a test case to test the post method. I think I couldn't built the correct relations the files.
Currently, just by doing a POST request to /api/task, the error will appear. That is because of these lines in index.js:
app.post('/api/task', (req, res) => {
res.status(201).send(req);
});
The req parameter is circular, hence cannot be JSON-stringified.
Solution
In routes/task.js export the router:
const express = require('express');
const router = express.Router();
router.post("/api/task", async (req,res) => {
try {
const task = await new Task(req.body).save();
res.send(task);
} catch (error) {
res.send(error);
}
})
// By adding this line you can export the router
module.exports = router
In index.js, include the routes/task.js file and pass it to app.use(...), also remove the now-obsolete /api/task route:
const connection = require('./db');
const express = require('express');
const app = express();
const cors = require("cors");
const taskRoutes = require("./routes/task")
const port = process.env.PORT || 8080;
app.use(express.json());
app.use(cors());
app.get('/', (req, res) => {
res.send('Hello World');
});
app.use(taskRoutes)
app.listen(port, () => console.log(`Listening on port ${port}...`));
module.exports = app;
This way we got rid of the circular structure stringifying and the tests should now pass.
I have recently started using socket-io for a live-chatting feature in a project of mine. I have everything working fine but as of now, I have all the server side socket-io stuff (connection, middleware, event handlers, etc.) in the main "index.js" file. It isn't a big deal now as I am only listening to a couple of events, but I would like to organize and separate the code into smaller files before it gets out of hand.
Here is an example of what the socket-io portion of the code looks like in my index.js file:
const express = require("express");
const app = express();
const http = require("http");
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const jwt = require("jsonwebtoken");
const activeSockets = {};
io.use((socket, next) => {
const { token } = socket.handshake.auth;
if (!token) return next(new Error("Invalid or missing token"));
const { _id } = jwt.verify(token, process.env.JWT_KEY);
socket.handshake.auth._id = _id;
next();
});
const addSocket = (socket) => {
const { _id } = socket.handshake.auth;
if (!activeSockets[_id]) activeSockets[_id] = [socket.id];
else activeSockets[_id] = [...activeSockets[_id], socket.id];
};
const removeSocket = (socket) => {
const { _id } = socket.handshake.auth;
if (!_id || !activeSockets[_id]) return;
const index = activeSockets[_id].indexOf(socket.id);
activeSockets[_id].splice(index, 1);
if (activeSockets[_id].length < 1) delete activeSockets[_id];
};
io.on("connection", (socket) => {
addSocket(socket);
socket.on("typing", (isTyping, recipients, conversation, sender) => {
recipients.forEach((recipient) => {
if (activeSockets[recipient._id]) {
activeSockets[recipient._id].forEach((r) => {
socket.to(r).emit("typing", isTyping, conversation, sender);
});
}
});
});
socket.on("sendMessage", ({ message, recipients, conversation }) => {
recipients.forEach((recipient) => {
if (activeSockets[recipient._id]) {
activeSockets[recipient._id].forEach((r) => {
socket.to(r).emit("receiveMessage", { message, conversation });
});
}
});
});
socket.on("disconnect", () => {
removeSocket(socket);
});
});
const port = process.env.PORT || 5000;
server.listen(port, () => {
console.log("Listening: ", port);
});
I'm just struggling to find an efficient way to extract the socket-io code into smaller more organized pieces. Should the only thing in index.js related to socket-io be the connection itself? And then I have files for different event handlers that take an "io" parameter and then I call "io.on(...)" in those external functions? Or perhaps should I listen for all the events in index.js and then extract only the logic of each event into separate files? Something like:
io.on("eventName", someExternalFunction)
This is my first experience with socket-io so I'm not too sure of the "best practices".
Thank you to anyone who can offer help!
You could put the socket event handlers into modules like.
chat/connection.js:
module.exports = (io) => {
io.on("connection", (socket) => {
console.log('connection was made');
});
}
Then in index.js require('./chat/connection.js')(io);
edit: added a bit more code.
const express = require('express');
var bodyParser = require('body-parser');
const app = express();
var urlencodedParser = bodyParser.urlencoded({extended: false})
const {google} = require('googleapis');
const {PubSub} = require('#google-cloud/pubsub');
const iot = require('#google-cloud/iot');
const API_VERSION = 'v1';
const DISCOVERY_API = 'https://cloudiot.googleapis.com/$discovery/rest';
app.get('/', urlencodedParser, (req, res) => {
const projectId = req.query.proyecto;
const cloudRegion = req.query.region;
const registryId = req.query.registro;
const numSerie = req.query.numSerie;
const command = req.query.command;
const client = new iot.v1.DeviceManagerClient();
if (client === undefined) {
console.log('Did not instantiate client.');
} else {
console.log('Did instantiate client.');
sendCom();
}
async function sendCom() {
const formattedName = await client.devicePath(projectId, cloudRegion, registryId, numSerie)
const binaryData = Buffer.from(command);
const request = {
name: formattedName,
binaryData: binaryData,
};
return client.sendCommandToDevice(request).then(responses => res.status(200).send(JSON.stringify({
data: OK
}))).catch(err => res.status(404).send('Could not send command. Is the device connected?'));
}
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
console.log('Press Ctrl+C to quit.');
});
module.exports = app;
I have this function, that I call after the client initiate: sendCom();
async function sendCom() {
const formattedName = await client.devicePath(projectId, cloudRegion, registryId, deviceId)
const binaryData = Buffer.from(command);
const request = { name: formattedName, binaryData: binaryData, };
client.sendCommandToDevice(request)
.then(responses => {
res.status(200).send(JSON.stringify({ data: OK })).end();
})
.catch(err => {
res.status(404).send('Could not send command. Is the device connected?').end();
});
}
My problem is that sendCommandToDevice gets executed perfectly, however I get the catch error.
As I understand it, it's because in the .then ends the connection.
I've looked at this and thats's what I tried, however I'm not sure I understand what's going on.
You can not use send with end.
end() is used when you want to end the request and want to respond with no data.
send() is used to end the request and respond with some data.
You can found more about it here.
I am following a related post here
I am struggling with awaiting the module import from my express application.
I understand that to use await, it must be wrapped in an async function. However I can't wrap my entire node program in an async function because it will exit without doing anything useful.
How can I properly await the database connection?
node/express:
require('dotenv').config();
var express = require('express');
var loginRouter = require('./routes/login/login');
var app = express();
async() => {
const { client } = await require('./db/db');
app.use('/login', loginRouter);
app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'));
console.log('Server listening on port ' + app.get('port'));
}
db module:
const { Client } = require('pg');
module.exports = (async() => {
const client = new Client();
await client.connect();
return { client };
})();
One option would be to export a Promise that resolves to a connected client. Then, when you import it, call .then on the imported Promise to get to the connected client:
const { Client } = require('pg');
const client = new Client();
module.exports = {
clientProm: client.connect().then(() => client)
};
And:
const { clientProm } = require('./db/db');
clientProm.then((client) => {
// do stuff with connected client
});