UNPKG

@jsprismarine/raknet

Version:
129 lines (126 loc) • 17.6 kB
import { EventEmitter } from 'events'; import Dgram from 'node:dgram'; import { RAKNET_TPS } from './Constants.es.js'; import Session from './Session.es.js'; import { BitFlags } from './protocol/BitFlags.es.js'; import { OfflineHandler } from './protocol/OfflineHandler.es.js'; class ServerSocket extends EventEmitter { constructor(maxConnections, onlineMode, serverName, logger) { super(); this.maxConnections = maxConnections; this.onlineMode = onlineMode; this.serverName = serverName; this.logger = logger; this.socket = Dgram.createSocket("udp4").unref(); this.guid = Buffer.allocUnsafe(8).readBigInt64BE(); if (this.onlineMode) { this.logger.warn("Online mode is currently not supported.", "RakNet/ServerSocket"); } } socket; guid; sessions = /* @__PURE__ */ new Set(); ticker; offlineHandler = new OfflineHandler(this); start(address, port) { try { this.socket.bind(port, address); } catch (error) { if (error instanceof Error) { this.logger.error("Failed to bind socket, error message=%s", "RakNet/ServerSocket/Start"); this.logger.error(error, "RakNet/ServerSocket/Start"); } } const tick = () => setTimeout(() => { for (const session of this.sessions.values()) { session.update(Date.now()); } tick(); }, RAKNET_TPS); this.ticker = tick(); this.ticker.unref(); this.socket.on("message", this.handleMessage.bind(this)); } handleMessage(msg, rinfo) { if ((msg[0] & BitFlags.VALID) === 0) { this.offlineHandler.process(msg, rinfo); } else { let session; if ((session = this.getSessionByAddress(rinfo)) !== null) { session.handle(msg); } else { this.logger.debug( `Cannot handle Datagram for unconnected client=${rinfo.address}:${rinfo.port}, buffer=${msg}`, "RakNet/ServerSocket/handleMessage" ); } } } kill() { for (const session of this.getSessions()) { session.sendFrameQueue(); } clearTimeout(this.ticker); this.removeAllListeners(); this.socket.close(); } /** * Used to retrieve if we are overflowing the maximum * connections we can allow, value given in the constructor. * @returns {boolean} if we can hold new connections. */ allowIncomingConnections() { return this.sessions.size < this.maxConnections; } /** * Returns the maximum number of incoming connections. * @returns {number} the maximum connections we can allow. */ getMaxConnections() { return this.maxConnections; } /** * Sets the maximum number of allowed incoming connections. * @param {number} allowed - maximum number of connections. */ setMaxConnections(allowed) { this.maxConnections = allowed; } addSession(rinfo, mtuSize, incomingGuid) { this.sessions.add(new Session(this, mtuSize, rinfo, incomingGuid)); this.logger.verbose(`Session created for client=${rinfo.address}:${rinfo.port}, mtu=${mtuSize}`); this.serverName.setOnlinePlayerCount(this.sessions.size); } removeSession(session, reason) { if (!this.sessions.delete(session)) return; this.emit("closeConnection", session.getAddress(), reason); this.logger.verbose(`Closed session for client=${session.getAddress()}, reason=${reason}`); this.serverName.setOnlinePlayerCount(this.sessions.size); } getLogger() { return this.logger; } getSessions() { return Array.from(this.sessions.values()); } getSessionByAddress(rinfo) { return this.getSessions().find( (session) => session.rinfo.address === rinfo.address && session.rinfo.port === rinfo.port ) ?? null; } getSessionByGUID(guid) { return this.getSessions().find((session) => session.guid === guid) ?? null; } getServerGuid() { return this.guid; } sendPacket(packet, rinfo) { packet.encode(); this.sendBuffer(packet.getBuffer(), rinfo); } sendBuffer(buffer, rinfo) { this.socket.send(buffer, rinfo.port, rinfo.address); } } export { ServerSocket as default }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2VydmVyU29ja2V0LmVzLmpzIiwic291cmNlcyI6WyIuLi9zcmMvU2VydmVyU29ja2V0LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gJ2V2ZW50cyc7XG5pbXBvcnQgRGdyYW0sIHsgdHlwZSBSZW1vdGVJbmZvIH0gZnJvbSAnbm9kZTpkZ3JhbSc7XG5pbXBvcnQgeyBSQUtORVRfVFBTIH0gZnJvbSAnLi9Db25zdGFudHMnO1xuaW1wb3J0IFJha05ldFNlc3Npb24gZnJvbSAnLi9TZXNzaW9uJztcbmltcG9ydCBCaXRGbGFncyBmcm9tICcuL3Byb3RvY29sL0JpdEZsYWdzJztcbmltcG9ydCB7IE9mZmxpbmVIYW5kbGVyIH0gZnJvbSAnLi9wcm90b2NvbC9PZmZsaW5lSGFuZGxlcic7XG5pbXBvcnQgdHlwZSBQYWNrZXQgZnJvbSAnLi9wcm90b2NvbC9QYWNrZXQnO1xuaW1wb3J0IHR5cGUgeyBTZXJ2ZXJOYW1lIH0gZnJvbSAnLi91dGlscy9TZXJ2ZXJOYW1lJztcblxudHlwZSBMb2dnZXIgPSB7XG4gICAgaW5mbzogRnVuY3Rpb247XG4gICAgd2FybjogRnVuY3Rpb247XG4gICAgZXJyb3I6IEZ1bmN0aW9uO1xuICAgIHZlcmJvc2U6IEZ1bmN0aW9uO1xuICAgIGRlYnVnOiBGdW5jdGlvbjtcbiAgICBzaWxseTogRnVuY3Rpb247XG59O1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBTZXJ2ZXJTb2NrZXQgZXh0ZW5kcyBFdmVudEVtaXR0ZXIge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgc29ja2V0OiBEZ3JhbS5Tb2NrZXQ7XG4gICAgcHJpdmF0ZSByZWFkb25seSBndWlkOiBiaWdpbnQ7XG4gICAgcHJpdmF0ZSByZWFkb25seSBzZXNzaW9uczogU2V0PFJha05ldFNlc3Npb24+ID0gbmV3IFNldCgpO1xuICAgIHByaXZhdGUgdGlja2VyOiBOb2RlSlMuVGltZW91dCB8IHVuZGVmaW5lZDtcblxuICAgIHByaXZhdGUgcmVhZG9ubHkgb2ZmbGluZUhhbmRsZXIgPSBuZXcgT2ZmbGluZUhhbmRsZXIodGhpcyk7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IoXG4gICAgICAgIHByaXZhdGUgbWF4Q29ubmVjdGlvbnM6IG51bWJlcixcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBvbmxpbmVNb2RlOiBib29sZWFuLFxuICAgICAgICBwdWJsaWMgcmVhZG9ubHkgc2VydmVyTmFtZTogU2VydmVyTmFtZSxcbiAgICAgICAgcHJpdmF0ZSByZWFkb25seSBsb2dnZXI6IExvZ2dlclxuICAgICkge1xuICAgICAgICBzdXBlcigpO1xuICAgICAgICB0aGlzLnNvY2tldCA9IERncmFtLmNyZWF0ZVNvY2tldCgndWRwNCcpLnVucmVmKCk7XG4gICAgICAgIHRoaXMuZ3VpZCA9IEJ1ZmZlci5hbGxvY1Vuc2FmZSg4KS5yZWFkQmlnSW50NjRCRSgpO1xuXG4gICAgICAgIGlmICh0aGlzLm9ubGluZU1vZGUpIHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2VyLndhcm4oJ09ubGluZSBtb2RlIGlzIGN1cnJlbnRseSBub3Qgc3VwcG9ydGVkLicsICdSYWtOZXQvU2VydmVyU29ja2V0Jyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhcnQoYWRkcmVzczogc3RyaW5nLCBwb3J0OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRoaXMuc29ja2V0LmJpbmQocG9ydCwgYWRkcmVzcyk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yOiB1bmtub3duKSB7XG4gICAgICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKCdGYWlsZWQgdG8gYmluZCBzb2NrZXQsIGVycm9yIG1lc3NhZ2U9JXMnLCAnUmFrTmV0L1NlcnZlclNvY2tldC9TdGFydCcpO1xuICAgICAgICAgICAgICAgIHRoaXMubG9nZ2VyLmVycm9yKGVycm9yLCAnUmFrTmV0L1NlcnZlclNvY2tldC9TdGFydCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgdGljayA9ICgpID0+XG4gICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IHNlc3Npb24gb2YgdGhpcy5zZXNzaW9ucy52YWx1ZXMoKSkge1xuICAgICAgICAgICAgICAgICAgICBzZXNzaW9uLnVwZGF0ZShEYXRlLm5vdygpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGljaygpO1xuICAgICAgICAgICAgfSwgUkFLTkVUX1RQUyk7XG5cbiAgICAgICAgLy8gU3RhcnQgdGlja2luZ1xuICAgICAgICB0aGlzLnRpY2tlciA9IHRpY2soKTtcbiAgICAgICAgdGhpcy50aWNrZXIudW5yZWYoKTtcblxuICAgICAgICB0aGlzLnNvY2tldC5vbignbWVzc2FnZScsIHRoaXMuaGFuZGxlTWVzc2FnZS5iaW5kKHRoaXMpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGhhbmRsZU1lc3NhZ2UobXNnOiBCdWZmZXIsIHJpbmZvOiBSZW1vdGVJbmZvKTogdm9pZCB7XG4gICAgICAgIC8vIERpcmVjdGx5IGNoZWNrIGlmIGl0J3MgYSBvZmZsaW5lIG1lc3NhZ2VcbiAgICAgICAgaWYgKChtc2dbMF0hICYgQml0RmxhZ3MuVkFMSUQpID09PSAwKSB7XG4gICAgICAgICAgICB0aGlzLm9mZmxpbmVIYW5kbGVyLnByb2Nlc3MobXNnLCByaW5mbyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBOb3JtYWxseSBSYWtOZXQgaWdub3JlcyB1bmhhbmRsZWQgcGFja2V0cywgYnV0IHdlIHN0aWxsIHdhbnQgc29tZSBsb2dzLi4uXG4gICAgICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vZmFjZWJvb2thcmNoaXZlL1Jha05ldC9ibG9iL21hc3Rlci9Tb3VyY2UvUmFrUGVlci5jcHAjTDU0NjVcbiAgICAgICAgICAgIGxldCBzZXNzaW9uO1xuICAgICAgICAgICAgaWYgKChzZXNzaW9uID0gdGhpcy5nZXRTZXNzaW9uQnlBZGRyZXNzKHJpbmZvKSkgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBzZXNzaW9uLmhhbmRsZShtc2cpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAvLyBNYXkgYmUgdHJpZ2dlcmVkIGJ5IHRoZSBBQ0sgb2YgZGlzY29ubmVjdCBwYWNrZXQgdGhhdCBpcyByZWNlaXZlZCBhZnRlciBzZXNzaW9uIGlzIGNsb3NlZFxuICAgICAgICAgICAgICAgIHRoaXMubG9nZ2VyLmRlYnVnKFxuICAgICAgICAgICAgICAgICAgICBgQ2Fubm90IGhhbmRsZSBEYXRhZ3JhbSBmb3IgdW5jb25uZWN0ZWQgY2xpZW50PSR7cmluZm8uYWRkcmVzc306JHtyaW5mby5wb3J0fSwgYnVmZmVyPSR7bXNnfWAsXG4gICAgICAgICAgICAgICAgICAgICdSYWtOZXQvU2VydmVyU29ja2V0L2hhbmRsZU1lc3NhZ2UnXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBraWxsKCk6IHZvaWQge1xuICAgICAgICAvLyBTZW5kIGxhc3QgcmVtYWluaW5nIHBhY2tldHMgdG8gYWxsIHBsYXllcnNcbiAgICAgICAgZm9yIChjb25zdCBzZXNzaW9uIG9mIHRoaXMuZ2V0U2Vzc2lvbnMoKSkge1xuICAgICAgICAgICAgLy8gRklYTUU6IFRoaXMgc2hvdWxkIGJlIGF3YWl0YWJsZS5cbiAgICAgICAgICAgIHNlc3Npb24uc2VuZEZyYW1lUXVldWUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNsZWFyVGltZW91dCh0aGlzLnRpY2tlcik7XG5cbiAgICAgICAgLy8gTWFrZSBzdXJlIHdlIGRvbid0IHNlbmQgYW55IG1vcmUgZXZlbnRzLlxuICAgICAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygpO1xuXG4gICAgICAgIC8vIEZpbmFsbHksIGNsb3NlIHRoZSBzb2NrZXQuXG4gICAgICAgIHRoaXMuc29ja2V0LmNsb3NlKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVXNlZCB0byByZXRyaWV2ZSBpZiB3ZSBhcmUgb3ZlcmZsb3dpbmcgdGhlIG1heGltdW1cbiAgICAgKiBjb25uZWN0aW9ucyB3ZSBjYW4gYWxsb3csIHZhbHVlIGdpdmVuIGluIHRoZSBjb25zdHJ1Y3Rvci5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gaWYgd2UgY2FuIGhvbGQgbmV3IGNvbm5lY3Rpb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBhbGxvd0luY29taW5nQ29ubmVjdGlvbnMoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLnNlc3Npb25zLnNpemUgPCB0aGlzLm1heENvbm5lY3Rpb25zO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIG1heGltdW0gbnVtYmVyIG9mIGluY29taW5nIGNvbm5lY3Rpb25zLlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IHRoZSBtYXhpbXVtIGNvbm5lY3Rpb25zIHdlIGNhbiBhbGxvdy5cbiAgICAgKi9cbiAgICBwdWJsaWMgZ2V0TWF4Q29ubmVjdGlvbnMoKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubWF4Q29ubmVjdGlvbnM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgbWF4aW11bSBudW1iZXIgb2YgYWxsb3dlZCBpbmNvbWluZyBjb25uZWN0aW9ucy5cbiAgICAgKiBAcGFyYW0ge251bWJlcn0gYWxsb3dlZCAtIG1heGltdW0gbnVtYmVyIG9mIGNvbm5lY3Rpb25zLlxuICAgICAqL1xuICAgIHB1YmxpYyBzZXRNYXhDb25uZWN0aW9ucyhhbGxvd2VkOiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5tYXhDb25uZWN0aW9ucyA9IGFsbG93ZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFkZFNlc3Npb24ocmluZm86IFJlbW90ZUluZm8sIG10dVNpemU6IG51bWJlciwgaW5jb21pbmdHdWlkOiBiaWdpbnQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5zZXNzaW9ucy5hZGQobmV3IFJha05ldFNlc3Npb24odGhpcywgbXR1U2l6ZSwgcmluZm8sIGluY29taW5nR3VpZCkpO1xuICAgICAgICB0aGlzLmxvZ2dlci52ZXJib3NlKGBTZXNzaW9uIGNyZWF0ZWQgZm9yIGNsaWVudD0ke3JpbmZvLmFkZHJlc3N9OiR7cmluZm8ucG9ydH0sIG10dT0ke210dVNpemV9YCk7XG4gICAgICAgIHRoaXMuc2VydmVyTmFtZS5zZXRPbmxpbmVQbGF5ZXJDb3VudCh0aGlzLnNlc3Npb25zLnNpemUpO1xuICAgIH1cblxuICAgIHB1YmxpYyByZW1vdmVTZXNzaW9uKHNlc3Npb246IFJha05ldFNlc3Npb24sIHJlYXNvbj86IHN0cmluZyk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuc2Vzc2lvbnMuZGVsZXRlKHNlc3Npb24pKSByZXR1cm47XG4gICAgICAgIHRoaXMuZW1pdCgnY2xvc2VDb25uZWN0aW9uJywgc2Vzc2lvbi5nZXRBZGRyZXNzKCksIHJlYXNvbik7XG4gICAgICAgIHRoaXMubG9nZ2VyLnZlcmJvc2UoYENsb3NlZCBzZXNzaW9uIGZvciBjbGllbnQ9JHtzZXNzaW9uLmdldEFkZHJlc3MoKX0sIHJlYXNvbj0ke3JlYXNvbn1gKTtcbiAgICAgICAgdGhpcy5zZXJ2ZXJOYW1lLnNldE9ubGluZVBsYXllckNvdW50KHRoaXMuc2Vzc2lvbnMuc2l6ZSk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldExvZ2dlcigpOiBMb2dnZXIge1xuICAgICAgICByZXR1cm4gdGhpcy5sb2dnZXI7XG4gICAgfVxuXG4gICAgcHVibGljIGdldFNlc3Npb25zKCk6IFJha05ldFNlc3Npb25bXSB7XG4gICAgICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMuc2Vzc2lvbnMudmFsdWVzKCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTZXNzaW9uQnlBZGRyZXNzKHJpbmZvOiBSZW1vdGVJbmZvKTogUmFrTmV0U2Vzc2lvbiB8IG51bGwge1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgdGhpcy5nZXRTZXNzaW9ucygpLmZpbmQoXG4gICAgICAgICAgICAgICAgKHNlc3Npb24pID0+IHNlc3Npb24ucmluZm8uYWRkcmVzcyA9PT0gcmluZm8uYWRkcmVzcyAmJiBzZXNzaW9uLnJpbmZvLnBvcnQgPT09IHJpbmZvLnBvcnRcbiAgICAgICAgICAgICkgPz8gbnVsbFxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRTZXNzaW9uQnlHVUlEKGd1aWQ6IGJpZ2ludCk6IFJha05ldFNlc3Npb24gfCBudWxsIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0U2Vzc2lvbnMoKS5maW5kKChzZXNzaW9uKSA9PiBzZXNzaW9uLmd1aWQgPT09IGd1aWQpID8/IG51bGw7XG4gICAgfVxuXG4gICAgcHVibGljIGdldFNlcnZlckd1aWQoKTogYmlnaW50IHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ3VpZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2VuZFBhY2tldDxUIGV4dGVuZHMgUGFja2V0PihwYWNrZXQ6IFQsIHJpbmZvOiBSZW1vdGVJbmZvKTogdm9pZCB7XG4gICAgICAgIHBhY2tldC5lbmNvZGUoKTtcbiAgICAgICAgdGhpcy5zZW5kQnVmZmVyKHBhY2tldC5nZXRCdWZmZXIoKSwgcmluZm8pO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZW5kQnVmZmVyKGJ1ZmZlcjogQnVmZmVyLCByaW5mbzogUmVtb3RlSW5mbyk6IHZvaWQge1xuICAgICAgICB0aGlzLnNvY2tldC5zZW5kKGJ1ZmZlciwgcmluZm8ucG9ydCwgcmluZm8uYWRkcmVzcyk7XG4gICAgfVxufVxuIl0sIm5hbWVzIjpbIlJha05ldFNlc3Npb24iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFrQkEsTUFBcUIscUJBQXFCLFlBQWEsQ0FBQTtBQUFBLEVBUTVDLFdB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