@jsprismarine/raknet
Version:
Basic RakNet implementation written in TypeScript
129 lines (126 loc) • 17.6 kB
JavaScript
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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