Socket.io - Emitted event on connect not received in client - node.js

I'm using ngx-socket-io on the client in my Angular app. I've followed the setup in the "How to use" section.
I'm trying to emit an event to all connected clients when one client connects using this code:
const app = require('express')();
const http = require('http').Server(app);
const io = require('socket.io')(http);
io.on('connect', socket => {
io.emit('foo', 'foo-event');
});
However the clients never receives this event when doing:
constructor(
private socket: Socket
) {
this.socket.fromEvent('foo')
.subscribe((e) => {
console.log(e);
});
}
However if I change the server code to:
io.on('connect', socket => {
socket.on('foo', () => {
io.emit('foo', 'foo-event');
});
});
And the client code to:
constructor(
private socket: Socket
) {
this.socket.emit('foo');
this.socket.fromEvent('foo')
.subscribe((e) => {
console.log(e);
});
}
Then it works as expected.
Why can't I just emit an event and receive it on the client without emitting an event from the client first like in the second example?

According to this answer, I think you should use connection event instead because connect emits just before a successful connection. Thus you can't emit new event.

Related

Connect to a third party server (twelvedata) from my own express server through web socket connection string

I want to connect to the twelevedata server through its provided socket connection to receive information.
import * as dotenv from 'dotenv'
import WebSocket from 'ws';
import express from 'express'
const app = express();
//setting up env
dotenv.config()
// setting up the websocket
const ws = new WebSocket(`wss://ws.twelvedata.com/v1/quotes/price?apikey=${process.env.API_KEY_TWELVEDATA}`);
const payload = {
"action": "subscribe",
"params": {
"symbols": "AAPL,INFY,TRP,QQQ,IXIC,EUR/USD,USD/JPY,BTC/USD,ETH/BTC"
},
}
ws.on('connection',function (steam) {
ws.on('open', (data) => {
console.log("data ==>",data);
ws.emit('subscribe',payload)
})
ws.on('subscribe', (data) => {
console.log("data ==>",data);
})
})
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`I am listening at ${port}`);
});
I created a websocket with my websocket connection on an express application but I am unable to receive any information from the twelvedata server regarding the subscribe event that I have emitted !
This is how the websocket should work as shown by the twelvedata website (look into the screen shots)
I am unable to connect and emit the subscribe event given by the twelvedata's documentation
You don't want to emit events from the websocket (that's for events you want to handle locally), but send, i.e., replace
ws.emit('subscribe',payload)
with
ws.send(payload)
// sending the parameters
ws.on('open', function open() {
ws.send(JSON.stringify(payload));
});
ws.on('message', function message(data) {
// receiving data
console.log('data ===>: ', JSON.parse(data));
});
ws.send did the charm for me

Nuxt Socket.io is unresponsive without any error

I'm using nuxt-socket-io along with an Express.js server with socketio as well.
When I start up the client/server, the server-side socket.io connects and console for the server will print "connected").
When I try to connect with nuxt (the client-side part of socket.io), nothing happens. Mounted() is called correctly (the "hm" console log prints out), but the socket never seems to be made. I tried testing this.socket.on('connect-error') and this.socket.on('connect-timeout') for the CLIENT side (the server-side socket.io connects properly), but nothing was ever emitted after about 5 minutes of waiting. The persist: true isn't the issue either; I tried to remove it and had the same issue. I initially didn't have this.socket.open() and had the same problems, so I don't think that line does anything, either.
NuxtJS frontend
mounted() {
console.log("hm");
this.socket = this.$nuxtSocket({
channel: '/profile',
persist: true
})
this.socket.open();
this.socket.on('connection', (socket) => {
console.log("connected")
})
//Listens for the SERVER-EMITTED event 'send'
this.socket.on('send', (message) => {
console.log("client received event!")
console.log(message);
});
},
methods: {
sendMessage() {
// This method IS CALLED correctly with a button (I checked), but the emit is not transmitting
// sends a CLIENT-EMITTED event to the server
this.socket.emit('send-message', {
message: "hey!"
}, (res) => {console.log(res)})
},
nuxt.config.js
io: {
sockets: [{
name: 'main',
default: true,
url: 'http://localhost:3000'
}]
},
My Express Backend (port is 8080)
import express from "express";
import { db } from "./app/config/db.config";
import { authRouter } from "./app/routes/auth.router";
import * as dotenv from "dotenv";
const http = require('http');
const socketio = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = socketio(server, {
cors: {
origin: '*',
methods: ["GET", "POST"]
}
});
// run on connection to socket
io.on('connection', (socket: any) => {
console.log("connected")
})
// listens for the CLIENT-EMITTED event 'send-message'
io.on('send-message', (message: any) => {
console.log(message + "server received!");
// sends a SERVER-EMITTED event "send" to be received by nuxt client
io.emit('send', "message!")
})
server.listen(process.env.PORT, () => {
console.log(`Server is running on port ${process.env.PORT}`);
});
Axios is also running on port 8080, I don't know if that would cause any issues but I don't get any errors when I try to run my whole program (which includes login/registration with axios).
Anyone know why my events aren't transmitting? Thank you!
In your server code, you're adding your 'send-message' event listener to the io object, which is your main socket.io Server instance. However, event listeners should be added to the socket object you get from the connection event. Something like:
// A new connection comes in
io.on('connection', (socket: Socket) => {
// Now we listen for the event that comes from this particular socket
socket.on('send-message', (message: any) => {
// You also use the Socket instance to send events back to clients, not to the `io` Server.
socket.emit('send', "message!");
});
});
The Socket instance docs have more info on what you can do with these sockets.

Trigger `socket.io` event from server(`node.js`), not from client

I am trying to make a game server with node.js, socket.io.
The basic idea likes below.
Initialize socket.io instance when the server starts
Store instance in global scope, so controllers can access it
When API calls, we trigger some socket.io event in the controller or some other points
Here is the implementation I made ...
First, in server.js - entry point
let GlobalVars = require('./state/GlobalVars');
const apiRouters = require('./router');
...
app.use('/api', apiRouters);
app.get('/', (req, res) => {
res.sendFile(`${__dirname}/test/simpleClient.html`)
});
const httpServer = http.createServer(app);
let socketIOInstance = socketIO(httpServer);
socketIOInstance.on('connection', (socket) => {
console.log('SOCKET.IO A USER CONNECTED');
socket.on('create', (data) => {
console.log('SOCKET.IO create called', socket);
socket.join(data.room);
socketIOInstance.emit('message', 'New people joined');
});
socket.on('join', (data) => {
console.log('SOCKET.IO join called', data);
})
socket.emit('message', 'Hi');
});
GlobalVars.socketIO = socketIOInstance;
// Add to global, so the controllers can manage own actions like create, join ...
httpServer.listen(port, () => {
console.log(`Server Listening on the port ${port}`);
})
...
When I access from a client, I am able to see SOCKET.IO A USER CONNECTED and Hi in the browser console.
Second, In api controller.
let GlobalVars = require('../state/GlobalVars');
...
router.post('/create', (req, res) => {
console.log('GenerateGameSokect');
let game = new Game();
let gameId = game.gameId;
// console.log('Global vars ', GlobalVars.socketIO);
GlobalVars.socketIO.emit('create', {
room: gameId
});
res.json({
result : 'SUCCESS',
game : game
})
});
I imported GlobalVars which contains socketIO instance. So what I expected was, socket create event triggered from the statement GlobalVars.socketIO.emit('create', Object) but could not find message in the server logs.
I got no clue what I was missing.
The final form I pursue is something like...
When user call create API, I creates socket connection and room
API will called in HTTP protocol, but in the API, the server publishes some events. - pubsub like.
Thanks for reading my questions b. Here is full source code till now(bitbucket public)
================== EDIT ====================
I got understood (maybe...)
The user-flow I wanted was ...
The client call API
(In the server) Checking validation in API and if valid emit to socket.io
If event accepted send new status to all clients
However, creating socket.io connection in the server looks strange for me, the solution is up to the client.
New user-flow I will change
The client call a validation API
If return is valid, the client emit socket.io event. This time server only do validation, not emit socket.io
In socket event, send new status to all other users
================== EDIT #2 ====================
This is a kind of conclusion. It looks I just misunderstanding the concept of socket communication. Like answer and replies say, Socket and HTTP are totally different channels, there is no way to connect both. (At least, without open new connection from http server to socket)
If this is wrong, you could add reply, Thanks
Now I understand you. Or at least I think!
Let's put it this way: there are two (asymetric) sides on a socket, server and client. What I called, respectively, "global manager" and "socket" in my comment to your post.
const server = require('socket.io')(yourHttpServer);
// client is installed as well when `npm i socket.io`
const client = require('socket.io-client')('http://localhost:' + yourServerPort);
// `socket` is the server side of the socket
server.on('connection', (socket) => {
// this will be triggered by client sides emitting 'create'
socket.on('create', (data) => {
console.log('a client socket just fired a "create" event!');
});
});
// this will be triggered by server side emitting 'create'
client.on('create', (data) => {
server.emit('create', {content: 'this will result in an infinite loop of "create" events!'});
});
In your /create route, when you GlobalVars.socketIO.emit('create', ...), the server-side socket handler isn't triggered, however if you have clients connected through a browser (or, like I showed above, if you connect a client socket directly from the server) then these will trigger their 'create' listener, if any.
Hope this helps you get on the right tracks!

Unable to connect to socket IO locally in reactjs?

I am using nodeJs as backend and reactJs as my frontend the thing is I emitted a socket emit function from node
var server = require('http').createServer();
var io = require('socket.io')(server);
io.emit('quantity_check', 'KR')
now the issue is I'm unable to catch the emit
let serverUrl = 'localhost:3008'
const socket = socketIOClient(serverUrl);
socket.on("quantity_check", data => this.setState({ kiiii: data }));`
const socket = socketIOClient(serverUrl);
I'm checking this locally even i tried with my ip its not connecting I am not sure where the issue occurs
pc:nodejs and reactjs running on different ports
Can you post the code of you node server file and the react file where are you are listening to the sockets?. Anyway i hope that emit event is inside the connection
io.on('connection', function(socket) {
io.emit('quantity_check', 'KR')
}
and did you use the life cycle method componentDidMount to receive message
componentDidMount() {
socket.on("quantity_check", data => {
console.log(data);
});
}
Try something like this.
server
const server = require('http').createServer();
const io = require('socket.io')(server);
io.on('connect', (socket) => {
io.emit('quantity_check', 'KR');
});
Client(React side)
import io from 'socket.io-client';
const socket = io('http://localhost:3008');
export class App extends Component {
componentDidMount() {
socket.on('connect', () => {
console.log(socket.connected);
});
socket.on("quantity_checke", data => {
console.log(data);
});
}
render().......
}

Multiple socket.io instances at different paths

I'm making a REST API that works with routes and actions like /api/route/action. But I want to add WebSocket functionalities. So I want WebSockets to also be addressable by url.
I have this code:
const socketio = require('socket.io');
//server is a http.createServer()
module.exports = server => {
const io = socketio(server, { route: '/socketapi/test' );
io.on('connection', s => {
s.on('a', () => s.emit('b'));
s.emit('message', 'You connected to /test.');
});
const io2 = socketio(server, { route: '/socketapi/something_else' });
io2.on('connection', s => {
s.on('z', () => s.emit('y'));
s.emit('message', 'Hi');
});
};
The reason why I want to split them is so I don't have to keep track of event names I've already used, and so I can separate the logic in the connection event.
But it seems this is not possible. If I have two socket.io instances running I can't connect to either.
Is this possible or will I have to use some tricks and perhaps an event that the client can send to let me know what it wants to subscribe to?
You can use a built in feature of socket.io called namespaces to achieve this behaviour.
Here is a basic example:
Server side:
const nsp = io.of('/my-namespace');
nsp.on('connection', function(socket){
console.log('someone connected');
});
nsp.emit('hi', 'everyone!');
Client side:
const socket = io('/my-namespace');
Now the client can emit and receive messages which are specific to a namespace. With the use of namespaces your problem of name conflicts of the events, will be solved.

Resources