Currently trying to learn how socket.io works and to create a room based game, but having trouble to get clients to the same room after trying to move my code in a seperated file.
If I use the same code from game.js in my app.js file within io.on("connection")... i´m able to access the room and put players in the same room.
app.js
const express = require("express");
const cors = require("cors");
var http = require("http");
const game = require("./core/game/game");
const app = express();
const port = process.env.PORT || 4001;
const index = require("./routes/index");
const server = http.createServer(app);
const io = require("socket.io")(server, {
cors: {
origin: "*",
},
});
/
app.use(cors({ origin: "*" }));
app.use("/", index);
// Reduce the logging output of Socket.IO
/* io.set('log level',1); */
io.on("connection", (socket) => {
console.log("New client connected");
game.initGame(io, socket);
});
server.listen(port, () => {
console.log(`listening on *:${port}`);
});
game.js
var io;
var gameSocket;
/**
* This function is called by index.js to initialize a new game instance.
*
* #param sio The Socket.IO library
* #param socket The socket object for the connected client.
*/
exports.initGame = function (sio, socket) {
io = sio;
gameSocket = socket;
gameSocket.emit("connected", { message: "You are connected!" });
// Host Events
gameSocket.on("hostCreateNewGame", createRoom);
/* gameSocket.on("hostRoomFull", hostPrepareGame);
gameSocket.on("hostCountdownFinished", hostStartGame);
gameSocket.on("hostNextRound", hostNextRound); */
// Player Events
gameSocket.on("playerJoinGame", addPlayer);
/* gameSocket.on("playerAnswer", playerAnswer);
gameSocket.on("playerRestart", playerRestart); */
};
async function createRoom(data) {
console.log("Create Session");
console.log(data);
console.log(data.username);
var gameId = (Math.random() * 100000) | 0;
console.log(data.username);
console.log(gameId);
//gameSocket.username = username;
gameSocket.join(gameId);
}
async function addPlayer(data) {
console.log("JOIN Session");
console.log(data.gameId);
//console.log(socket.username);
const clients = await io.in(data.gameId).allSockets();
console.log(clients);
if (!clients) {
console.error("[INTERNAL ERROR] Room creation failed!");
}
if (clients.size === 0) {
console.log("room does not exist");
return;
}
console.log(await io.in(data.gameId).allSockets());
gameSocket.username = data.username;
gameSocket.join(gameId);
console.log(await io.in(data.gameId).allSockets());
io.to(data.gameId).emit("joinSuccess", { message: "JUHU" });
If I try to use this code, the clients are always undefined which means I cannot the room from my current io object
const clients = await gameSocket.in(data.gameId).allSockets(); //undefined
Can someone show me what I would need to change in order to access the right io object and find the rooms. Maybe I´m trying to follow a bad approach here when trying to seperate the code from my app.js file.
Any help would be great.
Got this working finally.
The issue was that this returned a real number
var gameId = (Math.random() * 100000) | 0;
Whereas the value send to addPlayers function was a String...
Related
I'm trying to create a server that receives the request and sends it to the servers running on different ports. All child processes servers are the same, they just have different ports.
For example, port 4000 listens for a request, and sends it to the 4001 port which prepares a response and sends the response back to the 4000 port and from the 4000 port to the client and next requests 4000 sends to 4002 and so on.
But I want all processes to work with the same simple data object (without installing any packages) which is stored in a separate file that means if the 4001 port changes this object, the 4002 port should work with this changed object without creating a new one in memory.
Here is the sample code-
const cluster = require("cluster");
const http = require("http");
const os = require("os");
let port = 4000;
let current = 1;
if (cluster.isPrimary) {
const redirectHandler = (req, response) => {
const request = http.request(
{ ...req, path: req.url, port: 4000 + current },
(res) => {
res.pipe(response);
}
);
request.end();
if (current === os.cpus().length - 1) {
current = 0;
} else {
current++;
}
};
const server = http.createServer(redirectHandler);
server.listen(port, () => port++);
for (let i = 0; i < os.cpus().length - 1; i++) {
const worker = cluster.fork({ TASK_PORT: ++port });
}
}
if (cluster.isWorker) {
const workerPort = process.env["TASK_PORT"];
const workerServer = http.createServer((req, res) => {
/* change JS object which is located in separate file */
res.end("Text" + workerPort);
});
workerServer.listen(+workerPort);
}
I have implemented a user interface to do some wizard of oz testing. I have a user-side page (Page A), and a second page, the wizard page (Page B). They use the same data and page B receives some information from page A to load the correct data. When the user asks questions on page A, the question is sent to page B, and an answer should be sent back to page A. The problem is that Page A is open on device A and page B is open on Device B (both are on the same server).
I am trying to implement the communication between page A and page B using socketIO. I searched for hours and didn't find a complete example of connecting two apps using socketIO. They usually open the same app in multiple windows. That won't help me. My understanding so far is that I should create a server for each app, and then have the two servers communicate with each other. What I have so far doesn't work and no communication is happening. What I have is as follow:
for page A (index.html):
I added a index.js server file:
// Import packages
const express = require("express");
const socketIO = require("socket.io");
const path = require("path");
// Configuration
const PORT = process.env.PORT || 3000;
//const INDEX = path.join(__dirname, 'index.html');
const INDEX = path.join(__dirname, 'index.html');
console.log("INDEX", INDEX);
//const WIZARD = path.join(__dirname, 'wizard.html');
// Start server
const server = express()
//.use((req, res) => res.sendFile(INDEX), (req, res) => res.sendFile(WIZARD))
.use((req, res) => res.sendFile(INDEX))
.listen(PORT, () => console.log("Listening on localhost:" + PORT));
// Initiatlize SocketIO
const io = socketIO(server);
var other_server = require("socket.io-client")('http://localhost:4000');
other_server.on("connect",function(){
other_server.on('message',function(data){
// We received a message from Server 2
// We are going to forward/broadcast that message to the "Lobby" room
io.to('lobby').emit('message',data);
});
});
io.sockets.on("connection",function(socket){
// Display a connected message
console.log("User-Client Connected!");
// Lets force this connection into the lobby room.
socket.join('lobby');
// Some roster/user management logic to track them
// This would be upto you to add :)
// When we receive a message...
socket.on("message",function(data){
// We need to just forward this message to our other guy
// We are literally just forwarding the whole data packet
other_server.emit("message",data);
});
socket.on("disconnect",function(data){
// We need to notify Server 2 that the client has disconnected
other_server.emit("message","UD,"+socket.id);
// Other logic you may or may not want
// Your other disconnect code here
});
});
For the same app, to the index.html I added the following script:
<script type="text/javascript">
// Get WebSocket
var socket = io.connect('http://localhost:3000');
// Client
socket.on('connect', function(){
socket.emit("message","This is my message");
socket.on('message',function(data){
console.log("We got a message: ",data);
});
});
// Join a channel
var room = "test";
socket.emit("join", room);
let msg = "hello helloo helloooo from index.html";
socket.emit("new_message", msg);
socket.on("new_message", function (msg) {
console.log("sending a message through server from index.html", msg);
});
</script>
For the second app, wizard.html I added a server file, index.js:
// Import packages
const express = require("express");
const socketIO = require("socket.io");
const path = require("path");
// Configuration
const PORT = process.env.PORT || 4000;
//const INDEX = path.join(__dirname, 'index.html');
const INDEX = path.join(__dirname, 'wizard.html');
console.log("INDEX", INDEX);
//const WIZARD = path.join(__dirname, 'wizard.html');
// Start server
const server = express()
//.use((req, res) => res.sendFile(INDEX), (req, res) => res.sendFile(WIZARD))
.use((req, res) => res.sendFile(INDEX))
.listen(PORT, () => console.log("Listening on localhost:" + PORT));
// Server 2
const io = socketIO(server);
io.sockets.on("connection",function(socket){
// Display a connected message
console.log("Server-Client Connected!");
// When we receive a message...
socket.on("message",function(data){
// We got a message. I don't know, what we should do with this
});
});
and to the wizard.html, I added the script below:
<script type="text/javascript">
// Get WebSocket
//var socket = io();
var socket = io.connect('http://localhost:4000');
// Join a channel
var room = "test";
socket.emit("join", room);
let msg = "hello helloo helloooo from wizard";
socket.emit("new_message", msg);
socket.on("new_message", function (msg) {
console.log("sending message through server from wizard", msg);
});
/*
*/
</script>
I also added <script src="/socket.io/socket.io.js"></script> to both apps, index.html, and wizard.html.
In wizard.html I get this error:
POST http://localhost:4000/socket.io/?EIO=3&transport=polling&t=OAp7bZr 400 (Bad Request)
and in index.html I get this error:
Access to XMLHttpRequest at 'http://localhost/socket.io/?EIO=3&transport=polling&t=OAp7k5w' from origin 'http://localhost:3000' has been blocked by CORS policy:
If you can help me figure out what I am missing or if you know of any complete working example similar to what I am trying to accomplish, I would very much appreciate it if you let me know.
It would be even more helpful if someone could use the code and scenario I provided here and write a minimum working example in which the two apps, a.html, and b.html, can communicate through socketIO.
I'm implementing a websocket client in node and my webhook's trying to handle multiple connections from a chatbot service. For example: a new user income, a websocket connection is established on an external chatbot service. The websocket URL is obtained through XMLHttpRequest in my code. And then I use this url to connect to the chatbot service using the ws object (new WebSocket('wssUrlObtainedThroughAjaxRequest','default-protocol')). So each user have a WebSocket. The question is that my code runs sequentially. So if two people sends message to my webhook node, things don't works properly because parallelism. Well, I'll post example code here to make it better to understand.
const express = require('express');
const PORT = process.env.PORT || 8002;
let WebSocket = require('ws');
let CONNECTIONS = new Map();
...
...
...
const app = express()
.use(bodyparser.urlencoded({extended: false}))
.use(bodyparser.json());
app.post('/', (req, res) => {
...
...
...
} else if (req.body.type === 'MESSAGE') {
let DM = req.body.space.name;
let msg = req.body.message.text;
ws = (CONNECTIONS.get(DM)!=null) ? CONNECTIONS.get(DM) : null;
if(ws==null || ws.readyState==3){
controlws.gerarURLWS();
ws = new WebSocket(controlws.urlws, 'talk-protocol');
CONNECTIONS.set(DM,ws);
}
// Executes on websocket openning
ws.onopen = function (event) {
console.log('Canal aberto;');
keepAliveWS();
ws.send(JSON.stringify(msgKoreAi(msg)));
}
if(ws.readyState==1)
ws.send(JSON.stringify(msgKoreAi(msg)));
ws.onmessage = async function (event) {
let resp = JSON.parse(event.data);
if (resp.type == "bot_response") {
text = resp.message[0].component.payload.text;
if(text==null){ // tem quick reply
//mount card hangouts response
let qreplies = resp.message[0].component.payload.payload.quick_replies;
card = '{"sections": [{"widgets": [{"buttons": [';
for(let i=0; i<qreplies.length; i++){
if(i!=qreplies.length-1)
card+='{"textButton": {"text": "'+qreplies[i].payload+'","onClick": {"action": {"actionMethodName": "'+qreplies[i].payload+'"}}}},';
else
card+='{"textButton": {"text": "'+qreplies[i].payload+'","onClick": {"action": {"actionMethodName": "'+qreplies[i].payload+'"}}}}';
}
card+=']}]}],"name": "respostas"}';
card = JSON.parse(card);
text = resp.message[0].component.payload.payload.text;
{
await assyncMessage(DM, text);
await assyncMessage(DM, card);
}
return;
}
//Send assync messages if synchronous was already sent
if(res.headersSent){
{
return await assyncMessage(DM, text);
}
}
else
return res.json({text});
}
}
return;
}
...
...
...
app.listen(PORT, () => {
console.log(`Server is running in port - ${PORT}`);
});
I tried setting up parse live query, but for some reason it returns no results.
I can pull data from it, so I know the server and db are running fine.
The 'open' connection works when I run on localhost, but even then, the subscription events are never called.
Client
var Parse = require('parse/node');
Parse.initialize("key", "", "pass");
Parse.serverURL = parseServer;
Parse.liveQueryServerURL = 'ws://localhost:1337/';
let query = new Parse.Query('groups');
query.equalTo('name', 'name');
let subscription = query.subscribe();
subscription.on('update', (people) => {
console.log("YEAY");
// console.log(people.get('score')); // This should output 100
});
subscription.on('open', () => {
console.log('subscription opened');
});
Server
var app = new ParseServer({
startLiveQueryServer: true,
liveQuery: {
classNames: ["groups", "comments"] // List of classes to support for query subscriptions
},
..}
var port = process.env.PORT || 1337;
var httpServer = require('http').createServer(app);
httpServer.listen(port, function() {
console.log('parse-server-example running on port ' + port + '.');
});
// This will enable the Live Query real-time server
var parseLiveQueryServer = ParseServer.createLiveQueryServer(httpServer);
You can try changing this
let subscription = query.subscribe();
to this
let subscription = await query.subscribe();
Hope it helps.
If you had a server js like so:
var app = require('express'),
http = require('http'),
news = require('./server/api/news'),
db = require('mongoose');
/* app config..... */
app.get('/api/news', news.list);
var server = http.createServer(app);
server.listen(app.get('port'), function () {
console.log("Server running");
});
And I wanted to create an API to handle adding news items to the database:
var db = require('mongoose');
/*** Public Interfaces ***/
function list(req, res) {
var offset = ~~req.query.offset || 0,
limit = ~~req.query.limit || 25;
db.News.find(function (err, newsItems) {
res.json(newsItems.slice(offset*limit, offset*limit + limit));
});
}
exports.list = list;
This API would exist in its own file, how do I use the instance of the db created in the server.js inside the new module.
Or do you create and open a new connection each time you query the database?
Thanks
I would probably do it more like this
the server :
var express = require('express'),
app = express(),
http = require('http'),
db = require('mongoose'),
news = require('./server/api/news')(db); // you can pass anything as args
app.get('/api/news', news.list);
/* add routes here, or use a file for the routes */
// app.get('/api/morenews', news.more_news); .... etc
http.createServer(app).listen(8000);
and in the ../news/index.js file or whatever you're using, I'd use a literal, but you can always use exports to pass back each method as well
module.exports = function(db) {
/* now db is always accessible within this scope */
return {
list : function (req, res) {
var offset = ~~req.query.offset || 0,
limit = ~~req.query.limit || 25;
db.News.find(function (err, newsItems) {
res.json(newsItems.slice(offset*limit, offset*limit + limit));
});
}, // now you can easily add more properties
more_news : function(req, res) {
res.end('Hello kitty');
}
}
}