Express JS Websocket Connection to wss failed without error but still able to communicate - express

I am using an Express JS to initiate websocket connection. Below is the following configuration that I used.
socket.js
const ip_address = `${process.env.MIX_HTTPS_APP_URL}`;
const socket_port = `${process.env.MIX_EXPRESS_PORT}`;
const URL = ip_address + ":" + socket_port;
export const socket = io(URL, { autoConnect: true });
socket.onAny((event, ...args) => {
// console.log(event, args);
});
index.js
const app = express();
// app settings
/** Create HTTP server. */
const privateKey = fs.readFileSync(env.privateKey, "utf8");
const certificate = fs.readFileSync(env.certificate, "utf8");
const options = {
key: privateKey,
cert: certificate,
};
const server = https.createServer(options, app).listen(port);
/** Create socket connection */
const socketio = new Server(server);
global.io = socketio.listen(server, {
cors: {
origin: env.url,
},
});
global.io.on("connection", WebSockets.connection);
/** Listen on provided port, on all network interfaces. */
/** Event listener for HTTP server "listening" event. */
server.on("listening", () => {
console.log(`Listening on port:: ${env.url}:${port}/`);
});
Though I can emit and listen to socket, I am still getting this error message. How should I solve this so that users wont see this error message when they view the console?

With reference to your example, the listening on port should be on http server, & socket.io should just attach to on new conn.
see doc https://socket.io/docs/v4/server-initialization/#with-an-https-server
Hope this helps.

Related

Defining Websocket routes for Express

How can I define routes for Websockets using the ws library within an ExpressJS app? It's very easy to set it up the two layers in parallel, but the Websocket layer will not be able to benefit from ExpressJS middlewares (such as authentication). The only implementation I could find was express-ws, which is severely buggy due to not being up to date, and heavily relies on monkeypatching in order to work.
Partially modified from this answer. Modify your entry file to include this:
/* index.ts */
import http from 'http';
import express from 'express';
import exampleRouter from './exampleRouter';
// set up express and create a http server listen for websocket requests on the same port
const app = express();
const server = http.createServer(app);
// listen for websocket requests, which are simple HTTP GET requests with an upgrade header
// NOTE: this must occur BEFORE other middleware is set up if you want the additional ws.handled functionality to close unhandled requests
server.on('upgrade', (req: Request & { ws: { socket: Socket, head: Buffer, handled: Boolean } }, socket: Socket, head: Buffer) => {
// create a dummy response to pass the request into express
const res = new http.ServerResponse(req);
// assign socket and head to a new field in the request object
// optional **handled** field lets us know if there a route processed the websocket request, else we terminate it later on
req.ws = { socket, head, handled: false };
// have Express process the request
app(req, res);
});
/* whatever Express middlewares you want here, such as authentication */
app.use('/example', exampleRouter);
// set up a middleware to destroy unhandled websocket requests and returns a 403
// NOTE: this must occur AFTER your other middlewares but BEFORE the server starts listening for requests
app.use((req: Request & { ws?: { socket: Socket, head: Buffer, handled: Boolean } }, res: Response, next: NextFunction): void => {
if (req.ws && req.ws.handled === false) {
req.ws.socket.destroy();
res.status(404).json('404: Websocket route not found');
}
next();
});
const port = process.env.PORT || 8080;
server.listen(port);
Example of a Express Router with ws functionality, but the logic can be extracted to be used for one-offs
/* RouterWithWebSockets.ts */
// this is just a simple abstraction implementation so the you can set up multiple ws routes with the same router
// without having to rewrite the WSS code or monkeypatch the function into the Express Router directly
import express from 'express';
import { WebSocketServer, WebSocket } from 'ws';
class RouterWithWebSockets {
router;
constructor(router = express.Router()) {
this.router = router;
}
ws = (path: string, callback: (ws: WebSocket) => void, ...middleware: any): void => {
// set up a new WSS with the provided path/route to handle websockets
const wss = new WebSocketServer({
noServer: true,
path,
});
this.router.get(path, ...middleware, (req: any, res, next) => {
// just an extra check to deny upgrade requests if the path/route does not match
// you can process this route as a regular HTTP GET request if it's not a websocket upgrade request by replacing the next()
if (!req.headers.upgrade || path !== req.url) {
next();
} else {
req.ws.handled = true;
wss.handleUpgrade(req, req.ws.socket, req.ws.head, (ws: WebSocket) => {
callback(ws);
});
}
});
};
}
export default RouterWithWebSockets;
Finally, here is an example router with the Websocket routes
/* exampleRouter.ts */
const routerWithWebSockets = new RouterWithWebSockets();
routerWithWebSockets.router.get('/nonWSRoute', doSomething1); // processed as HTTP GET request
routerWithWebSockets.router.get('/wsRoute1', doSomething2); // processed as HTTP GET request
routerWithWebSockets.ws('/wsRoute1', (ws) => doSomethingWithWS1); // processed as Websocket upgrade request
routerWithWebSockets.ws('/wsRoute2', (ws) => doSomethingWithWS2); // processed as Websocket upgrade request
export default routerWithWebSockets.router;

xhr poll error socket io / React-Native / ExpressJs

I'm building an app with you can pay by scanning a QR code with some points.
I'm trying to open web socket with socket io :
In my client (RN app)
import io from "socket.io-client";
//Inside my component vvv
const socket = io(url)
socket.on("connect_error", (err) => {
console.log(err.message)
});
On My server :
const app = express()
const http = require('http').Server(app);
const io = require('socket.io')(http);
/**
* Socket io
*/
io.on('connection',(socket)=>{
console.log('new connection')
})
This code log me an error on my client console:
xhr poll error
I tried every solutions I found on the internet but I'm not able to fix this error.
I also try with url ="localhost" & with url="myIP" but it does not work.
Edit : After 2 days, I resolved my problem !
On my server, I was listening on my app but I had to listen on my server :
I replaced :
app.listen(4000, () => {
console.log('listening on 4000')
})
by
server.listen(4000, () => {
console.log('listening on 4000')
})
where
const server = http.createServer(app);
And now it's working well... What a mistake...

Open socket on dynamic endpoint

I am using loopback to build a route:
/users/{id}
where users can listen for new information pertaining to their account on their own endpoint.
I know I need the socket.io package but I'm not sure what to do with it. How can I open a socket on this dynamic endpoint in the function:
#get('/users/{id}', {
responses: {
'200': {
description: 'User socket',
content: {'application/json': {schema: {'x-ts-type': User}}},
},
},
})
async updateUser(#param.path.string('id') userId: typeof User.prototype.id)
: Promise<boolean> {
\\ Open socket here
console.log(userId)
return true;
}
if I do this:
const express = require("express");
const app = express();
const server = require("http").createServer(app);
const io = require("socket.io").listen(server);
const port = 3000;
io.on("connection", socket => {
console.log("User has connected!");
});
It doesn't open a socket on the dynamic endpoint that I want it to.
I am using loopback-4 for the backend and react-native for the front-end.

Not able to connect socket in react native

I'm trying to connect socket in react native. I am able to connect same socket in html file.
Server Code :
const express = require("express")
, app = express()
, http = require("http").createServer(app)
, fs = require("fs")
, io = require("socket.io")(http);
app.use(express.static("public"));
http.listen("8080", () => {
console.log("Server Started");
});
function socketIdsInRoom(name) {
var socketIds = io.nsps['/'].adapter.rooms[name];
if (socketIds) {
var collection = [];
for (var key in socketIds) {
collection.push(key);
}
return collection;
} else {
return [];
}
}
io.on('connection', function (socket) {
console.log('connection');
socket.on('disconnect', function () {
console.log('disconnect');
});
});
React Native Code:
import io from 'socket.io-client';
const socket = io.connect('http://127.0.0.1:8080', { transports: ['websocket'] });
//const socket = io("http://127.0.0.1:8080"); /* I've also tried this */
socket.on('connect', function (data) {
console.log('connect');
});
I'm using socket.io-client for socket connections in react native
Problem is related to 127.0.0.1 ip. Android can't connect to 127.0.0.1 ip because it is internal loop back IP.
You should replace 127.0.0.1 with your server Ip ether external or internal IP.

how to get socketid in socket.io(nodejs)

In my nodejs application, i am using socket.io for sockets connection.
I am configuring my server side code like this
socket.io configuration in separate file.
//socket_io.js
var socket_io = require('socket.io');
var io = socket_io();
var socketApi = {};
socketApi.io = io;
module.exports = socketApi;
below is my server.js file in which i am attaching my socket io to the server like this
var socketApi = require('./server/socket_io');
// Create HTTP server.
const server = http.createServer(app);
// Attach Socket IO
var io = socketApi.io;
io.attach(server);
// Listen on provided port, on all network interfaces.
server.listen(port, () => console.log(`API running on localhost:${port}`));
and then i am using socket.io in my game.js file to emit updated user coins like this.
//game.js
var socketIO = require('../socket_io');
function updateUserCoins(userBet) {
userId = mongoose.Types.ObjectId(userBet.user);
User.findUserWithId(userId).then((user) => {
user.coins = user.coins - userBet.betAmount;
user.save((err, updatedUser) => {
socketIO.io.sockets.emit('user coins', {
userCoins: updatedUser.coins,
});
});
})
}
and then in my client side, i am doing something like this,
socket.on('user coins', (data) => {
this.coins = data.userCoins;
});
but with the above implementation, updating coins of any user, updates all user coins at the client side, since all the clients are listening to the same socket user coins.
To solve the above problem, i know that i have to do something like this,
// sending to individual socketid (private message)
socketIO.io.sockets.to(<socketid>).emit('user coins', {
userCoins: updatedUser.coins,
});
but my concern is that how will get <socketid> with my current implementation.
You can get it by listening to connection to your socket.io server :
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Here you have a socket object ( io.on('connection', function (socket) ) and you can get his id with socket.id
So you'll probably need to wrap your code with the connection listener.
Source of the exemple for the connection listener
Socket object description