commit
						c904d854d9
					
				
					 13 changed files with 140 additions and 58 deletions
				
			
		|  | @ -116,11 +116,11 @@ export interface VoiceServerUpdateData { | ||||||
| // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
 | // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
 | ||||||
| export type ClientEvents = { | export type ClientEvents = { | ||||||
|   /** When Client has successfully connected to Discord */ |   /** When Client has successfully connected to Discord */ | ||||||
|   ready: [] |   ready: [shard: number] | ||||||
|   /** When a successful reconnect has been made */ |   /** When a successful reconnect has been made */ | ||||||
|   reconnect: [] |   reconnect: [shard: number] | ||||||
|   /** When a successful session resume has been done */ |   /** When a successful session resume has been done */ | ||||||
|   resumed: [] |   resumed: [shard: number] | ||||||
|   /** |   /** | ||||||
|    * When a new Channel is created |    * When a new Channel is created | ||||||
|    * @param channel New Channel object |    * @param channel New Channel object | ||||||
|  |  | ||||||
|  | @ -20,5 +20,5 @@ export const ready: GatewayEventHandler = async ( | ||||||
|     gateway.client.guilds.set(guild.id, guild) |     gateway.client.guilds.set(guild.id, guild) | ||||||
|   }) |   }) | ||||||
| 
 | 
 | ||||||
|   gateway.client.emit('ready') |   gateway.client.emit('ready', gateway.shards?.[0] ?? 0) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -8,11 +8,11 @@ export const resume: GatewayEventHandler = async ( | ||||||
|   d: Resume |   d: Resume | ||||||
| ) => { | ) => { | ||||||
|   gateway.debug(`Session Resumed!`) |   gateway.debug(`Session Resumed!`) | ||||||
|   gateway.client.emit('resumed') |   gateway.client.emit('resumed', gateway.shards?.[0] ?? 0) | ||||||
|   if (gateway.client.user === undefined) |   if (gateway.client.user === undefined) | ||||||
|     gateway.client.user = new User( |     gateway.client.user = new User( | ||||||
|       gateway.client, |       gateway.client, | ||||||
|       await gateway.client.rest.get(CLIENT_USER()) |       await gateway.client.rest.get(CLIENT_USER()) | ||||||
|     ) |     ) | ||||||
|   gateway.client.emit('ready') |   gateway.client.emit('ready', gateway.shards?.[0] ?? 0) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -111,7 +111,7 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
| 
 | 
 | ||||||
|         if (!this.initialized) { |         if (!this.initialized) { | ||||||
|           this.initialized = true |           this.initialized = true | ||||||
|           await this.sendIdentify(this.client.forceNewSession) |           this.enqueueIdentify(this.client.forceNewSession) | ||||||
|         } else { |         } else { | ||||||
|           // eslint-disable-next-line @typescript-eslint/no-floating-promises
 |           // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|           this.sendResume() |           this.sendResume() | ||||||
|  | @ -134,14 +134,14 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|         ) |         ) | ||||||
|         if (d !== true) { |         if (d !== true) { | ||||||
|           this.debug(`Session was invalidated, deleting from cache`) |           this.debug(`Session was invalidated, deleting from cache`) | ||||||
|           await this.cache.delete('session_id') |           await this.cache.delete(`session_id_${this.shards?.join('-') ?? '0'}`) | ||||||
|           await this.cache.delete('seq') |           await this.cache.delete(`seq_${this.shards?.join('-') ?? '0'}`) | ||||||
|           this.sessionID = undefined |           this.sessionID = undefined | ||||||
|           this.sequenceID = undefined |           this.sequenceID = undefined | ||||||
|         } |         } | ||||||
|         this.timedIdentify = setTimeout(async () => { |         this.timedIdentify = setTimeout(async () => { | ||||||
|           this.timedIdentify = null |           this.timedIdentify = null | ||||||
|           await this.sendIdentify(!(d as boolean)) |           this.enqueueIdentify(!(d as boolean)) | ||||||
|         }, 5000) |         }, 5000) | ||||||
|         break |         break | ||||||
| 
 | 
 | ||||||
|  | @ -149,7 +149,7 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|         this.heartbeatServerResponded = true |         this.heartbeatServerResponded = true | ||||||
|         if (s !== null) { |         if (s !== null) { | ||||||
|           this.sequenceID = s |           this.sequenceID = s | ||||||
|           await this.cache.set('seq', s) |           await this.cache.set(`seq_${this.shards?.join('-') ?? '0'}`, s) | ||||||
|         } |         } | ||||||
|         if (t !== null && t !== undefined) { |         if (t !== null && t !== undefined) { | ||||||
|           this.emit(t as any, d) |           this.emit(t as any, d) | ||||||
|  | @ -167,8 +167,11 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|         // this.token = d.token
 |         // this.token = d.token
 | ||||||
|         this.sessionID = d.session_id |         this.sessionID = d.session_id | ||||||
|         this.sequenceID = d.seq |         this.sequenceID = d.seq | ||||||
|         await this.cache.set('seq', d.seq) |         await this.cache.set(`seq_${this.shards?.join('-') ?? '0'}`, d.seq) | ||||||
|         await this.cache.set('session_id', this.sessionID) |         await this.cache.set( | ||||||
|  |           `session_id_${this.shards?.join('-') ?? '0'}`, | ||||||
|  |           this.sessionID | ||||||
|  |         ) | ||||||
|         this.emit('resume') |         this.emit('resume') | ||||||
|         break |         break | ||||||
|       } |       } | ||||||
|  | @ -233,10 +236,12 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|         this.debug( |         this.debug( | ||||||
|           'Unknown Close code, probably connection error. Reconnecting in 5s.' |           'Unknown Close code, probably connection error. Reconnecting in 5s.' | ||||||
|         ) |         ) | ||||||
|  | 
 | ||||||
|         if (this.timedIdentify !== null) { |         if (this.timedIdentify !== null) { | ||||||
|           clearTimeout(this.timedIdentify) |           clearTimeout(this.timedIdentify) | ||||||
|           this.debug('Timed Identify found. Cleared timeout.') |           this.debug('Timed Identify found. Cleared timeout.') | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|         await delay(5000) |         await delay(5000) | ||||||
|         await this.reconnect(true) |         await this.reconnect(true) | ||||||
|         break |         break | ||||||
|  | @ -255,7 +260,12 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|     error.name = 'ErrorEvent' |     error.name = 'ErrorEvent' | ||||||
|     console.log(error) |     console.log(error) | ||||||
|     this.emit('error', error, event) |     this.emit('error', error, event) | ||||||
|     await this.reconnect() |   } | ||||||
|  | 
 | ||||||
|  |   private enqueueIdentify(forceNew?: boolean): void { | ||||||
|  |     this.client.shards.enqueueIdentify( | ||||||
|  |       async () => await this.sendIdentify(forceNew) | ||||||
|  |     ) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   private async sendIdentify(forceNewSession?: boolean): Promise<void> { |   private async sendIdentify(forceNewSession?: boolean): Promise<void> { | ||||||
|  | @ -279,7 +289,9 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (forceNewSession === undefined || !forceNewSession) { |     if (forceNewSession === undefined || !forceNewSession) { | ||||||
|       const sessionIDCached = await this.cache.get('session_id') |       const sessionIDCached = await this.cache.get( | ||||||
|  |         `session_id_${this.shards?.join('-') ?? '0'}` | ||||||
|  |       ) | ||||||
|       if (sessionIDCached !== undefined) { |       if (sessionIDCached !== undefined) { | ||||||
|         this.debug(`Found Cached SessionID: ${sessionIDCached}`) |         this.debug(`Found Cached SessionID: ${sessionIDCached}`) | ||||||
|         this.sessionID = sessionIDCached |         this.sessionID = sessionIDCached | ||||||
|  | @ -320,12 +332,16 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
|       throw new Error('Intents not specified') |       throw new Error('Intents not specified') | ||||||
| 
 | 
 | ||||||
|     if (this.sessionID === undefined) { |     if (this.sessionID === undefined) { | ||||||
|       this.sessionID = await this.cache.get('session_id') |       this.sessionID = await this.cache.get( | ||||||
|       if (this.sessionID === undefined) return await this.sendIdentify() |         `session_id_${this.shards?.join('-') ?? '0'}` | ||||||
|  |       ) | ||||||
|  |       if (this.sessionID === undefined) return this.enqueueIdentify() | ||||||
|     } |     } | ||||||
|     this.debug(`Preparing to resume with Session: ${this.sessionID}`) |     this.debug(`Preparing to resume with Session: ${this.sessionID}`) | ||||||
|     if (this.sequenceID === undefined) { |     if (this.sequenceID === undefined) { | ||||||
|       const cached = await this.cache.get('seq') |       const cached = await this.cache.get( | ||||||
|  |         `seq_${this.shards?.join('-') ?? '0'}` | ||||||
|  |       ) | ||||||
|       if (cached !== undefined) |       if (cached !== undefined) | ||||||
|         this.sequenceID = typeof cached === 'string' ? parseInt(cached) : cached |         this.sequenceID = typeof cached === 'string' ? parseInt(cached) : cached | ||||||
|     } |     } | ||||||
|  | @ -389,11 +405,13 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> { | ||||||
| 
 | 
 | ||||||
|   async reconnect(forceNew?: boolean): Promise<void> { |   async reconnect(forceNew?: boolean): Promise<void> { | ||||||
|     this.emit('reconnecting') |     this.emit('reconnecting') | ||||||
|  | 
 | ||||||
|     clearInterval(this.heartbeatIntervalID) |     clearInterval(this.heartbeatIntervalID) | ||||||
|     if (forceNew === true) { |     if (forceNew === true) { | ||||||
|       await this.cache.delete('session_id') |       await this.cache.delete(`session_id_${this.shards?.join('-') ?? '0'}`) | ||||||
|       await this.cache.delete('seq') |       await this.cache.delete(`seq_${this.shards?.join('-') ?? '0'}`) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     this.close(1000, RECONNECT_REASON) |     this.close(1000, RECONNECT_REASON) | ||||||
|     this.initWebsocket() |     this.initWebsocket() | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -14,7 +14,7 @@ import { Extension } from './extensions.ts' | ||||||
| import { SlashClient } from './slashClient.ts' | import { SlashClient } from './slashClient.ts' | ||||||
| import { Interaction } from '../structures/slash.ts' | import { Interaction } from '../structures/slash.ts' | ||||||
| import { SlashModule } from './slashModule.ts' | import { SlashModule } from './slashModule.ts' | ||||||
| import type { ShardManager } from './shard.ts' | import { ShardManager } from './shard.ts' | ||||||
| import { Application } from '../structures/application.ts' | import { Application } from '../structures/application.ts' | ||||||
| import { Invite } from '../structures/invite.ts' | import { Invite } from '../structures/invite.ts' | ||||||
| import { INVITE } from '../types/endpoint.ts' | import { INVITE } from '../types/endpoint.ts' | ||||||
|  | @ -67,7 +67,7 @@ export interface ClientOptions { | ||||||
|   fetchGatewayInfo?: boolean |   fetchGatewayInfo?: boolean | ||||||
|   /** ADVANCED: Shard ID to launch on */ |   /** ADVANCED: Shard ID to launch on */ | ||||||
|   shard?: number |   shard?: number | ||||||
|   /** Shard count. Set to 'auto' for automatic sharding */ |   /** ADVACNED: Shard count. */ | ||||||
|   shardCount?: number | 'auto' |   shardCount?: number | 'auto' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -75,8 +75,6 @@ export interface ClientOptions { | ||||||
|  * Discord Client. |  * Discord Client. | ||||||
|  */ |  */ | ||||||
| export class Client extends HarmonyEventEmitter<ClientEvents> { | export class Client extends HarmonyEventEmitter<ClientEvents> { | ||||||
|   /** Gateway object */ |  | ||||||
|   gateway: Gateway |  | ||||||
|   /** REST Manager - used to make all requests */ |   /** REST Manager - used to make all requests */ | ||||||
|   rest: RESTManager |   rest: RESTManager | ||||||
|   /** User which Client logs in to, undefined until logs in */ |   /** User which Client logs in to, undefined until logs in */ | ||||||
|  | @ -133,11 +131,11 @@ export class Client extends HarmonyEventEmitter<ClientEvents> { | ||||||
|   _id?: string |   _id?: string | ||||||
| 
 | 
 | ||||||
|   /** Shard on which this Client is */ |   /** Shard on which this Client is */ | ||||||
|   shard: number = 0 |   shard?: number | ||||||
|   /** Shard Count */ |   /** Shard Count */ | ||||||
|   shardCount: number | 'auto' = 1 |   shardCount: number | 'auto' = 'auto' | ||||||
|   /** Shard Manager of this Client if Sharded */ |   /** Shard Manager of this Client if Sharded */ | ||||||
|   shards?: ShardManager |   shards: ShardManager | ||||||
|   /** Collectors set */ |   /** Collectors set */ | ||||||
|   collectors: Set<Collector> = new Set() |   collectors: Set<Collector> = new Set() | ||||||
| 
 | 
 | ||||||
|  | @ -151,11 +149,17 @@ export class Client extends HarmonyEventEmitter<ClientEvents> { | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   get gateway(): Gateway { | ||||||
|  |     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
 | ||||||
|  |     return this.shards.list.get('0') as Gateway | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   constructor(options: ClientOptions = {}) { |   constructor(options: ClientOptions = {}) { | ||||||
|     super() |     super() | ||||||
|     this._id = options.id |     this._id = options.id | ||||||
|     this.token = options.token |     this.token = options.token | ||||||
|     this.intents = options.intents |     this.intents = options.intents | ||||||
|  |     this.shards = new ShardManager(this) | ||||||
|     this.forceNewSession = options.forceNewSession |     this.forceNewSession = options.forceNewSession | ||||||
|     if (options.cache !== undefined) this.cache = options.cache |     if (options.cache !== undefined) this.cache = options.cache | ||||||
|     if (options.presence !== undefined) |     if (options.presence !== undefined) | ||||||
|  | @ -175,7 +179,7 @@ export class Client extends HarmonyEventEmitter<ClientEvents> { | ||||||
|       Object.keys(this._decoratedEvents).length !== 0 |       Object.keys(this._decoratedEvents).length !== 0 | ||||||
|     ) { |     ) { | ||||||
|       Object.entries(this._decoratedEvents).forEach((entry) => { |       Object.entries(this._decoratedEvents).forEach((entry) => { | ||||||
|         this.on(entry[0] as keyof ClientEvents, entry[1]) |         this.on(entry[0] as keyof ClientEvents, entry[1].bind(this)) | ||||||
|       }) |       }) | ||||||
|       this._decoratedEvents = undefined |       this._decoratedEvents = undefined | ||||||
|     } |     } | ||||||
|  | @ -192,12 +196,6 @@ export class Client extends HarmonyEventEmitter<ClientEvents> { | ||||||
|     if (options.shard !== undefined) this.shard = options.shard |     if (options.shard !== undefined) this.shard = options.shard | ||||||
|     if (options.shardCount !== undefined) this.shardCount = options.shardCount |     if (options.shardCount !== undefined) this.shardCount = options.shardCount | ||||||
| 
 | 
 | ||||||
|     this.slash = new SlashClient({ |  | ||||||
|       id: () => this.getEstimatedID(), |  | ||||||
|       client: this, |  | ||||||
|       enabled: options.enableSlash |  | ||||||
|     }) |  | ||||||
| 
 |  | ||||||
|     this.fetchGatewayInfo = options.fetchGatewayInfo ?? true |     this.fetchGatewayInfo = options.fetchGatewayInfo ?? true | ||||||
| 
 | 
 | ||||||
|     if (this.token === undefined) { |     if (this.token === undefined) { | ||||||
|  | @ -220,7 +218,12 @@ export class Client extends HarmonyEventEmitter<ClientEvents> { | ||||||
|     if (options.restOptions !== undefined) |     if (options.restOptions !== undefined) | ||||||
|       Object.assign(restOptions, options.restOptions) |       Object.assign(restOptions, options.restOptions) | ||||||
|     this.rest = new RESTManager(restOptions) |     this.rest = new RESTManager(restOptions) | ||||||
|     this.gateway = new Gateway(this) | 
 | ||||||
|  |     this.slash = new SlashClient({ | ||||||
|  |       id: () => this.getEstimatedID(), | ||||||
|  |       client: this, | ||||||
|  |       enabled: options.enableSlash | ||||||
|  |     }) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** |   /** | ||||||
|  | @ -301,9 +304,11 @@ export class Client extends HarmonyEventEmitter<ClientEvents> { | ||||||
|     } else throw new Error('No Gateway Intents were provided') |     } else throw new Error('No Gateway Intents were provided') | ||||||
| 
 | 
 | ||||||
|     this.rest.token = token |     this.rest.token = token | ||||||
|     this.gateway.token = token |     if (this.shard !== undefined) { | ||||||
|     this.gateway.intents = intents |       if (typeof this.shardCount === 'number') | ||||||
|     this.gateway.initWebsocket() |         this.shards.cachedShardCount = this.shardCount | ||||||
|  |       await this.shards.launch(this.shard) | ||||||
|  |     } else await this.shards.connect() | ||||||
|     return this.waitFor('ready', () => true).then(() => this) |     return this.waitFor('ready', () => true).then(() => this) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -420,7 +425,7 @@ export function event(name?: keyof ClientEvents) { | ||||||
|   ) { |   ) { | ||||||
|     const listener = ((client as unknown) as { |     const listener = ((client as unknown) as { | ||||||
|       [name in keyof ClientEvents]: (...args: ClientEvents[name]) => any |       [name in keyof ClientEvents]: (...args: ClientEvents[name]) => any | ||||||
|     })[name ?? ((prop as unknown) as keyof ClientEvents)] |     })[(prop as unknown) as keyof ClientEvents] | ||||||
|     if (typeof listener !== 'function') |     if (typeof listener !== 'function') | ||||||
|       throw new Error('@event decorator requires a function') |       throw new Error('@event decorator requires a function') | ||||||
|     if (client._decoratedEvents === undefined) client._decoratedEvents = {} |     if (client._decoratedEvents === undefined) client._decoratedEvents = {} | ||||||
|  |  | ||||||
|  | @ -91,7 +91,7 @@ export class Extension { | ||||||
|       Object.keys(this._decoratedEvents).length !== 0 |       Object.keys(this._decoratedEvents).length !== 0 | ||||||
|     ) { |     ) { | ||||||
|       Object.entries(this._decoratedEvents).forEach((entry) => { |       Object.entries(this._decoratedEvents).forEach((entry) => { | ||||||
|         this.listen(entry[0] as keyof ClientEvents, entry[1]) |         this.listen(entry[0] as keyof ClientEvents, entry[1].bind(this)) | ||||||
|       }) |       }) | ||||||
|       this._decoratedEvents = undefined |       this._decoratedEvents = undefined | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,9 +1,10 @@ | ||||||
| import { Collection } from '../utils/collection.ts' | import { Collection } from '../utils/collection.ts' | ||||||
| import { Client } from './client.ts' | import type { Client } from './client.ts' | ||||||
| import { RESTManager } from './rest.ts' | import { RESTManager } from './rest.ts' | ||||||
| import { Gateway } from '../gateway/index.ts' | import { Gateway } from '../gateway/index.ts' | ||||||
| import { HarmonyEventEmitter } from '../utils/events.ts' | import { HarmonyEventEmitter } from '../utils/events.ts' | ||||||
| import { GatewayEvents } from '../types/gateway.ts' | import { GatewayEvents } from '../types/gateway.ts' | ||||||
|  | import { delay } from '../utils/delay.ts' | ||||||
| 
 | 
 | ||||||
| // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
 | // eslint-disable-next-line @typescript-eslint/consistent-type-definitions
 | ||||||
| export type ShardManagerEvents = { | export type ShardManagerEvents = { | ||||||
|  | @ -18,6 +19,8 @@ export class ShardManager extends HarmonyEventEmitter<ShardManagerEvents> { | ||||||
|   list: Collection<string, Gateway> = new Collection() |   list: Collection<string, Gateway> = new Collection() | ||||||
|   client: Client |   client: Client | ||||||
|   cachedShardCount?: number |   cachedShardCount?: number | ||||||
|  |   queueProcessing: boolean = false | ||||||
|  |   queue: CallableFunction[] = [] | ||||||
| 
 | 
 | ||||||
|   get rest(): RESTManager { |   get rest(): RESTManager { | ||||||
|     return this.client.rest |     return this.client.rest | ||||||
|  | @ -28,6 +31,32 @@ export class ShardManager extends HarmonyEventEmitter<ShardManagerEvents> { | ||||||
|     this.client = client |     this.client = client | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   debug(msg: string): void { | ||||||
|  |     this.client.debug('Shards', msg) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   enqueueIdentify(fn: CallableFunction): ShardManager { | ||||||
|  |     this.queue.push(fn) | ||||||
|  |     // eslint-disable-next-line @typescript-eslint/no-floating-promises
 | ||||||
|  |     if (!this.queueProcessing) this.processQueue() | ||||||
|  |     return this | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   private async processQueue(): Promise<void> { | ||||||
|  |     if (this.queueProcessing || this.queue.length === 0) return | ||||||
|  |     this.queueProcessing = true | ||||||
|  |     const item = this.queue[0] | ||||||
|  |     await item() | ||||||
|  |     this.queue.shift() | ||||||
|  |     await delay(5000) | ||||||
|  |     this.queueProcessing = false | ||||||
|  |     if (this.queue.length === 0) { | ||||||
|  |       this.queueProcessing = false | ||||||
|  |     } else { | ||||||
|  |       await this.processQueue() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   async getShardCount(): Promise<number> { |   async getShardCount(): Promise<number> { | ||||||
|     let shardCount: number |     let shardCount: number | ||||||
|     if (this.cachedShardCount !== undefined) shardCount = this.cachedShardCount |     if (this.cachedShardCount !== undefined) shardCount = this.cachedShardCount | ||||||
|  | @ -46,10 +75,14 @@ export class ShardManager extends HarmonyEventEmitter<ShardManagerEvents> { | ||||||
|     if (this.list.has(id.toString()) === true) |     if (this.list.has(id.toString()) === true) | ||||||
|       throw new Error(`Shard ${id} already launched`) |       throw new Error(`Shard ${id} already launched`) | ||||||
| 
 | 
 | ||||||
|  |     this.debug(`Launching Shard: ${id}`) | ||||||
|     const shardCount = await this.getShardCount() |     const shardCount = await this.getShardCount() | ||||||
| 
 | 
 | ||||||
|     const gw = new Gateway(this.client, [Number(id), shardCount]) |     const gw = new Gateway(this.client, [Number(id), shardCount]) | ||||||
|  |     gw.token = this.client.token | ||||||
|  |     gw.intents = this.client.intents | ||||||
|     this.list.set(id.toString(), gw) |     this.list.set(id.toString(), gw) | ||||||
|  | 
 | ||||||
|     gw.initWebsocket() |     gw.initWebsocket() | ||||||
|     this.emit('launch', id) |     this.emit('launch', id) | ||||||
| 
 | 
 | ||||||
|  | @ -65,11 +98,24 @@ export class ShardManager extends HarmonyEventEmitter<ShardManagerEvents> { | ||||||
|     return gw.waitFor(GatewayEvents.Ready, () => true).then(() => this) |     return gw.waitFor(GatewayEvents.Ready, () => true).then(() => this) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async start(): Promise<ShardManager> { |   /** Launches all Shards */ | ||||||
|  |   async connect(): Promise<ShardManager> { | ||||||
|     const shardCount = await this.getShardCount() |     const shardCount = await this.getShardCount() | ||||||
|     for (let i = 0; i <= shardCount; i++) { |     this.client.shardCount = shardCount | ||||||
|  |     this.debug(`Launching ${shardCount} shard${shardCount === 1 ? '' : 's'}...`) | ||||||
|  |     const startTime = Date.now() | ||||||
|  |     for (let i = 0; i < shardCount; i++) { | ||||||
|       await this.launch(i) |       await this.launch(i) | ||||||
|     } |     } | ||||||
|  |     const endTime = Date.now() | ||||||
|  |     const diff = endTime - startTime | ||||||
|  |     this.debug( | ||||||
|  |       `Launched ${shardCount} shards! Time taken: ${Math.floor(diff / 1000)}s` | ||||||
|  |     ) | ||||||
|     return this |     return this | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   get(id: number): Gateway | undefined { | ||||||
|  |     return this.list.get(id.toString()) | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -201,13 +201,11 @@ export class SlashBuilder { | ||||||
| 
 | 
 | ||||||
| export class SlashCommandsManager { | export class SlashCommandsManager { | ||||||
|   slash: SlashClient |   slash: SlashClient | ||||||
| 
 |   rest: RESTManager | ||||||
|   get rest(): RESTManager { |  | ||||||
|     return this.slash.rest |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   constructor(client: SlashClient) { |   constructor(client: SlashClient) { | ||||||
|     this.slash = client |     this.slash = client | ||||||
|  |     this.rest = client.rest | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   /** Get all Global Slash Commands */ |   /** Get all Global Slash Commands */ | ||||||
|  | @ -378,7 +376,6 @@ export class SlashClient { | ||||||
|     this.id = id |     this.id = id | ||||||
|     this.client = options.client |     this.client = options.client | ||||||
|     this.token = options.token |     this.token = options.token | ||||||
|     this.commands = new SlashCommandsManager(this) |  | ||||||
|     this.publicKey = options.publicKey |     this.publicKey = options.publicKey | ||||||
| 
 | 
 | ||||||
|     if (options !== undefined) { |     if (options !== undefined) { | ||||||
|  | @ -387,12 +384,14 @@ export class SlashClient { | ||||||
| 
 | 
 | ||||||
|     if (this.client?._decoratedSlash !== undefined) { |     if (this.client?._decoratedSlash !== undefined) { | ||||||
|       this.client._decoratedSlash.forEach((e) => { |       this.client._decoratedSlash.forEach((e) => { | ||||||
|  |         e.handler = e.handler.bind(this.client) | ||||||
|         this.handlers.push(e) |         this.handlers.push(e) | ||||||
|       }) |       }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (this._decoratedSlash !== undefined) { |     if (this._decoratedSlash !== undefined) { | ||||||
|       this._decoratedSlash.forEach((e) => { |       this._decoratedSlash.forEach((e) => { | ||||||
|  |         e.handler = e.handler.bind(this.client) | ||||||
|         this.handlers.push(e) |         this.handlers.push(e) | ||||||
|       }) |       }) | ||||||
|     } |     } | ||||||
|  | @ -409,6 +408,8 @@ export class SlashClient { | ||||||
|     this.client?.on('interactionCreate', (interaction) => |     this.client?.on('interactionCreate', (interaction) => | ||||||
|       this._process(interaction) |       this._process(interaction) | ||||||
|     ) |     ) | ||||||
|  | 
 | ||||||
|  |     this.commands = new SlashCommandsManager(this) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   getID(): string { |   getID(): string { | ||||||
|  |  | ||||||
|  | @ -181,6 +181,11 @@ export class Guild extends Base { | ||||||
|   approximatePresenceCount?: number |   approximatePresenceCount?: number | ||||||
|   bans: GuildBans |   bans: GuildBans | ||||||
| 
 | 
 | ||||||
|  |   /** Get Shard ID of Guild on which it is */ | ||||||
|  |   get shardID(): number { | ||||||
|  |     return Number((BigInt(this.id) << 22n) % BigInt(this.client.shardCount)) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   constructor(client: Client, data: GuildPayload) { |   constructor(client: Client, data: GuildPayload) { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.id = data.id |     this.id = data.id | ||||||
|  | @ -301,7 +306,7 @@ export class Guild extends Base { | ||||||
|     timeout: number = 60000 |     timeout: number = 60000 | ||||||
|   ): Promise<Guild> { |   ): Promise<Guild> { | ||||||
|     return await new Promise((resolve, reject) => { |     return await new Promise((resolve, reject) => { | ||||||
|       this.client.gateway?.requestMembers(this.id, options) |       this.client.shards.get(this.shardID)?.requestMembers(this.id, options) | ||||||
|       if (!wait) return resolve(this) |       if (!wait) return resolve(this) | ||||||
|       else { |       else { | ||||||
|         let chunked = false |         let chunked = false | ||||||
|  |  | ||||||
|  | @ -57,7 +57,9 @@ export class VoiceChannel extends Channel { | ||||||
|         if (done >= 2) resolve(vcdata) |         if (done >= 2) resolve(vcdata) | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       this.client.gateway?.updateVoiceState(this.guild.id, this.id, options) |       this.client.shards | ||||||
|  |         .get(this.guild.shardID) | ||||||
|  |         ?.updateVoiceState(this.guild.id, this.id, options) | ||||||
| 
 | 
 | ||||||
|       this.client.on('voiceStateAdd', onVoiceStateAdd) |       this.client.on('voiceStateAdd', onVoiceStateAdd) | ||||||
|       this.client.on('voiceServerUpdate', onVoiceServerUpdate) |       this.client.on('voiceServerUpdate', onVoiceServerUpdate) | ||||||
|  | @ -77,7 +79,9 @@ export class VoiceChannel extends Channel { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   leave(): void { |   leave(): void { | ||||||
|     this.client.gateway?.updateVoiceState(this.guild.id, undefined) |     this.client.shards | ||||||
|  |       .get(this.guild.shardID) | ||||||
|  |       ?.updateVoiceState(this.guild.id, undefined) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   readFromData(data: GuildVoiceChannelPayload): void { |   readFromData(data: GuildVoiceChannelPayload): void { | ||||||
|  |  | ||||||
|  | @ -32,10 +32,6 @@ client.on('messageUpdate', (before, after) => { | ||||||
|   console.log(`After: ${after.author.tag}: ${after.content}`) |   console.log(`After: ${after.author.tag}: ${after.content}`) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on('messageUpdateUncached', (msg) => { |  | ||||||
|   console.log(`Message: ${msg.author.tag}: ${msg.content}`) |  | ||||||
| }) |  | ||||||
| 
 |  | ||||||
| client.on('guildMemberAdd', (member) => { | client.on('guildMemberAdd', (member) => { | ||||||
|   console.log(`Member Join: ${member.user.tag}`) |   console.log(`Member Join: ${member.user.tag}`) | ||||||
| }) | }) | ||||||
|  | @ -73,7 +69,7 @@ client.on('inviteDelete', (invite: Invite) => { | ||||||
|   console.log(`Invite Delete: ${invite.code}`) |   console.log(`Invite Delete: ${invite.code}`) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on('inviteDeleteUncached', (invite: Invite) => { | client.on('inviteDeleteUncached', (invite) => { | ||||||
|   console.log(invite) |   console.log(invite) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,7 +23,8 @@ const client = new Client({ | ||||||
|   // cache: new RedisCacheAdapter({
 |   // cache: new RedisCacheAdapter({
 | ||||||
|   //   hostname: '127.0.0.1',
 |   //   hostname: '127.0.0.1',
 | ||||||
|   //   port: 6379
 |   //   port: 6379
 | ||||||
|   // }) // Defaults to in-memory Caching
 |   // }), // Defaults to in-memory Caching
 | ||||||
|  |   // shardCount: 2
 | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.on('ready', () => { | client.on('ready', () => { | ||||||
|  | @ -154,6 +155,11 @@ client.on('messageCreate', async (msg: Message) => { | ||||||
|     msg.channel.send({ |     msg.channel.send({ | ||||||
|       file: new MessageAttachment('hello.txt', 'hello world') |       file: new MessageAttachment('hello.txt', 'hello world') | ||||||
|     }) |     }) | ||||||
|  |   } else if (msg.content === '!join') { | ||||||
|  |     if (msg.member === undefined) return | ||||||
|  |     const vs = await msg.guild?.voiceStates.get(msg.member.id) | ||||||
|  |     if (typeof vs !== 'object') return | ||||||
|  |     vs.channel?.join() | ||||||
|   } |   } | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  | @ -166,7 +172,7 @@ client.on('messageReactionRemove', (reaction, user) => { | ||||||
|   } |   } | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
| client.connect(TOKEN, Intents.All) | client.connect(TOKEN, Intents.None) | ||||||
| 
 | 
 | ||||||
| // OLD: Was a way to reproduce reconnect infinite loop
 | // OLD: Was a way to reproduce reconnect infinite loop
 | ||||||
| // setTimeout(() => {
 | // setTimeout(() => {
 | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ export class MyClient extends Client { | ||||||
|   @event() |   @event() | ||||||
|   ready(): void { |   ready(): void { | ||||||
|     console.log(`Logged in as ${this.user?.tag}!`) |     console.log(`Logged in as ${this.user?.tag}!`) | ||||||
|  |     this.slash.commands.bulkEdit([{ name: 'send', description: 'idk' }]) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   @event('debug') |   @event('debug') | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue