mirror of
https://github.com/discordjs/discord.js.git
synced 2026-03-14 02:23:31 +01:00
feat(core): implement some ws send events (#8941)
* feat(core): implement some ws send events * fix: check guild id and add a timeout * fix: only check for nonce * chore: update readme * chore: make requested changes * chore: make methods consistent * chore: fix readme example * chore: move shard ID calculation to util Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
@@ -1,66 +1,74 @@
|
||||
import { setTimeout } from 'node:timers';
|
||||
import type { REST } from '@discordjs/rest';
|
||||
import { calculateShardId } from '@discordjs/util';
|
||||
import { WebSocketShardEvents, type WebSocketManager } from '@discordjs/ws';
|
||||
import { DiscordSnowflake } from '@sapphire/snowflake';
|
||||
import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
|
||||
import type {
|
||||
GatewayAutoModerationActionExecutionDispatchData,
|
||||
GatewayAutoModerationRuleCreateDispatchData,
|
||||
GatewayAutoModerationRuleDeleteDispatchData,
|
||||
GatewayAutoModerationRuleUpdateDispatchData,
|
||||
GatewayChannelCreateDispatchData,
|
||||
GatewayChannelDeleteDispatchData,
|
||||
GatewayChannelPinsUpdateDispatchData,
|
||||
GatewayChannelUpdateDispatchData,
|
||||
import {
|
||||
GatewayDispatchEvents,
|
||||
GatewayGuildBanAddDispatchData,
|
||||
GatewayGuildBanRemoveDispatchData,
|
||||
GatewayGuildCreateDispatchData,
|
||||
GatewayGuildDeleteDispatchData,
|
||||
GatewayGuildEmojisUpdateDispatchData,
|
||||
GatewayGuildIntegrationsUpdateDispatchData,
|
||||
GatewayGuildMemberAddDispatchData,
|
||||
GatewayGuildMemberRemoveDispatchData,
|
||||
GatewayGuildMembersChunkDispatchData,
|
||||
GatewayGuildMemberUpdateDispatchData,
|
||||
GatewayGuildRoleCreateDispatchData,
|
||||
GatewayGuildRoleDeleteDispatchData,
|
||||
GatewayGuildRoleUpdateDispatchData,
|
||||
GatewayGuildScheduledEventCreateDispatchData,
|
||||
GatewayGuildScheduledEventDeleteDispatchData,
|
||||
GatewayGuildScheduledEventUpdateDispatchData,
|
||||
GatewayGuildScheduledEventUserAddDispatchData,
|
||||
GatewayGuildScheduledEventUserRemoveDispatchData,
|
||||
GatewayGuildStickersUpdateDispatchData,
|
||||
GatewayGuildUpdateDispatchData,
|
||||
GatewayIntegrationCreateDispatchData,
|
||||
GatewayIntegrationDeleteDispatchData,
|
||||
GatewayIntegrationUpdateDispatchData,
|
||||
GatewayInteractionCreateDispatchData,
|
||||
GatewayInviteCreateDispatchData,
|
||||
GatewayInviteDeleteDispatchData,
|
||||
GatewayMessageCreateDispatchData,
|
||||
GatewayMessageDeleteBulkDispatchData,
|
||||
GatewayMessageDeleteDispatchData,
|
||||
GatewayMessageReactionAddDispatchData,
|
||||
GatewayMessageReactionRemoveAllDispatchData,
|
||||
GatewayMessageReactionRemoveDispatchData,
|
||||
GatewayMessageReactionRemoveEmojiDispatchData,
|
||||
GatewayMessageUpdateDispatchData,
|
||||
GatewayPresenceUpdateDispatchData,
|
||||
GatewayReadyDispatchData,
|
||||
GatewayStageInstanceCreateDispatchData,
|
||||
GatewayStageInstanceDeleteDispatchData,
|
||||
GatewayStageInstanceUpdateDispatchData,
|
||||
GatewayThreadCreateDispatchData,
|
||||
GatewayThreadDeleteDispatchData,
|
||||
GatewayThreadListSyncDispatchData,
|
||||
GatewayThreadMembersUpdateDispatchData,
|
||||
GatewayThreadMemberUpdateDispatchData,
|
||||
GatewayThreadUpdateDispatchData,
|
||||
GatewayTypingStartDispatchData,
|
||||
GatewayUserUpdateDispatchData,
|
||||
GatewayVoiceServerUpdateDispatchData,
|
||||
GatewayVoiceStateUpdateDispatchData,
|
||||
GatewayWebhooksUpdateDispatchData,
|
||||
GatewayOpcodes,
|
||||
type GatewayVoiceStateUpdateData,
|
||||
type APIGuildMember,
|
||||
type GatewayAutoModerationActionExecutionDispatchData,
|
||||
type GatewayAutoModerationRuleCreateDispatchData,
|
||||
type GatewayAutoModerationRuleDeleteDispatchData,
|
||||
type GatewayAutoModerationRuleUpdateDispatchData,
|
||||
type GatewayChannelCreateDispatchData,
|
||||
type GatewayChannelDeleteDispatchData,
|
||||
type GatewayChannelPinsUpdateDispatchData,
|
||||
type GatewayChannelUpdateDispatchData,
|
||||
type GatewayGuildBanAddDispatchData,
|
||||
type GatewayGuildBanRemoveDispatchData,
|
||||
type GatewayGuildCreateDispatchData,
|
||||
type GatewayGuildDeleteDispatchData,
|
||||
type GatewayGuildEmojisUpdateDispatchData,
|
||||
type GatewayGuildIntegrationsUpdateDispatchData,
|
||||
type GatewayGuildMemberAddDispatchData,
|
||||
type GatewayGuildMemberRemoveDispatchData,
|
||||
type GatewayGuildMembersChunkDispatchData,
|
||||
type GatewayGuildMemberUpdateDispatchData,
|
||||
type GatewayGuildRoleCreateDispatchData,
|
||||
type GatewayGuildRoleDeleteDispatchData,
|
||||
type GatewayGuildRoleUpdateDispatchData,
|
||||
type GatewayGuildScheduledEventCreateDispatchData,
|
||||
type GatewayGuildScheduledEventDeleteDispatchData,
|
||||
type GatewayGuildScheduledEventUpdateDispatchData,
|
||||
type GatewayGuildScheduledEventUserAddDispatchData,
|
||||
type GatewayGuildScheduledEventUserRemoveDispatchData,
|
||||
type GatewayGuildStickersUpdateDispatchData,
|
||||
type GatewayGuildUpdateDispatchData,
|
||||
type GatewayIntegrationCreateDispatchData,
|
||||
type GatewayIntegrationDeleteDispatchData,
|
||||
type GatewayIntegrationUpdateDispatchData,
|
||||
type GatewayInteractionCreateDispatchData,
|
||||
type GatewayInviteCreateDispatchData,
|
||||
type GatewayInviteDeleteDispatchData,
|
||||
type GatewayMessageCreateDispatchData,
|
||||
type GatewayMessageDeleteBulkDispatchData,
|
||||
type GatewayMessageDeleteDispatchData,
|
||||
type GatewayMessageReactionAddDispatchData,
|
||||
type GatewayMessageReactionRemoveAllDispatchData,
|
||||
type GatewayMessageReactionRemoveDispatchData,
|
||||
type GatewayMessageReactionRemoveEmojiDispatchData,
|
||||
type GatewayMessageUpdateDispatchData,
|
||||
type GatewayPresenceUpdateDispatchData,
|
||||
type GatewayReadyDispatchData,
|
||||
type GatewayRequestGuildMembersData,
|
||||
type GatewayStageInstanceCreateDispatchData,
|
||||
type GatewayStageInstanceDeleteDispatchData,
|
||||
type GatewayStageInstanceUpdateDispatchData,
|
||||
type GatewayThreadCreateDispatchData,
|
||||
type GatewayThreadDeleteDispatchData,
|
||||
type GatewayThreadListSyncDispatchData,
|
||||
type GatewayThreadMembersUpdateDispatchData,
|
||||
type GatewayThreadMemberUpdateDispatchData,
|
||||
type GatewayThreadUpdateDispatchData,
|
||||
type GatewayTypingStartDispatchData,
|
||||
type GatewayUserUpdateDispatchData,
|
||||
type GatewayVoiceServerUpdateDispatchData,
|
||||
type GatewayVoiceStateUpdateDispatchData,
|
||||
type GatewayWebhooksUpdateDispatchData,
|
||||
type GatewayPresenceUpdateData,
|
||||
} from 'discord-api-types/v10';
|
||||
import { API } from './api/index.js';
|
||||
|
||||
@@ -158,22 +166,106 @@ export interface ClientOptions {
|
||||
ws: WebSocketManager;
|
||||
}
|
||||
|
||||
export function createClient({ rest, ws }: ClientOptions) {
|
||||
const api = new API(rest);
|
||||
const emitter = new AsyncEventEmitter<ManagerShardEventsMap>();
|
||||
export class Client extends AsyncEventEmitter<ManagerShardEventsMap> {
|
||||
public readonly rest: REST;
|
||||
|
||||
function wrapIntrinsicProps<T>(obj: T, shardId: number): WithIntrinsicProps<T> {
|
||||
public readonly ws: WebSocketManager;
|
||||
|
||||
public readonly api: API;
|
||||
|
||||
public constructor({ rest, ws }: ClientOptions) {
|
||||
super();
|
||||
this.rest = rest;
|
||||
this.ws = ws;
|
||||
this.api = new API(rest);
|
||||
|
||||
this.ws.on(WebSocketShardEvents.Dispatch, ({ data: dispatch, shardId }) => {
|
||||
// @ts-expect-error event props can't be resolved properly, but they are correct
|
||||
this.emit(dispatch.t, this.wrapIntrinsicProps(dispatch.d, shardId));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests guild members from the gateway.
|
||||
*
|
||||
* @see {@link https://discord.com/developers/docs/topics/gateway-events#request-guild-members}
|
||||
* @param options - The options for the request
|
||||
* @param timeout - The timeout for waiting for each guild members chunk event
|
||||
*/
|
||||
public async requestGuildMembers(options: GatewayRequestGuildMembersData, timeout = 10_000) {
|
||||
const shardId = calculateShardId(options.guild_id, await this.ws.getShardCount());
|
||||
const nonce = options.nonce ?? DiscordSnowflake.generate().toString();
|
||||
|
||||
const promise = new Promise<APIGuildMember[]>((resolve, reject) => {
|
||||
const guildMembers: APIGuildMember[] = [];
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
reject(new Error('Request timed out'));
|
||||
}, timeout);
|
||||
|
||||
const handler = ({ data }: MappedEvents[GatewayDispatchEvents.GuildMembersChunk][0]) => {
|
||||
timer.refresh();
|
||||
|
||||
if (data.nonce !== nonce) return;
|
||||
|
||||
guildMembers.push(...data.members);
|
||||
|
||||
if (data.chunk_index >= data.chunk_count - 1) {
|
||||
this.off(GatewayDispatchEvents.GuildMembersChunk, handler);
|
||||
resolve(guildMembers);
|
||||
}
|
||||
};
|
||||
|
||||
this.on(GatewayDispatchEvents.GuildMembersChunk, handler);
|
||||
});
|
||||
|
||||
await this.ws.send(shardId, {
|
||||
op: GatewayOpcodes.RequestGuildMembers,
|
||||
// eslint-disable-next-line id-length
|
||||
d: {
|
||||
...options,
|
||||
nonce,
|
||||
},
|
||||
});
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the voice state of the bot user
|
||||
*
|
||||
* @see {@link https://discord.com/developers/docs/topics/gateway-events#update-voice-state}
|
||||
* @param options - The options for updating the voice state
|
||||
*/
|
||||
public async updateVoiceState(options: GatewayVoiceStateUpdateData) {
|
||||
const shardId = calculateShardId(options.guild_id, await this.ws.getShardCount());
|
||||
|
||||
await this.ws.send(shardId, {
|
||||
op: GatewayOpcodes.VoiceStateUpdate,
|
||||
// eslint-disable-next-line id-length
|
||||
d: options,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the presence of the bot user
|
||||
*
|
||||
* @param shardId - The id of the shard to update the presence in
|
||||
* @param options - The options for updating the presence
|
||||
*/
|
||||
public async updatePresence(shardId: number, options: GatewayPresenceUpdateData) {
|
||||
await this.ws.send(shardId, {
|
||||
op: GatewayOpcodes.PresenceUpdate,
|
||||
// eslint-disable-next-line id-length
|
||||
d: options,
|
||||
});
|
||||
}
|
||||
|
||||
private wrapIntrinsicProps<T>(obj: T, shardId: number): WithIntrinsicProps<T> {
|
||||
return {
|
||||
api,
|
||||
api: this.api,
|
||||
shardId,
|
||||
data: obj,
|
||||
};
|
||||
}
|
||||
|
||||
ws.on(WebSocketShardEvents.Dispatch, ({ data: dispatch, shardId }) => {
|
||||
// @ts-expect-error event props can't be resolved properly, but they are correct
|
||||
emitter.emit(dispatch.t, wrapIntrinsicProps(dispatch.d, shardId));
|
||||
});
|
||||
|
||||
return emitter;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user