// Copyright 2020 Campbell Crowley. All rights reserved. // Author: Campbell Crowley (web@campbellcrowley.com) /** * @description Configuration for the Shard Master. This config will be updated * during runtime if it is edited. Relevant settings may be sent to each shard * during each initial setup. * @class * @memberof ShardingMaster * @inner * @static */ class ShardMasterConfig { /** * @description Create config object. */ constructor() { /** * @description The number of shards to start if auto detection is turned * off. * @default * @public * @type {number} */ this.numShards = 2; /** * @description Whether to use the shard count Discord recommends for us. If * true, the bot name must be specified, and the corresponding token must be * available in `../auth.js`. * @default * @public * @type {boolean} */ this.autoDetectNumShards = false; /** * @description The interval to check for how many shards we should have at * one time, in milliseconds. * @public * @default * @type {number} */ this.autoDetectInterval = 24 * 60 * 60 * 1000; /** * @description The name of the bot that corresponds to the token to use in * `../auth.js`. * @default * @public * @type {string} */ this.botName = 'release'; /** * @description CLI args to pass to NodeJS when spawning a shard. * @public * @type {string[]} * @default */ this.shardNodeLaunchArgs = ['--max-old-space-size=2048']; /** * @description Arguments to pass to the bot's scripts when the shard is * started. * @public * @type {string[]} * @default */ this.shardBotLaunchArgs = []; /** * @description The largest acceptable difference in timestamp values * received from shards in milliseconds. * @public * @default * @type {number} * @default 5 Minutes */ this.tsPrecision = 1000 * 60 * 5; /** * @description The maximum number of connection attempts within * {@link connTime} before the IP address is blocked. * @public * @default * @type {number} */ this.connCount = 10; /** * @description The duration in milliseconds to store connection attempt * history. * @public * @default * @type {number} */ this.connTime = 10000; /** * @description Delay between shard reboot requests in milliseconds. * @public * @type {number} * @default */ this.respawnDelay = 5000; /** * @description Host information for remote shards to use in order to be * able to find us. * @public * @type {object} * @default */ this.remoteHost = { host: 'kamino.spikeybot.com', port: 443, protocol: 'https:', path: '/socket.io/', }; /** * @description Host information for the master shard to use in order to be * able to find us. * @public * @type {object} * @default */ this.masterHost = { host: 'localhost', port: 8024, protocol: 'http:', path: '/socket.io/', }; /** * @description Paths to files to send to slave shards every time they * successfully connect. These are expected to be immediately overwritten on * the slave shards once received. * @default * @public * @type {string[]} */ this.copyFiles = [ './auth.js', './gApiCredentials.json', './save/patreonCreatorTokens.json', ]; /** * @description Configuration specifying how detecting if shards are still * online shall work. * @default * @public * @type {ShardMasterConfig~HeartbeatConfig} */ this.heartbeat = new HeartbeatConfig(); /** * @description Configuration specifying how to alert admins about important * system updates. * @default * @public * @type {ShardMasterConfig~MailConfig} */ this.mail = new MailConfig(); } } /** * @description Configuration for the Shard Master. This config will be updated * during runtime if it is edited. Relevant settings may be sent to each shard * during each initial setup. These settings are related to heartbeat and uptime * management. This is included in {@link ShardMasterConfig}. This interval is * also used to update shard configuration if necessary. * @class * @memberof ShardingMaster.ShardMasterConfig * @inner * @static */ class HeartbeatConfig { /** * @description Create config object. */ constructor() { /** * @description The method used to update shard status. * * "pull" specifies that the master will attempt to pull the information * from the shards at the configured interval. * * "push" specifies that the shards are expected to push their status to * the master at the specified interval. * * "event" would only send updates from either side if one believes a * state to have changed. * * @public * @type {string} * @default */ this.updateStyle = 'pull'; /** * @description If relevant, this is the expected interval at which to * send/receive updates about an individual shard's status in milliseconds. * @public * @type {number} * @default */ // this.interval = (15 + 1) * 5 * 1100; // this.interval = (2 + 1) * 5 * 1100; this.interval = (2 + 1) * 30 * 1000; /** * @description If relevant, should we attempt to disperse the heartbeat * requests throughout the interval such that not all requests are made at * the same time. This could cause statistics to not line up or be * inconsistent. * @public * @type {boolean} * @default */ this.disperse = true; /** * @description If statistics about messages received from Discord should be * used in the evaluation of a shard's alive state. This means, that if no * messages are received from Discord between heartbeats, we can assume the * shard is dead. This may not be feasible on smaller bots. * @public * @type {boolean} * @default */ this.useMessageStats = false; /** * @description The timeout after not receiving a heartbeat from a shard to * request that it reboots, in milliseconds. * @public * @type {number} * @default */ this.requestRebootAfter = this.interval * 2.5; /** * @description The timeout after the master does not receive an update from * the shard to assume the shard has died, and we can begin recovery * procedueres (milliseconds). * @public * @type {number} * @default */ this.assumeDeadAfter = this.requestRebootAfter * 2; /** * @description The timeout after the shard does not receive an update from * the master to reboot. This is the threshold that once crossed, the master * assumes the shard is rebooting or has otherwise lost connection, and * stops sending reboot requests. The shard is not considered completely * dead yet, and will not be replaced until after the {@link * assumeDeadAfter} timeout. * @public * @type {number} * @default */ this.expectRebootAfter = this.assumeDeadAfter + 60 * 1000; /** * @description How far back to store shard status data for analysis * (milliseconds). * @public * @type {number} * @default 1 Day */ this.historyLength = 1 * 24 * 60 * 60 * 1000; } } /** * @description Configuration for the Shard Master. This config will be updated * during runtime if it is edited. Relevant settings may be sent to each shard * during each initial setup. These settings are related to informing sysadmins * of important updates. * @class * @memberof ShardingMaster.ShardMasterConfig * @inner * @static */ class MailConfig { /** * @description Create config object. */ constructor() { /** * @description Is the mail system enabled. It must also be configured * properly on the system in order for it to work. * @public * @default * @type {boolean} */ this.enabled = true; /** * @description The command that will be used to send the email. * @public * @default * @type {string} */ this.command = 'mutt'; /** * @description Additional arguments to pass to the mail command. * `%ATTACHMENT%` is replaced with the absolute path to the file to attach. * @public * @default * @type {string[]} */ this.args = [ '-a', '%ATTACHMENT%', '-s Automated Sharding Update', '--', 'sysadmin@spikeybot.com', ]; /** * @description Additional arguments to pass to the mail command, when a * failure has occurred. * @public * @default * @type {string[]} */ this.failArgs = [ '-s Automated Sharding Update FAILURE', '--', 'sysadmin@spikeybot.com', ]; /** * @description Options to pass to the spawn function when calling the * command. * @see {@link * https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options} * @public * @type {object} * @default */ this.spawnOpts = {env: null, timeout: 120000}; /** * @description The message to send in the email when a shard config file * was created successfully and has been attached to the emai. * @public * @type {string} * @default */ this.shardConfigCreateMessage = 'Hello!\n\nA config file for a new shard was generated at {date}.' + '\n\nID: {id}\nPubKey: {pubkey}\n\nYours Truly,\nSpikeyBot Sharding ' + 'Master.'; /** * @description The message to send in the email when a shard config file * was created successfully and has been attached to the emai. * @public * @type {string} * @default */ this.shardConfigCreateFailMessage = 'Hello!\n\nA config file for a new shard failed to be generated at ' + '{date}.\n\n{errors}\n\nYours Truly,\nSpikeyBot Sharding Master.'; } } ShardMasterConfig.HeartbeatConfig = HeartbeatConfig; ShardMasterConfig.MailConfig = MailConfig; module.exports = ShardMasterConfig;