// Copyright 2020 Campbell Crowley. All rights reserved. // Author: Campbell Crowley (web@campbellcrowley.com) /** * @description Stores information about a single shard necessary for * the ShardingMaster to operate. * @class * @memberof ShardingMaster * @inner * @static */ class ShardInfo { /** * @description Create new instance. * @param {string} id The ID of the shard this status object contains data * for. */ constructor(id) { if (typeof id !== 'string' || id.length < 3) { throw new TypeError('Invalid Shard ID for ShardInfo object: ' + id); } /** * @description The ID of the shard this status object contains data for. * @public * @type {string} */ this.id = id; /** * @description The public key identifying this shard, used for signing and * verification. * @public * @type {?string} * @default */ this.key = null; /** * @description Is this shard considered the master shard. There must be * exactly one of these configured at all times, and in most cases can run * in the same directory as the ShardingMaster. This shard will be told to * not connect to Discord, and act as the master node for web requests. * @public * @type {boolean} * @default */ this.isMaster = false; /** * @description Timestamp of the last time the shard has been seen. This * will be 0 if the shard has never attempted to communicate with the * master. * @public * @type {number} * @default */ this.lastSeen = 0; /** * @description The last time at which a valid heartbeat was received from * the shard indicating that it is still alive. * @public * @type {number} * @default */ this.lastHeartbeat = 0; /** * @description The timestamp at which the information for this shard was * created, and sent to a sysadmin. * @public * @type {number} * @default */ this.createdTime = Date.now(); /** * @description The most recent timestamp at which the shard was told to * boot up. * @public * @type {number} * @default */ this.bootTime = 0; /** * @description The most recent timestamp at which the shard was told to * shut down. * @public * @type {number} * @default */ this.stopTime = 0; /** * @description The Discord shard ID this shard should be currently. A value * less than 0 means the shard should be shutdown. * @public * @type {number} * @default */ this.goalShardId = -1; /** * @description The Discord shard ID this shard currently is. A value less * than 0 means the shard is currently shutdown. * @public * @type {number} * @default */ this.currentShardId = -1; /** * @description The number of shards intended to be running currently. A * value of 1 or less denotes this is the only shard. A default value of -1 * is used to be similar to the ID values, but any value less than 2 is * semantically the identical. * @public * @type {number} * @default */ this.goalShardCount = -1; /** * @description The number of shards intended to be running according to * this shard's current configuration. A value of 1 or less denotes this is * the only shard. A default value of -1 is used to be similar to the ID * values, but any value less than 2 is semantically the identical. * @public * @type {number} * @default */ this.currentShardCount = -1; /** * @description ShardStatus instance for this shard if it's been received. * @public * @type {?ShardingMaster.ShardStatus} * @default */ this.stats = null; } /** * @description Get the version of this object that can be converted to a * string. Additionally, this will only contain the data intended to be saved * to disk. `stats` will be excluded, and is intended to be saved separately. * @public * @returns {object} Serializable version of ShardInfo. */ get serializable() { const all = Object.entries(Object.getOwnPropertyDescriptors(this)); const output = {}; for (const one of all) { if (typeof one[1].value === 'function' || one[0].startsWith('_')) { continue; } else if (one[0] === 'stats') { continue; } else if (one[1].value && one[1].value.serializable) { output[one[0]] = one[1].value.serializable; } else { output[one[0]] = one[1].value; } } return output; } /** * @description Format this object into a request for a shard's state. This * does not handle cold stops or full reboots, only modifying running state of * the shard. * @public * @returns {object} Object with minimal data to inform the shard how it * should currently be configured. */ request() { return { id: this.goalShardId, count: this.goalShardCount, master: this.isMaster, }; } /** * @description Convert a given object to a ShardInfo object. Values are only * copied if their types exactly match. * @public * @static * @param {object} obj The ShardInfo-like object to copy. * @param {string} [id] If the given object does not specify the shard's ID, * it may be passed here instead. * @returns {ShardingMaster.ShardInfo} Created ShardInfo object. */ static from(obj, id) { const out = new ShardInfo(id || obj.id); for (const prop of Object.keys(out)) { if (prop === 'id') continue; if (typeof out[prop] === 'function') continue; if (out[prop] !== null && typeof out[prop] !== typeof obj[prop]) continue; out[prop] = obj[prop]; } return out; } } module.exports = ShardInfo;