Files
discordeno/src/api/controllers/misc.ts
ITOH 2c3692810d refactor(structures): rename create* functions (#395)
* structures: rename structure create functions

* fix: errors occured because of structure rename

* fix(controllers): errors occured because of structure rename

* fix

* fix createServer to createGuild rename

* rename create*structure to create*Struct

* update docs

* Phew

* rename createguildrole

* fix that

* fmt?

* idk

* why

* fixxess

* Update member.ts

* Update member.ts

* ahh found it

* revert this

* Update mod.ts

Co-authored-by: ayntee <ayyantee@gmail.com>
2021-03-08 20:37:06 +04:00

292 lines
8.2 KiB
TypeScript

import { eventHandlers, setApplicationID, setBotID } from "../../bot.ts";
import {
DiscordPayload,
IntegrationCreateUpdateEvent,
IntegrationDeleteEvent,
InviteCreateEvent,
InviteDeleteEvent,
PresenceUpdatePayload,
ReadyPayload,
TypingStartPayload,
UserPayload,
VoiceStateUpdatePayload,
WebhookUpdatePayload,
} from "../../types/mod.ts";
import { cache } from "../../util/cache.ts";
import { delay } from "../../util/utils.ts";
import { allowNextShard } from "../../ws/shard_manager.ts";
import { initialMemberLoadQueue } from "../structures/guild.ts";
import { structures } from "../structures/mod.ts";
import { cacheHandlers } from "./cache.ts";
/** This function is the internal handler for the ready event. Users can override this with controllers if desired. */
export async function handleInternalReady(
data: DiscordPayload,
shardID: number,
) {
if (data.t !== "READY") return;
const payload = data.d as ReadyPayload;
setBotID(payload.user.id);
setApplicationID(payload.application.id);
// Triggered on each shard
eventHandlers.shardReady?.(shardID);
if (payload.shard && shardID === payload.shard[1] - 1) {
const loadedAllGuilds = async () => {
const guildsMissing = async () => {
for (const g of payload.guilds) {
if (!(await cacheHandlers.has("guilds", g.id))) return true;
}
return false;
};
if (await guildsMissing()) {
setTimeout(loadedAllGuilds, 2000);
} else {
// The bot has already started, the last shard is resumed, however.
if (cache.isReady) return;
cache.isReady = true;
eventHandlers.ready?.();
// All the members that came in on guild creates should now be processed 1 by 1
for (const [guildID, members] of initialMemberLoadQueue.entries()) {
await Promise.all(
members.map(async (member) => {
const memberStruct = await structures.createMemberStruct(
member,
guildID,
);
return cacheHandlers.set(
"members",
memberStruct.id,
memberStruct,
);
}),
);
}
}
};
setTimeout(loadedAllGuilds, 2000);
}
// Wait 5 seconds to spawn next shard
await delay(5000);
allowNextShard();
}
/** This function is the internal handler for the presence update event. Users can override this with controllers if desired. */
export async function handleInternalPresenceUpdate(data: DiscordPayload) {
if (data.t !== "PRESENCE_UPDATE") return;
const payload = data.d as PresenceUpdatePayload;
const oldPresence = await cacheHandlers.get("presences", payload.user.id);
await cacheHandlers.set("presences", payload.user.id, payload);
eventHandlers.presenceUpdate?.(payload, oldPresence);
}
/** This function is the internal handler for the typings event. Users can override this with controllers if desired. */
export function handleInternalTypingStart(data: DiscordPayload) {
if (data.t !== "TYPING_START") return;
eventHandlers.typingStart?.(data.d as TypingStartPayload);
}
/** This function is the internal handler for the user update event. Users can override this with controllers if desired. */
export async function handleInternalUserUpdate(data: DiscordPayload) {
if (data.t !== "USER_UPDATE") return;
const userData = data.d as UserPayload;
const member = await cacheHandlers.get("members", userData.id);
if (!member) return;
Object.entries(userData).forEach(([key, value]) => {
// @ts-ignore index signatures
if (member[key] !== value) return member[key] = value;
});
await cacheHandlers.set("members", userData.id, member);
eventHandlers.botUpdate?.(userData);
}
/** This function is the internal handler for the voice state update event. Users can override this with controllers if desired. */
export async function handleInternalVoiceStateUpdate(data: DiscordPayload) {
if (data.t !== "VOICE_STATE_UPDATE") return;
const payload = data.d as VoiceStateUpdatePayload;
if (!payload.guild_id) return;
const guild = await cacheHandlers.get("guilds", payload.guild_id);
if (!guild) return;
const member = payload.member
? await structures.createMemberStruct(payload.member, guild.id)
: await cacheHandlers.get("members", payload.user_id);
if (!member) return;
// No cached state before so lets make one for em
const cachedState = guild.voiceStates.get(payload.user_id);
guild.voiceStates.set(payload.user_id, {
...payload,
guildID: payload.guild_id,
channelID: payload.channel_id || "",
userID: payload.user_id,
sessionID: payload.session_id,
selfDeaf: payload.self_deaf,
selfMute: payload.self_mute,
selfStream: payload.self_stream || false,
});
await cacheHandlers.set("guilds", payload.guild_id, guild);
if (cachedState?.channelID !== payload.channel_id) {
// Either joined or moved channels
if (payload.channel_id) {
if (cachedState?.channelID) { // Was in a channel before
eventHandlers.voiceChannelSwitch?.(
member,
payload.channel_id,
cachedState.channelID,
);
} else { // Was not in a channel before so user just joined
eventHandlers.voiceChannelJoin?.(member, payload.channel_id);
}
} // Left the channel
else if (cachedState?.channelID) {
guild.voiceStates.delete(payload.user_id);
eventHandlers.voiceChannelLeave?.(member, cachedState.channelID);
}
}
eventHandlers.voiceStateUpdate?.(member, payload);
}
/** This function is the internal handler for the webhooks update event. Users can override this with controllers if desired. */
export function handleInternalWebhooksUpdate(data: DiscordPayload) {
if (data.t !== "WEBHOOKS_UPDATE") return;
const options = data.d as WebhookUpdatePayload;
eventHandlers.webhooksUpdate?.(
options.channel_id,
options.guild_id,
);
}
export function handleInternalIntegrationCreate(
data: DiscordPayload,
) {
if (data.t !== "INTEGRATION_CREATE") return;
const {
guild_id: guildID,
enable_emoticons: enableEmoticons,
expire_behavior: expireBehavior,
expire_grace_period: expireGracePeriod,
subscriber_count: subscriberCount,
role_id: roleID,
synced_at: syncedAt,
...rest
} = data.d as IntegrationCreateUpdateEvent;
eventHandlers.integrationCreate?.({
...rest,
guildID,
enableEmoticons,
expireBehavior,
expireGracePeriod,
syncedAt,
subscriberCount,
roleID,
});
}
export function handleInternalIntegrationUpdate(data: DiscordPayload) {
if (data.t !== "INTEGRATION_UPDATE") return;
const {
enable_emoticons: enableEmoticons,
expire_behavior: expireBehavior,
expire_grace_period: expireGracePeriod,
role_id: roleID,
subscriber_count: subscriberCount,
synced_at: syncedAt,
guild_id: guildID,
...rest
} = data.d as IntegrationCreateUpdateEvent;
eventHandlers.integrationUpdate?.({
...rest,
guildID,
subscriberCount,
enableEmoticons,
expireGracePeriod,
roleID,
expireBehavior,
syncedAt,
});
}
export function handleInternalIntegrationDelete(data: DiscordPayload) {
if (data.t !== "INTEGRATION_DELETE") return;
const {
guild_id: guildID,
application_id: applicationID,
...rest
} = data.d as IntegrationDeleteEvent;
eventHandlers.integrationDelete?.({
...rest,
applicationID,
guildID,
});
}
export function handleInternalInviteCreate(payload: DiscordPayload) {
if (payload.t !== "INVITE_CREATE") return;
const {
channel_id: channelID,
created_at: createdAt,
max_age: maxAge,
guild_id: guildID,
target_user: targetUser,
target_user_type: targetUserType,
max_uses: maxUses,
...rest
} = payload.d as InviteCreateEvent;
eventHandlers.inviteCreate?.({
...rest,
channelID,
guildID,
maxAge,
targetUser,
targetUserType,
maxUses,
createdAt,
});
}
export function handleInternalInviteDelete(payload: DiscordPayload) {
if (payload.t !== "INVITE_DELETE") return;
const {
channel_id: channelID,
guild_id: guildID,
...rest
} = payload.d as InviteDeleteEvent;
eventHandlers.inviteDelete?.({
...rest,
channelID,
guildID,
});
}