Socket.io namespace with variable/id in route - javascript

I have a problem:
I use a room join system [which I programmed only in NodeJS] and socket.io.
https://example.com/room/:roomid/
e.g. https://example.com/room/764363553/
my route:
router.get('/room/:roomid/', function (req, res, next) {
var id = req.params.roomid;
//....
});
I want to make sockets in rooms, but how I make it with the namespace?
io.of("/room/:roomid/").on('connection', function (socket) {
io.of("/room/:roomid/").emit('testsocket');
}
-> does not work
client code:
var socketIO = io(window.location.pathname);
socketIO.on('testsocket', function (data) {
console.log("socket successful connected!");
});

Socketio supports Dynamic namespace since 2.1.0.
The pr is here.
document is here:
A regex or a function can also be provided, in order to create namespace in a dynamic way:
const dynamicNsp = io.of(/^\/dynamic-\d+$/).on('connect', (socket) => {
const newNamespace = socket.nsp; // newNamespace.name === '/dynamic-101'
// broadcast to all clients in the given sub-namespace
newNamespace.emit('hello');
});
// client-side
const socket = io('/dynamic-101');
// broadcast to all clients in each sub-namespace
dynamicNsp.emit('hello');
// use a middleware for each sub-namespace
dynamicNsp.use((socket, next) => { /* ... */ });
With a function:
io.of((name, query, next) => {
next(null, checkToken(query.token));
}).on('connect', (socket) => { /* ... */ });

Server
var manager = io.of("/room").on('connection', function (socket) {
socket.on("join", function(roomid){
socket.join(roomid);
manager.to(roomid).emit('testsocket',roomid);
}
}
Client:
var socketIO = io("/room");
var roomID = window.location.pathname.splitOnLast("/")[1]; //Should ideally be got from req.params.roomid
socketIO.emit("join", roomID)
socketIO.on('testsocket', function (data) {
console.log("Connected to room", data);
});

Related

How export variable outside a class module

I found this example to use mqtt in node.js like a class:
mqtt_handler.js:
const mqtt = require('mqtt');
class MqttHandler {
constructor() {
this.mqttClient = null;
this.host = 'YOUR_HOST';
this.username = 'YOUR_USER'; // mqtt credentials if these are needed to connect
this.password = 'YOUR_PASSWORD';
}
connect() {
// Connect mqtt with credentials (in case of needed, otherwise we can omit 2nd param)
this.mqttClient = mqtt.connect(this.host, { username: this.username, password: this.password });
// Mqtt error calback
this.mqttClient.on('error', (err) => {
console.log(err);
this.mqttClient.end();
});
// Connection callback
this.mqttClient.on('connect', () => {
console.log(`mqtt client connected`);
});
// mqtt subscriptions
this.mqttClient.subscribe('mytopic', {qos: 0});
// When a message arrives, console.log it
this.mqttClient.on('message', function (topic, message) {
console.log(message.toString());
});
this.mqttClient.on('close', () => {
console.log(`mqtt client disconnected`);
});
}
// Sends a mqtt message to topic: mytopic
sendMessage(message) {
this.mqttClient.publish('mytopic', message);
}
}
module.exports = MqttHandler;
and then, in app.js:
var express = require("express");
var bodyParser = require("body-parser");
var app = express();
var mqttHandler = require('./mqtt_handler.js');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }))
var mqttClient = new mqttHandler();
mqttClient.connect();
// Routes
app.post("/send-mqtt", function(req, res) {
mqttClient.sendMessage(req.body.message);
res.status(200).send("Message sent to mqtt");
});
var server = app.listen(3000, function () {
console.log("app running on port.", server.address().port);
});
Works fine, and the mqtt code written in other file, can help me to write a tidier code.
I would need to be able to use incoming messages directly in app.js, because then I would have to handle them with socket.io, but I would like to leave the mqtt related code separate from app.js. But I can't find a way to export incoming message values directly to app.js.
this.mqttClient.on('message', function (topic, message) {
console.log(message.toString());
});

How can i send data and get data via angular to socket server

currently i am trying to send and get the data via angular client to socket server and from socket server to angular i need to get data i able to push the data but i need to know how can i push data to the api which is there in socket server and get data from the api to socket server and emit it to client
below is my
For sending data from angular client to socket server
component code
constructor(public socketService: SocketioService){
}
ngOnInit(){
this.socketService.setupSocketConnection();
}
// For sending post request
sendMsg(){
this.socketService.sendData(this.title);
}
// For getting the request
getMsg(){
this.socketService.getMsg().subscribe(res => {
console.log(res);
})
Angular service code
import * as io from 'socket.io-client';
import { Observable } from 'rxjs';
socket;
constructor() {
}
setupSocketConnection() {
this.socket = io(environment.SOCKET_ENDPOINT);
}
// for posting data
sendData(values){
console.log(values);
this.socket.emit('my message', values);
}
//for getting data
getMsg(){
return Observable.create((observer) => {
this.socket.on('grabMsg', (message) => {
observer.next(message);
});
});
}
Node server code
const app = require('express')();
const http = require('http').createServer(app);
const io = require('socket.io')(http);
app.get('/', (req, res) => {
res.send('<h1>Hey Socket.io</h1>');
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('disconnect', () => {
console.log('user disconnected');
});
socket.on('my message', (msg) => {
//here i want to consume api like
// localhost:3000(post) {"title":"ss"}
console.log('message: ' + msg);
});
socket.on('grabMsg', () => {
//here i want to consume api like
// localhost:3000(get)
let ms = 'max'
io.emit(ms);
});
});
http.listen(3001, () => {
console.log('listening on *:3001');
});
so here how can i send and post data in socket server
in short i will send data to from angular client to socket server then to some api
//server-side
socket.on('grabMsg', () => {
let ms = 'max'
io.emit(ms);
});
//client-side
this.socket.on('grabMsg', (message) => {
observer.next(message);
});
In the above code you are using socket.on on both client and server-side also, use one as emit as one as on according to your requirement.
And in below code you are only emitting and there is the first parameter for emitting (any text enclosed in side quote) like below code
socket.on('grabMsg', () => {
let ms = 'max'
io.emit("thatText",ms);
});
the same text(thatText) should be on client-side too, like
this.socket.on('thatText', (message) => {
console.log(message)
});
You can use the nodeJs eventEmitter API. So you can emit an event by eventEmitter when someone hits your endpoint(GET request) and listen that event inside your socket server and vice-versa.
More details:- Custom Events in Node.js with Express framework
export class LiveSocket implements OnInit {
//define a socket
public socket = new WebSocket(environment.SOCKET_ENDPOINT);
ngOnInit() {
// Add an event listener for when a connection is open
this.socket.onopen = () => {
console.log('WebSocket connection opened. Ready to send messages.');
// Send a message to the server
this.socket.send('message');
};
// Add an event listener for when a message is received from the server
this.socket.onmessage = (message) => {
//handle getting data from server
var data = JSON.parse(message.data);
console.log(data)
};
}
}

How to define socket variable globally

I have this piece of code in my socketio file and here I can use socket simply.
import _ from 'lodash'
import mongoose from 'mongoose'
exports.register = (server, options, next) => {
var io = require('socket.io')(server.listener)
io.on('connection', async(socket) => {
// here I can use socket.emit() and all
})
next()
}
exports.register.attributes = {
name: 'socket'
}
Now, I need to use theio socket to emit events from various files and don't want to connect this io.on('connection', async(socket) => {}) every time.
How can I do this?
Thank you!!!
next callback doesn't serve a good purpose here because it's synchronous. Since socket.io connection event can be triggered multiple times, it cannot be converted to a promise for easier chaining, so it's better for it to stay callback-based.
It can be:
var socketIo = require('socket.io')
exports.register = (server, options) => {
var io = socketIo(server.listener);
return onConnect => {
io.on('connection', onConnect);
};
}
So connection function is created once:
const myConnection = register(myServer);
And used through the application:
myConnection(client => {
...
});
This situation can also benefit from observables, e.g. RxJS.
In case the socket shouldn't support reconnections, this could be simplified to:
exports.register = (server, options) => {
var io = socketIo(server.listener);
return new Promise(resolve => {
io.once('connection', resolve);
});
}
Connection promise is created once:
So connection function is created once:
const myConnection = register(myServer);
And used through the application:
const client = await myConnection;
...
You can share functionality across your server instance with Server methods
import _ from 'lodash'
import mongoose from 'mongoose'
exports.register = (server, options, next) => {
var io = require('socket.io')(server.listener)
io.on('connection', async(socket) => {
// here I can use socket.emit() and all
})
// here use server methods
server.decorate('server', 'io', io);
next()
}
exports.register.attributes = {
name: 'socket'
}
Then in your controller
handler: function (request, reply) {
const io = request.server.io;
}

Express promise chain error

I've written a simple express.js server that handles REST API requests and fetches data from a MongoDB database. When I make a GET request to a specific endpoint ("localhost:8081/api/getUserData"), the promise chain doesn't work the way I want it to, and I still don't understand.
This is the error I get:
"[TypeError: Cannot read property 'db' of undefined]"
var MongoClient = require('mongodb').MongoClient;
var express = require('express');
var app = express();
var rp = require("request-promise");
var cors = require('cors');
// use it before all route definitions
app.use(cors({ origin: '*' }));
/********************** REST API FUNCTIONS **********************/
app.get('/api/getUserData', function (req, res, next) {
var context = {};
console.log("in api getUserData")
context.db_url = 'mongodb://localhost:27017/test';
openDatabaseConnection(context)
.then(getAllUserLocations)
.then(closeDatabaseConnection)
.then(function (context) {
res.send(context.userLocations)
})
.catch(function (error) {
console.log("ERROR :");
console.log(error);
})
})
/********************** END REST API FUNCTIONS **********************/
function getAllUserLocations(context) {
context.db.collection("test").find().toArray().then(function (err, result) {
console.log("Received from db: " + result.length + " objects");
context.userLocations = result;
return context;
});
}
function openDatabaseConnection(context) {
console.log("Opening DB connection...");
return MongoClient.connect(context.db_url)
.then(function (db) {
console.log("DB connection opened.");
context.db = db;
return context;
})
}
function closeDatabaseConnection(context) {
console.log("Closing DB connection");
return context.db.close()
.then(function () {
console.log("DB connection closed");
return context;
})
}
/********************** STARTING SERVER **********************/
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Githex server listening at http://%s:%s", host, port)
})
Any help would be appreciated, and even more with an explanation because I don't understand what I've done wrong.
Thanks!
Just like #adeneo mentioned on the first comment, you are missing the db property. Look at your first function:
app.get('/api/getUserData', function (req, res, next) {
var context = {};
console.log("in api getUserData")
context.db_url = 'mongodb://localhost:27017/test';
openDatabaseConnection(context)
.then(getAllUserLocations)
.then(closeDatabaseConnection)
.then(function (context) {
res.send(context.userLocations)
})
.catch(function (error) {
console.log("ERROR :");
console.log(error);
})
});
Now going through the lines within this function:
You setup context as an empty object
You added a db_url property onto the object, so far you have
context = {db_url: "mongodb://localhost:27017/test}
You pass the context object into the openDatabaseConnection function
Within the openDatabaseConnection function, you return a context object. This new returned object doesn't get set anywhere, it just gets returned and never used. You want to call the getuserlocation() function with that returned value.
So instead of just calling
.then(getAllUserConnection)
I would do
.then(function(context){getAllUserConnection(context);})
That should make use of the returned value and make sure you are using it.

how to bind middleware to events in socket.io

Right now you can bind middleware to io.use(middleware);, but this is triggered only when a socket connection is made. Is there a way to intercept it before passing it to an event handle like in expressjs?
In other word....
In express.js you can do:
app.get('/', middleware1, middleware2, function(req, res){
res.end();
});
Can I do the same in socket.io?
socket.on('someEvent', middleware1, middleware2, function(data){
console.log(data); // data is now filtered by 2 previous middlewares
});
As of Socket.io v2.0.4 (found this while inspecting this) you can use a socket middleware like so:
io.on('connection', (socket) => {
socket.use((packet, next) => {
// Handler
next();
});
});
Which means that you can set your code like so:
io.on('connection', (socket) => {
socket.use((packet,next) => {
if (packet[0] === 'someEvent') {
if (authorizationCondition) {
return next(new Error('nope'))
}
}
next();
})
socket.on('someEvent', function(data){
console.log(data);
});
})
You will then be able to catch errors like this with a client-side
io.on('error', err => { ... }) // err will equal "nope"
The npm module socket.io-events can help you. The npm repository is well documented.
var router = require('socket.io-events')();
// handles all events
router.on(function (socket, args, next) {
next();
});
var io = require('socket.io')(3000);
io.use(router);

Categories

Resources