Socket.io with Adonis.js - node.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

Related

socket.io only working in main server file, not in route files

Version 2 of post
Okay, first the file structure:
app
|___app.js
|___models/
|_user.js
|___routes/
|___admin.js
|___public/
|___js/
|___script.js
app.js:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
http.listen(3000, function (err){
if (err) throw err;
console.log("Server is running");
});
script.js:
var socket = io();
//Next, this tells the browser that is has connected to the socket.io server
socket.on('connect', function() {
console.log('Connected to socket.io server!');
});
socket.on('message', function(message){
console.log('New message: ');
console.log(message.text);
});
var $newUsername = $('#Username');
$newUsername.on('blur', function(event){
socket.emit('message', {
text: $newUsername.val()
});
});
So on a registration page, if a user enters a 'username' already in the database, it will console.log 'This user already exists'. At least, that's the idea.
There is still sockets.io code I need to add on the server side. I am trying to put it here:
admin.js:
var router = require('express').Router();
var User = require('../models/user');
io.on('connection', function(socket) {
console.log('User connected via socket.io!');
socket.on('message', function(message) {
Username.findOne({username: message.text}, function (err, existingUsername) {
if (existingUsername) {
console.log('This user already exists: ' + message.text);
}
});
});
});
So, as this stands, the sockets.io code in admin.js won't work because it can't access the io function. I would like to know how I can fix this.
To add to this: The sockets.io code I have in the admin.js file will work fine if I placed it in my app.js file.
The key here is to pass the io instance to any module that needs it when that module is first loaded. This is called the "push" method of sharing as you share by pushing data from one module to another by passing it in the constructor function of the other module.
There is also a "pull" module where one module asks some other module for some shared data by calling a method in that module.
Here's how you could implement the "push" model:
In your admin.js file, you define a constructor function that you call and pass the io instance to when you load it:
var router = require('express').Router();
var User = require('../models/user');
var io;
// define constructor function that receives the io instance so the rest
// of the module can use it
module.exports = function(ioInstance) {
io = ioInstance;
io.on('connection', function(socket) {
console.log('User connected via socket.io!');
socket.on('message', function(message) {
Username.findOne({
username: message.text
}, function(err, existingUsername) {
if (existingUsername) {
console.log('This user already exists: ' + message.text);
}
});
});
});
}
Then, in your app.js file:
var express = require('express');
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
http.listen(3000, function (err){
if (err) throw err;
console.log("Server is running");
});
// when you load the admin.js file, you pass it the io instance
require('./routes/admin.js')(io);
Below are 2 answers. While both answers will technically work, it is advised that you do not use either of them. Use the answer provided above.
Answer 2
So my route files all have this:
var router = require('express').Router();
Now, in any of the route files where I need sockets.io I did this:
var http = require('http').Server(router);
var io = require('socket.io')(http);
And this got my sockets.io code working.
Answer 1
So to get sockets.io code working in my route files, I simply removed 'var' in front of my http and io variables.
I changed:
//Socket io config
var http = require('http').Server(app);
var io = require('socket.io')(http);
to this:
//Socket io config
http = require('http').Server(app);
io = require('socket.io')(http);
Now my sockets.io code in my route files work fine.

socket.io - trigger emit from server-side?

How can I trigger an emit from the server-side with socketIO ?
I have a socket.on('My_Event') on my nodejs server and I wish to trigger that event from some place else on my server with .emit('My_Event').
My goal here is to broadcast to the client-side some notification datas.
server side - app.js
var app = express(),
server = http.createServer(app),
io = require('socket.io')(server);
io.on('connection', function(socket){
socket.on('My_Event', function(data){
socket.volatile.emit('event', data);
});
});
server.listen(config.listenPort, '0.0.0.0', 511, function() {
// config.listenPort is already defined
console.log('node Server - listening on port: ' + config.listenPort);
});
export - the module from which I'd like to trigger the event
var io = require('socket.io')();
exports.addStrategy = function(app) {
var fn = {
doSomething : function(req, res, next) {
// HERE I wish to trigger my socket event
// io.emit('MY_EVENT', {}); ????
res.status(200).json(done());
};
return fn;
};
so far I can't get it to work. is it how I should do it ?
One option is to create a single global instance of Socket.IO that could eventually be shared across multiple modules/applications.
global.socket = require('socket.io').listen(app);
Happy Helping!

How to emit event in socket.io based on client?

I am working on realtime data visualization application using node.js, express and socket.io.
Requirement:
Have to emit the events based on the client request.
For example: If user enter the url as http://localhost:8080/pages socket.io should emit the topic pages to client and another user request for http://localhost:8080/locations socket should emit location to that particular user.
Code
var server = app.listen("8080");
var socket = require('socket.io');
var io = socket.listen(server);
var config = {};
io.on('connection', function (socket) {
config.socket = io.sockets.socket(socket.id);
socket.on('disconnect', function () {
console.log('socket.io is disconnected');
});
});
app.get('/*', function(req, res) {
var url = req.url;
var eventName = url.substring('/'.length);
//pages and locations
config.socket.volatile.emit(eventName, result);
});
Client Code:
//No problem in client code.Its working correctly.
Sample code as follows
socket.on('pages', function (result) {
console.log(result);
});
Problem:
It is emitting pages and locations to both the clients.
Any suggestion to overcome this problem.
I couldn't understand your approach on this, but because you said you're rendering different pages, It means you can serve different code, so what about doing it like this:
Server Side:
var server = app.listen("8080");
var socket = require('socket.io');
var io = socket.listen(server);
var config = {};
app.get('/pages', function(req, res) {
res.render('pages.html');
});
app.get('/locations', function(req, res) {
res.render('locations.html');
});
io.on('connection', function (socket) {
socket.on('pagesEvent', function(data){
socket.volatile.emit('pages', {your: 'data'});
});
socket.on('locationsEvent', function(data){
socket.volatile.emit('locations', {your: 'data'});
});
});
On Client side:
pages.html:
socket.on('connect', function(){
socket.emit('pagesEvent', {});
});
socket.on('pages', function(data){
// do stuff here
});
locations.html:
socket.on('connect', function(){
socket.emit('locationsEvent', {});
});
socket.on('locations', function(data){
// do stuff here
});
You are doing it wrong, WebSockets supposed to work same in both directions. Client emit event to Server, server emit back to Client/Subscribers.
The way you are doing things, seems like a way of implementing API, but for some reason you are trying to implement it with WebSockets, instead of XHR.

Node.js client for a socket.io server

I have a socket.io server running and a matching webpage with a socket.io.js client. All works fine.
But, I am wondering if it is possible, on another machine, to run a separate node.js application which would act as a client and connect to the mentioned socket.io server?
That should be possible using Socket.IO-client: https://github.com/LearnBoost/socket.io-client
Adding in example for solution given earlier. By using socket.io-client https://github.com/socketio/socket.io-client
Client Side:
//client.js
var io = require('socket.io-client');
var socket = io.connect('http://localhost:3000', {reconnect: true});
// Add a connect listener
socket.on('connect', function (socket) {
console.log('Connected!');
});
socket.emit('CH01', 'me', 'test msg');
Server Side :
//server.js
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
io.on('connection', function (socket){
console.log('connection');
socket.on('CH01', function (from, msg) {
console.log('MSG', from, ' saying ', msg);
});
});
http.listen(3000, function () {
console.log('listening on *:3000');
});
Run :
Open 2 console and run node server.js and node client.js
After installing socket.io-client:
npm install socket.io-client
This is how the client code looks like:
var io = require('socket.io-client'),
socket = io.connect('http://localhost', {
port: 1337,
reconnect: true
});
socket.on('connect', function () { console.log("socket connected"); });
socket.emit('private message', { user: 'me', msg: 'whazzzup?' });
Thanks alessioalex.
const io = require('socket.io-client');
const socket_url = "http://localhost:8081";
let socket = io.connect(socket_url);
socket.on('connect', function () {
socket.emit("event_name", {});
});
Yes you can use any client as long as it is supported by socket.io. No matter whether its node, java, android or swift. All you have to do is install the client package of socket.io.
Client side code: I had a requirement where my nodejs webserver should work as both server as well as client, so i added below code when i need it as client, It should work fine, i am using it and working fine for me!!!
const socket = require('socket.io-client')('http://192.168.0.8:5000', {
reconnection: true,
reconnectionDelay: 10000
});
socket.on('connect', (data) => {
console.log('Connected to Socket');
});
socket.on('event_name', (data) => {
console.log("-----------------received event data from the socket io server");
});
//either 'io server disconnect' or 'io client disconnect'
socket.on('disconnect', (reason) => {
console.log("client disconnected");
if (reason === 'io server disconnect') {
// the disconnection was initiated by the server, you need to reconnect manually
console.log("server disconnected the client, trying to reconnect");
socket.connect();
}else{
console.log("trying to reconnect again with server");
}
// else the socket will automatically try to reconnect
});
socket.on('error', (error) => {
console.log(error);
});
something like this worked for me
const WebSocket = require('ws');
const ccStreamer = new WebSocket('wss://somthing.com');
ccStreamer.on('open', function open() {
var subRequest = {
"action": "SubAdd",
"subs": [""]
};
ccStreamer.send(JSON.stringify(subRequest));
});
ccStreamer.on('message', function incoming(data) {
console.log(data);
});

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