galactic.ts 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Connection, Server } from 'net-ipc';
2
- import { GatewayIntentsString, Client } from 'discord.js';
2
+ import { GatewayIntentsString, Snowflake, Client } from 'discord.js';
3
3
  import { ChildProcess } from 'child_process';
4
4
 
5
5
  type EventPayload = {
@@ -32,6 +32,7 @@ declare class BridgeClientConnection {
32
32
  readonly data: unknown;
33
33
  connectionStatus: BridgeClientConnectionStatus;
34
34
  readonly dev: boolean;
35
+ readonly establishedAt: number;
35
36
  private _onMessage?;
36
37
  private _onRequest?;
37
38
  constructor(instanceID: number, connection: Connection, data: unknown, dev: boolean);
@@ -103,9 +104,10 @@ declare class Bridge {
103
104
  private readonly intents;
104
105
  private readonly shardsPerCluster;
105
106
  private readonly clusterToStart;
107
+ private readonly reclusteringTimeoutInMs;
106
108
  private readonly clusterCalculator;
107
109
  private readonly eventMap;
108
- constructor(port: number, token: string, intents: GatewayIntentsString[], shardsPerCluster: number, clusterToStart: number);
110
+ constructor(port: number, token: string, intents: GatewayIntentsString[], shardsPerCluster: number, clusterToStart: number, reclusteringTimeoutInMs: number);
109
111
  start(): void;
110
112
  private interval;
111
113
  private checkRecluster;
@@ -121,6 +123,7 @@ declare class Bridge {
121
123
  stopAllInstancesWithRestart(): Promise<void>;
122
124
  moveCluster(instance: BridgeClientConnection, cluster: BridgeClientCluster): Promise<void>;
123
125
  stopInstance(instance: BridgeClientConnection, recluster?: boolean): Promise<void>;
126
+ sendRequestToGuild(cluster: BridgeClientCluster, guildID: Snowflake, data: unknown, timeout?: number): Promise<unknown>;
124
127
  }
125
128
  type BridgeEventListeners = {
126
129
  'CLUSTER_READY': ((cluster: BridgeClientCluster, guilds: number, members: number) => void) | undefined;
@@ -199,6 +202,7 @@ declare class Cluster<T extends Client> {
199
202
  readonly intents: GatewayIntentsString[];
200
203
  eventManager: EventManager;
201
204
  client: T;
205
+ onSelfDestruct?: () => void;
202
206
  private readonly eventMap;
203
207
  constructor(instanceID: number, clusterID: number, shardList: number[], totalShards: number, token: string, intents: GatewayIntentsString[]);
204
208
  static initial<T extends Client>(): Cluster<T>;
@@ -264,6 +268,7 @@ type BotInstanceEventListeners = {
264
268
  'message': ((client: ClusterProcess, message: unknown) => void) | undefined;
265
269
  'request': ((client: ClusterProcess, message: unknown, resolve: (data: unknown) => void, reject: (error: any) => void) => void) | undefined;
266
270
  'PROCESS_KILLED': ((client: ClusterProcess, reason: string, processKilled: boolean) => void) | undefined;
271
+ 'PROCESS_SELF_DESTRUCT_ERROR': ((client: ClusterProcess, reason: string, error: unknown) => void) | undefined;
267
272
  'PROCESS_SPAWNED': ((client: ClusterProcess) => void) | undefined;
268
273
  'PROCESS_ERROR': ((client: ClusterProcess, error: unknown) => void) | undefined;
269
274
  'CLUSTER_READY': ((client: ClusterProcess) => void) | undefined;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Connection, Server } from 'net-ipc';
2
- import { GatewayIntentsString, Client } from 'discord.js';
2
+ import { GatewayIntentsString, Snowflake, Client } from 'discord.js';
3
3
  import { ChildProcess } from 'child_process';
4
4
 
5
5
  type EventPayload = {
@@ -32,6 +32,7 @@ declare class BridgeClientConnection {
32
32
  readonly data: unknown;
33
33
  connectionStatus: BridgeClientConnectionStatus;
34
34
  readonly dev: boolean;
35
+ readonly establishedAt: number;
35
36
  private _onMessage?;
36
37
  private _onRequest?;
37
38
  constructor(instanceID: number, connection: Connection, data: unknown, dev: boolean);
@@ -103,9 +104,10 @@ declare class Bridge {
103
104
  private readonly intents;
104
105
  private readonly shardsPerCluster;
105
106
  private readonly clusterToStart;
107
+ private readonly reclusteringTimeoutInMs;
106
108
  private readonly clusterCalculator;
107
109
  private readonly eventMap;
108
- constructor(port: number, token: string, intents: GatewayIntentsString[], shardsPerCluster: number, clusterToStart: number);
110
+ constructor(port: number, token: string, intents: GatewayIntentsString[], shardsPerCluster: number, clusterToStart: number, reclusteringTimeoutInMs: number);
109
111
  start(): void;
110
112
  private interval;
111
113
  private checkRecluster;
@@ -121,6 +123,7 @@ declare class Bridge {
121
123
  stopAllInstancesWithRestart(): Promise<void>;
122
124
  moveCluster(instance: BridgeClientConnection, cluster: BridgeClientCluster): Promise<void>;
123
125
  stopInstance(instance: BridgeClientConnection, recluster?: boolean): Promise<void>;
126
+ sendRequestToGuild(cluster: BridgeClientCluster, guildID: Snowflake, data: unknown, timeout?: number): Promise<unknown>;
124
127
  }
125
128
  type BridgeEventListeners = {
126
129
  'CLUSTER_READY': ((cluster: BridgeClientCluster, guilds: number, members: number) => void) | undefined;
@@ -199,6 +202,7 @@ declare class Cluster<T extends Client> {
199
202
  readonly intents: GatewayIntentsString[];
200
203
  eventManager: EventManager;
201
204
  client: T;
205
+ onSelfDestruct?: () => void;
202
206
  private readonly eventMap;
203
207
  constructor(instanceID: number, clusterID: number, shardList: number[], totalShards: number, token: string, intents: GatewayIntentsString[]);
204
208
  static initial<T extends Client>(): Cluster<T>;
@@ -264,6 +268,7 @@ type BotInstanceEventListeners = {
264
268
  'message': ((client: ClusterProcess, message: unknown) => void) | undefined;
265
269
  'request': ((client: ClusterProcess, message: unknown, resolve: (data: unknown) => void, reject: (error: any) => void) => void) | undefined;
266
270
  'PROCESS_KILLED': ((client: ClusterProcess, reason: string, processKilled: boolean) => void) | undefined;
271
+ 'PROCESS_SELF_DESTRUCT_ERROR': ((client: ClusterProcess, reason: string, error: unknown) => void) | undefined;
267
272
  'PROCESS_SPAWNED': ((client: ClusterProcess) => void) | undefined;
268
273
  'PROCESS_ERROR': ((client: ClusterProcess, error: unknown) => void) | undefined;
269
274
  'CLUSTER_READY': ((client: ClusterProcess) => void) | undefined;
package/dist/index.js CHANGED
@@ -244,6 +244,7 @@ var BridgeClientConnection = class {
244
244
  data;
245
245
  connectionStatus = "ready" /* READY */;
246
246
  dev = false;
247
+ establishedAt = Date.now();
247
248
  _onMessage;
248
249
  _onRequest;
249
250
  constructor(instanceID, connection, data, dev) {
@@ -437,6 +438,7 @@ var Bridge = class {
437
438
  intents;
438
439
  shardsPerCluster = 1;
439
440
  clusterToStart = 1;
441
+ reclusteringTimeoutInMs;
440
442
  clusterCalculator;
441
443
  eventMap = {
442
444
  CLUSTER_READY: void 0,
@@ -449,12 +451,13 @@ var Bridge = class {
449
451
  ERROR: void 0,
450
452
  CLIENT_STOP: void 0
451
453
  };
452
- constructor(port, token, intents, shardsPerCluster, clusterToStart) {
454
+ constructor(port, token, intents, shardsPerCluster, clusterToStart, reclusteringTimeoutInMs) {
453
455
  this.port = port;
454
456
  this.token = token;
455
457
  this.intents = intents;
456
458
  this.clusterToStart = clusterToStart;
457
459
  this.shardsPerCluster = shardsPerCluster;
460
+ this.reclusteringTimeoutInMs = reclusteringTimeoutInMs;
458
461
  this.clusterCalculator = new ClusterCalculator(this.clusterToStart, this.shardsPerCluster);
459
462
  this.server = new import_net_ipc.Server({
460
463
  port: this.port
@@ -478,7 +481,7 @@ var Bridge = class {
478
481
  if (!up) {
479
482
  return;
480
483
  }
481
- const connectedClients = this.connectedClients.values().filter((c) => c.connectionStatus == "ready" /* READY */ && !c.dev).toArray();
484
+ const connectedClients = this.connectedClients.values().filter((c) => c.connectionStatus == "ready" /* READY */).filter((c) => !c.dev).filter((c) => c.establishedAt + this.reclusteringTimeoutInMs < Date.now()).toArray();
482
485
  const { most, least } = this.clusterCalculator.findMostAndLeastClustersForConnections(connectedClients);
483
486
  if (most) {
484
487
  const clusterToSteal = this.clusterCalculator.getClusterForConnection(most)[0] || void 0;
@@ -780,6 +783,17 @@ var Bridge = class {
780
783
  await instance.connection.close("Instance stopped.", false);
781
784
  }
782
785
  }
786
+ sendRequestToGuild(cluster, guildID, data, timeout = 5e3) {
787
+ if (!cluster.connection) {
788
+ return Promise.reject(new Error("No connection defined for cluster " + cluster.clusterID));
789
+ }
790
+ return cluster.connection.eventManager.request({
791
+ type: "REDIRECT_REQUEST_TO_GUILD",
792
+ clusterID: cluster.clusterID,
793
+ guildID,
794
+ data
795
+ }, timeout);
796
+ }
783
797
  };
784
798
 
785
799
  // src/cluster/Cluster.ts
@@ -793,6 +807,7 @@ var Cluster = class _Cluster {
793
807
  intents;
794
808
  eventManager;
795
809
  client;
810
+ onSelfDestruct;
796
811
  eventMap = {
797
812
  message: void 0,
798
813
  request: void 0,
@@ -931,6 +946,10 @@ var Cluster = class _Cluster {
931
946
  } else {
932
947
  return result;
933
948
  }
949
+ } else if (m.type == "SELF_DESTRUCT") {
950
+ if (this.onSelfDestruct) {
951
+ this.onSelfDestruct();
952
+ }
934
953
  }
935
954
  return void 0;
936
955
  }
@@ -1064,6 +1083,7 @@ var BotInstance = class {
1064
1083
  "message": void 0,
1065
1084
  "request": void 0,
1066
1085
  "PROCESS_KILLED": void 0,
1086
+ "PROCESS_SELF_DESTRUCT_ERROR": void 0,
1067
1087
  "PROCESS_SPAWNED": void 0,
1068
1088
  "ERROR": void 0,
1069
1089
  "PROCESS_ERROR": void 0,
@@ -1093,7 +1113,8 @@ var BotInstance = class {
1093
1113
  },
1094
1114
  stdio: "inherit",
1095
1115
  execArgv: this.execArgv,
1096
- silent: false
1116
+ silent: false,
1117
+ detached: true
1097
1118
  });
1098
1119
  const client = new ClusterProcess(clusterID, child, shardList, totalShards);
1099
1120
  child.stdout?.on("data", (data) => {
@@ -1128,18 +1149,29 @@ var BotInstance = class {
1128
1149
  }
1129
1150
  killProcess(client, reason) {
1130
1151
  client.status = "stopped";
1131
- if (client.child && client.child.pid) {
1132
- if (client.child.kill("SIGKILL")) {
1133
- if (this.eventMap.PROCESS_KILLED) this.eventMap.PROCESS_KILLED(client, reason, true);
1152
+ client.eventManager.request({
1153
+ type: "SELF_DESTRUCT",
1154
+ reason
1155
+ }, 5e3).catch(() => {
1156
+ if (this.eventMap.PROCESS_SELF_DESTRUCT_ERROR) this.eventMap.PROCESS_SELF_DESTRUCT_ERROR(client, reason, "Cluster didnt respond to shot-call.");
1157
+ }).finally(() => {
1158
+ if (client.child && client.child.pid) {
1159
+ if (client.child.kill("SIGKILL")) {
1160
+ if (this.eventMap.PROCESS_KILLED) this.eventMap.PROCESS_KILLED(client, reason, true);
1161
+ } else {
1162
+ if (this.eventMap.ERROR) this.eventMap.ERROR(`Failed to kill process for cluster ${client.id}`);
1163
+ client.child.kill("SIGKILL");
1164
+ }
1165
+ try {
1166
+ process.kill(-client.child.pid);
1167
+ } catch {
1168
+ }
1134
1169
  } else {
1135
- if (this.eventMap.ERROR) this.eventMap.ERROR(`Failed to kill process for cluster ${client.id}`);
1136
- client.child.kill("SIGKILL");
1170
+ if (this.eventMap.PROCESS_KILLED) this.eventMap.PROCESS_KILLED(client, reason, false);
1137
1171
  }
1138
- } else {
1139
- if (this.eventMap.PROCESS_KILLED) this.eventMap.PROCESS_KILLED(client, reason, false);
1140
- }
1141
- this.clients.delete(client.id);
1142
- this.setClusterStopped(client, reason);
1172
+ this.clients.delete(client.id);
1173
+ this.setClusterStopped(client, reason);
1174
+ });
1143
1175
  }
1144
1176
  onMessage(client, message2) {
1145
1177
  if (message2.type === "CLUSTER_READY") {