mirror of
https://github.com/discordeno/discordeno.git
synced 2026-06-16 03:18:17 +00:00
handlers
This commit is contained in:
+40
-2
@@ -293,6 +293,8 @@ import {
|
||||
validDiscoveryTerm,
|
||||
} from "./helpers/mod.ts";
|
||||
import { DiscordenoEmoji, transformEmoji } from "./transformers/emoji.ts";
|
||||
import { transformActivity } from "./transformers/activity.ts";
|
||||
import { DiscordenoPresence, transformPresence } from "./transformers/presence.ts";
|
||||
|
||||
export async function createBot(options: CreateBotOptions) {
|
||||
return {
|
||||
@@ -309,6 +311,9 @@ export async function createBot(options: CreateBotOptions) {
|
||||
cache: {
|
||||
execute: async function (
|
||||
type:
|
||||
| "DELETE_MESSAGES_FROM_CHANNEL"
|
||||
| "DELETE_ROLE_FROM_MEMBER"
|
||||
| "BULK_DELETE_MESSAGES"
|
||||
| "GUILD_MEMBER_CHUNK"
|
||||
| "GUILD_MEMBER_COUNT_DECREMENT"
|
||||
| "GUILD_MEMBER_COUNT_INCREMENT"
|
||||
@@ -374,6 +379,20 @@ export async function createBot(options: CreateBotOptions) {
|
||||
return;
|
||||
},
|
||||
},
|
||||
presence: {
|
||||
get: async function (id: bigint): Promise<DiscordenoPresence | undefined> {
|
||||
return {} as any as DiscordenoPresence;
|
||||
},
|
||||
has: async function (id: bigint): Promise<boolean> {
|
||||
return false;
|
||||
},
|
||||
set: async function (id: bigint, guild: DiscordenoPresence): Promise<void> {
|
||||
return;
|
||||
},
|
||||
delete: async function (id: bigint): Promise<void> {
|
||||
return;
|
||||
},
|
||||
},
|
||||
users: {
|
||||
get: async function (id: bigint): Promise<DiscordenoUser | undefined> {
|
||||
return {} as any as DiscordenoUser;
|
||||
@@ -440,6 +459,9 @@ export function createEventHandlers(events: Partial<EventHandlers>): EventHandle
|
||||
reactionRemove: events.reactionRemove ?? ignore,
|
||||
reactionRemoveAll: events.reactionRemoveAll ?? ignore,
|
||||
reactionRemoveEmoji: events.reactionRemoveEmoji ?? ignore,
|
||||
presenceUpdate: events.presenceUpdate ?? ignore,
|
||||
voiceServerUpdate: events.voiceServerUpdate ?? ignore,
|
||||
voiceStateUpdate: events.voiceStateUpdate ?? ignore,
|
||||
channelCreate: events.channelCreate ?? ignore,
|
||||
voiceChannelLeave: events.voiceChannelLeave ?? ignore,
|
||||
channelDelete: events.channelDelete ?? ignore,
|
||||
@@ -1018,10 +1040,13 @@ export interface Transformers {
|
||||
application: typeof transformApplication;
|
||||
team: typeof transformTeam;
|
||||
emoji: typeof transformEmoji;
|
||||
activity: typeof transformActivity;
|
||||
presence: typeof transformPresence;
|
||||
}
|
||||
|
||||
export function createTransformers(options: Partial<Transformers>) {
|
||||
return {
|
||||
activity: options.activity || transformActivity,
|
||||
application: options.application || transformApplication,
|
||||
channel: options.channel || transformChannel,
|
||||
emoji: options.emoji || transformEmoji,
|
||||
@@ -1031,6 +1056,7 @@ export function createTransformers(options: Partial<Transformers>) {
|
||||
invite: options.invite || transformInvite,
|
||||
member: options.member || transformMember,
|
||||
message: options.message || transformMessage,
|
||||
presence: options.presence || transformPresence,
|
||||
role: options.role || transformRole,
|
||||
user: options.user || transformUser,
|
||||
team: options.team || transformTeam,
|
||||
@@ -1149,7 +1175,7 @@ export interface EventHandlers {
|
||||
interactionCreate: (bot: Bot, interaction: DiscordenoInteraction) => any;
|
||||
integrationCreate: (bot: Bot, integration: DiscordenoIntegration) => any;
|
||||
integrationDelete: (bot: Bot, payload: { id: bigint; guildId: bigint; applicationId?: bigint }) => any;
|
||||
integrationUpdate: (bot: Bot, integration: DiscordenoIntegration) => any;
|
||||
integrationUpdate: (bot: Bot, payload: { guildId: bigint }) => any;
|
||||
inviteCreate: (bot: Bot, invite: DiscordenoInvite) => any;
|
||||
inviteDelete: (
|
||||
bot: Bot,
|
||||
@@ -1207,9 +1233,21 @@ export interface EventHandlers {
|
||||
guildId?: bigint;
|
||||
}
|
||||
) => any;
|
||||
presenceUpdate: (bot: Bot, presence: DiscordenoPresence, oldPresence?: DiscordenoPresence) => any;
|
||||
voiceServerUpdate: (bot: Bot, payload: { token: string; endpoint?: string; guildId: bigint }) => any;
|
||||
voiceStateUpdate: (
|
||||
bot: Bot,
|
||||
voiceState: DiscordenoVoiceState,
|
||||
payload: { guild?: DiscordenoGuild; member?: DiscordenoMember; user?: DiscordenoUser }
|
||||
) => any;
|
||||
channelCreate: (bot: Bot, channel: DiscordenoChannel) => any;
|
||||
dispatchRequirements: (bot: Bot, data: GatewayPayload, shardId: number) => any;
|
||||
voiceChannelLeave: (bot: Bot, voiceState: DiscordenoVoiceState, channel: DiscordenoChannel) => any;
|
||||
voiceChannelLeave: (
|
||||
bot: Bot,
|
||||
voiceState: DiscordenoVoiceState,
|
||||
guild: DiscordenoGuild,
|
||||
channel?: DiscordenoChannel
|
||||
) => any;
|
||||
channelDelete: (bot: Bot, channel: DiscordenoChannel) => any;
|
||||
channelPinsUpdate: (bot: Bot, data: { guildId?: bigint; channelId: bigint; lastPinTimestamp?: number }) => any;
|
||||
channelUpdate: (bot: Bot, channel: DiscordenoChannel, oldChannel: DiscordenoChannel) => any;
|
||||
|
||||
@@ -6,18 +6,22 @@ import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export async function handleChannelDelete(bot: Bot, data: SnakeCasedPropertiesDeep<DiscordGatewayPayload>) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<Channel>;
|
||||
if (!payload.guild_id) return;
|
||||
|
||||
const channel = await bot.cache.channels.get(bot.transformers.snowflake(payload.id));
|
||||
const [channel, guild] = await Promise.all([
|
||||
bot.cache.channels.get(bot.transformers.snowflake(payload.id)),
|
||||
bot.cache.guilds.get(bot.transformers.snowflake(payload.guild_id)),
|
||||
]);
|
||||
if (!channel) return;
|
||||
|
||||
if ([DiscordChannelTypes.GuildVoice, DiscordChannelTypes.GuildStageVoice].includes(channel.type)) {
|
||||
channel.voiceStates?.forEach((vs, key) => {
|
||||
if (guild && [DiscordChannelTypes.GuildVoice, DiscordChannelTypes.GuildStageVoice].includes(channel.type)) {
|
||||
guild.voiceStates?.forEach((vs, key) => {
|
||||
if (vs.channelId !== channel.id) return;
|
||||
|
||||
// Since this channel was deleted all voice states for this channel should be deleted
|
||||
channel.voiceStates?.delete(key);
|
||||
guild.voiceStates?.delete(key);
|
||||
|
||||
bot.events.voiceChannelLeave(bot, vs, channel);
|
||||
bot.events.voiceChannelLeave(bot, vs, guild, channel);
|
||||
});
|
||||
} else if (
|
||||
[
|
||||
@@ -27,7 +31,7 @@ export async function handleChannelDelete(bot: Bot, data: SnakeCasedPropertiesDe
|
||||
DiscordChannelTypes.GuildNews,
|
||||
].includes(payload.type)
|
||||
) {
|
||||
await bot.cache.channels.forEach("DELETE_MESSAGES_FROM_CHANNEL", {
|
||||
await bot.cache.execute("DELETE_MESSAGES_FROM_CHANNEL", {
|
||||
channelId: bot.transformers.snowflake(payload.id),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@ import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
export async function handleGuildIntegrationsUpdate(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<GuildIntegrationsUpdate>;
|
||||
|
||||
bot.events.integrationsUpdate(bot, { guildId: bot.transformers.snowflake(payload.guild_id) });
|
||||
bot.events.integrationUpdate(bot, { guildId: bot.transformers.snowflake(payload.guild_id) });
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import type { PresenceUpdate } from "../../types/activity/presence_update.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export async function handlePresenceUpdate(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as PresenceUpdate;
|
||||
export async function handlePresenceUpdate(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<PresenceUpdate>;
|
||||
|
||||
const oldPresence = await cacheHandlers.get("presences", snowflakeToBigint(payload.user.id));
|
||||
await cacheHandlers.set("presences", snowflakeToBigint(payload.user.id), payload);
|
||||
const id = bot.transformers.snowflake(payload.user.id);
|
||||
|
||||
eventHandlers.presenceUpdate?.(payload, oldPresence);
|
||||
const oldPresence = await bot.cache.presence.get(id);
|
||||
const presence = bot.transformers.presence(bot, payload);
|
||||
await bot.cache.presence.set(id, presence)
|
||||
|
||||
|
||||
bot.events.presenceUpdate(bot, presence, oldPresence);
|
||||
}
|
||||
|
||||
+15
-62
@@ -1,67 +1,20 @@
|
||||
import { eventHandlers, setApplicationId, setBotId } from "../../bot.ts";
|
||||
import { cache } from "../../cache.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { Ready } from "../../types/gateway/ready.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { DiscordenoShard, ws } from "../../ws/ws.ts";
|
||||
import type { DiscordReady } from "../../types/gateway/ready.ts";
|
||||
|
||||
export function handleReady(data: DiscordGatewayPayload, shardId: number) {
|
||||
export function handleReady(bot: Bot, data: DiscordGatewayPayload, shardId: number) {
|
||||
const payload = data.d as DiscordReady;
|
||||
// Triggered on each shard
|
||||
eventHandlers.shardReady?.(shardId);
|
||||
bot.events.ready(bot, {
|
||||
shardId,
|
||||
v: payload.v,
|
||||
user: bot.transformers.user(bot, payload.user),
|
||||
guilds: payload.guilds.map((p) => bot.transformers.snowflake(p.id)),
|
||||
sessionId: payload.session_id,
|
||||
shard: payload.shard,
|
||||
applicationId: bot.transformers.snowflake(payload.application.id),
|
||||
}, payload);
|
||||
|
||||
// The bot has already started, the last shard is resumed, however.
|
||||
if (cache.isReady) return;
|
||||
|
||||
const shard = ws.shards.get(shardId);
|
||||
if (!shard) return;
|
||||
|
||||
const payload = data.d as Ready;
|
||||
setBotId(payload.user.id);
|
||||
setApplicationId(payload.application.id);
|
||||
|
||||
// Set ready to false just to go sure
|
||||
shard.ready = false;
|
||||
// All guilds are unavailable at first
|
||||
shard.unavailableGuildIds = new Set(payload.guilds.map((g) => snowflakeToBigint(g.id)));
|
||||
|
||||
// Falied to load check
|
||||
shard.failedToLoadTimeoutId = setTimeout(() => {
|
||||
eventHandlers.shardFailedToLoad?.(shard.id, shard.unavailableGuildIds);
|
||||
// Force execute the loaded function to prevent infinite loop
|
||||
return loaded(shard);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
export function guildAvailable(shard: DiscordenoShard, guildId: bigint) {
|
||||
if (!shard.failedToLoadTimeoutId) return;
|
||||
|
||||
clearTimeout(shard.failedToLoadTimeoutId);
|
||||
shard.unavailableGuildIds.delete(guildId);
|
||||
if (!shard.unavailableGuildIds.size) return loaded(shard);
|
||||
|
||||
shard.failedToLoadTimeoutId = setTimeout(() => {
|
||||
eventHandlers.shardFailedToLoad?.(shard.id, shard.unavailableGuildIds);
|
||||
// Force execute the loaded function to prevent infinite loop
|
||||
return loaded(shard);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function loaded(shard: DiscordenoShard) {
|
||||
shard.ready = true;
|
||||
|
||||
// If it is not the last shard we can't go full ready
|
||||
if (shard.id !== ws.lastShardId) return;
|
||||
|
||||
// Still some shards are loading so wait another 2 seconds for them
|
||||
if (ws.shards.some((shard) => !shard.ready)) {
|
||||
setTimeout(() => {
|
||||
eventHandlers.debug?.("loop", `3. Running setTimeout in READY file.`);
|
||||
loaded(shard);
|
||||
}, 2000);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
cache.isReady = true;
|
||||
eventHandlers.ready?.();
|
||||
if (!bot.id) bot.id = bot.transformers.snowflake(payload.user.id);
|
||||
if (!bot.applicationId) bot.applicationId = bot.transformers.snowflake(payload.application.id);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,18 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { TypingStart } from "../../types/misc/typing_start.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export function handleTypingStart(data: DiscordGatewayPayload) {
|
||||
eventHandlers.typingStart?.(data.d as TypingStart);
|
||||
export function handleTypingStart(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<TypingStart>;
|
||||
|
||||
const guildId = payload.guild_id ? bot.transformers.snowflake(payload.guild_id) : undefined;
|
||||
|
||||
bot.events.typingStart(bot, {
|
||||
guildId,
|
||||
channelId: bot.transformers.snowflake(payload.channel_id),
|
||||
userId: bot.transformers.snowflake(payload.user_id),
|
||||
timestamp: payload.timestamp,
|
||||
member: payload.member && guildId ? bot.transformers.member(bot, payload.member, guildId) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,35 +1,12 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { memberToggles } from "../../structures/member.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { User } from "../../types/users/user.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { iconHashToBigInt } from "../../util/hash.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export async function handleUserUpdate(data: DiscordGatewayPayload) {
|
||||
const userData = data.d as User;
|
||||
export async function handleUserUpdate(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<User>;
|
||||
const user = bot.transformers.user(bot, payload);
|
||||
await bot.cache.users.set(user.id, user);
|
||||
|
||||
const member = await cacheHandlers.get("members", snowflakeToBigint(userData.id));
|
||||
if (!member) return;
|
||||
|
||||
// Update username
|
||||
member.username = userData.username;
|
||||
// Update discriminator
|
||||
member.discriminator = Number(userData.discriminator);
|
||||
|
||||
// Check if a avatar is available
|
||||
const hash = userData.avatar ? iconHashToBigInt(userData.avatar) : undefined;
|
||||
// Update the avatar
|
||||
member.avatar = hash?.bigint || 0n;
|
||||
// Update the animated status if its animated
|
||||
if (hash?.animated) member.bitfield |= memberToggles.animatedAvatar;
|
||||
else member.bitfield &= ~memberToggles.animatedAvatar;
|
||||
|
||||
member.flags = userData.flags;
|
||||
member.premiumType = userData.premiumType;
|
||||
member.publicFlags = userData.publicFlags;
|
||||
|
||||
await cacheHandlers.set("members", snowflakeToBigint(userData.id), member);
|
||||
|
||||
eventHandlers.botUpdate?.(userData);
|
||||
bot.events.botUpdate(bot, user);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { GuildRoleCreate } from "../../types/guilds/guild_role_create.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export async function handleGuildRoleCreate(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as GuildRoleCreate;
|
||||
const guild = await cacheHandlers.get("guilds", snowflakeToBigint(payload.guildId));
|
||||
export async function handleGuildRoleCreate(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<GuildRoleCreate>;
|
||||
|
||||
const guildId = bot.transformers.snowflake(payload.guild_id);
|
||||
const guild = await bot.cache.guilds.get(guildId);
|
||||
if (!guild) return;
|
||||
|
||||
const role = await structures.createDiscordenoRole({
|
||||
...payload,
|
||||
guildId: guild.id,
|
||||
});
|
||||
guild.roles = guild.roles.set(snowflakeToBigint(payload.role.id), role);
|
||||
await cacheHandlers.set("guilds", guild.id, guild);
|
||||
const role = bot.transformers.role(bot, { role: payload.role, guildId });
|
||||
|
||||
eventHandlers.roleCreate?.(guild, role);
|
||||
guild.roles = guild.roles.set(role.id, role);
|
||||
await bot.cache.guilds.set(guild.id, guild);
|
||||
|
||||
bot.events.roleCreate(bot, guild, role);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,23 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { GuildRoleDelete } from "../../types/guilds/guild_role_delete.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export async function handleGuildRoleDelete(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as GuildRoleDelete;
|
||||
const guild = await cacheHandlers.get("guilds", snowflakeToBigint(payload.guildId));
|
||||
export async function handleGuildRoleDelete(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<GuildRoleDelete>;
|
||||
const guildId = bot.transformers.snowflake(payload.guild_id);
|
||||
const guild = await bot.cache.guilds.get(guildId);
|
||||
if (!guild) return;
|
||||
|
||||
const roleId = snowflakeToBigint(payload.roleId);
|
||||
const roleId = bot.transformers.snowflake(payload.role_id);
|
||||
|
||||
const cachedRole = guild.roles.get(roleId)!;
|
||||
const cachedRole = guild.roles.get(roleId);
|
||||
guild.roles.delete(roleId);
|
||||
|
||||
if (cachedRole) eventHandlers.roleDelete?.(guild, cachedRole);
|
||||
await bot.cache.guilds.set(guild.id, guild);
|
||||
|
||||
if (cachedRole) bot.events.roleDelete(bot, guild, cachedRole);
|
||||
|
||||
// For bots without GUILD_MEMBERS member.roles is never updated breaking permissions checking.
|
||||
await cacheHandlers.forEach("DELETE_ROLE_FROM_MEMBER", { guildId: guild.id, roleId });
|
||||
await bot.cache.execute("DELETE_ROLE_FROM_MEMBER", { guildId: guild.id, roleId });
|
||||
}
|
||||
|
||||
@@ -1,24 +1,17 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { GuildRoleUpdate } from "../../types/guilds/guild_role_update.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export async function handleGuildRoleUpdate(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as GuildRoleUpdate;
|
||||
const guild = await cacheHandlers.get("guilds", snowflakeToBigint(payload.guildId));
|
||||
export async function handleGuildRoleUpdate(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<GuildRoleUpdate>;
|
||||
const guildId = bot.transformers.snowflake(payload.guild_id);
|
||||
const guild = await bot.cache.guilds.get(guildId);
|
||||
if (!guild) return;
|
||||
|
||||
const cachedRole = guild.roles.get(snowflakeToBigint(payload.role.id));
|
||||
if (!cachedRole) return;
|
||||
const role = bot.transformers.role(bot, { role: payload.role, guildId });
|
||||
guild.roles = guild.roles.set(role.id, role);
|
||||
await bot.cache.guilds.set(guild.id, guild);
|
||||
|
||||
const role = await structures.createDiscordenoRole({
|
||||
...payload,
|
||||
guildId: guild.id,
|
||||
});
|
||||
guild.roles.set(snowflakeToBigint(payload.role.id), role);
|
||||
await cacheHandlers.set("guilds", guild.id, guild);
|
||||
|
||||
eventHandlers.roleUpdate?.(guild, role, cachedRole);
|
||||
bot.events.roleUpdate(bot, guild, role, guild.roles.get(role.id));
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { VoiceServerUpdate } from "../../types/voice/voice_server_update.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
|
||||
export async function handleVoiceServerUpdate(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as VoiceServerUpdate;
|
||||
export async function handleVoiceServerUpdate(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<VoiceServerUpdate>;
|
||||
|
||||
const guild = await cacheHandlers.get("guilds", snowflakeToBigint(payload.guildId));
|
||||
if (!guild) return;
|
||||
|
||||
eventHandlers.voiceServerUpdate?.(payload, guild);
|
||||
bot.events.voiceServerUpdate(bot, {
|
||||
token: payload.token,
|
||||
guildId: bot.transformers.snowflake(payload.guild_id),
|
||||
endpoint: payload.endpoint ?? undefined,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,50 +1,23 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import { cacheHandlers } from "../../cache.ts";
|
||||
import { structures } from "../../structures/mod.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { VoiceState } from "../../types/voice/voice_state.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export async function handleVoiceStateUpdate(data: DiscordGatewayPayload) {
|
||||
const payload = data.d as VoiceState;
|
||||
if (!payload.guildId) return;
|
||||
export async function handleVoiceStateUpdate(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<VoiceState>;
|
||||
if (!payload.guild_id) return;
|
||||
|
||||
const guild = await cacheHandlers.get("guilds", snowflakeToBigint(payload.guildId));
|
||||
if (!guild) return;
|
||||
const guildId = bot.transformers.snowflake(payload.guild_id);
|
||||
const voiceState = bot.transformers.voiceState(bot, { voiceState: payload, guildId });
|
||||
|
||||
const member = payload.member
|
||||
? await structures.createDiscordenoMember(payload.member, guild.id)
|
||||
: await cacheHandlers.get("members", snowflakeToBigint(payload.userId));
|
||||
if (!member) return;
|
||||
|
||||
if (!payload.member?.joinedAt) return eventHandlers.lurkerVoiceStateUpdate?.(member, payload);
|
||||
|
||||
// No cached state before so lets make one for em
|
||||
const cachedState = guild.voiceStates.get(snowflakeToBigint(payload.userId));
|
||||
|
||||
guild.voiceStates.set(
|
||||
snowflakeToBigint(payload.userId),
|
||||
await structures.createDiscordenoVoiceState(guild.id, payload)
|
||||
);
|
||||
|
||||
await cacheHandlers.set("guilds", guild.id, guild);
|
||||
|
||||
if (cachedState?.channelId !== (payload.channelId ? snowflakeToBigint(payload.channelId) : null)) {
|
||||
// Either joined or moved channels
|
||||
if (payload.channelId) {
|
||||
if (cachedState?.channelId) {
|
||||
// Was in a channel before
|
||||
eventHandlers.voiceChannelSwitch?.(member, snowflakeToBigint(payload.channelId), cachedState.channelId);
|
||||
} else {
|
||||
// Was not in a channel before so user just joined
|
||||
eventHandlers.voiceChannelJoin?.(member, snowflakeToBigint(payload.channelId));
|
||||
}
|
||||
} // Left the channel
|
||||
else if (cachedState?.channelId) {
|
||||
guild.voiceStates.delete(snowflakeToBigint(payload.userId));
|
||||
eventHandlers.voiceChannelLeave?.(member, cachedState.channelId);
|
||||
}
|
||||
const guild = await bot.cache.guilds.get(guildId);
|
||||
if (guild) {
|
||||
guild.voiceStates.set(voiceState.userId, voiceState);
|
||||
await bot.cache.guilds.set(guild.id, guild);
|
||||
}
|
||||
|
||||
eventHandlers.voiceStateUpdate?.(member, payload);
|
||||
const member = payload.member ? bot.transformers.member(bot, payload.member, guildId) : undefined;
|
||||
const user = payload.member ? bot.transformers.user(bot, payload.member.user) : undefined;
|
||||
|
||||
bot.events.voiceStateUpdate(bot, voiceState, { guild, member, user });
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { eventHandlers } from "../../bot.ts";
|
||||
import type { DiscordGatewayPayload } from "../../types/gateway/gateway_payload.ts";
|
||||
import type { WebhookUpdate } from "../../types/webhooks/webhooks_update.ts";
|
||||
import { snowflakeToBigint } from "../../util/bigint.ts";
|
||||
import { Bot } from "../../bot.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../../types/util.ts";
|
||||
|
||||
export function handleWebhooksUpdate(data: DiscordGatewayPayload) {
|
||||
const options = data.d as WebhookUpdate;
|
||||
eventHandlers.webhooksUpdate?.(snowflakeToBigint(options.channelId), snowflakeToBigint(options.guildId));
|
||||
export function handleWebhooksUpdate(bot: Bot, data: DiscordGatewayPayload) {
|
||||
const payload = data.d as SnakeCasedPropertiesDeep<WebhookUpdate>;
|
||||
bot.events.webhooksUpdate(bot, {
|
||||
channelId: bot.transformers.snowflake(payload.channel_id),
|
||||
guildId: bot.transformers.snowflake(payload.guild_id),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { Bot } from "../bot.ts";
|
||||
import { Activity } from "../types/activity/activity.ts";
|
||||
import { DiscordActivityTypes } from "../types/activity/activity_types.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../types/util.ts";
|
||||
import { DiscordenoEmoji } from "./emoji.ts";
|
||||
|
||||
export function transformActivity(bot: Bot, payload: SnakeCasedPropertiesDeep<Activity>): DiscordenoActivity {
|
||||
return {
|
||||
name: payload.name,
|
||||
type: payload.type,
|
||||
url: payload.url ?? undefined,
|
||||
createdAt: payload.created_at,
|
||||
startedAt: payload.timestamps?.start,
|
||||
endedAt: payload.timestamps?.end,
|
||||
applicationId: payload.application_id ? bot.transformers.snowflake(payload.application_id) : undefined,
|
||||
details: payload.details ?? undefined,
|
||||
state: payload.state ?? undefined,
|
||||
emoji: payload.emoji ? bot.transformers.emoji(bot, payload.emoji) : undefined,
|
||||
partyId: payload.party?.id,
|
||||
partyCurrentSize: payload.party?.size?.[0],
|
||||
partyMaxSize: payload.party?.size?.[1],
|
||||
largeImage: payload.assets?.large_image,
|
||||
largeText: payload.assets?.large_text,
|
||||
smallImage: payload.assets?.small_image,
|
||||
smallText: payload.assets?.small_text,
|
||||
join: payload.secrets?.join,
|
||||
spectate: payload.secrets?.spectate,
|
||||
match: payload.secrets?.match,
|
||||
instance: payload.instance,
|
||||
flags: payload.flags,
|
||||
buttonLabels: payload.buttons?.map((button) => button.label),
|
||||
};
|
||||
}
|
||||
|
||||
export interface DiscordenoActivity {
|
||||
/** The activity's name */
|
||||
name: string;
|
||||
/** Activity type */
|
||||
type: DiscordActivityTypes;
|
||||
/** Stream url, is validated when type is 1 */
|
||||
url?: string;
|
||||
/** Unix timestamp of when the activity was added to the user's session */
|
||||
createdAt: number;
|
||||
/** Unix time (in milliseconds) of when the activity started */
|
||||
startedAt?: number;
|
||||
/** Unix time (in milliseconds) of when the activity ends */
|
||||
endedAt?: number;
|
||||
/** Application id for the game */
|
||||
applicationId?: bigint;
|
||||
/** What the player is currently doing */
|
||||
details?: string;
|
||||
/** The user's current party status */
|
||||
state?: string;
|
||||
/** The emoji used for a custom status */
|
||||
emoji?: DiscordenoEmoji;
|
||||
/** the id of the party */
|
||||
partyId?: string;
|
||||
/** The current size of the party if one exists */
|
||||
partyCurrentSize?: number;
|
||||
/** The max size of the party if one exists */
|
||||
partyMaxSize?: number;
|
||||
/** The id for a large asset of the activity, usually a snowflake */
|
||||
largeImage?: string;
|
||||
/** Text displayed when hovering over the large image of the activity */
|
||||
largeText?: string;
|
||||
/** The id for a small asset of the activity, usually a snowflake */
|
||||
smallImage?: string;
|
||||
/** Text displayed when hovering over the small image of the activity */
|
||||
smallText?: string;
|
||||
/** The secret for joining a party */
|
||||
join?: string;
|
||||
/** The secret for spectating a game */
|
||||
spectate?: string;
|
||||
/** The secret for a specific instanced match */
|
||||
match?: string;
|
||||
/** Whether or not the activity is an instanced game session */
|
||||
instance?: boolean;
|
||||
/** Activity flags `OR`d together, describes what the payload includes */
|
||||
flags?: number;
|
||||
/** The custom button's labels shown in the Rich Presence */
|
||||
buttonLabels?: string[];
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Bot } from "../bot.ts";
|
||||
import { PresenceUpdate } from "../types/activity/presence_update.ts";
|
||||
import { SnakeCasedPropertiesDeep } from "../types/util.ts";
|
||||
import { DiscordenoActivity } from "./activity.ts";
|
||||
import { DiscordenoUser } from "./member.ts";
|
||||
|
||||
export const statusTypes = {
|
||||
online: 0,
|
||||
dnd: 1,
|
||||
idle: 2,
|
||||
invisible: 3,
|
||||
offline: 4,
|
||||
} as const;
|
||||
|
||||
export function transformPresence(bot: Bot, payload: SnakeCasedPropertiesDeep<PresenceUpdate>): DiscordenoPresence {
|
||||
return {
|
||||
user: bot.transformers.user(bot, payload.user),
|
||||
guildId: bot.transformers.snowflake(payload.guild_id),
|
||||
status: statusTypes[payload.status],
|
||||
activities: payload.activities.map((activity) => bot.transformers.activity(bot, activity)),
|
||||
desktop: payload.client_status.desktop,
|
||||
mobile: payload.client_status.mobile,
|
||||
web: payload.client_status.web,
|
||||
};
|
||||
}
|
||||
|
||||
export interface DiscordenoPresence {
|
||||
/** The user presence is being updated for */
|
||||
user: DiscordenoUser;
|
||||
/** id of the guild */
|
||||
guildId: bigint;
|
||||
/** Either online: 0, dnd: 1, idle: 2, invisible: 3, offline: 4 */
|
||||
status: 0 | 1 | 2 | 3 | 4;
|
||||
/** User's current activities */
|
||||
activities: DiscordenoActivity[];
|
||||
/** The user's status set for an active desktop (Windows, Linux, Mac) application session */
|
||||
desktop?: string;
|
||||
/** The user's status set for an active mobile (iOS, Android) application session */
|
||||
mobile?: string;
|
||||
/** The user's status set for an active web (browser, bot account) application session */
|
||||
web?: string;
|
||||
}
|
||||
@@ -16,7 +16,7 @@ export function transformVoiceState(
|
||||
(payload.voiceState.self_video ? 32n : 0n) |
|
||||
(payload.voiceState.suppress ? 64n : 0n),
|
||||
|
||||
requestToSpeakTimestamp: payload.voiceState.request_to_speak_timestamp,
|
||||
requestToSpeakTimestamp: payload.voiceState.request_to_speak_timestamp ? Date.parse(payload.voiceState.request_to_speak_timestamp) : undefined,
|
||||
sessionId: payload.voiceState.session_id,
|
||||
|
||||
channelId: payload.voiceState.channel_id ? bot.transformers.snowflake(payload.voiceState.channel_id) : undefined,
|
||||
@@ -27,7 +27,7 @@ export function transformVoiceState(
|
||||
};
|
||||
}
|
||||
|
||||
export interface DiscordenoVoiceState extends Omit<VoiceState, "channelId" | "guildId" | "userId" | "member"> {
|
||||
export interface DiscordenoVoiceState {
|
||||
/** The guild id */
|
||||
guildId: bigint;
|
||||
/** The channel id this user is connected to */
|
||||
@@ -36,4 +36,6 @@ export interface DiscordenoVoiceState extends Omit<VoiceState, "channelId" | "gu
|
||||
userId: bigint;
|
||||
/** Holds all the boolean toggles. */
|
||||
bitfield: bigint;
|
||||
/** The time at which the user requested to speak */
|
||||
requestToSpeakTimestamp?: number;
|
||||
}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
/** https://discord.com/developers/docs/topics/gateway#update-status-status-types */
|
||||
export type DiscordStatusTypes = "online" | "dnd" | "idle" | "invisible" | "offline";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user