mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 07:24:52 +09:00
Add time unit suffixes to variables (#561)
Add suffixes like Ms and Ns to variables whos time unit is not in seconds. This is aligning with a new code style of putting units on variables that are not in SI base units.
This commit is contained in:
1 parent
9842705eb9
commit
c53781d16c
38 files changed
+221
-201
No files matched your search
+12
-1
@@ -19,6 +19,7 @@ Though we have some conventions and workflows that we kindly ask you to follow.
|
||||
- [Supported Node.js and Factorio Version](#supported-node.js-and-factorio-version)
|
||||
- [Code Style](#code-style)
|
||||
- [Naming Style](#naming-style)
|
||||
- [Units](#units)
|
||||
- [Indenting](#indenting)
|
||||
- [Line Length](#line-length)
|
||||
- [Markdown](#markdown)
|
||||
@@ -202,7 +203,7 @@ But there are at least a few things that have been agreed upon.
|
||||
JavaScript variables in general uses camelCase.
|
||||
The exception is for classes/constructors which use PascalCase and variables destructured from over the wire objects.
|
||||
|
||||
Fields in configs and messages sent over links uses lowercase_underscore.
|
||||
Fields in configs uses lowercase_underscore.
|
||||
|
||||
JavaScript files are named using lowercase_underscore for files that export multiple items.
|
||||
Files containing and exporting a single class should be named the same as the class in PascalCase.
|
||||
@@ -217,6 +218,16 @@ Note that no sub-modules of the lib package is imported directly from the outsid
|
||||
|
||||
For lua code lowercase_underscore is used for everything.
|
||||
|
||||
### Units
|
||||
|
||||
When naming variables whos unit is not a base SI unit like seconds or metres the unit used should be suffixed in the variable name:
|
||||
E.g.:
|
||||
|
||||
const startTimeMs = date.now();
|
||||
const endNs = process.hrtime();
|
||||
|
||||
This makes it easier to spot different unit bases are being mixed in the code.
|
||||
|
||||
|
||||
### Strings
|
||||
|
||||
|
||||
@@ -596,7 +596,7 @@ export default class Controller {
|
||||
const host = HostInfo.fromJSON(json);
|
||||
if (host.connected) {
|
||||
host.connected = false;
|
||||
host.updatedAt = Date.now();
|
||||
host.updatedAtMs = Date.now();
|
||||
}
|
||||
hosts.set(id, host);
|
||||
}
|
||||
@@ -617,13 +617,13 @@ export default class Controller {
|
||||
) as Static<typeof InstanceInfo.jsonSchema>[];
|
||||
for (let json of serialized) {
|
||||
if (!json.config) { // migrate: from pre Alpha 14 format.
|
||||
json = { config: json as any, status: "running" }; // Use running to force updatedAt
|
||||
json = { config: json as any, status: "running" }; // Use running to force updatedAtMs
|
||||
}
|
||||
const instance = InstanceInfo.fromJSON(json, "controller");
|
||||
const status = instance.config.get("instance.assigned_host") === null ? "unassigned" : "unknown";
|
||||
if (instance.status !== status) {
|
||||
instance.status = status;
|
||||
instance.updatedAt = Date.now();
|
||||
instance.updatedAtMs = Date.now();
|
||||
}
|
||||
instances.set(instance.id, instance);
|
||||
}
|
||||
@@ -719,14 +719,14 @@ export default class Controller {
|
||||
|
||||
static addAppRoutes(app: Application, pluginInfos: any[]) {
|
||||
app.use((req: Request, res: Response, next) => {
|
||||
let start = process.hrtime.bigint();
|
||||
let startNs = process.hrtime.bigint();
|
||||
stream.finished(res, () => {
|
||||
let routePath = "static";
|
||||
if (req.route && req.route.path) {
|
||||
routePath = req.route.path;
|
||||
}
|
||||
let end = process.hrtime.bigint();
|
||||
endpointDurationSummary.labels(routePath).observe(Number(end - start) / 1e9);
|
||||
let endNs = process.hrtime.bigint();
|
||||
endpointDurationSummary.labels(routePath).observe(Number(endNs - startNs) / 1e9);
|
||||
});
|
||||
next();
|
||||
});
|
||||
@@ -759,7 +759,7 @@ export default class Controller {
|
||||
|
||||
async handleSystemInfoSubscription(request: lib.SubscriptionRequest) {
|
||||
const systems = [...this.systems.values()].filter(
|
||||
metric => metric.updatedAt > request.lastRequestTime,
|
||||
metric => metric.updatedAtMs > request.lastRequestTimeMs,
|
||||
);
|
||||
return systems.length ? new lib.SystemInfoUpdateEvent(systems) : null;
|
||||
}
|
||||
@@ -780,7 +780,7 @@ export default class Controller {
|
||||
hostsUpdated(hosts: HostInfo[]) {
|
||||
const now = Date.now();
|
||||
for (const host of hosts) {
|
||||
host.updatedAt = now;
|
||||
host.updatedAtMs = now;
|
||||
}
|
||||
this.hostsDirty = true;
|
||||
let updates = hosts.map(host => host.toHostDetails());
|
||||
@@ -789,7 +789,7 @@ export default class Controller {
|
||||
|
||||
async handleHostSubscription(request: lib.SubscriptionRequest) {
|
||||
const hosts = [...this.hosts.values()].filter(
|
||||
host => host.updatedAt > request.lastRequestTime,
|
||||
host => host.updatedAtMs > request.lastRequestTimeMs,
|
||||
).map(host => host.toHostDetails());
|
||||
return hosts.length ? new lib.HostUpdatesEvent(hosts) : null;
|
||||
}
|
||||
@@ -937,7 +937,7 @@ export default class Controller {
|
||||
);
|
||||
} else {
|
||||
instance.status = "unassigned";
|
||||
instance.updatedAt = Date.now();
|
||||
instance.updatedAtMs = Date.now();
|
||||
this.instanceDetailsUpdated([instance]);
|
||||
}
|
||||
}
|
||||
@@ -963,7 +963,7 @@ export default class Controller {
|
||||
|
||||
let prev = instance.status;
|
||||
instance.status = "deleted";
|
||||
instance.updatedAt = Date.now();
|
||||
instance.updatedAtMs = Date.now();
|
||||
this.instanceDetailsUpdated([instance]);
|
||||
await lib.invokeHook(this.plugins, "onInstanceStatusChanged", instance, prev);
|
||||
}
|
||||
@@ -991,7 +991,7 @@ export default class Controller {
|
||||
|
||||
addInstanceHooks(instance: InstanceInfo) {
|
||||
instance.config.on("fieldChanged", (field: string, curr: any, prev: any) => {
|
||||
instance.updatedAt = Date.now();
|
||||
instance.updatedAtMs = Date.now();
|
||||
if (field === "instance.name") {
|
||||
this.instanceDetailsUpdated([instance]);
|
||||
}
|
||||
@@ -1008,7 +1008,7 @@ export default class Controller {
|
||||
|
||||
async handleInstanceDetailsSubscription(request: lib.SubscriptionRequest) {
|
||||
const instances = [...this.instances.values()].filter(
|
||||
instance => instance.updatedAt > request.lastRequestTime,
|
||||
instance => instance.updatedAtMs > request.lastRequestTimeMs,
|
||||
).map(instance => instance.toInstanceDetails());
|
||||
return instances.length ? new lib.InstanceDetailsUpdatesEvent(instances) : null;
|
||||
}
|
||||
@@ -1019,7 +1019,7 @@ export default class Controller {
|
||||
}
|
||||
|
||||
async handleInstanceSaveDetailsSubscription(request: lib.SubscriptionRequest) {
|
||||
const saves = [...this.saves.values()].filter(save => save.updatedAt > request.lastRequestTime);
|
||||
const saves = [...this.saves.values()].filter(save => save.updatedAtMs > request.lastRequestTimeMs);
|
||||
return saves.length ? new lib.InstanceSaveDetailsUpdatesEvent(saves) : null;
|
||||
}
|
||||
|
||||
@@ -1027,7 +1027,7 @@ export default class Controller {
|
||||
modPacksUpdated(modPacks: lib.ModPack[]) {
|
||||
const now = Date.now();
|
||||
for (const modPack of modPacks) {
|
||||
modPack.updatedAt = now;
|
||||
modPack.updatedAtMs = now;
|
||||
}
|
||||
this.modPacksDirty = true;
|
||||
this.subscriptions.broadcast(new lib.ModPackUpdatesEvent(modPacks));
|
||||
@@ -1036,20 +1036,20 @@ export default class Controller {
|
||||
|
||||
async handleModPackSubscription(request: lib.SubscriptionRequest) {
|
||||
const modPacks = [...this.modPacks.values()].filter(
|
||||
modPack => modPack.updatedAt > request.lastRequestTime,
|
||||
modPack => modPack.updatedAtMs > request.lastRequestTimeMs,
|
||||
);
|
||||
return modPacks.length ? new lib.ModPackUpdatesEvent(modPacks) : null;
|
||||
}
|
||||
|
||||
modsUpdated(mods: lib.ModInfo[]) {
|
||||
// ModStore sets updatedAt for mods
|
||||
// ModStore sets updatedAtMs for mods
|
||||
this.subscriptions.broadcast(new lib.ModUpdatesEvent(mods));
|
||||
lib.invokeHook(this.plugins, "onModsUpdated", mods);
|
||||
}
|
||||
|
||||
async handleModSubscription(request: lib.SubscriptionRequest) {
|
||||
const mods = [...this.modStore.files.values()].filter(
|
||||
mod => mod.updatedAt > request.lastRequestTime,
|
||||
mod => mod.updatedAtMs > request.lastRequestTimeMs,
|
||||
);
|
||||
return mods.length ? new lib.ModUpdatesEvent(mods) : null;
|
||||
}
|
||||
@@ -1057,7 +1057,7 @@ export default class Controller {
|
||||
usersUpdated(users: ControllerUser[]) {
|
||||
const now = Date.now();
|
||||
for (const user of users) {
|
||||
user.updatedAt = now;
|
||||
user.updatedAtMs = now;
|
||||
}
|
||||
this.userManager.dirty = true;
|
||||
this.subscriptions.broadcast(new lib.UserUpdatesEvent(users));
|
||||
@@ -1065,7 +1065,7 @@ export default class Controller {
|
||||
|
||||
async handleUserSubscription(request: lib.SubscriptionRequest) {
|
||||
const users = [...this.userManager.users.values()].filter(
|
||||
user => user.updatedAt > request.lastRequestTime,
|
||||
user => user.updatedAtMs > request.lastRequestTimeMs,
|
||||
);
|
||||
return users.length ? new lib.UserUpdatesEvent(users) : null;
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ export default class ControllerUser extends User implements IControllerUser {
|
||||
json.is_banned,
|
||||
json.is_whitelisted,
|
||||
json.ban_reason,
|
||||
json.updated_at,
|
||||
json.updated_at_ms,
|
||||
json.is_deleted,
|
||||
playerStats,
|
||||
instanceStats,
|
||||
|
||||
@@ -68,7 +68,7 @@ export default class HostConnection extends BaseConnection {
|
||||
instances.push(instance);
|
||||
let prev = instance.status;
|
||||
instance.status = "unknown";
|
||||
instance.updatedAt = now;
|
||||
instance.updatedAtMs = now;
|
||||
lib.invokeHook(this._controller.plugins, "onInstanceStatusChanged", instance, prev);
|
||||
}
|
||||
this._controller.instanceDetailsUpdated(instances);
|
||||
@@ -185,7 +185,7 @@ export default class HostConnection extends BaseConnection {
|
||||
let prev = instance.status;
|
||||
instance.status = request.status;
|
||||
instance.gamePort = request.gamePort;
|
||||
instance.updatedAt = Date.now();
|
||||
instance.updatedAtMs = Date.now();
|
||||
logger.verbose(`Instance ${instance.config.get("instance.name")} State: ${instance.status}`);
|
||||
this._controller.instanceDetailsUpdated([instance]);
|
||||
await lib.invokeHook(this._controller.plugins, "onInstanceStatusChanged", instance, prev);
|
||||
@@ -222,7 +222,7 @@ export default class HostConnection extends BaseConnection {
|
||||
let prev = controllerInstance.status;
|
||||
controllerInstance.status = instanceData.status;
|
||||
controllerInstance.gamePort = instanceData.gamePort;
|
||||
controllerInstance.updatedAt = Date.now();
|
||||
controllerInstance.updatedAtMs = Date.now();
|
||||
logger.verbose(`Instance ${instanceConfig.get("instance.name")} State: ${instanceData.status}`);
|
||||
instanceUpdates.push(controllerInstance);
|
||||
await lib.invokeHook(
|
||||
@@ -283,7 +283,7 @@ export default class HostConnection extends BaseConnection {
|
||||
if (existingSave && save.equals(existingSave)) {
|
||||
continue;
|
||||
}
|
||||
save.updatedAt = now;
|
||||
save.updatedAtMs = now;
|
||||
this._controller.saves.set(save.id, save);
|
||||
updates.push(save);
|
||||
}
|
||||
@@ -292,7 +292,7 @@ export default class HostConnection extends BaseConnection {
|
||||
for (const [id, save] of this._controller.saves) {
|
||||
if (save.instanceId === event.instanceId && !updatedSaves.has(id)) {
|
||||
save.isDeleted = true;
|
||||
save.updatedAt = now;
|
||||
save.updatedAtMs = now;
|
||||
updates.push(save);
|
||||
this._controller.saves.delete(id);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ export default class HostInfo {
|
||||
/** Unix timestamp in seconds host token must be issued after to be valid */
|
||||
public tokenValidAfter: number = 0,
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
public updatedAt: number = 0,
|
||||
public updatedAtMs: number = 0,
|
||||
/** True if this host has been deleted */
|
||||
public isDeleted: boolean = false,
|
||||
) { }
|
||||
@@ -37,7 +37,7 @@ export default class HostInfo {
|
||||
"remote_address": Type.String(),
|
||||
"public_address": Type.String(),
|
||||
"token_valid_after": Type.Number(),
|
||||
"updated_at": Type.Number(),
|
||||
"updated_at_ms": Type.Number(),
|
||||
"is_deleted": Type.Boolean(),
|
||||
});
|
||||
|
||||
@@ -51,7 +51,7 @@ export default class HostInfo {
|
||||
json.remote_address,
|
||||
json.public_address,
|
||||
json.token_valid_after,
|
||||
json.updated_at,
|
||||
json.updated_at_ms,
|
||||
json.is_deleted,
|
||||
);
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export default class HostInfo {
|
||||
remote_address: this.remoteAddress,
|
||||
public_address: this.publicAddress,
|
||||
token_valid_after: this.tokenValidAfter,
|
||||
updated_at: this.updatedAt,
|
||||
updated_at_ms: this.updatedAtMs,
|
||||
is_deleted: this.isDeleted,
|
||||
};
|
||||
}
|
||||
@@ -80,7 +80,7 @@ export default class HostInfo {
|
||||
this.remoteAddress,
|
||||
this.publicAddress,
|
||||
this.tokenValidAfter,
|
||||
this.updatedAt,
|
||||
this.updatedAtMs,
|
||||
this.isDeleted,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -67,10 +67,10 @@ export default class HttpCloser {
|
||||
* If there's requests in progress that still haven't been completed
|
||||
* after the timeout value passed they will be aborted.
|
||||
*
|
||||
* @param timeout -
|
||||
* @param timeoutMs -
|
||||
* Time in ms to wait for connections to close.
|
||||
*/
|
||||
async close(timeout:number = 5000): Promise<void> {
|
||||
async close(timeoutMs: number = 5000): Promise<void> {
|
||||
let activeSockets = new Set();
|
||||
for (let response of this._responses) {
|
||||
if (!response.headersSent) {
|
||||
@@ -97,7 +97,7 @@ export default class HttpCloser {
|
||||
// Node.js, see nodejs/node#27428.
|
||||
socket.destroy();
|
||||
}
|
||||
}, timeout);
|
||||
}, timeoutMs);
|
||||
this._server.close(err => {
|
||||
clearTimeout(timer);
|
||||
if (err) {
|
||||
|
||||
@@ -11,7 +11,7 @@ export default class InstanceInfo {
|
||||
public config: lib.InstanceConfig,
|
||||
public status: lib.InstanceStatus,
|
||||
public gamePort?: number,
|
||||
public updatedAt = 0,
|
||||
public updatedAtMs = 0,
|
||||
) {
|
||||
this.config = config;
|
||||
this.status = status;
|
||||
@@ -21,7 +21,7 @@ export default class InstanceInfo {
|
||||
"config": lib.InstanceConfig.jsonSchema,
|
||||
"status": lib.InstanceStatus,
|
||||
"gamePort": Type.Optional(Type.Number()),
|
||||
"updatedAt": Type.Optional(Type.Number()),
|
||||
"updatedAtMs": Type.Optional(Type.Number()),
|
||||
});
|
||||
|
||||
static fromJSON(json: Static<typeof this.jsonSchema>, location: lib.ConfigLocation) {
|
||||
@@ -29,7 +29,7 @@ export default class InstanceInfo {
|
||||
lib.InstanceConfig.fromJSON(json.config, location),
|
||||
json.status,
|
||||
json.gamePort,
|
||||
json.updatedAt,
|
||||
json.updatedAtMs,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export default class InstanceInfo {
|
||||
this.config.get("instance.assigned_host") ?? undefined,
|
||||
this.gamePort,
|
||||
this.status,
|
||||
this.updatedAt,
|
||||
this.updatedAtMs,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ async function getMetrics(req: Request, res: Response, next: any) {
|
||||
}
|
||||
|
||||
let requests: Promise<InstanceType<typeof lib.HostMetricsRequest["Response"]> | null>[] = [];
|
||||
let timeout = controller.config.get("controller.metrics_timeout") * 1000;
|
||||
let timeoutMs = controller.config.get("controller.metrics_timeout") * 1000;
|
||||
for (let [hostId, hostConnection] of controller.wsServer.hostConnections) {
|
||||
if (!hostConnection.connected) {
|
||||
continue;
|
||||
@@ -68,7 +68,7 @@ async function getMetrics(req: Request, res: Response, next: any) {
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
timeout, null
|
||||
timeoutMs, null
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -495,7 +495,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " ");
|
||||
}
|
||||
|
||||
async _loadPlugin(pluginInfo: lib.PluginNodeEnvInfo, host: Host) {
|
||||
let pluginLoadStarted = Date.now();
|
||||
let pluginLoadStartedMs = Date.now();
|
||||
let InstancePluginClass = await lib.loadPluginClass(
|
||||
pluginInfo.name,
|
||||
path.posix.join(pluginInfo.requirePath, pluginInfo.instanceEntrypoint!),
|
||||
@@ -506,7 +506,7 @@ rcon.print(game.table_to_json(players))`.replace(/\r?\n/g, " ");
|
||||
this.plugins.set(pluginInfo.name, instancePlugin);
|
||||
await instancePlugin.init();
|
||||
|
||||
this.logger.info(`Loaded plugin ${pluginInfo.name} in ${Date.now() - pluginLoadStarted}ms`);
|
||||
this.logger.info(`Loaded plugin ${pluginInfo.name} in ${Date.now() - pluginLoadStartedMs}ms`);
|
||||
}
|
||||
|
||||
async _loadStats() {
|
||||
|
||||
@@ -427,7 +427,7 @@ export interface FactorioServerOptions {
|
||||
*/
|
||||
maxConcurrentCommands?: number
|
||||
/** Timeout in ms to wait for a response to a shutdown command. */
|
||||
hangTimeout?: number,
|
||||
hangTimeoutMs?: number,
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,7 +463,7 @@ export class FactorioServer extends events.EventEmitter {
|
||||
/** Enable verbose logging */
|
||||
verboseLogging: boolean;
|
||||
/** Timeout in ms to wait for a response to a shutdown command */
|
||||
hangTimeout = 5000;
|
||||
hangTimeoutMs = 5000;
|
||||
|
||||
_factorioDir: string;
|
||||
_writeDir: string;
|
||||
@@ -519,7 +519,7 @@ export class FactorioServer extends events.EventEmitter {
|
||||
/** Maximum number of RCON commands transmitted in parallel on the RCON connection */
|
||||
this.maxConcurrentCommands = options.maxConcurrentCommands || 5;
|
||||
/** Timeout in ms to wait for a response to a shutdown command */
|
||||
this.hangTimeout = options.hangTimeout ?? 5000;
|
||||
this.hangTimeoutMs = options.hangTimeoutMs ?? 5000;
|
||||
|
||||
if (options.stripPaths) {
|
||||
let charSet = new Set(path.resolve(this.writePath("temp")));
|
||||
@@ -1012,7 +1012,7 @@ export class FactorioServer extends events.EventEmitter {
|
||||
}
|
||||
this._server!.kill("SIGKILL");
|
||||
}
|
||||
}, this.hangTimeout);
|
||||
}, this.hangTimeoutMs);
|
||||
|
||||
// It's possible the server decides to exit on its own, in which
|
||||
// case the stop operation has to be cancelled.
|
||||
|
||||
@@ -30,7 +30,7 @@ export default class ExponentialBackoff {
|
||||
reset: number;
|
||||
|
||||
private _exp = 0;
|
||||
private _lastInvocationTime = Date.now();
|
||||
private _lastInvocationTimeMs = Date.now();
|
||||
|
||||
/**
|
||||
* Construct ExponentialBackoff helper
|
||||
@@ -65,9 +65,9 @@ export default class ExponentialBackoff {
|
||||
* @returns time in milliseconds to wait.
|
||||
*/
|
||||
delay() {
|
||||
let invocationTime = Date.now();
|
||||
let interval = (invocationTime - this._lastInvocationTime) / 1000;
|
||||
this._lastInvocationTime = invocationTime;
|
||||
let invocationTimeMs = Date.now();
|
||||
let interval = (invocationTimeMs - this._lastInvocationTimeMs) / 1000;
|
||||
this._lastInvocationTimeMs = invocationTimeMs;
|
||||
|
||||
if (interval > this.reset) {
|
||||
this._exp = 0;
|
||||
|
||||
@@ -56,7 +56,7 @@ export default class ModStore extends TypedEventEmitter<keyof ModStoreEvents, Mo
|
||||
await fs.unlink(path.join(this.modsDirectory, file));
|
||||
this.files.delete(file);
|
||||
modInfo.isDeleted = true;
|
||||
modInfo.updatedAt = Date.now();
|
||||
modInfo.updatedAtMs = Date.now();
|
||||
this.emit("change", modInfo);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export default class RateLimiter {
|
||||
*/
|
||||
action?: () => void;
|
||||
|
||||
private _lastRun = 0;
|
||||
private _lastRunMs = 0;
|
||||
private _runTimeout?: ReturnType<typeof setTimeout>;
|
||||
|
||||
/**
|
||||
@@ -60,15 +60,15 @@ export default class RateLimiter {
|
||||
*/
|
||||
activate() {
|
||||
let now = Date.now();
|
||||
if (now < this._lastRun + 1000 / this.maxRate) {
|
||||
if (now < this._lastRunMs + 1000 / this.maxRate) {
|
||||
if (!this._runTimeout && this.action) {
|
||||
this._runTimeout = setTimeout(() => {
|
||||
this._runTimeout = undefined;
|
||||
this._lastRun = Date.now();
|
||||
this._lastRunMs = Date.now();
|
||||
if (this.action) {
|
||||
this.action();
|
||||
}
|
||||
}, this._lastRun + 1000 / this.maxRate - now);
|
||||
}, this._lastRunMs + 1000 / this.maxRate - now);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -79,7 +79,7 @@ export default class RateLimiter {
|
||||
this._runTimeout = undefined;
|
||||
}
|
||||
|
||||
this._lastRun = now;
|
||||
this._lastRunMs = now;
|
||||
if (this.action) {
|
||||
this.action();
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ export default class ModInfo {
|
||||
sha1?: string;
|
||||
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
updatedAt = 0;
|
||||
updatedAtMs = 0;
|
||||
|
||||
/**
|
||||
* True if this mod has been deleted
|
||||
@@ -148,7 +148,7 @@ export default class ModInfo {
|
||||
...this.infoJsonSchema.properties,
|
||||
"size": Type.Optional(Type.Integer()),
|
||||
"sha1": Type.Optional(Type.String()),
|
||||
"updated_at": Type.Optional(Type.Number()),
|
||||
"updated_at_ms": Type.Optional(Type.Number()),
|
||||
"is_deleted": Type.Optional(Type.Boolean()),
|
||||
});
|
||||
|
||||
@@ -171,7 +171,7 @@ export default class ModInfo {
|
||||
// Additional data
|
||||
if (json.size) { modInfo.size = json.size; }
|
||||
if (json.sha1) { modInfo.sha1 = json.sha1; }
|
||||
if (json.updated_at) { modInfo.updatedAt = json.updated_at; }
|
||||
if (json.updated_at_ms) { modInfo.updatedAtMs = json.updated_at_ms; }
|
||||
if (json.is_deleted) { modInfo.isDeleted = json.is_deleted; }
|
||||
|
||||
return modInfo;
|
||||
@@ -193,7 +193,7 @@ export default class ModInfo {
|
||||
}
|
||||
if (this.size) { json.size = this.size; }
|
||||
if (this.sha1) { json.sha1 = this.sha1; }
|
||||
if (this.updatedAt) { json.updated_at = this.updatedAt; }
|
||||
if (this.updatedAtMs) { json.updated_at_ms = this.updatedAtMs; }
|
||||
if (this.isDeleted) { json.is_deleted = this.isDeleted; }
|
||||
return json;
|
||||
}
|
||||
@@ -229,7 +229,7 @@ export default class ModInfo {
|
||||
|
||||
size: stat.size,
|
||||
sha1: await libHash.hashFile(modPath),
|
||||
updated_at: stat.mtimeMs,
|
||||
updated_at_ms: stat.mtimeMs,
|
||||
is_deleted: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export default class ModPack {
|
||||
exportManifest?: ExportManifest;
|
||||
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
updatedAt = 0;
|
||||
updatedAtMs = 0;
|
||||
|
||||
/**
|
||||
* True if this mod pack has been deleted from the list of mod packs.
|
||||
@@ -118,7 +118,7 @@ export default class ModPack {
|
||||
clone.mods = this.mods;
|
||||
clone.settings = this.settings;
|
||||
clone.exportManifest = this.exportManifest;
|
||||
clone.updatedAt = this.updatedAt;
|
||||
clone.updatedAtMs = this.updatedAtMs;
|
||||
clone.isDeleted = this.isDeleted;
|
||||
return clone;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ export default class ModPack {
|
||||
"runtime-per-user": ModSettingsJsonSchema,
|
||||
}),
|
||||
"export_manifest": Type.Optional(ExportManifest.jsonSchema),
|
||||
"updated_at": Type.Optional(Type.Number()),
|
||||
"updated_at_ms": Type.Optional(Type.Number()),
|
||||
"is_deleted": Type.Optional(Type.Boolean()),
|
||||
});
|
||||
|
||||
@@ -161,7 +161,7 @@ export default class ModPack {
|
||||
};
|
||||
}
|
||||
if (json.export_manifest) { modPack.exportManifest = ExportManifest.fromJSON(json.export_manifest); }
|
||||
if (json.updated_at) { modPack.updatedAt = json.updated_at; }
|
||||
if (json.updated_at_ms) { modPack.updatedAtMs = json.updated_at_ms; }
|
||||
if (json.is_deleted) { modPack.isDeleted = json.is_deleted; }
|
||||
|
||||
if (!modPack.mods.has("base")) {
|
||||
@@ -185,7 +185,7 @@ export default class ModPack {
|
||||
},
|
||||
};
|
||||
if (this.exportManifest) { json.export_manifest = this.exportManifest; }
|
||||
if (this.updatedAt) { json.updated_at = this.updatedAt; }
|
||||
if (this.updatedAtMs) { json.updated_at_ms = this.updatedAtMs; }
|
||||
if (this.isDeleted) { json.is_deleted = this.isDeleted; }
|
||||
return json;
|
||||
}
|
||||
@@ -194,7 +194,7 @@ export default class ModPack {
|
||||
const json = this.toJSON();
|
||||
delete json.id;
|
||||
delete json.export_manifest;
|
||||
delete json.updated_at;
|
||||
delete json.updated_at_ms;
|
||||
delete json.is_deleted;
|
||||
|
||||
// eslint-disable-next-line node/no-sync
|
||||
|
||||
@@ -37,30 +37,33 @@ export default class PlayerStats {
|
||||
static jsonSchema = Type.Object({
|
||||
"join_count": Type.Optional(Type.Integer()),
|
||||
"online_time_ms": Type.Optional(Type.Number()),
|
||||
"first_join_at": Type.Optional(Type.Number()),
|
||||
"first_join_at_ms": Type.Optional(Type.Number()),
|
||||
"last_join_at_ms": Type.Optional(Type.Number()),
|
||||
"last_leave_at_ms": Type.Optional(Type.Number()),
|
||||
"last_leave_reason": Type.Optional(Type.String()),
|
||||
// migrate: renamed fields from alpha 13
|
||||
"last_join_at": Type.Optional(Type.Number()),
|
||||
"last_leave_at": Type.Optional(Type.Number()),
|
||||
"last_leave_reason": Type.Optional(Type.String()),
|
||||
});
|
||||
|
||||
constructor(json: Static<typeof PlayerStats.jsonSchema> = {}) {
|
||||
if (json["join_count"]) {
|
||||
this.joinCount = json["join_count"];
|
||||
}
|
||||
if (json["first_join_at"]) {
|
||||
this.firstJoinAt = new Date(json["first_join_at"]);
|
||||
if (json["first_join_at_ms"]) {
|
||||
this.firstJoinAt = new Date(json["first_join_at_ms"]);
|
||||
}
|
||||
if (json["online_time_ms"]) {
|
||||
this.onlineTimeMs = json["online_time_ms"];
|
||||
}
|
||||
if (json["last_join_at"]) {
|
||||
this.lastJoinAt = new Date(json["last_join_at"]);
|
||||
if (json["last_join_at_ms"] ?? json["last_join_at"]) {
|
||||
this.lastJoinAt = new Date(json["last_join_at_ms"] ?? json["last_join_at"]!);
|
||||
if (!this.firstJoinAt) { // migrate: pre-alpha 14 did not have this field.
|
||||
this.firstJoinAt = this.lastJoinAt;
|
||||
}
|
||||
}
|
||||
if (json["last_leave_at"]) {
|
||||
this.lastLeaveAt = new Date(json["last_leave_at"]);
|
||||
if (json["last_leave_at_ms"] ?? json["last_leave_at"]) {
|
||||
this.lastLeaveAt = new Date(json["last_leave_at_ms"] ?? json["last_leave_at"]!);
|
||||
this.lastLeaveReason = json["last_leave_reason"] || "quit";
|
||||
}
|
||||
}
|
||||
@@ -78,13 +81,13 @@ export default class PlayerStats {
|
||||
json["online_time_ms"] = this.onlineTimeMs;
|
||||
}
|
||||
if (this.firstJoinAt) {
|
||||
json["first_join_at"] = this.firstJoinAt.getTime();
|
||||
json["first_join_at_ms"] = this.firstJoinAt.getTime();
|
||||
}
|
||||
if (this.lastJoinAt) {
|
||||
json["last_join_at"] = this.lastJoinAt.getTime();
|
||||
json["last_join_at_ms"] = this.lastJoinAt.getTime();
|
||||
}
|
||||
if (this.lastLeaveAt) {
|
||||
json["last_leave_at"] = this.lastLeaveAt.getTime();
|
||||
json["last_leave_at_ms"] = this.lastLeaveAt.getTime();
|
||||
json["last_leave_reason"] = this.lastLeaveReason;
|
||||
}
|
||||
return json;
|
||||
|
||||
@@ -24,7 +24,7 @@ export default class User {
|
||||
/** Reason for being banned. Ignored if isBanned is false. */
|
||||
public banReason = "",
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
public updatedAt = 0,
|
||||
public updatedAtMs = 0,
|
||||
/** True if this user object has been removed from the cluster. */
|
||||
public isDeleted = false,
|
||||
/** Combined statistics for the player this user account is tied to. */
|
||||
@@ -42,7 +42,7 @@ export default class User {
|
||||
is_banned: Type.Optional(Type.Boolean()),
|
||||
is_whitelisted: Type.Optional(Type.Boolean()),
|
||||
ban_reason: Type.Optional(Type.String()),
|
||||
updated_at: Type.Optional(Type.Number()),
|
||||
updated_at_ms: Type.Optional(Type.Number()),
|
||||
is_deleted: Type.Optional(Type.Boolean()),
|
||||
instance_stats: Type.Optional(
|
||||
Type.Array(
|
||||
@@ -67,7 +67,7 @@ export default class User {
|
||||
json.is_banned,
|
||||
json.is_whitelisted,
|
||||
json.ban_reason,
|
||||
json.updated_at,
|
||||
json.updated_at_ms,
|
||||
json.is_deleted,
|
||||
playerStats,
|
||||
instanceStats,
|
||||
@@ -103,8 +103,8 @@ export default class User {
|
||||
json.ban_reason = this.banReason;
|
||||
}
|
||||
|
||||
if (this.updatedAt) {
|
||||
json.updated_at = this.updatedAt;
|
||||
if (this.updatedAtMs) {
|
||||
json.updated_at_ms = this.updatedAtMs;
|
||||
}
|
||||
|
||||
if (this.isDeleted) {
|
||||
|
||||
@@ -239,7 +239,7 @@ export class SystemInfo {
|
||||
public diskAvailable: number,
|
||||
public canRestart: boolean,
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
public updatedAt: number,
|
||||
public updatedAtMs: number,
|
||||
public isDeleted: boolean,
|
||||
) { }
|
||||
|
||||
@@ -256,7 +256,7 @@ export class SystemInfo {
|
||||
"diskCapacity": Type.Number(),
|
||||
"diskAvailable": Type.Number(),
|
||||
"canRestart": Type.Boolean(),
|
||||
"updatedAt": Type.Number(),
|
||||
"updatedAtMs": Type.Number(),
|
||||
"isDeleted": Type.Boolean(),
|
||||
});
|
||||
|
||||
@@ -274,7 +274,7 @@ export class SystemInfo {
|
||||
json.diskCapacity,
|
||||
json.diskAvailable,
|
||||
json.canRestart,
|
||||
json.updatedAt,
|
||||
json.updatedAtMs,
|
||||
json.isDeleted,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ export class HostDetails {
|
||||
public publicAddress: string = "",
|
||||
public tokenValidAfter: number = 0,
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
public updatedAt = 0,
|
||||
public updatedAtMs = 0,
|
||||
public isDeleted = false,
|
||||
) { }
|
||||
|
||||
@@ -96,7 +96,7 @@ export class HostDetails {
|
||||
"remoteAddress": Type.Optional(Type.String()),
|
||||
"publicAddress": Type.Optional(Type.String()),
|
||||
"tokenValidAfter": Type.Optional(Type.Number()),
|
||||
"updatedAt": Type.Optional(Type.Number()),
|
||||
"updatedAtMs": Type.Optional(Type.Number()),
|
||||
"isDeleted": Type.Optional(Type.Boolean()),
|
||||
});
|
||||
|
||||
@@ -109,7 +109,7 @@ export class HostDetails {
|
||||
json.remoteAddress,
|
||||
json.publicAddress,
|
||||
json.tokenValidAfter,
|
||||
json.updatedAt,
|
||||
json.updatedAtMs,
|
||||
json.isDeleted,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ export class InstanceDetails {
|
||||
public gamePort: number | undefined,
|
||||
public status: InstanceStatus,
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
public updatedAt = 0,
|
||||
public updatedAtMs = 0,
|
||||
) { }
|
||||
|
||||
static jsonSchema = Type.Object({
|
||||
@@ -55,7 +55,7 @@ export class InstanceDetails {
|
||||
"unknown", "unassigned", "stopped", "starting", "running", "stopping",
|
||||
"creating_save", "exporting_data", "deleted",
|
||||
]),
|
||||
"updatedAt": Type.Optional(Type.Number()),
|
||||
"updatedAtMs": Type.Optional(Type.Number()),
|
||||
});
|
||||
|
||||
static fromJSON(json: Static<typeof this.jsonSchema>) {
|
||||
@@ -65,7 +65,7 @@ export class InstanceDetails {
|
||||
json.assignedHost,
|
||||
json.gamePort,
|
||||
json.status,
|
||||
json.updatedAt,
|
||||
json.updatedAtMs,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -289,7 +289,7 @@ export class SaveDetails {
|
||||
public loaded: boolean,
|
||||
public loadByDefault: boolean,
|
||||
/** Millisecond Unix timestamp this entry was last updated at */
|
||||
public updatedAt: number,
|
||||
public updatedAtMs: number,
|
||||
public isDeleted: boolean,
|
||||
) { }
|
||||
|
||||
@@ -301,7 +301,7 @@ export class SaveDetails {
|
||||
"mtimeMs": Type.Number(),
|
||||
"loaded": Type.Boolean(),
|
||||
"loadByDefault": Type.Boolean(),
|
||||
"updatedAt": Type.Number(),
|
||||
"updatedAtMs": Type.Number(),
|
||||
"isDeleted": Type.Boolean(),
|
||||
});
|
||||
|
||||
@@ -314,7 +314,7 @@ export class SaveDetails {
|
||||
json.mtimeMs,
|
||||
json.loaded,
|
||||
json.loadByDefault,
|
||||
json.updatedAt,
|
||||
json.updatedAtMs,
|
||||
json.isDeleted,
|
||||
);
|
||||
}
|
||||
@@ -330,8 +330,8 @@ export class SaveDetails {
|
||||
* @returns true if this save is identical to the provided save
|
||||
*/
|
||||
equals(other: SaveDetails) {
|
||||
// Note that updatedAt is not included in the equality check because
|
||||
// instances send the whole list of saves with updatedAt set to zero
|
||||
// Note that updatedAtMs is not included in the equality check because
|
||||
// instances send the whole list of saves with updatedAtMs set to zero
|
||||
// to the controller whenever any save changes and this equals check
|
||||
// is used to filter whether a save was updated.
|
||||
return (
|
||||
|
||||
@@ -22,10 +22,10 @@ export function basicType(value: unknown) {
|
||||
/**
|
||||
* Asynchronously wait for the given duration
|
||||
*
|
||||
* @param duration - Time to wait for in milliseconds.
|
||||
* @param durationMs - Time to wait for in milliseconds.
|
||||
*/
|
||||
export async function wait(duration: number) {
|
||||
await new Promise(resolve => { setTimeout(resolve, duration); });
|
||||
export async function wait(durationMs: number) {
|
||||
await new Promise(resolve => { setTimeout(resolve, durationMs); });
|
||||
}
|
||||
|
||||
|
||||
@@ -33,16 +33,16 @@ export async function wait(duration: number) {
|
||||
* Resolve a promise with a timeout.
|
||||
*
|
||||
* @param {Promise} promise - Promise to wait for.
|
||||
* @param {number} time - Maximum time im milliseconds to wait for.
|
||||
* @param {number} limitMs - Maximum time im milliseconds to wait for.
|
||||
* @param {*=} timeoutResult - Value to return if the operation timed out.
|
||||
*/
|
||||
export async function timeout<T>(promise: Promise<T>, time: number, timeoutResult: T) {
|
||||
export async function timeout<T>(promise: Promise<T>, limitMs: number, timeoutResult: T) {
|
||||
let timer: ReturnType<typeof setTimeout> | undefined;
|
||||
try {
|
||||
return await Promise.race([
|
||||
promise,
|
||||
new Promise<T>(resolve => {
|
||||
timer = setTimeout(() => resolve(timeoutResult), time);
|
||||
timer = setTimeout(() => resolve(timeoutResult), limitMs);
|
||||
}),
|
||||
]);
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ export abstract class WebSocketBaseConnector extends BaseConnector {
|
||||
_state: ConnectorState = "closed";
|
||||
_closing = false;
|
||||
_socket: WebSocketClusterio | null = null;
|
||||
_lastHeartbeat: number | null = null;
|
||||
_lastHeartbeatMs: number | null = null;
|
||||
_heartbeatId: ReturnType<typeof setInterval> | null = null;
|
||||
_heartbeatInterval: number | null = null;
|
||||
_lastReceivedSeq = undefined;
|
||||
@@ -105,7 +105,7 @@ export abstract class WebSocketBaseConnector extends BaseConnector {
|
||||
this._state = "closed";
|
||||
this._closing = false;
|
||||
assert(this._socket === null);
|
||||
this._lastHeartbeat = null;
|
||||
this._lastHeartbeatMs = null;
|
||||
assert(this._heartbeatId === null);
|
||||
this._heartbeatInterval = null;
|
||||
this._lastReceivedSeq = undefined;
|
||||
@@ -117,7 +117,7 @@ export abstract class WebSocketBaseConnector extends BaseConnector {
|
||||
this._state = "connecting";
|
||||
assert(this._closing === false);
|
||||
assert(this._socket);
|
||||
this._lastHeartbeat = null;
|
||||
this._lastHeartbeatMs = null;
|
||||
assert(this._heartbeatId === null);
|
||||
this._heartbeatInterval = null;
|
||||
this._lastReceivedSeq = undefined;
|
||||
@@ -192,7 +192,7 @@ export abstract class WebSocketBaseConnector extends BaseConnector {
|
||||
|
||||
_doHeartbeat() {
|
||||
this._check("connected");
|
||||
if (Date.now() - this._lastHeartbeat! > 2000 * this._heartbeatInterval!) {
|
||||
if (Date.now() - this._lastHeartbeatMs! > 2000 * this._heartbeatInterval!) {
|
||||
logger.verbose("Connector | closing after heartbeat timed out");
|
||||
// eslint-disable-next-line node/no-process-env
|
||||
if (process.env.APP_ENV === "browser") {
|
||||
@@ -207,7 +207,7 @@ export abstract class WebSocketBaseConnector extends BaseConnector {
|
||||
}
|
||||
|
||||
_processHeartbeat(message: libData.MessageHeartbeat) {
|
||||
this._lastHeartbeat = Date.now();
|
||||
this._lastHeartbeatMs = Date.now();
|
||||
this._dropSendBufferSeq(message.seq);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ export abstract class WebSocketBaseConnector extends BaseConnector {
|
||||
if (this._heartbeatId) {
|
||||
throw new Error("heartbeat is already running");
|
||||
}
|
||||
this._lastHeartbeat = Date.now();
|
||||
this._lastHeartbeatMs = Date.now();
|
||||
this._heartbeatId = setInterval(() => {
|
||||
this._doHeartbeat();
|
||||
}, this._heartbeatInterval! * 1000);
|
||||
@@ -327,7 +327,7 @@ export abstract class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
_reconnectId?: ReturnType<typeof setTimeout>;
|
||||
_sessionToken: string | null = null;
|
||||
_sessionTimeout: number | null = null;
|
||||
_startedResuming: number | null = null;
|
||||
_startedResumingMs: number | null = null;
|
||||
_backoff: ExponentialBackoff;
|
||||
|
||||
constructor(
|
||||
@@ -350,7 +350,7 @@ export abstract class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
this._reconnectId = undefined;
|
||||
this._sessionToken = null;
|
||||
this._sessionTimeout = null;
|
||||
this._startedResuming = null;
|
||||
this._startedResumingMs = null;
|
||||
super._reset();
|
||||
this.src = undefined as any;
|
||||
}
|
||||
@@ -359,7 +359,7 @@ export abstract class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
assert(this._reconnectId === undefined);
|
||||
this._sessionToken = null;
|
||||
this._sessionTimeout = null;
|
||||
this._startedResuming = null;
|
||||
this._startedResumingMs = null;
|
||||
super._invalidate();
|
||||
this.src = undefined as any;
|
||||
}
|
||||
@@ -473,10 +473,10 @@ export abstract class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
logger.error("Unexpected double call to reconnect");
|
||||
}
|
||||
|
||||
let delay = this._backoff.delay();
|
||||
let delayMs = this._backoff.delay();
|
||||
if (
|
||||
this._state === "resuming"
|
||||
&& this._startedResuming! + this._sessionTimeout! * 1000 < Date.now() + delay
|
||||
&& this._startedResumingMs! + this._sessionTimeout! * 1000 < Date.now() + delayMs
|
||||
) {
|
||||
logger.error("Connector | Session timed out trying to resume");
|
||||
this._reset();
|
||||
@@ -489,12 +489,12 @@ export abstract class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
}
|
||||
}
|
||||
logger.verbose(
|
||||
`Connector | waiting ${(Math.round(delay / 10) / 100)} seconds for reconnect`
|
||||
`Connector | waiting ${(Math.round(delayMs / 10) / 100)} seconds for reconnect`
|
||||
);
|
||||
this._reconnectId = setTimeout(() => {
|
||||
this._reconnectId = undefined;
|
||||
this._doConnect();
|
||||
}, delay);
|
||||
}, delayMs);
|
||||
}
|
||||
|
||||
_attachSocketHandlers() {
|
||||
@@ -516,7 +516,7 @@ export abstract class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
|
||||
} else {
|
||||
this._state = "resuming";
|
||||
this._startedResuming = Date.now();
|
||||
this._startedResumingMs = Date.now();
|
||||
this.reconnect();
|
||||
this.emit("drop");
|
||||
}
|
||||
@@ -625,7 +625,7 @@ export abstract class WebSocketClientConnector extends WebSocketBaseConnector {
|
||||
for (let bufferedMessage of this._sendBuffer) {
|
||||
this._sendInternal(bufferedMessage);
|
||||
}
|
||||
this._startedResuming = null;
|
||||
this._startedResumingMs = null;
|
||||
this.emit("resume");
|
||||
|
||||
} else if (type === "invalidate") {
|
||||
|
||||
@@ -740,10 +740,10 @@ class GaugeChild extends ValueCollectorChild {
|
||||
* seconds from when the timer was started
|
||||
*/
|
||||
startTimer() {
|
||||
let start = process.hrtime.bigint();
|
||||
let startNs = process.hrtime.bigint();
|
||||
return () => {
|
||||
let end = process.hrtime.bigint();
|
||||
this.set(Number(end - start) / 1e9);
|
||||
let endNs = process.hrtime.bigint();
|
||||
this.set(Number(endNs - startNs) / 1e9);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -979,10 +979,10 @@ class SummaryChild {
|
||||
* when the timer was started into the metric.
|
||||
*/
|
||||
startTimer() {
|
||||
let start = process.hrtime.bigint();
|
||||
let startNs = process.hrtime.bigint();
|
||||
return () => {
|
||||
let end = process.hrtime.bigint();
|
||||
this.observe(Number(end - start) / 1e9);
|
||||
let endNs = process.hrtime.bigint();
|
||||
this.observe(Number(endNs - startNs) / 1e9);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1260,10 +1260,10 @@ class HistogramChild {
|
||||
* when the timer was started into the metric.
|
||||
*/
|
||||
startTimer() {
|
||||
let start = process.hrtime.bigint();
|
||||
let startNs = process.hrtime.bigint();
|
||||
return () => {
|
||||
let end = process.hrtime.bigint();
|
||||
this.observe(Number(end - start) / 1e9);
|
||||
let endNs = process.hrtime.bigint();
|
||||
this.observe(Number(endNs - startNs) / 1e9);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export class SubscriptionRequest {
|
||||
constructor(
|
||||
public eventName: string,
|
||||
public subscribe: boolean,
|
||||
public lastRequestTime: number = 0,
|
||||
public lastRequestTimeMs: number = 0,
|
||||
) {
|
||||
if (!Link._eventsByName.has(eventName)) {
|
||||
throw new Error(`Unregistered Event class ${eventName}`);
|
||||
@@ -47,7 +47,7 @@ export class SubscriptionRequest {
|
||||
]);
|
||||
|
||||
toJSON() {
|
||||
return [this.eventName, this.subscribe, this.lastRequestTime];
|
||||
return [this.eventName, this.subscribe, this.lastRequestTimeMs];
|
||||
}
|
||||
|
||||
static fromJSON(json: Static<typeof SubscriptionRequest.jsonSchema>): SubscriptionRequest {
|
||||
@@ -152,7 +152,7 @@ export class SubscriptionController {
|
||||
|
||||
export interface SubscribableValue {
|
||||
id: number | string,
|
||||
updatedAt: number,
|
||||
updatedAtMs: number,
|
||||
isDeleted: boolean,
|
||||
}
|
||||
|
||||
@@ -175,8 +175,8 @@ export class EventSubscriber<
|
||||
/** True if this subscriber is currently synced with the source */
|
||||
synced = false;
|
||||
_snapshot?: readonly [ReadonlyMap<K, Readonly<V>>, boolean];
|
||||
_snapshotLastUpdated = 0;
|
||||
lastResponseTime = -1;
|
||||
_snapshotLastUpdatedMs = 0;
|
||||
lastResponseTimeMs = -1;
|
||||
|
||||
constructor(
|
||||
private Event: EventClass<T>,
|
||||
@@ -203,7 +203,7 @@ export class EventSubscriber<
|
||||
*/
|
||||
async _handle(event: EventSubscribable<T, V>) {
|
||||
for (const value of event.updates) {
|
||||
this.lastResponseTime = Math.max(this.lastResponseTime, value.updatedAt);
|
||||
this.lastResponseTimeMs = Math.max(this.lastResponseTimeMs, value.updatedAtMs);
|
||||
if (value.isDeleted) {
|
||||
this.values.delete(value.id as K);
|
||||
} else {
|
||||
@@ -257,8 +257,8 @@ export class EventSubscriber<
|
||||
* @returns tuple of values map snapshot and synced property.
|
||||
*/
|
||||
getSnapshot() {
|
||||
if (this._snapshotLastUpdated !== this.lastResponseTime) {
|
||||
this._snapshotLastUpdated = this.lastResponseTime;
|
||||
if (this._snapshotLastUpdatedMs !== this.lastResponseTimeMs) {
|
||||
this._snapshotLastUpdatedMs = this.lastResponseTimeMs;
|
||||
this._snapshot = [new Map(this.values), this.synced];
|
||||
}
|
||||
return this._snapshot!;
|
||||
@@ -277,10 +277,10 @@ export class EventSubscriber<
|
||||
await this.control.send(new SubscriptionRequest(
|
||||
entry.name,
|
||||
this._callbacks.length > 0,
|
||||
this.lastResponseTime
|
||||
this.lastResponseTimeMs
|
||||
));
|
||||
this.synced = this._callbacks.length > 0;
|
||||
this._snapshotLastUpdated = 0;
|
||||
this._snapshotLastUpdatedMs = 0;
|
||||
for (let callback of this._callbacks) {
|
||||
callback([], this.synced);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export function formatDuration(ms: number): string {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function formatTimestamp(timestamp: number): string {
|
||||
export function formatTimestamp(timestampMs: number): string {
|
||||
const options = {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
@@ -39,5 +39,5 @@ export function formatTimestamp(timestamp: number): string {
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
} as const;
|
||||
return new Intl.DateTimeFormat(undefined, options).format(new Date(timestamp));
|
||||
return new Intl.DateTimeFormat(undefined, options).format(new Date(timestampMs));
|
||||
}
|
||||
@@ -36,7 +36,7 @@ async function saveDatabase(
|
||||
}
|
||||
|
||||
export class ControllerPlugin extends BaseControllerPlugin {
|
||||
acquiredPlayers!: Map<string, { instanceId: number, expires?: number }>;
|
||||
acquiredPlayers!: Map<string, { instanceId: number, expiresMs?: number }>;
|
||||
playerDatastore!: Map<string, IpcPlayerData>;
|
||||
playerDatastoreDirty = false;
|
||||
|
||||
@@ -62,18 +62,18 @@ export class ControllerPlugin extends BaseControllerPlugin {
|
||||
}
|
||||
|
||||
if (["unknown", "stopped"].includes(instance.status)) {
|
||||
let timeout = this.controller.config.get("inventory_sync.player_lock_timeout") * 1000;
|
||||
let timeoutMs = this.controller.config.get("inventory_sync.player_lock_timeout") * 1000;
|
||||
for (let acquisitonRecord of this.acquiredPlayers.values()) {
|
||||
if (acquisitonRecord.instanceId === instanceId && !acquisitonRecord.expires) {
|
||||
acquisitonRecord.expires = Date.now() + timeout;
|
||||
if (acquisitonRecord.instanceId === instanceId && !acquisitonRecord.expiresMs) {
|
||||
acquisitonRecord.expiresMs = Date.now() + timeoutMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (instance.status === "running") {
|
||||
for (let acquisitonRecord of this.acquiredPlayers.values()) {
|
||||
if (acquisitonRecord.instanceId === instanceId && acquisitonRecord.expires) {
|
||||
delete acquisitonRecord.expires;
|
||||
if (acquisitonRecord.instanceId === instanceId && acquisitonRecord.expiresMs) {
|
||||
delete acquisitonRecord.expiresMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ export class ControllerPlugin extends BaseControllerPlugin {
|
||||
!acquisitionRecord
|
||||
|| acquisitionRecord.instanceId === instanceId
|
||||
|| !this.controller.instances.has(acquisitionRecord.instanceId)
|
||||
|| acquisitionRecord.expires && acquisitionRecord.expires < Date.now()
|
||||
|| acquisitionRecord.expiresMs && acquisitionRecord.expiresMs < Date.now()
|
||||
) {
|
||||
this.acquiredPlayers.set(playerName, { instanceId });
|
||||
return true;
|
||||
|
||||
@@ -26,7 +26,7 @@ async function generateCode(length: number): Promise<string> {
|
||||
}
|
||||
|
||||
|
||||
type PlayerCode = { playerCode: string, verifyCode: string | null, expires: number };
|
||||
type PlayerCode = { playerCode: string, verifyCode: string | null, expiresMs: number };
|
||||
|
||||
export class ControllerPlugin extends BaseControllerPlugin {
|
||||
players!: Map<string, PlayerCode>;
|
||||
@@ -39,7 +39,7 @@ export class ControllerPlugin extends BaseControllerPlugin {
|
||||
setInterval(() => {
|
||||
let now = Date.now();
|
||||
for (let [player, entry] of this.players) {
|
||||
if (entry.expires < now) {
|
||||
if (entry.expiresMs < now) {
|
||||
this.players.delete(player);
|
||||
}
|
||||
}
|
||||
@@ -88,13 +88,13 @@ export class ControllerPlugin extends BaseControllerPlugin {
|
||||
}
|
||||
|
||||
for (let entry of this.players.values()) {
|
||||
if (entry.playerCode === playerCode && entry.expires > Date.now()) {
|
||||
if (entry.playerCode === playerCode && entry.expiresMs > Date.now()) {
|
||||
let verifyCode = await generateCode(this.controller.config.get("player_auth.code_length"));
|
||||
let secret = Buffer.from(this.controller.config.get("controller.auth_secret"), "base64");
|
||||
let verifyToken = jwt.sign(
|
||||
{
|
||||
aud: "player_auth.verify_code",
|
||||
exp: Math.floor(entry.expires / 1000),
|
||||
exp: Math.floor(entry.expiresMs / 1000),
|
||||
verify_code: verifyCode,
|
||||
player_code: playerCode,
|
||||
},
|
||||
@@ -150,7 +150,7 @@ export class ControllerPlugin extends BaseControllerPlugin {
|
||||
}
|
||||
|
||||
for (let [player, entry] of this.players) {
|
||||
if (entry.playerCode === playerCode && entry.expires > Date.now()) {
|
||||
if (entry.playerCode === playerCode && entry.expiresMs > Date.now()) {
|
||||
if (entry.verifyCode === verifyCode) {
|
||||
let user = this.controller.userManager.users.get(player);
|
||||
if (!user) {
|
||||
@@ -174,8 +174,8 @@ export class ControllerPlugin extends BaseControllerPlugin {
|
||||
|
||||
async handleFetchPlayerCodeRequest(request: FetchPlayerCodeRequest) {
|
||||
let playerCode = await generateCode(this.controller.config.get("player_auth.code_length"));
|
||||
let expires = Date.now() + this.controller.config.get("player_auth.code_timeout") * 1000;
|
||||
this.players.set(request.player, { playerCode, verifyCode: null, expires });
|
||||
let expiresMs = Date.now() + this.controller.config.get("player_auth.code_timeout") * 1000;
|
||||
this.players.set(request.player, { playerCode, verifyCode: null, expiresMs });
|
||||
return { player_code: playerCode, controller_url: this.controller.getControllerUrl() };
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ export class ControllerPlugin extends BaseControllerPlugin {
|
||||
let { player, verifyCode } = request;
|
||||
|
||||
let entry = this.players.get(player);
|
||||
if (!entry || entry.expires < Date.now()) {
|
||||
if (!entry || entry.expiresMs < Date.now()) {
|
||||
throw new lib.RequestError("invalid player");
|
||||
}
|
||||
|
||||
|
||||
@@ -123,8 +123,8 @@ describe("player_auth", function() {
|
||||
}
|
||||
});
|
||||
it("should return invalid player_code if the code is expired", async function() {
|
||||
let expires = Date.now() - 1000;
|
||||
controllerPlugin.players.set("expired", { playerCode: "expried", verifyCode: null, expires });
|
||||
let expiresMs = Date.now() - 1000;
|
||||
controllerPlugin.players.set("expired", { playerCode: "expired", verifyCode: null, expiresMs });
|
||||
let result = await phin({
|
||||
url: `${controllerUrl}/api/player_auth/player_code`,
|
||||
method: "POST",
|
||||
@@ -134,8 +134,8 @@ describe("player_auth", function() {
|
||||
assert.deepEqual(result.body, { error: true, message: "invalid player_code" });
|
||||
});
|
||||
it("should return a verify code and token if code is valid", async function() {
|
||||
let expires = Date.now() + 1000;
|
||||
controllerPlugin.players.set("valid", { playerCode: "valid", verifyCode: null, expires });
|
||||
let expiresMs = Date.now() + 1000;
|
||||
controllerPlugin.players.set("valid", { playerCode: "valid", verifyCode: null, expiresMs });
|
||||
let result = await phin({
|
||||
url: `${controllerUrl}/api/player_auth/player_code`,
|
||||
method: "POST",
|
||||
@@ -214,8 +214,8 @@ describe("player_auth", function() {
|
||||
await verify({ aud: "not_player_auth" });
|
||||
});
|
||||
it("should return invalid player_code if the code is expired", async function() {
|
||||
let expires = Date.now() - 1000;
|
||||
controllerPlugin.players.set("expired", { playerCode: "expried", verifyCode: "verify", expires });
|
||||
let expiresMs = Date.now() - 1000;
|
||||
controllerPlugin.players.set("expired", { playerCode: "expired", verifyCode: "verify", expiresMs });
|
||||
let result = await phin({
|
||||
url: `${controllerUrl}/api/player_auth/verify`,
|
||||
method: "POST",
|
||||
@@ -233,8 +233,11 @@ describe("player_auth", function() {
|
||||
assert.deepEqual(result.body, { error: true, message: "invalid player_code" });
|
||||
});
|
||||
it("should return verified false if verify code has not yet been set", async function() {
|
||||
let expires = Date.now() + 1000;
|
||||
controllerPlugin.players.set("unverified", { playerCode: "unverified", verifyCode: null, expires });
|
||||
let expiresMs = Date.now() + 1000;
|
||||
controllerPlugin.players.set(
|
||||
"unverified",
|
||||
{ playerCode: "unverified", verifyCode: null, expiresMs },
|
||||
);
|
||||
let result = await phin({
|
||||
url: `${controllerUrl}/api/player_auth/verify`,
|
||||
method: "POST",
|
||||
@@ -252,8 +255,8 @@ describe("player_auth", function() {
|
||||
assert.deepEqual(result.body, { verified: false });
|
||||
});
|
||||
it("should return error if user is missing", async function() {
|
||||
let expires = Date.now() + 1000;
|
||||
controllerPlugin.players.set("missing", { playerCode: "missing", verifyCode: "verify", expires });
|
||||
let expiresMs = Date.now() + 1000;
|
||||
controllerPlugin.players.set("missing", { playerCode: "missing", verifyCode: "verify", expiresMs });
|
||||
let result = await phin({
|
||||
url: `${controllerUrl}/api/player_auth/verify`,
|
||||
method: "POST",
|
||||
@@ -271,8 +274,8 @@ describe("player_auth", function() {
|
||||
assert.deepEqual(result.body, { error: true, message: "invalid user" });
|
||||
});
|
||||
it("should return verified true with token if valid verification", async function() {
|
||||
let expires = Date.now() + 1000;
|
||||
controllerPlugin.players.set("player", { playerCode: "player", verifyCode: "verify", expires });
|
||||
let expiresMs = Date.now() + 1000;
|
||||
controllerPlugin.players.set("player", { playerCode: "player", verifyCode: "verify", expiresMs });
|
||||
let result = await phin({
|
||||
url: `${controllerUrl}/api/player_auth/verify`,
|
||||
method: "POST",
|
||||
@@ -299,8 +302,8 @@ describe("player_auth", function() {
|
||||
);
|
||||
assert(typeof result.player_code === "string", "no code returned");
|
||||
assert(result.player_code.length === 10, "incorrect code length returned");
|
||||
let expires = controllerPlugin.players.get("test").expires;
|
||||
let msFromExpected = Math.abs(expires - Date.now() - 1000);
|
||||
let expiresMs = controllerPlugin.players.get("test").expiresMs;
|
||||
let msFromExpected = Math.abs(expiresMs - Date.now() - 1000);
|
||||
assert(msFromExpected < 100, `expiry time expected outside window (${msFromExpected}ms)`);
|
||||
});
|
||||
});
|
||||
@@ -315,8 +318,8 @@ describe("player_auth", function() {
|
||||
);
|
||||
});
|
||||
it("should throw if player code has expired", async function() {
|
||||
let expires = Date.now() - 1000;
|
||||
controllerPlugin.players.set("expired", { playerCode: "expried", verifyCode: null, expires });
|
||||
let expiresMs = Date.now() - 1000;
|
||||
controllerPlugin.players.set("expired", { playerCode: "expired", verifyCode: null, expiresMs });
|
||||
await assert.rejects(
|
||||
controllerPlugin.handleSetVerifyCodeRequest(
|
||||
new SetVerifyCodeRequest("expired", "expired")
|
||||
|
||||
@@ -109,8 +109,8 @@ export class InstancePlugin extends BaseInstancePlugin {
|
||||
// take a long time for the command to go through if the command
|
||||
// stream is overloaded. Should the timeout be exceeded the
|
||||
// previous values for the metrics will end up being sent to controller.
|
||||
let timeout = this.instance.config.get("statistics_exporter.command_timeout") * 1000;
|
||||
await lib.timeout(this.gatherMetrics(), timeout, undefined);
|
||||
let timeoutMs = this.instance.config.get("statistics_exporter.command_timeout") * 1000;
|
||||
await lib.timeout(this.gatherMetrics(), timeoutMs, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ describe("controller/InstanceInfo", function() {
|
||||
check(InstanceInfo.fromJSON({ config, status: "stopped" }, "controller"));
|
||||
check(InstanceInfo.fromJSON({ config, status: "running" }, "controller"));
|
||||
check(InstanceInfo.fromJSON({ config, status: "running", gamePort: 34197 }, "controller"));
|
||||
check(InstanceInfo.fromJSON({ config, status: "running", updatedAt: Date.now() }, "controller"));
|
||||
check(InstanceInfo.fromJSON({ config, status: "running", updatedAtMs: Date.now() }, "controller"));
|
||||
|
||||
// All at once
|
||||
check(InstanceInfo.fromJSON({
|
||||
|
||||
@@ -64,7 +64,7 @@ describe("class Instance", function() {
|
||||
"player",
|
||||
new PlayerStats({
|
||||
join_count: 1,
|
||||
last_join_at: stats.lastJoinAt.getTime(),
|
||||
last_join_at_ms: stats.lastJoinAt.getTime(),
|
||||
})
|
||||
)
|
||||
),
|
||||
@@ -111,8 +111,8 @@ describe("class Instance", function() {
|
||||
new PlayerStats({
|
||||
join_count: 1,
|
||||
online_time_ms: stats.onlineTimeMs,
|
||||
last_join_at: stats.lastJoinAt.getTime(),
|
||||
last_leave_at: stats.lastLeaveAt.getTime(),
|
||||
last_join_at_ms: stats.lastJoinAt.getTime(),
|
||||
last_leave_at_ms: stats.lastLeaveAt.getTime(),
|
||||
last_leave_reason: "quit",
|
||||
}),
|
||||
"quit",
|
||||
@@ -162,7 +162,7 @@ describe("class Instance", function() {
|
||||
"foo",
|
||||
new PlayerStats({
|
||||
join_count: 1,
|
||||
last_join_at: stats.lastJoinAt.getTime(),
|
||||
last_join_at_ms: stats.lastJoinAt.getTime(),
|
||||
})
|
||||
)
|
||||
)
|
||||
@@ -185,8 +185,8 @@ describe("class Instance", function() {
|
||||
new PlayerStats({
|
||||
join_count: 1,
|
||||
online_time_ms: stats.onlineTimeMs,
|
||||
last_join_at: stats.lastJoinAt.getTime(),
|
||||
last_leave_at: stats.lastLeaveAt.getTime(),
|
||||
last_join_at_ms: stats.lastJoinAt.getTime(),
|
||||
last_leave_at_ms: stats.lastLeaveAt.getTime(),
|
||||
last_leave_reason: "quit",
|
||||
}),
|
||||
"quit",
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ describe("host/server", function() {
|
||||
if (process.platform === "win32") {
|
||||
this.skip();
|
||||
}
|
||||
server.hangTimeout = 20;
|
||||
server.hangTimeoutMs = 20;
|
||||
server._server = new events.EventEmitter();
|
||||
server._server.kill = () => true;
|
||||
server._state = "running";
|
||||
|
||||
@@ -113,7 +113,7 @@ describe("Integration of Clusterio", function() {
|
||||
let controlB = new TestControl(connectorB);
|
||||
connectorB._sessionToken = connectorA._sessionToken;
|
||||
connectorB._sessionTimeout = connectorA._sessionTimeout;
|
||||
connectorB._startedResuming = Date.now();
|
||||
connectorB._startedResumingMs = Date.now();
|
||||
connectorB._state = "resuming";
|
||||
connectorB._doConnect();
|
||||
await events.once(connectorB, "resume");
|
||||
@@ -898,7 +898,7 @@ describe("Integration of Clusterio", function() {
|
||||
reference.settings["runtime-global"].set("MyInt", { value: 1235 });
|
||||
reference.settings["runtime-global"].set("MyDouble", { value: 12.25 });
|
||||
reference.settings["runtime-per-user"].set("MyString", { value: "a-string" });
|
||||
reference.updatedAt = modPack.updatedAt;
|
||||
reference.updatedAtMs = modPack.updatedAtMs;
|
||||
assert.deepEqual(modPack, reference);
|
||||
});
|
||||
});
|
||||
@@ -1003,7 +1003,7 @@ describe("Integration of Clusterio", function() {
|
||||
"dependencies:\n" +
|
||||
`size: ${stat.size}\n` +
|
||||
`sha1: ${hash}\n` +
|
||||
`updatedAt: ${stat.mtimeMs}\n` +
|
||||
`updatedAtMs: ${stat.mtimeMs}\n` +
|
||||
"isDeleted: false\n",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@ describe("lib/ExponentialBackoff", function() {
|
||||
for (let max of [0.1, 0.5, 1, 2, 50, 100, 1000, 100000]) {
|
||||
let backoff = new ExponentialBackoff({ base: 1, max });
|
||||
for (let j = 0; j < 100; j++) {
|
||||
let value = backoff.delay() / 1000; // Divide by 100 for ms to s conversion
|
||||
let value = backoff.delay() / 1000; // Divide by 1000 for ms to s conversion
|
||||
assert(value <= max, `delay returned a value greater than max: ${value} > ${max}`);
|
||||
}
|
||||
}
|
||||
@@ -46,10 +46,10 @@ describe("lib/ExponentialBackoff", function() {
|
||||
let backoff = new ExponentialBackoff({ reset: 100 });
|
||||
backoff.delay();
|
||||
assert.equal(backoff._exp, 1);
|
||||
backoff._lastInvocationTime = Date.now() - 99 * 1000;
|
||||
backoff._lastInvocationTimeMs = Date.now() - 99 * 1000;
|
||||
backoff.delay();
|
||||
assert.equal(backoff._exp, 2);
|
||||
backoff._lastInvocationTime = Date.now() - 101 * 1000;
|
||||
backoff._lastInvocationTimeMs = Date.now() - 101 * 1000;
|
||||
backoff.delay();
|
||||
assert.equal(backoff._exp, 1);
|
||||
});
|
||||
|
||||
@@ -92,7 +92,7 @@ describe("lib/data/ModInfo", function() {
|
||||
dependencies: [],
|
||||
filename: "empty_mod_1.0.0.zip",
|
||||
size: stat.size,
|
||||
updated_at: stat.mtimeMs,
|
||||
updated_at_ms: stat.mtimeMs,
|
||||
sha1: hash,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -28,15 +28,15 @@ describe("lib/data/User", function() {
|
||||
[1, {
|
||||
join_count: 1,
|
||||
online_time_ms: 60e3,
|
||||
last_join_at: new Date("2020-05T12:00Z").getTime(),
|
||||
last_leave_at: new Date("2020-05T12:01Z").getTime(),
|
||||
last_join_at_ms: new Date("2020-05T12:00Z").getTime(),
|
||||
last_leave_at_ms: new Date("2020-05T12:01Z").getTime(),
|
||||
last_leave_reason: "quit",
|
||||
}],
|
||||
[2, {
|
||||
join_count: 1,
|
||||
online_time_ms: 0,
|
||||
first_join_at: new Date("2020-05T12:00Z").getTime(),
|
||||
last_join_at: new Date("2020-05T12:02Z").getTime(),
|
||||
first_join_at_ms: new Date("2020-05T12:00Z").getTime(),
|
||||
last_join_at_ms: new Date("2020-05T12:02Z").getTime(),
|
||||
}],
|
||||
]});
|
||||
|
||||
@@ -52,9 +52,9 @@ describe("lib/data/User", function() {
|
||||
lib.PlayerStats.fromJSON({
|
||||
join_count: 2,
|
||||
online_time_ms: 120e3,
|
||||
first_join_at: new Date("2020-05T11:00Z").getTime(),
|
||||
last_join_at: new Date("2020-05T13:00Z").getTime(),
|
||||
last_leave_at: new Date("2020-05T13:02Z").getTime(),
|
||||
first_join_at_ms: new Date("2020-05T11:00Z").getTime(),
|
||||
last_join_at_ms: new Date("2020-05T13:00Z").getTime(),
|
||||
last_leave_at_ms: new Date("2020-05T13:02Z").getTime(),
|
||||
last_leave_reason: "afk",
|
||||
}),
|
||||
);
|
||||
|
||||
+2
-2
@@ -21,10 +21,10 @@ describe("lib/helpers", function() {
|
||||
it("should wait the approximate amount of time given", async function() {
|
||||
let startNs = hrtime();
|
||||
await lib.wait(100);
|
||||
let duration = Number(hrtime() - startNs) / 1e6;
|
||||
let durationMs = Number(hrtime() - startNs) / 1e6;
|
||||
|
||||
// On windows the time waited is normally up to 15 ms late with outliers in the 20ms range.
|
||||
assert(duration > 90 && duration < 130, `duration (${duration}ms) not within (90-130)`);
|
||||
assert(durationMs > 90 && durationMs < 130, `duration (${durationMs}ms) not within (90-130)`);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -347,7 +347,7 @@ describe("lib/subscriptions", function() {
|
||||
it("should allow subscriptions to an event", async function() {
|
||||
let calledWith = null;
|
||||
let calledWithTwo = null;
|
||||
const item = { id: 1, updatedAt: 1, isDeleted: false };
|
||||
const item = { id: 1, updatedAtMs: 1, isDeleted: false };
|
||||
const event = new RegisteredEvent([item]);
|
||||
registeredEvent.subscribe(function(updates, synced) { calledWith = [updates, synced]; });
|
||||
registeredEvent.subscribe(function(updates, synced) { calledWithTwo = [updates, synced]; });
|
||||
@@ -382,9 +382,12 @@ describe("lib/subscriptions", function() {
|
||||
|
||||
describe("getSnapshot()", function() {
|
||||
it("should give an immutable copy of the tracked values", async function() {
|
||||
const update1 = [{ id: 1, updatedAt: 1, isDeleted: false }];
|
||||
const update2 = [{ id: 1, updatedAt: 2, isDeleted: false }, { id: 2, updatedAt: 3, isDeleted: false }];
|
||||
const update3 = [{ id: 1, updatedAt: 4, isDeleted: true }];
|
||||
const update1 = [{ id: 1, updatedAtMs: 1, isDeleted: false }];
|
||||
const update2 = [
|
||||
{ id: 1, updatedAtMs: 2, isDeleted: false },
|
||||
{ id: 2, updatedAtMs: 3, isDeleted: false },
|
||||
];
|
||||
const update3 = [{ id: 1, updatedAtMs: 4, isDeleted: true }];
|
||||
const snap0 = registeredEvent.getSnapshot();
|
||||
assert.deepEqual(snap0, [new Map(), false]);
|
||||
await registeredEvent._handle(new RegisteredEvent(update1));
|
||||
|
||||
Reference in new issue
Block a user