Socket.IO on controller - node.js

I'm pretty new to sockets and I've been struggling to implement some of the documentation i've seen online. This is my set up currently and I wanted to run socket.io against just the healthcheck api endpoint (/api/v1/healthcheck) how would I go about running socket io in the healthcheck controller? and emit changes to the response? Any help is appreciated, i'm tearing my hair out :(
Server.js
const socket = require('socket.io')
const healthcheck = require('./routes/healthcheck');
const auth = require('./routes/auth');
const users = require('./routes/users');
const server = app.listen(
PORT,
console.log(
`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.cyan.bold
)
);
let io = require('socket.io')(server);
app.set("io", io);
//Auth
app.use('/api/v1/auth', auth);
app.use('/api/v1/users', users);
//Health check
app.use('/api/v1/healthcheck', healthcheck);
/routes/healthcheck.js
const express = require('express');
const { checkHealth } = require('../controllers/healthcheck');
const router = express.Router();
router.post('/', checkHealth);
module.exports = router;
/controllers/healthcheck.js
const asyncHandler = require('../middleware/async');
exports.checkHealth = asyncHandler(async (req, res, next) => {
res.status(200).json({
success: true,
data: {
status: "Alive!"
}
});
});

You can pass in the instance of io into that healthcheck route and then simply listen to events and take action. Sample code below.
server.js
const socket = require('socket.io')
const server = app.listen(
PORT,
console.log(
`Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.cyan.bold
)
);
let io = require('socket.io')(server);
app.set("io", io);
// pass in io to the relevant route
const healthcheck = require('./routes/healthcheck')(io);
const auth = require('./routes/auth');
const users = require('./routes/users');
//Auth
app.use('/api/v1/auth', auth);
app.use('/api/v1/users', users);
//Health check
app.use('/api/v1/healthcheck', healthcheck);
healthcheck route
const express = require('express');
const { checkHealth } = require('../controllers/healthcheck');
const router = express.Router();
module.exports = (io) => {
router.post('/', checkHealth);
io.on('connection', socket => {
socket.emit('hello', {message: 'helloworld'});
socket.on('reply', checkHealth.someMethod);
});
return router;
}
I would rather create endpoints in files - same as you do for express routes, and init these in your server.js as follows:
let io = require('socket.io')(server);
app.set("io", io);
io.on('connection', socket => {
require('./myendpointexample')(socket);
});
myendpointexample.js
module.exports = (socket) => {
socket.on('myevent', (message) => {
mycontroller.myFunction(message).then(result => {
socket.emit('myEvent', result);
});
});
};

Related

My socket event don't trigger when I am emit it in Nodejs

My socket event doesn't trigger when I emit it in Nodejs, I know it because I don't see "Pizza" in my console.
This is my code:
const express = require("express");
const cors = require("cors");
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server, {
});
app.use((req, res, next) => {
req.io = io;
next()
})
app.use(cors());
io.on('connection', (socket) => {
socket.on("dummy_event", (data) => {
console.log(`Socket 🍕`); // I don't see this message in my console
if(!data.name) return;
})
});
app.get("/socket_test", (req, res) => {
req.io.emit("dummy_event", {name: "pizza"})
return res.json({data: 'dummy text'})
})
server.listen(4000, () => {
console.log(`Server Started on Port 4000`);
})

Emit socket on post request

I`m trying to create emit for the socket on post request from postman but got some troubles. I found an issue here but it seems not working for me. I have this code in my app.js
App.js
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
const http = require('http').createServer(app)
const eventsRoute = require('./routes/eventsRoute')
const io = require('socket.io')(http, {
cors: {origin: "*"},
path: '/api/events'
})
io.of('/api/events/').on('connection', socket => console.log('connected'))
...
app.use('/api/events', eventsRoute(io))
module.exports = app
And here I got eventsRoute.js code. Here, I think, is the main problem
eventsRoute.js
const express = require('express')
const errorHandler = require('../utils/errorHandler')
const router = express.Router()
const returnRouter = io => {
router.post('/', async (req, res) => {
try {
io.sockets.emit('create', req.body)
res.status(200).json({message: 'successful'})
} catch (e) {
errorHandler(e)
}
})
router.get("/", function (req, res) {
try {
res.send({})
} catch (e) {
errorHandler(e)
}
})
return router
}
module.exports = returnRouter
And on my client side, I have some code in the script tag. Here it is
<script src="https://cdn.socket.io/3.1.3/socket.io.min.js"></script>
<script>
const socket = io('ws://localhost:5000', {path: '/api/events'})
socket.on('create', data => {
console.log(data)
})
</script>
So, the main reason was in ... all files. Let's begin with index.js. I'm exporting the app. Instead of that, I have to export http. Then in app.js, I will have to change line with sockets to this
const io = require('socket.io')(http, options)
io.of('/api/events')
.on('connection', socket => {
app.use('/api/events', eventsRoute(socket))
})

socket.io problems. Not able to connect. front end says connection: false and backend doesn't log anything

i am new to socket.io and i can't get it to connect to react app. here is my app.js in node
const express = require('express');
const port = process.env.PORT || 4000;
const router = require('./routes/routes');
const cors = require('cors');
const app = express();
const bodyParser = require('body-parser');
const db = require('./db/db');
const server = require('http').createServer(app);
const io = require('socket.io')(server);
io.on('connection', () => {
console.log('connected');
});
app.use('*', cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
(router);
app.listen(port, () => {
console.log('listening on port ' + port);
db.sync({
// force: true,
logging: false,
});
});
and my front end code.
import React, { useState, useEffect, useRef } from 'react';
import { io } from 'socket.io-client';
import classes from './Chatroom.module.css';
const Chatroom = ({ user, getAllMessages, setGetAllMessages }) => {
const ENDPOINT = 'http://localhost:4000/getallmessages';
var socket = io(ENDPOINT);
const messagesEndRef = useRef(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
socket.on('connect', () => {
socket.send('hello');
console.log('connected.');
});
console.log(socket);
}, []);
Whenever i look in the console on it shows connected: false and nothing is logging on the backend.
In order to fix the issue i had to add options to my io declaration as follows.
const server = require('http').createServer(app);
const options = {
cors: true,
origins: ['http://127.0.0.1:3000'],
};
const io = require('socket.io')(server, options);
127.0.0.1 being home and on client side my server is on 3000 so that's where that comes from. and on the client side you were right i had to remove "getallmessages" route so now it is as follows.
onst ENDPOINT = 'http://localhost:4000/';
var socket = io(ENDPOINT);
const messagesEndRef = useRef(null);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};
useEffect(() => {
socket.on('connect', () => {
socket.send('hello');
console.log('connected.');
});
console.log(socket);
}, []);
socket.io is bound to the server object so you should listen to the server instead of the app.
Change app.listen to server.listen
Change endpoint by removing getallmessages if you are not using namespaces

Sending Object to group of users Node.js by using Socket.IO

I am using Node.js with Express.js and for realtime data I am using socket.io.
I am trying to create on booking app.
So when the user will request through REST api the server will store the information to mongoDB via mongoose and after that the same data will be send to other users.
I am using router for different paths. below is my server.js
var express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const app = express();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const routes = require('./routes/routes');
const port = process.env.PORT || 8080;
app.use(express.json());
app.use(cors())
app.use(express.urlencoded({ extended: false }));
app.set('socketio', io);
app.use(routes);
mongoose.Promise = global.Promise;
mongoose.connect(
'mongodb://localhost:27017/myapp',
{ useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, }
).then(() => {
console.log('db connected');
}).catch(err => {
console.log(err,"hello 1998");
});
server.listen(8080);
And below is my route
const { Router } = require('express');
var router = Router();
const { main } = require('../helper/db_main')
const { checkAuthentication } = require('../helper/auth')
router.use('/api/v1/services',main,checkAuthentication,require('../controllers/services'));
router.use('/api/v1/category',main,checkAuthentication,require('../controllers/category'));
router.use('/api/v1/socket',main,checkAuthentication,require('../controllers/socket'));
module.exports = router;
and below is the place where I am trying to send/emit data to specific user but it is not working on client side i.e not able to see emit message on front-end side.
const list_all_category = (req,res) => {
console.log("Hjdnckjsdck")
var io = req.app.get('socketio');
// global.io.to("notify_me").emit("message", "hello ftomr");
let result_data
category.list_all_category().then(save_res => {
if (save_res)
result_data = res.status(200).send(save_res)
else{
result = 'fail'
res.send()
}
})
console.log("Here is ninja",io.id)
io.on('connection', function(socket){
console.log(socket.id); // same respective alphanumeric id...
})
io.sockets.on('connect', function(socket) {
const sessionID = socket.id;
})
io.on('notify',function(){
console.log("Galgotia")
})
io.sockets.emit('chat_message', 'world');
}
make use of this
socket.broadcast.to('ID').emit( 'send msg', {somedata : somedata_server} );
you can het each socket id for a specific user by using ${Socket.id}
If you are emitting anything always send the socket.id of a user to the client and send them back to the server.

How can i share socket.io into other modules in nodejs?

I have the following structure of my project in node
project structure
in a app.js, let's say i have a app.js like this
'use strict'
const express = require('express');
const realtime = require('./controllers/realtime');
const app = express();
const server = require('http').Server(app);
var sessionMiddleware = session(sessionConfig);
realtime(server,sessionMiddleware);
in a controllers/realtime.js
"use strict";
const config = require("../config");
module.exports = (server,sessionMiddleware) => {
const io = require('socket.io')(server);
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
io.on('connection', (socket) => {
socket.on('statusConnetion',(data)=>{
console.log(data)
});
socket.on('disconnect', function () {
console.log(socket.id,"Un socket se desconecto");
});
console.log(`New socket connection: ${socket.id}`);
});
}
in controllers/cargos.js
const express = require('express');
const router = express.Router();
let cargos = {};
cargos.update = (req, res, next) =>{
//How can I use sockets here?
}
module.exports = cargos;
How can I use sockets in the file cargos.js and other controllers?
You can export not only the function that initiates the server, but a class that handles all the socket.io connection and functionality. This class will be a singleton and will have functions that uses the connection, and can be usable in the different modules.
example:
app.js:
'use strict'
const express = require('express');
const realtime = require('./controllers/realtime');
const app = express();
const server = require('http').Server(app);
var sessionMiddleware = session(sessionConfig);
realtime.connect(server,sessionMiddleware);
realtime.js:
let connection = null;
class Realtime {
constructor() {
this._socket = null;
}
connect(server,sessionMiddleware) {
const io = require('socket.io')(server);
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
io.on('connection', (socket) => {
this._socket = socket;
this._socket.on('statusConnetion',(data)=>{
console.log(data)
});
this._socket.on('disconnect', function () {
console.log(socket.id,"Un socket se desconecto");
});
console.log(`New socket connection: ${socket.id}`);
});
}
sendEvent(event, data) {
this._socket.emit(event, data);
}
registerEvent(event, handler) {
this._socket.on(event, handler);
}
static init(server,sessionMiddleware) {
if(!connection) {
connection = new Realtime();
connection.connect(server,sessionMiddleware);
}
}
static getConnection() {
if(!connection) {
throw new Error("no active connection");
}
return connection;
}
}
module.exports = {
connect: Realtime.init,
connection: Realtime.getConnection
}
cargos.js:
const express = require('express');
const router = express.Router();
let cargos = {};
cargos.update = (req, res, next) =>{
const connection = require('./controllers/realtime').connection();
connection.sendEvent("update", {params: req.params});
}
module.exports = cargos;
Use separate endpoints for each controller like:
var io = require('socket.io').listen(80);
var user_controller = require('./controllers/user');
var chat_controller = require('./controllers/chat');
var user= io
.of('/user')
.on('connection', function (socket) {
user_controller.userData(user,socket);
});
var chat = io
.of('/chat')
.on('connection', function (socket) {
chat_controller.chatData(chat,socket);
});
And in controller simply export the module like this:
module.exports.chatData = function(endpoint,socket){
// this function now expects an endpoint as argument
socket.on('chat',function(newsreel){
// as is proper, protocol logic like
// this belongs in a controller:
endpoint.emit(chatreel); // broadcast chat to everyone subscribing
// to our endpoint/namespace
});
}
Same way you can use socket.io in multiple controllers by separating endpoints

Resources