// 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;