How to maintain the same socket connection on two different pages? - javascript

I am creating a page to play a card game, this is for several players who can connect to different rooms. I am having problems in the lobby, where you can see which players are connected to a room. It happens that using the sockets I call the io() function in a section, this connection that is generated is used to connect the client to a room when requested, as I need to use the connection (socket) in another section, I import it with javascript, but this makes me call the io() function again and create a new connection and this is not connected to the room that I had already specified.
This is my code of one of the client parts:
const socket = io();
$("#createParty").click(() => {
const code = newCode();
socket.emit("client: newParty", {userName: sessionStorage.getItem("userName"), code: code});
window.location.href = "/room";
});
$("#connectParty").click(() => {
const codeConnect = $("#txt-codeConnect").val();
socket.emit("client: tryConnectParty", {userName: sessionStorage.getItem("userName"), codeConnect: codeConnect});
window.location.href = "/room";
});
export default socket;
There are two buttons, one that creates the room or party and another one that connects you to one of them, both emit different events to the server.
Here is my server side code:
// Import for server...
import { Server as WebSocketServer } from "socket.io";
import http from "http";
import app from "./app.js";
const server = http.createServer(app);
const io = new WebSocketServer(server);
var rooms = [];
export var usersRoom = [];
// Events socket...
io.on("connection", (socket) => {
console.log("New conection:", socket.id);
socket.on("client: newParty", (data) => { // data = {userName, code}
const code = data.code;
socket.join("room-"+ code);
rooms.push(
{
room: code,
users: [
data.userName
]
}
);
});
socket.on("client: tryConnectParty", (data) => { // data = {userName, codeConnect}
const code = data.codeConnect;
for (let i = 0; i < rooms.length; i++) {
if (rooms[i].room == code) {
const userName = data.userName;
const room = "room-"+ code;
socket.join(room);
rooms[i].users.push(userName);
usersRoom = rooms[i].users;
socket.to(room).emit("server: newConnection", userName);
}
}
});
});
export default server;
I use a variable called rooms, that is composed by the existing rooms and the users connected in it, this is so that the new player that connects can see all the players already connected, the problem is for the players that were already connected at the moment that a new one enters.
As you can see the server receives the two different events, in the event "tryConnectParty" the server checks if the code of the room is in the rooms variable, when it finds it, it emits an event to that room.
This is my code from another part of the client:
import socket from "/main.js";
const userName = sessionStorage.getItem("userName");
$("#txt-userName").html(`<b class='text-white'>${userName}</b>`);
$("#txt-codeRoom").html(`<b>${sessionStorage.getItem("code")}</b>`);
var divPlayers = $("#players");
socket.on("server: newConnection", (userName) => {
divPlayers.append(createCard(userName));
});
function createCard(user) {
return `
<div class="card d-inline-flex text-center" style="width: 300px;">
<div class="card-body">
<span class="h1 text-dark">${user}</span>
</div>
<img class="card-img-bottom" src="img/avatar.png" alt="avatar">
</div>
`;
}
This javascript code is called by a html one:
<script src="/logic/players.js" type="module"> </script>
This is the "room" section, here you can receive the "newConnection" event that creates a card with the name of the new user so that the user can see the new player.
The event "newConnection" never arrives or is received. I was checking several times the code and it was when I realized that when the "socket" is imported is when the io() function is called again and the connection is lost, as this is a new connection and the event is only sent to those who are in the room.
I want to know if there is a better way to do it or how I could solve this, since I can't move forward without this.

Related

initial socket.join() isnt recognized when socket.room is printed out after the following sockets join

[My problem is that my initial socket.join (user that created the game) isnt recognized when I leave the handleNewGame() function. This image contains console.log after each socket.join call I make, I make the initial socket.join call when the game is first created by a user, and the rest are made when a user uses the code to join the game.
VERSION 2.3.0 Socket.io
IMAGE HERE! Image containing console.log made after each socket.join,]1
io.on('connection', socket => {
console.log("Connection")
socket.on('newGame', handleNewGame);
socket.on('joinGame', handleJoinGame);
async function handleNewGame() {
let roomName = makeid(5);
const game = await Game.create({roomID: roomName, Players: [socket.id]});
clientRooms[socket.id] = roomName;
socket.emit('gameCode', game.roomID);
state[roomName] = game.GameState;
socket.join(roomName);
console.log(`Socket ID: ${socket.id}`);
console.log(io.sockets.adapter.rooms);
}
function handleJoinGame(roomName) {
clientRooms[socket.id] = roomName;
socket.join(roomName);
console.log(`Socket ID: ${socket.id}`);
console.log(io.sockets.adapter.rooms);
}
});`
});

socket.io Get data io.sockets.clients(); Not working anymore

Before you can create objects with user properties on frontend and assign it to the socket.user property for each connection using a code like this ex below in the backend.
socket.on("new_visitor", user => {
console.log("new_visitor", user);
socket.user = user;
emitVisitors();
});
then retrieve all these data through the sockets object eg.
const getVisitors = () => {
let clients = io.sockets.clients().connected;
let sockets = Object.values(clients);
let users = sockets.map(s => s.user);
return users;
};
//frontend
componentWillMount() {
axios.get('http://geoplugin.net/json.gp').then(res => {
const {
geoplugin_request,
geoplugin_countryCode,
geoplugin_city,
geoplugin_region,
geoplugin_countryName
} = res.data;
const visitor = {
ip: geoplugin_request,
countrycode: geoplugin_countryCode,
city: geoplugin_city,
state: geoplugin_region,
country: geoplugin_countryName
}
socket.emit("new_visitor", visitor);
socket.on("visitors", visitors => {
this.setState({
visitors: visitors
})
})
});
}
But now the io.sockets.clients is not working anymore and is not recognized as a function.Every API provided seem t return only the Id. For anyone who knows a workaround on this please let us know. Thanks a lot.
Problem : How to hold custom data for each socket (serverside)
For each socket that connects to your socket-io server you want to be able to store some custom data in reference to said socket, so at a later point, other sockets can retrieve this information.
Solution : Add a simple in-memory-store (serverside)
I strongly advise to not add anything or mutating the socket object. Instead use the socket id to maintain a simple in-memory store for all connected sockets.
🚧 Please note: the following snippets are just pointers and are not meant to just be copy pasted. Instead, try to use them to understand your problem and adjust them to your needs.
Server Side
const store = {};
io.on('connection', function (socket) {
// add socket to store, like this
// note 'data' is null at this point, yet needs to be set
store[socket.id] = {
socket : socket,
data : null
}
socket.on('SET_CLIENT_DATA', function (clientdata) {
// here we receive data from frontend, and add it to the serverside reference
store[socket.id].data = clientdata;
// once a socket updates his custom client data
// emit all custom data to all clients
io.emit('ALL_CONNECTED_CLIENTS', Object.values(store).map(e => e.data));
});
socket.on('disconnect', function () {
// if socket disconnects, make sure to remove the reference in your store
delete store[socket.id];
});
});
Client Side
socket.emit("SET_CLIENT_DATA", clientdata);
socket.on("ALL_CONNECTED_CLIENTS", (allclients) => {
/* here the client receives all custom client data that we kept serverside for each connected client */
/* do some more code here */
});

How to store socket id and emit to that user

Hey guys i am working on a webrtc app using socket.io and node, and i have this issue where i made a database in mongodb to store every admin who created a room then fetch the admin id when a user joins the room, but my problem is how do i store the id and emit to that specific user. i tried using io.to(socketID).emit(event,message) but it doesn't emit to the user please help
my code
const users = {}
const admins = {}
io.on('connection',socket =>{
socket.on('join-class',async(classId,palsid)=>{
socket.join(classId)
const gEtLectID = await LiveClass.findOne({"address":classId})
if(gEtLectID){
socketId = gEtLectID.startedBy
}
console.log(socketId,'is admin')
io.to(socketId).emit('user-connected', "let's play a game");
// socket.to(admins[socket.id]).emit('user-connected',userID)
//on disconnection
socket.on('disconnect',()=>{
socket.to(classId).broadcast.emit('user-disconnect',palsid)
})
})
You need to handle the id in the client. when you send an event to the server, include the toId and fromId. So, in the client var socket = io("http://127.0.0.1:3000/", { query: "id=4ny1d" });.
And in the server
io.on('connection', socket => {
var id = socket.handshake.query['id'];
socket.leave(socket.id);//leaving default room
socket.join(id);//joining to custom room(this is admin room)
//maybe you'll want a roomId, but the steps are the same
socket.on('join-class', data => {
socket.join(data.classId);//Here you join to the class
socket.emit('class-ready', data);//message with class info to the suscriber
//here you can store classId in a var or in an array to use socket.to().emit()
})
}

How to use socket io inside class

I'm trying to create game using socket io. I want to implement socket inside server.js but I would like to keep events inside Room.js.:
server.js
const io = require('socket.io').listen(server)
io.sockets.on('connection', socket => {
socket.on('join room', data => {
let room = new Room(data.id, socket)
socket.join(`room${data.id}`)
}
}
Room.js
class Room{
constuctor(id, socket){
this.id = id,
this.socket = socket,
this.handlerOfEvents()
}
handlerOfEvents() {
this.socket.on('new player connected', data => {
console.log('New player connected!')
}
}
}
I tried do as above but it doesn't work:
\node_modules\has-binary2\index.js:30
function hasBinary (obj) {
^
RangeError: Maximum call stack size exceeded
Is there any solution to do sth like this?
Or maybe there is another perfect way to implement events for particular room.
This problem occurs when I try assign socket to this.socket but when I put it directly as argument like below:
class Room{
constuctor(id, socket){
this.id = id,
//this.socket = socket,
this.handlerOfEvents(socket)
}
handlerOfEvents(socket) {
socket.on('new player connected', data => {
console.log('New player connected!')
}
}
}
then just invoke this method in server.js
socket.on('joined new player', data => {
...
room.handlerOfEvents(socket)
}
so, this solution is working for now. But if this is proper way?
Issue from link in comments didn't solve my problem unfortunately.
Thanks for helping!

socket.broadcast.to isn't received by any client in the room

I cannot get to broadcast an event to a specific room.
I check the clients that are in the room, and they seem to have properly join the room.
However socket.broadcast.to(socket.roomChannel).emit("cardSelected", cardInfo)
is simply not working,
whereas socket.broadcast.emit("cardSelected", cardInfo) works (but I need to broadcast only to the room).
This is driving me insane...
Here is my code, the part that is not working is all the way to the bottom:
// Setup basic express server
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var port = '4000';
server.listen(port, function () {
});
this.rooms = [];
let lastRoomId = 0
let lastPlayerId = 0
io.on('connection', function (socket) {
// send list of rooms at connect
socket.emit("connected", {rooms: this.rooms});
socket.id = ++lastPlayerId;
// Room
socket.on('createRoom', (roomName) => {
const room = {
id: ++lastRoomId,
name: roomName,
players: [],
}
this.rooms.push(room);
socket.emit("roomCreated", room);
socket.broadcast.emit("update_rooms", {rooms: this.rooms});
});
socket.on('joinRoom', (id) => {
const index = this.rooms.map(room => room.id).indexOf(id);
if (index >= 0) {
this.rooms[index].players.push(socket.id);
socket.emit("roomJoined", this.rooms[index]);
socket.roomId = id;
socket.roomChannel = this.rooms[index].name;
socket.join(socket.roomChannel);
socket.broadcast.emit("update_rooms", {rooms: this.rooms});
}
});
// Game
socket.on('cardSelected', (cardInfo) => {
console.log("broadcasting to", socket.roomChannel);
console.log("socket room", socket.rooms);
var clients = io.sockets.adapter.rooms[socket.roomChannel].sockets;
// Shows that the clients ARE in the room
// returns "{ '1': true, '2': true }" if I have two clients
console.log(clients);
// DOESNT WORK!!
socket.broadcast.to(socket.roomChannel).emit("cardSelected", cardInfo)
// DOESNT WORK!!
io.to(socket.roomChannel).emit("cardSelected");
// Works
socket.broadcast.emit("cardSelected", cardInfo);
});
});
I also tried socket.to(socket.roomChannel).emit("cardSelected", cardInfo); (without broadcast), without any success
After debugging the code inside socket.io, I found out that changing the value of "id" for the socket was breaking everything!
I removed this line socket.id = ++lastPlayerId; and now everything works fine :)
So, remember: Never manually change the id of a socket.

Categories

Resources