I'm trying to emit to all the sockets connected from a seperate file. However I cannot seem to figure it out.
Socket.js
var socketio = require('socket.io');
var users = require('./modules/users');
var io = socketio();
socket.io = io;
io.on('connection', function(socket){
//Stuff
console.log('Hello :)');
});
module.exports = socket;
Users.js
var socket = require('../socket');
function news(){
socket.io.sockets.emit('news', {
message: 'Woah! Thats new :)'
})
}
setInterval(function(){
news();
}, 5 * 1000);
However, socket
in users.js seems to be empty and I can't seem to access to io object. How can I make it so I can emit to all users? Without parsing the io.sockets to the news function or moving my function to the socket file?
I'm trying to emit to all the sockets connected from a seperate file. However I cannot seem to figure it out.
Socket.js
var socketio = require('socket.io');
var users = require('./modules/users');
var io = socketio();
socket.io = io;
io.on('connection', function(socket){
//Stuff
console.log('Hello :)');
});
module.exports = socket;
Users.js
var socket = require('../socket');
function news(){
socket.io.sockets.emit('news', {
message: 'Woah! Thats new :)'
})
}
setInterval(function(){
news();
}, 5 * 1000);
However, socket
in users.js seems to be empty and I can't seem to access to io object. How can I make it so I can emit to all users? Without parsing the io.sockets to the news function or moving my function to the socket file?
4 Answers
Reset to default 14You can define io object with let as global variable in utils and io functions there. You can call these functions from any file. For example:
// app.js
const { socketConnection } = require('./utils/socket-io');
const http = require('http');
const express = require('express');
const app = express();
const server = http.createServer(app);
socketConnection(server);
// utils/socket-io
let io;
exports.socketConnection = (server) => {
io = require('socket.io')(server);
io.on('connection', (socket) => {
console.info(`Client connected [id=${socket.id}]`);
socket.join(socket.request._query.id);
socket.on('disconnect', () => {
console.info(`Client disconnected [id=${socket.id}]`);
});
});
};
exports.sendMessage = (roomId, key, message) => io.to(roomId).emit(key, message);
exports.getRooms = () => io.sockets.adapter.rooms;
// any file
const { sendMessage } = require('../utils/socket-io');
const foo = async () => {
const roomId = '12345';
const key = 'new-order';
const message = 'new order assigned';
sendMessage(roomId, key, message);
};
Just create a socket service
object, the service object only published some helper
functions.
Example for your case:
// Socket.js
var socketio = require('socket.io');
var users = require('./modules/users');
var io = socketio();
socket.io = io;
io.on('connection', function (socket) {
//Stuff
console.log('Hello :)');
});
var toAll = function (eventName, data) {
io.sockets.emit(event, data);
}
module.exports = {
toAll: toAll // publish `toAll` function to call every where
};
// Users.js
var socketService = require('../socket');
function news() {
socketService.toAll('news', {
message: 'Woah! Thats new :)'
});
}
setInterval(function () {
news();
}, 5 * 1000);
Based on the answer from Furkan Uyar, I created a Typescript service
// utils/socket-io.service.ts
import {Server, ServerOptions} from "socket.io";
import {Server as HttpServer} from "http";
export class SocketIOService {
private static _instance: SocketIOService | undefined;
private static server: Server | undefined;
private constructor() {
// Private constructor ensures singleton instance
}
static instance(): SocketIOService {
if (!this._instance) {
return new SocketIOService();
}
return this._instance;
}
initialize(httpServer: HttpServer, opts?: Partial<ServerOptions>) {
SocketIOService.server = new Server(httpServer, opts);
return SocketIOService.server;
}
ready() {
return SocketIOService.server !== null;
}
getServer(): Server {
if (!SocketIOService.server) {
throw new Error('IO server requested before initialization');
}
return SocketIOService.server;
}
sendMessage(roomId: string | string[], key: string, message: string) {
this.getServer().to(roomId).emit(key, message)
}
emitAll(key: string, message: string) {
this.getServer().emit(key, message)
}
getRooms() {
return this.getServer().sockets.adapter.rooms;
}
}
The service must be initialized before use:
// app.ts
import express from "express";
import log from "./logger";
import cors from "cors";
import {createServer} from "http";
import {SocketIOService} from "./utils/socket-io.service";
const app = express();
const httpServer = createServer(app);
SocketIOService.instance().initialize(httpServer, {
cors: {
origin: ['http://localhost:4200']
}
});
const io = SocketIOService.instance().getServer();
io.on('connection', (socket) => {
log.info('a user connected');
socket.on('disconnect', () => {
log.info('user disconnected');
});
socket.on('my message', (msg) => {
console.log('message: ' + msg);
io.emit('my broadcast', `server: ${msg}`);
});
socket.on('room_update', (msg) => {
console.log('message: ' + msg);
})
});
// ...
And then to call the service from another file (e.g. a HTTP Handler)
import {SocketIOService} from "../utils/socket-io.service";
import log from "../logger";
function notifyUpdatedRoom(roomId: string) {
log.info(`Notifying on updated room: ${roomId}`);
if (roomId && SocketIOService.instance().ready()) {
SocketIOService.instance().emitAll('room_update', roomId);
}
}
I managed to solve this by changing the position from the module.exports
. I immediately put it after I initialized the socket
variable, as it's the only thing I'm exporting it works.
.js
or not, I like doing it like this as it looks clean. – Borda Commented Feb 22, 2019 at 1:49