Get parent `io` from `socket` - node.js

In Socket.IO you can send a message to *everyone* with the following:
const io = require("socket.io");
io.broadcast.emit("message", data);
You can also send a message to *everyone but one person* using a pattern like so:
const io = require("socket.io");
io.on("connection", function(socket) {
socket.on("message", function(msg) {
socket.broadcast.emit("message", msg);
});
});
This allows for the creation of simple chat apps and the like
Now suppose I have the socket handler defined in another file:
// index.js
const io = require("socket.io");
const handler = require("./handler.js");
io.on("connection", function(socket) {
socket.on("message", handler);
});
// handler.js
module.exports = function(socket) {
socket.broadcast.emit("message", msg);
}
In this situation, I want to send a message to everyone - including the socket that initiated the message. So given the socket, how do I get access to its parent io object?
I've tried some things like:
socket.io.broadcast
socket.server.broadcast
socket.server.eio.broadcast
etc
But none of these seem to work

What about passing in the io to the handler? Originally the handler function would accept a payload (msg in your handler) not a socket?
// index.js
const io = require("socket.io");
const handler = require("./handler.js");
io.on("connection", function(socket) {
socket.on("message", data => handler(io, data) );
});
// handler.js
module.exports = function(socket, msg) {
socket.broadcast.emit("message", msg);
}

Related

Using socket.io connection as a module

I created a queue system via Rabbitmq and send notifications to users via socket. There are 3 files basically.
-index.js //some functions to save data and send to Rabbitmq
-socket.js //socket io modules
-consumer.js //some functions to consume data from Rabbitmq
When npm run index.js and consumer.js are started.
index.js
const Express = require('express');
const app = Express();
//init server
server = app.listen(3000);
//init socket io
require('./socket').initialize(server);
socket.js
const sio = require('socket.io');
let io;
module.exports = {
//Initialize the socket server
initialize: (server) => {
io = sio(server, {
cors: {
origin: '*',
}
});
io.on('connection', (socket) => {
console.log('New client connected with id = ', socket.id);
socket.on('disconnect', () => {
console.log("User disconnected");
});
});
},
//return the io instance
getInstance: () => {
return io;
}
}
consumer.js
const socket = require('./socket');
const io = socket.getInstance();
console.log("io", io);
//io is undefined
Io returns undefined in consumer.js. Where is mistake?
You can't call socket.getInstance() until someone has called socket.initialize() first.
You don't show where consumer.js is loaded so we can't follow the full sequence of module loading, but it appears that consumer.js is getting loaded before you initialize socket and thus it is trying to call socket.getInstance() before there's a socket instance to get.
When using methods that return state that built from previous methods, it is obviously important that things are called in the right order.

Socket.io extend Socket class

I want to create a new function for the Socket class in socket.io but i have no idea how to accomplish this.
I would like to call the function like this socket.nearby().emit().
My code below:
const server = require('http').createServer()
const socketio = require('socket.io')
const io = socketio(server)
io.on('connection', (socket) => {
socket.on('join', (data, callback) => {
// process data
socket.nearby().emit('join', data)
callback(data)
})
})
io.prototype.nearby = function() {
// do function
}
io is not the constructor for the socket.io Socket class so that's why what you showed wouldn't work as you don't have the correct prototype.
The simplest way, without delving into the socket.io source code to try to find how you can access the socket prototype, would be to just do this:
const server = require('http').createServer()
const socketio = require('socket.io')
const io = socketio(server)
io.on('connection', (socket) => {
// add our custom method to each newly created socket object
socket.nearby = function() {
// add implementation code here
}
socket.on('join', (data, callback) => {
// process data
socket.nearby().emit('join', data)
callback(data)
})
})

Socket.io with Adonis.js

I am using Adonis 4.1.0 and Adonis-websocket is only been available for v3. Can anyone tell me workaround for using socket.io with Adonis 4.1.0?
apparently they have been working on this not long ago, it was based on socket.io but because of some issues like memory leaks and others, they decided to use websockets directly instead, check these discussions :
https://github.com/adonisjs/discussion/issues/51
https://forum.adonisjs.com/t/integrating-socket-io-with-adonis-4/519
have you tried using socket.io without relying on Adonis ? ,
something like :
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
io.on('connection', function(socket){
console.log('a user connected');
});
http.listen(3000, function(){
console.log('listening on *:3000');
});
But you should be able to do this with Adonis by now according to : https://github.com/adonisjs/adonis-websocket-protocol
Example :
const filereader = require('simple-filereader')
const msgpack = require('msgpack-lite')
const packets = require('#adonisjs/websocket-packets')
const client = new WebSocket('ws://localhost:3000/adonis-ws')
client.onopen = function () {
// TCP connection created
}
client.onerror = function () {
// TCP connection error
}
client.onmessage = function (message) {
filereader(message, function (error, payload) {
const packet = msgpack.decode(payload)
handlePacket(packet)
})
}
function handlePacket (packet) {
if (packets.isOpenPacket(packet)) {
console.log('Server ack connection. Make channel subscriptions now')
}
if (packets.isJoinAck(packet)) {
console.log('subscription created for %s', packet.d.topic)
}
}
check this for broadcast examples using WS : https://github.com/websockets/ws#broadcast-example
Create start/socket.js file and paste following code inside it.
const Server = use('Server')
const io = use('socket.io')(Server.getInstance())
io.on('connection', function (socket) {
console.log(socket.id)
})
From Virk Himself in this forum:https://forum.adonisjs.com/t/integrating-socket-io-with-adonis-4/519
create a standalone socket io configuration file in start/socket.js
const io = require('socket.io')();
io.listen(3000);
io.on('connection', function (socket) {
console.log(socket.id)
})
to start your socket io server you can configure your server.js as below
new Ignitor(require('#adonisjs/fold'))
.appRoot(__dirname)
.preLoad('start/socket') //path of socket.js
.fireHttpServer()
.catch(console.error)
now when you start your server then it will start along with socket io

Node server cannot receive message from Socket.IO

I am having trouble sending "hi" message from the client to the server. There socket is connected and I am receiving a message when the connection is established on the client. But when I try to emit a message back to the server, it doesn't work.
I have tried both Android and HTML. So I am pretty sure its the server.
NODE
var socket = require('socket.io');
var io;
module.exports = {
initialize: function(server) {
io = socket.listen(server);
io.on('connection', function(socket) {
socket.emit('message');
console.log('connected to socket');
});
io.on('hi', function(message) {
console.log(message);
});
}
}
HTML
doctype html
html
head
title Example
script(src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js')
script(src='/socket.io/socket.io.js')
script(type"text/javascript").
var socket = io.connect('http://localhost:3000')
socket.on('message', function(data){
console.log('receive message from server on webpage');
});
body
div.container
header
h1 Socket Test
button#hiButton Send Hi
footer
script(type"text/javascript").
$('#hiButton').click(function(){
socket.emit('hi', 'send hi to server from webpage');
});
Found the answer
var socket = require('socket.io');
var io;
module.exports = {
initialize: function(server) {
io = socket.listen(server);
io.sockets.on('connection', function(socket) {
socket.emit('message');
socket.on('hi', function(message) {
console.log(message);
});
console.log('connected to socket');
});
}
}

Socket.io Error (socket.send is not a function)

I'm trying out Websockets/Node.js/Socket.io/Express for the first time and I'm trying to create a simple chat program. Everything runs fine and I see both clients in my node termial.
But when I try to execute my socket.send(), I get an error in Firefox (socket.send is not a function). It doesn't complain about socket.connect() so I know the socket.io.js is loaded.
Here is my server code:
var sys = require('util');
var express = require('express');
var io = require('socket.io');
var app = express.createServer();
app.listen(8080);
app.use(express.static(__dirname));
app.get('/', function (req, res) {
res.render('index.html', {
title: 'Chat'
});
});
var socket = io.listen(app);
socket.on('connection', function (client) {
client.on('message', function (message) {
console.log("Message: " + JSON.stringify(data));
socket.broadcast(message);
});
client.on('disconnect', function () {});
});
My client code:
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
var socket = new io.Socket("http://localhost:8080");
socket.connect();
Then I do some code to get the chat message and send it.
socket.send(JSON.stringify(values));
Explanations
You haven't initialized Socket.io correctly on the server-side and client-side.
Client Side
new io.Socket("http://localhost:8080"); doesn't give you the object that you want, you need new io.connect("http://localhost:8080");.
You need to wait until the client is connected to the server before sending a message.
Server side
socket is the object send back by Socket.IO, you need to use socket.sockets to have access to on.
To broadcast a message, you need to use the client object like this: client.broadcast.send()
The variable data doesn't exist on your broadcast. You probably mean message.
Solution
Server
var sys = require('util'),
express = require('express'),
io = require('socket.io'),
app = express.createServer();
app.listen(8080);
app.use(express.static(__dirname));
app.get('/', function (req, res) {
res.render('index.html', {
title: 'Chat'
});
});
var io = io.listen(app);
io.sockets.on('connection', function (client) {
client.on('message', function (message) {
console.log("Message: " + JSON.stringify(message));
client.broadcast.send(message);
});
client.on('disconnect', function () {});
});
Client
<script src="http://localhost:8080/socket.io/socket.io.js"></script>
<script>
var socket = new io.connect("http://localhost:8080"),
connected = false;
socket.on('connect', function () {
connected = true;
});
// Use this in your chat function.
if (connected) {
socket.send(JSON.stringify(values));
}
</script>
socket.broadcast(message); should be io.sockets.emit('key', message);
when you use the socket object passed in threw the connect event your only emitting information to that client, to emit to all clients you have to use io.sockets.emit().
also with socket.send(JSON.stringify(values)); I think you want to do socket.emit(namespace, data);
see my connection file from one of my projects here: https://github.com/AdminSpot/HangoutCanopy/blob/master/javascripts/connection.js
You have to wait for socket.io to connect on the client side
var socket = new io.Socket("http://localhost:8080");
socket.connect();
socket.on('connect', function() {
socket.emit('event', data);
});

Resources