status-sharding
Version:
Welcome to Status Sharding! This package is designed to provide an efficient and flexible solution for sharding Discord bots, allowing you to scale your bot across multiple processes or workers.
201 lines (200 loc) • 9.87 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClusterClientHandler = exports.ClusterHandler = void 0;
const types_1 = require("../types");
const shardingUtils_1 = require("../other/shardingUtils");
/** Handles messages for the cluster. */
class ClusterHandler {
cluster;
ipc;
/** Creates an instance of ClusterHandler. */
constructor(cluster, ipc) {
this.cluster = cluster;
this.ipc = ipc;
}
/** Handles the message received, and executes the callback. (Not meant to be used by the user.) */
async handleMessage(message) {
switch (message._type) {
case types_1.MessageTypes.ClientReady: {
if (this.cluster.ready) {
this.cluster.manager._debug(`[Cluster ${this.cluster.id}] Received duplicate ready signal, ignoring.`);
return;
}
const readyData = message.data;
if (readyData?.packageType && !this.cluster.manager.options.packageType) {
this.cluster.manager.options.packageType = readyData.packageType;
this.cluster.manager._debug(`[Cluster ${this.cluster.id}] Package type set to: ${readyData.packageType}`);
}
this.cluster.ready = true;
this.cluster.exited = false;
this.cluster.lastHeartbeatReceived = Date.now();
this.cluster.emit('ready', this.cluster);
this.cluster.manager._debug(`[Cluster ${this.cluster.id}] Cluster is ready.`);
const allReady = this.cluster.manager.clusters.every((cluster) => cluster.ready);
if (!this.cluster.manager.ready && allReady && this.cluster.manager.clusters.size === this.cluster.manager.options.totalClusters) {
this.cluster.manager.ready = true;
this.cluster.manager.emit('ready', this.cluster.manager);
this.cluster.manager._debug('All clusters are ready.');
for (const cluster of this.cluster.manager.clusters.values()) {
cluster._sendInstance({ _type: types_1.MessageTypes.ManagerReady });
}
}
break;
}
case types_1.MessageTypes.ClientBroadcastRequest: {
const { script, options } = message.data;
const results = await this.cluster.manager.broadcastEval(script, options);
this.ipc.send({
_type: types_1.MessageTypes.ClientBroadcastResponse,
_nonce: message._nonce,
data: results,
}).catch((err) => {
this.ipc.send({
_type: types_1.MessageTypes.ClientBroadcastResponseError,
_nonce: message._nonce,
data: shardingUtils_1.ShardingUtils.makePlainError(err),
});
});
break;
}
case types_1.MessageTypes.ClientBroadcast: {
const data = message.data;
await this.cluster.manager.broadcast(data.message, data.ignore !== undefined ? [data.ignore] : undefined);
break;
}
case types_1.MessageTypes.ClientManagerEvalRequest: {
const { script, options } = message.data;
const result = await this.cluster.manager.eval(script, options);
if (result.error) {
this.ipc.send({
_type: types_1.MessageTypes.ClientManagerEvalResponseError,
_nonce: message._nonce,
data: shardingUtils_1.ShardingUtils.makePlainError(result.error),
});
}
else {
this.ipc.send({
_type: types_1.MessageTypes.ClientManagerEvalResponse,
_nonce: message._nonce,
data: result.result,
});
}
break;
}
case types_1.MessageTypes.CustomReply:
case types_1.MessageTypes.ClientEvalResponseError:
case types_1.MessageTypes.ClientEvalResponse: {
this.cluster.manager.promise.resolve(message);
break;
}
case types_1.MessageTypes.ClientRespawnAll: {
const { clusterDelay, respawnDelay, timeout, except } = message.data;
this.cluster.manager.respawnAll(clusterDelay, respawnDelay, timeout, except);
break;
}
case types_1.MessageTypes.ClientRespawnSpecific: {
const { clusterDelay, respawnDelay, timeout, clusterIds } = message.data;
this.cluster.manager.respawnClusters(clusterIds, clusterDelay, respawnDelay, timeout);
break;
}
case types_1.MessageTypes.ClientRespawn: {
const { respawnDelay, timeout } = message.data;
this.cluster.respawn(respawnDelay, timeout);
break;
}
case types_1.MessageTypes.ClientSpawnNextCluster: {
this.cluster.manager.clusterQueue.next();
break;
}
case types_1.MessageTypes.HeartbeatAck: {
this.cluster.lastHeartbeatReceived = Date.now();
this.cluster.manager._debug(`[Cluster ${this.cluster.id}] Received heartbeat.`);
break;
}
}
}
}
exports.ClusterHandler = ClusterHandler;
/** Handles messages for the cluster client. */
class ClusterClientHandler {
clusterClient;
/** Creates an instance of ClusterClientHandler. */
constructor(clusterClient) {
this.clusterClient = clusterClient;
}
/** Handles the message received, and executes the callback. (Not meant to be used by the user.) */
async handleMessage(message) {
switch (message._type) {
case types_1.MessageTypes.ClientEvalRequest: {
const { script } = message.data;
try {
if (!script)
return this.clusterClient._respond({
_type: types_1.MessageTypes.ClientEvalResponseError,
_nonce: message._nonce,
data: shardingUtils_1.ShardingUtils.makePlainError(new Error('No script provided.')),
});
try {
const result = await this.clusterClient.evalOnClient(script);
this.clusterClient._respond({
_type: types_1.MessageTypes.ClientEvalResponse,
_nonce: message._nonce,
data: shardingUtils_1.ShardingUtils.isSerializable(result) ? result : {
...shardingUtils_1.ShardingUtils.makePlainError(new Error('Evaluated script returned an unserializable value.')),
script: script?.replace(/(\n|\r|\t)/g, '').replace(/( )+/g, ' ').replace(/(\/\/.*)/g, ''),
},
});
}
catch (err) {
if (err instanceof Error) {
this.clusterClient._respond({
_type: types_1.MessageTypes.ClientEvalResponseError,
_nonce: message._nonce,
data: {
...shardingUtils_1.ShardingUtils.makePlainError(err),
script: script?.replace(/(\n|\r|\t)/g, '').replace(/( )+/g, ' ').replace(/(\/\/.*)/g, ''),
},
});
}
else {
this.clusterClient._respond({
_type: types_1.MessageTypes.ClientEvalResponseError,
_nonce: message._nonce,
data: {
...shardingUtils_1.ShardingUtils.makePlainError(new Error('An error occurred while evaluating the script.')),
script: script?.replace(/(\n|\r|\t)/g, '').replace(/( )+/g, ' ').replace(/(\/\/.*)/g, ''),
},
});
}
throw err;
}
}
catch (err) {
this.clusterClient._respond({
_type: types_1.MessageTypes.ClientEvalResponseError,
_nonce: message._nonce,
data: shardingUtils_1.ShardingUtils.makePlainError(err),
});
}
break;
}
case types_1.MessageTypes.CustomReply:
case types_1.MessageTypes.ClientManagerEvalResponse:
case types_1.MessageTypes.ClientManagerEvalResponseError:
case types_1.MessageTypes.ClientBroadcastResponse:
case types_1.MessageTypes.ClientBroadcastResponseError: {
this.clusterClient.promise.resolve(message);
break;
}
case types_1.MessageTypes.ManagerReady: {
this.clusterClient.emit('managerReady');
break;
}
case types_1.MessageTypes.Heartbeat: {
this.clusterClient._respond({ _type: types_1.MessageTypes.HeartbeatAck });
break;
}
}
}
}
exports.ClusterClientHandler = ClusterClientHandler;