javascript - Socket.io 在 ES6 类中发出值

标签 javascript node.js sockets oop socket.io

我想知道是否有聪明的人可以告诉我如何在 OOP 环境中使用 ES6 类实现 Socket.IO。我在使用 Socket.io 时遇到的主要问题是传递服务器对象,在我的例子中称为“io”。我见过的几乎每个 socket.io 示例都是纯粹的意大利面条式代码,一个文件包含许多与套接字相关的事件和逻辑。首先,我尝试将服务器对象 io 传递给新类的构造函数,但由于某种原因,您最终会收到令人讨厌的“RangeError:超出最大调用堆栈大小”错误消息。然后我尝试将我的类包装在 module.exports 函数中,该函数的参数应包含 io 对象。对于头等舱来说这很好。假设我将 io 对象传递到我的游戏中,效果如预期的那样出色。但是当我尝试将 io 对象引用到 Round 类时(Game 包含 Rounds 数组),我不能这样做。因为这是 NodeJS 中一种糟糕的做法,所以 require 应该是全局的,而不是在模块/函数内部。所以我再次遇到同样的问题。

app.js(我需要主套接字文件)

const io = socketio(server, { origins: '*:*' });
...
require('./sockets')(io);

sockets/index.js(我在其中初始化游戏服务器,并处理来自客户端套接字的传入消息)

const actions = require('../actions.js');
const chatSockets = require('./chat-sockets');
const climbServer = require('./climb-server');
const authFunctions = require('../auth-functions');

module.exports = (io) => {
    io.on('connection', (client) => {
        console.log('client connected...');
        // Standard join, verify the requested room; if it exists let the client join it.
        client.on('join', (data) => {
            console.log(data);
            console.log(`User ${data.username} tries to join ${data.room}`);
            console.log(`Client joined ${data.room}`);
            client.join(data.room);
        });

        client.on('disconnect', () => {
            console.log('Client disconnected');
        });

        client.on(actions.CREATE_GAME, (hostParticipant) => {
            console.log('CREATE_GAME', hostParticipant);

            // Authorize socket sender by token?
            // Create a new game, and set the host to the host participant
            climbServer.createGame(io, hostParticipant);
        });

        client.on(actions.JOIN_GAME, (tokenizedGameId) => {
            console.log('JOIN_GAME');

            const user = authFunctions.getPayload(tokenizedGameId.token);

            // Authorize socket sender by token?
            // Create a new game, and set the host to the host participant
            const game = climbServer.findGame(tokenizedGameId.content);
            game.joinGame(user);
        });
    });
};

climbServer.js(我的游戏服务器,用于跟踪事件游戏)

const actions = require('../actions.js');
const Game = require('../models/game');

const climbServer = { games: { }, gameCount: 0 };

climbServer.createGame = (io, hostParticipant) => {
    // Create a new game instance
    const newGame = new Game(hostParticipant);
    console.log('New game object created', newGame);

    // Store it in the list of game
    climbServer.games[newGame.id] = newGame;

    // Keep track
    climbServer.gameCount += 1;

    // Notify clients that a new game was created
    io.sockets.in('climb').emit(actions.CLIMB_GAME_CREATED, newGame);
};

climbServer.findGame = gameId => climbServer.games[gameId];

module.exports = climbServer;

Game.js(应该能够向所有连接的套接字发出信号的 ES6 类)

const UUID = require('uuid');
const Round = require('./round');

class Game {
    // Constructor
    constructor(hostParticipant) {
        this.id = UUID();
        this.playerHost = hostParticipant;
        this.playerClient = null;
        this.playerCount = 1;
        this.rounds = [];
        this.timestamp = Date.now();
    }

    joinGame(clientParticipant) {
        console.log('Joining game', clientParticipant);
        this.playerClient = clientParticipant;
        this.playerCount += 1;

        // Start the game by creating the first round
        return this.createRound();
    }

    createRound() {
        console.log('Creating new round at Game: ', this.id);
        const newRound = new Round(this.id);

        return this.rounds.push(newRound);
    }
}

module.exports = Game;

Round.js(Game类使用的ES6类(存储在rounds数组中))

const actions = require('../actions.js');

class Round {
    constructor(gameId) {
        console.log('Initializing round of gameId', gameId);
        this.timeLeft = 60;
        this.gameId = gameId;
        this.winner = null;
        this.timestamp = Date.now();

        // Start countdown when class is instantiated
        this.startCountdown();
    }

    startCountdown() {
        const countdown = setInterval(() => {
            // broadcast to every client
            io.sockets.in(this.gameId).emit(actions.ROUND_TIMER, { gameId: this.gameId, timeLeft: this.timeLeft });
            if (this.timeLeft === 0) {
                // when no time left, stop counting down
                clearInterval(countdown);
                this.onRoundEnd();
            } else {
                // Countdown
                this.timeLeft -= 1;
                console.log('Countdown', this.timeLeft);
            }
        }, 1000);
    }

    onRoundEnd() {
        // Evaluate who won
        console.log('onRoundEnd: ', this.gameId);
    }
}

module.exports = Round;

总结一个问题:如何将 io 的引用传递给我的类,以便我能够向这些类中连接的套接字发出信号? 这不一定是 ES6 类,它可以是使用 .prototype 属性的 NodeJS 对象。我只是想要一种可维护的方式来使用套接字处理我的游戏服务器...感谢任何帮助!

最佳答案

经过几个小时的努力,我找到了一个解决方案。如果有人遇到同样的事情,请查看下面我的解决方案。不是最好的,但比将所有套接字相关代码放在一个文件中要好得多......

Game.js(ES6 类)。关注包含“module.exports”的第一行。

const GameFactory = require('../models/game');

const climbServer = { games: { }, gameCount: 0 };

climbServer.createGame = (io, hostParticipant) => {
    // Create a new game instance
    const Game = GameFactory(io);
    const newGame = new Game(hostParticipant);
    console.log('New game object created', newGame);

    // Store it in the list of game
    climbServer.games[newGame.id] = newGame;

    // Keep track
    climbServer.gameCount += 1;

    return newGame;
};

climbServer.findGame = gameId => climbServer.games[gameId];

module.exports = climbServer;

诀窍是在您首先声明的地方使用此工厂模式:

const GameFactory = require('../models/game');

然后通过传入 Socket.io 服务器对象(在我的例子中为“io”)来初始化工厂。如果您通过构造函数传递它,您最终会得到 RangeError,因此这是唯一的方法。再次不确定此代码与意大利面条代码相比的性能如何。

const Game = GameFactory(io);

最后,您现在可以实例化类的实例:

const newGame = new Game(hostParticipant);

如果有人有改进或想法,请给我留言。仍然不确定这段代码的质量。

关于javascript - Socket.io 在 ES6 类中发出值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47341491/

相关文章:

android - GCM : how to avoid throttling

javascript - 如何创建关键事件并将其传递给文档?

javascript - 使用 jQuery 和一些输入创建键/对对象

javascript - 在 Meteor 中实现多账户类型 + 注册表单的最佳解决方案

javascript - Typescript 类构造函数生成的代码顺序

Java 套接字 : can I write a TCP server with one thread?

javascript - 将类添加到表行没有效果

javascript - 尝试在 angular2 中使用 stomp.js

php - AWS Beanstalk 使用 Grunt 任务部署 Laravel

r - R打开一个套接字连接服务器并从一个脚本启动套接字连接客户端