@colyseus/core
Version:
Multiplayer Framework for Node.js.
294 lines (293 loc) • 8.81 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var LocalPresence_exports = {};
__export(LocalPresence_exports, {
LocalPresence: () => LocalPresence
});
module.exports = __toCommonJS(LocalPresence_exports);
var import_fs = __toESM(require("fs"));
var import_path = __toESM(require("path"));
var import_events = require("events");
var import_Utils = require("../utils/Utils.js");
var import_DevMode = require("../utils/DevMode.js");
const DEVMODE_CACHE_FILE_PATH = import_path.default.resolve(".devmode.json");
class LocalPresence {
constructor() {
this.subscriptions = new import_events.EventEmitter();
this.data = {};
this.hash = {};
this.keys = {};
this.timeouts = {};
if (import_DevMode.isDevMode && import_fs.default.existsSync(DEVMODE_CACHE_FILE_PATH)) {
const cache = import_fs.default.readFileSync(DEVMODE_CACHE_FILE_PATH).toString("utf-8") || "{}";
const parsed = JSON.parse(cache);
if (parsed.data) {
this.data = parsed.data;
}
if (parsed.hash) {
this.hash = parsed.hash;
}
if (parsed.keys) {
this.keys = parsed.keys;
}
}
}
subscribe(topic, callback) {
this.subscriptions.on(topic, callback);
return Promise.resolve(this);
}
unsubscribe(topic, callback) {
if (callback) {
this.subscriptions.removeListener(topic, callback);
} else {
this.subscriptions.removeAllListeners(topic);
}
return this;
}
publish(topic, data) {
this.subscriptions.emit(topic, data);
return this;
}
async channels(pattern) {
let eventNames = this.subscriptions.eventNames();
if (pattern) {
const regexp = new RegExp(
pattern.replaceAll(".", "\\.").replaceAll("$", "\\$").replaceAll("*", ".*").replaceAll("?", "."),
"gi"
);
eventNames = eventNames.filter((eventName) => regexp.test(eventName));
}
return eventNames;
}
async exists(key) {
return this.keys[key] !== void 0 || this.data[key] !== void 0 || this.hash[key] !== void 0;
}
set(key, value) {
this.keys[key] = value;
}
setex(key, value, seconds) {
this.keys[key] = value;
this.expire(key, seconds);
}
expire(key, seconds) {
if (this.timeouts[key]) {
clearTimeout(this.timeouts[key]);
}
this.timeouts[key] = setTimeout(() => {
delete this.keys[key];
delete this.timeouts[key];
}, seconds * 1e3);
}
get(key) {
return this.keys[key];
}
del(key) {
delete this.keys[key];
delete this.data[key];
delete this.hash[key];
}
sadd(key, value) {
if (!this.data[key]) {
this.data[key] = [];
}
if (this.data[key].indexOf(value) === -1) {
this.data[key].push(value);
}
}
async smembers(key) {
return this.data[key] || [];
}
async sismember(key, field) {
return this.data[key] && this.data[key].includes(field) ? 1 : 0;
}
srem(key, value) {
if (this.data[key]) {
(0, import_Utils.spliceOne)(this.data[key], this.data[key].indexOf(value));
}
}
scard(key) {
return (this.data[key] || []).length;
}
async sinter(...keys) {
const intersection = {};
for (let i = 0, l = keys.length; i < l; i++) {
(await this.smembers(keys[i])).forEach((member) => {
if (!intersection[member]) {
intersection[member] = 0;
}
intersection[member]++;
});
}
return Object.keys(intersection).reduce((prev, curr) => {
if (intersection[curr] > 1) {
prev.push(curr);
}
return prev;
}, []);
}
hset(key, field, value) {
if (!this.hash[key]) {
this.hash[key] = {};
}
this.hash[key][field] = value;
return Promise.resolve(true);
}
hincrby(key, field, incrBy) {
if (!this.hash[key]) {
this.hash[key] = {};
}
let value = Number(this.hash[key][field] || "0");
value += incrBy;
this.hash[key][field] = value.toString();
return Promise.resolve(value);
}
hincrbyex(key, field, incrBy, expireInSeconds) {
if (!this.hash[key]) {
this.hash[key] = {};
}
let value = Number(this.hash[key][field] || "0");
value += incrBy;
this.hash[key][field] = value.toString();
if (this.timeouts[key]) {
clearTimeout(this.timeouts[key]);
}
this.timeouts[key] = setTimeout(() => {
delete this.hash[key];
delete this.timeouts[key];
}, expireInSeconds * 1e3);
return Promise.resolve(value);
}
async hget(key, field) {
return typeof this.hash[key] === "object" ? this.hash[key][field] ?? null : null;
}
async hgetall(key) {
return this.hash[key] || {};
}
hdel(key, field) {
const success = this.hash?.[key]?.[field] !== void 0;
if (success) {
delete this.hash[key][field];
}
return Promise.resolve(success);
}
async hlen(key) {
return this.hash[key] && Object.keys(this.hash[key]).length || 0;
}
async incr(key) {
if (!this.keys[key]) {
this.keys[key] = 0;
}
this.keys[key]++;
return Promise.resolve(this.keys[key]);
}
async decr(key) {
if (!this.keys[key]) {
this.keys[key] = 0;
}
this.keys[key]--;
return Promise.resolve(this.keys[key]);
}
llen(key) {
return Promise.resolve(this.data[key] && this.data[key].length || 0);
}
rpush(key, ...values) {
if (!this.data[key]) {
this.data[key] = [];
}
let lastLength = 0;
values.forEach((value) => {
lastLength = this.data[key].push(value);
});
return Promise.resolve(lastLength);
}
lpush(key, ...values) {
if (!this.data[key]) {
this.data[key] = [];
}
let lastLength = 0;
values.forEach((value) => {
lastLength = this.data[key].unshift(value);
});
return Promise.resolve(lastLength);
}
lpop(key) {
return Promise.resolve(Array.isArray(this.data[key]) ? this.data[key].shift() : null);
}
rpop(key) {
return Promise.resolve(this.data[key].pop());
}
brpop(...args) {
const keys = args.slice(0, -1);
const timeoutInSeconds = args[args.length - 1];
const getFirstPopulated = () => {
const keyWithValue = keys.find((key) => this.data[key] && this.data[key].length > 0);
if (keyWithValue) {
return [keyWithValue, this.data[keyWithValue].pop()];
} else {
return null;
}
};
const firstPopulated = getFirstPopulated();
if (firstPopulated) {
return Promise.resolve(firstPopulated);
} else {
const maxRetries = timeoutInSeconds * 8;
let tries = 0;
return new Promise((resolve) => {
const interval = setInterval(() => {
tries++;
const firstPopulated2 = getFirstPopulated();
if (firstPopulated2) {
clearInterval(interval);
return resolve(firstPopulated2);
} else if (tries >= maxRetries) {
clearInterval(interval);
return resolve(null);
}
}, timeoutInSeconds * 1e3 / maxRetries);
});
}
}
setMaxListeners(number) {
this.subscriptions.setMaxListeners(number);
}
shutdown() {
if (import_DevMode.isDevMode) {
const cache = JSON.stringify({
data: this.data,
hash: this.hash,
keys: this.keys
});
import_fs.default.writeFileSync(DEVMODE_CACHE_FILE_PATH, cache, { encoding: "utf-8" });
}
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
LocalPresence
});