Merge pull request #19 from DjDeveloperr/main
feature: Roles & Members Caching and Child Managers
This commit is contained in:
commit
536f070366
43 changed files with 751 additions and 327 deletions
10
README.md
10
README.md
|
@ -4,13 +4,13 @@
|
||||||
|
|
||||||
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
|
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
|
||||||
|
|
||||||
Discord Deno API that is easy to use
|
**An easy to use Discord API Library for Deno**
|
||||||
|
|
||||||
## Table of Contents
|
## Table of Contents
|
||||||
|
|
||||||
- [Usage](#usage)
|
- [Usage](#usage)
|
||||||
- [Docs](#docs)
|
- [Docs](#docs)
|
||||||
- [Maintainers](#maintainers)
|
- [Maintainer](#maintainer)
|
||||||
- [Contributing](#contributing)
|
- [Contributing](#contributing)
|
||||||
- [License](#license)
|
- [License](#license)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ bot.connect(TOKEN, [GatewayIntents.GUILD_MESSAGES])
|
||||||
|
|
||||||
Not made yet
|
Not made yet
|
||||||
|
|
||||||
## Maintainers
|
## Maintainer
|
||||||
|
|
||||||
[@Helloyunho](https://github.com/Helloyunho)
|
[@Helloyunho](https://github.com/Helloyunho)
|
||||||
|
|
||||||
|
@ -43,10 +43,10 @@ Not made yet
|
||||||
|
|
||||||
See [the contributing file](CONTRIBUTING.md)!
|
See [the contributing file](CONTRIBUTING.md)!
|
||||||
|
|
||||||
PRs accepted.
|
PRs are accepted.
|
||||||
|
|
||||||
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
|
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT © 2020 Helloyunho
|
[MIT © 2020 Helloyunho](LICENSE)
|
||||||
|
|
55
mod.ts
Normal file
55
mod.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
export * from './src/gateway/index.ts'
|
||||||
|
export * from './src/models/client.ts'
|
||||||
|
export * from './src/models/rest.ts'
|
||||||
|
export * from './src/models/CacheAdapter.ts'
|
||||||
|
export * from './src/models/shard.ts'
|
||||||
|
export * from './src/managers/BaseManager.ts'
|
||||||
|
export * from './src/managers/BaseChildManager.ts'
|
||||||
|
export * from './src/managers/ChannelsManager.ts'
|
||||||
|
export * from './src/managers/EmojisManager.ts'
|
||||||
|
export * from './src/managers/GatewayCache.ts'
|
||||||
|
export * from './src/managers/GuildChannelsManager.ts'
|
||||||
|
export * from './src/managers/GuildsManager.ts'
|
||||||
|
export * from './src/managers/MembersManager.ts'
|
||||||
|
export * from './src/managers/MessagesManager.ts'
|
||||||
|
export * from './src/managers/RolesManager.ts'
|
||||||
|
export * from './src/managers/UsersManager.ts'
|
||||||
|
export * from './src/structures/base.ts'
|
||||||
|
export * from './src/structures/cdn.ts'
|
||||||
|
export * from './src/structures/channel.ts'
|
||||||
|
export * from './src/structures/dmChannel.ts'
|
||||||
|
export * from './src/structures/embed.ts'
|
||||||
|
export * from './src/structures/emoji.ts'
|
||||||
|
export * from './src/structures/groupChannel.ts'
|
||||||
|
export * from './src/structures/guild.ts'
|
||||||
|
export * from './src/structures/guildCategoryChannel.ts'
|
||||||
|
export * from './src/structures/guildNewsChannel.ts'
|
||||||
|
export * from './src/structures/guildTextChannel.ts'
|
||||||
|
export * from './src/structures/guildVoiceChannel.ts'
|
||||||
|
export * from './src/structures/invite.ts'
|
||||||
|
export * from './src/structures/member.ts'
|
||||||
|
export * from './src/structures/message.ts'
|
||||||
|
export * from './src/structures/MessageMentions.ts'
|
||||||
|
export * from './src/structures/presence.ts'
|
||||||
|
export * from './src/structures/role.ts'
|
||||||
|
export * from './src/structures/snowflake.ts'
|
||||||
|
export * from './src/structures/textChannel.ts'
|
||||||
|
export * from './src/structures/user.ts'
|
||||||
|
export * from './src/structures/webhook.ts'
|
||||||
|
export * from './src/types/cdn.ts'
|
||||||
|
export * from './src/types/channel.ts'
|
||||||
|
export * from './src/types/emoji.ts'
|
||||||
|
export * from './src/types/endpoint.ts'
|
||||||
|
export * from './src/types/gateway.ts'
|
||||||
|
export * from './src/types/gatewayBot.ts'
|
||||||
|
export * from './src/types/gatewayResponse.ts'
|
||||||
|
export * from './src/types/guild.ts'
|
||||||
|
export * from './src/types/invite.ts'
|
||||||
|
export * from './src/types/permissionFlags.ts'
|
||||||
|
export * from './src/types/presence.ts'
|
||||||
|
export * from './src/types/role.ts'
|
||||||
|
export * from './src/types/template.ts'
|
||||||
|
export * from './src/types/user.ts'
|
||||||
|
export * from './src/types/voice.ts'
|
||||||
|
export * from './src/types/webhook.ts'
|
||||||
|
export * from './src/utils/collection.ts'
|
|
@ -1,12 +1,11 @@
|
||||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||||
import { Channel } from '../../structures/channel.ts'
|
|
||||||
import { ChannelPayload } from '../../types/channel.ts'
|
import { ChannelPayload } from '../../types/channel.ts'
|
||||||
|
|
||||||
export const channelDelete: GatewayEventHandler = async (
|
export const channelDelete: GatewayEventHandler = async (
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
d: ChannelPayload
|
d: ChannelPayload
|
||||||
) => {
|
) => {
|
||||||
const channel: Channel = await gateway.client.channels.get(d.id)
|
const channel = await gateway.client.channels.get(d.id)
|
||||||
if (channel !== undefined) {
|
if (channel !== undefined) {
|
||||||
await gateway.client.channels.delete(d.id)
|
await gateway.client.channels.delete(d.id)
|
||||||
gateway.client.emit('channelDelete', channel)
|
gateway.client.emit('channelDelete', channel)
|
||||||
|
|
|
@ -6,7 +6,7 @@ export const channelPinsUpdate: GatewayEventHandler = async (
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
d: ChannelPinsUpdatePayload
|
d: ChannelPinsUpdatePayload
|
||||||
) => {
|
) => {
|
||||||
const after: TextChannel = await gateway.client.channels.get(d.channel_id)
|
const after: TextChannel | void = await gateway.client.channels.get<TextChannel>(d.channel_id)
|
||||||
if (after !== undefined) {
|
if (after !== undefined) {
|
||||||
const before = after.refreshFromData({
|
const before = after.refreshFromData({
|
||||||
last_pin_timestamp: d.last_pin_timestamp
|
last_pin_timestamp: d.last_pin_timestamp
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { Channel } from '../../structures/channel.ts'
|
import { Channel } from '../../structures/channel.ts'
|
||||||
|
import { Guild } from "../../structures/guild.ts"
|
||||||
import { ChannelPayload } from '../../types/channel.ts'
|
import { ChannelPayload } from '../../types/channel.ts'
|
||||||
import getChannelByType from '../../utils/getChannelByType.ts'
|
import getChannelByType from '../../utils/getChannelByType.ts'
|
||||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||||
|
@ -7,12 +8,16 @@ export const channelUpdate: GatewayEventHandler = async (
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
d: ChannelPayload
|
d: ChannelPayload
|
||||||
) => {
|
) => {
|
||||||
const oldChannel: Channel = await gateway.client.channels.get(d.id)
|
const oldChannel: Channel | undefined = await gateway.client.channels.get(d.id)
|
||||||
|
|
||||||
if (oldChannel !== undefined) {
|
if (oldChannel !== undefined) {
|
||||||
await gateway.client.channels.set(d.id, d)
|
await gateway.client.channels.set(d.id, d)
|
||||||
|
let guild: undefined | Guild;
|
||||||
|
if((d as any).guild_id !== undefined) {
|
||||||
|
guild = await gateway.client.guilds.get((d as any).guild_id) as Guild | undefined
|
||||||
|
}
|
||||||
if (oldChannel.type !== d.type) {
|
if (oldChannel.type !== d.type) {
|
||||||
const channel: Channel = getChannelByType(gateway.client, d) ?? oldChannel
|
const channel: Channel = getChannelByType(gateway.client, d, guild) ?? oldChannel
|
||||||
gateway.client.emit('channelUpdate', oldChannel, channel)
|
gateway.client.emit('channelUpdate', oldChannel, channel)
|
||||||
} else {
|
} else {
|
||||||
const before = oldChannel.refreshFromData(d)
|
const before = oldChannel.refreshFromData(d)
|
||||||
|
|
|
@ -13,7 +13,7 @@ export const guildBanAdd: GatewayEventHandler = async (
|
||||||
new User(gateway.client, d.user)
|
new User(gateway.client, d.user)
|
||||||
|
|
||||||
if (guild !== undefined) {
|
if (guild !== undefined) {
|
||||||
guild.members = guild.members?.filter(member => member.id !== d.user.id)
|
await guild.members.delete(user.id)
|
||||||
gateway.client.emit('guildBanAdd', guild, user)
|
gateway.client.emit('guildBanAdd', guild, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,54 @@
|
||||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||||
import { Guild } from '../../structures/guild.ts'
|
import { Guild } from '../../structures/guild.ts'
|
||||||
import { GuildPayload } from '../../types/guild.ts'
|
import { GuildPayload, MemberPayload } from "../../types/guild.ts"
|
||||||
|
import { MembersManager } from "../../managers/MembersManager.ts"
|
||||||
|
import { ChannelPayload } from "../../types/channel.ts"
|
||||||
|
import { RolePayload } from "../../types/role.ts"
|
||||||
|
import { RolesManager } from "../../managers/RolesManager.ts"
|
||||||
|
|
||||||
export const guildCreate: GatewayEventHandler = async (
|
export const guildCreate: GatewayEventHandler = async(gateway: Gateway, d: GuildPayload) => {
|
||||||
gateway: Gateway,
|
|
||||||
d: GuildPayload
|
|
||||||
) => {
|
|
||||||
let guild: Guild | undefined = await gateway.client.guilds.get(d.id)
|
let guild: Guild | undefined = await gateway.client.guilds.get(d.id)
|
||||||
if (guild !== undefined) {
|
if (guild !== undefined) {
|
||||||
// It was just lazy load, so we don't fire the event as its gonna fire for every guild bot is in
|
// It was just lazy load, so we don't fire the event as its gonna fire for every guild bot is in
|
||||||
await gateway.client.guilds.set(d.id, d)
|
await gateway.client.guilds.set(d.id, d)
|
||||||
|
if ((d as any).members !== undefined) {
|
||||||
|
const members = new MembersManager(gateway.client, guild)
|
||||||
|
await members.fromPayload((d as any).members as MemberPayload[])
|
||||||
|
guild.members = members
|
||||||
|
}
|
||||||
|
if ((d as any).channels !== undefined) {
|
||||||
|
for (const ch of (d as any).channels as ChannelPayload[]) {
|
||||||
|
(ch as any).guild_id = d.id
|
||||||
|
await gateway.client.channels.set(ch.id, ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((d as any).roles !== undefined) {
|
||||||
|
const roles = new RolesManager(gateway.client, guild)
|
||||||
|
await roles.fromPayload((d as any).roles as RolePayload[])
|
||||||
|
guild.roles = roles
|
||||||
|
}
|
||||||
guild.refreshFromData(d)
|
guild.refreshFromData(d)
|
||||||
} else {
|
} else {
|
||||||
await gateway.client.guilds.set(d.id, d)
|
await gateway.client.guilds.set(d.id, d)
|
||||||
guild = new Guild(gateway.client, d)
|
guild = new Guild(gateway.client, d)
|
||||||
|
if ((d as any).members !== undefined) {
|
||||||
|
const members = new MembersManager(gateway.client, guild)
|
||||||
|
await members.fromPayload((d as any).members as MemberPayload[])
|
||||||
|
guild.members = members
|
||||||
|
}
|
||||||
|
if ((d as any).channels !== undefined) {
|
||||||
|
for (const ch of (d as any).channels as ChannelPayload[]) {
|
||||||
|
(ch as any).guild_id = d.id
|
||||||
|
await gateway.client.channels.set(ch.id, ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((d as any).roles !== undefined) {
|
||||||
|
const roles = new RolesManager(gateway.client, guild)
|
||||||
|
await roles.fromPayload((d as any).roles as RolePayload[])
|
||||||
|
guild.roles = roles
|
||||||
|
}
|
||||||
|
await guild.roles.fromPayload(d.roles)
|
||||||
|
guild = new Guild(gateway.client, d)
|
||||||
gateway.client.emit('guildCreate', guild)
|
gateway.client.emit('guildCreate', guild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,9 @@ export const guildDelte: GatewayEventHandler = async (
|
||||||
|
|
||||||
if (guild !== undefined) {
|
if (guild !== undefined) {
|
||||||
guild.refreshFromData(d)
|
guild.refreshFromData(d)
|
||||||
|
await guild.members.flush()
|
||||||
|
await guild.channels.flush()
|
||||||
|
await guild.roles.flush()
|
||||||
await gateway.client.guilds.delete(d.id)
|
await gateway.client.guilds.delete(d.id)
|
||||||
gateway.client.emit('guildDelete', guild)
|
gateway.client.emit('guildDelete', guild)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import cache from '../../models/cache.ts'
|
import cache from '../../models/cache.ts'
|
||||||
import { Guild } from '../../structures/guild.ts'
|
import { Guild } from '../../structures/guild.ts'
|
||||||
import { GuildEmojiUpdatePayload } from '../../types/gatewayTypes.ts'
|
import { GuildEmojiUpdatePayload } from '../../types/gateway.ts'
|
||||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||||
|
|
||||||
const guildEmojiUpdate: GatewayEventHandler = (
|
export const guildEmojiUpdate: GatewayEventHandler = (
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
d: GuildEmojiUpdatePayload
|
d: GuildEmojiUpdatePayload
|
||||||
) => {
|
) => {
|
||||||
const guild: Guild = cache.get('guild', d.guild_id)
|
const guild: Guild = cache.get('guild', d.guild_id)
|
||||||
if (guild !== undefined) {
|
if (guild !== undefined) {
|
||||||
const emojis = guild.emojis
|
// const emojis = guild.emojis
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,12 +12,13 @@ import { ready } from './ready.ts'
|
||||||
import { guildBanRemove } from './guildBanRemove.ts'
|
import { guildBanRemove } from './guildBanRemove.ts'
|
||||||
import { messageCreate } from "./messageCreate.ts"
|
import { messageCreate } from "./messageCreate.ts"
|
||||||
import { resume } from "./resume.ts"
|
import { resume } from "./resume.ts"
|
||||||
|
import { reconnect } from './reconnect.ts'
|
||||||
|
|
||||||
export const gatewayHandlers: {
|
export const gatewayHandlers: {
|
||||||
[eventCode in GatewayEvents]: GatewayEventHandler | undefined
|
[eventCode in GatewayEvents]: GatewayEventHandler | undefined
|
||||||
} = {
|
} = {
|
||||||
READY: ready,
|
READY: ready,
|
||||||
RECONNECT: undefined,
|
RECONNECT: reconnect,
|
||||||
RESUMED: resume,
|
RESUMED: resume,
|
||||||
CHANNEL_CREATE: channelCreate,
|
CHANNEL_CREATE: channelCreate,
|
||||||
CHANNEL_DELETE: channelDelete,
|
CHANNEL_DELETE: channelDelete,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { Channel } from '../../structures/channel.ts'
|
|
||||||
import { Message } from '../../structures/message.ts'
|
import { Message } from '../../structures/message.ts'
|
||||||
import { MessageMentions } from '../../structures/MessageMentions.ts'
|
import { MessageMentions } from '../../structures/MessageMentions.ts'
|
||||||
import { TextChannel } from '../../structures/textChannel.ts'
|
import { TextChannel } from '../../structures/textChannel.ts'
|
||||||
|
@ -10,13 +9,18 @@ export const messageCreate: GatewayEventHandler = async (
|
||||||
gateway: Gateway,
|
gateway: Gateway,
|
||||||
d: MessagePayload
|
d: MessagePayload
|
||||||
) => {
|
) => {
|
||||||
let channel = (await gateway.client.channels.get(d.channel_id)) as TextChannel
|
let channel = await gateway.client.channels.get<TextChannel>(d.channel_id)
|
||||||
// Fetch the channel if not cached
|
// Fetch the channel if not cached
|
||||||
if (channel === undefined)
|
if (channel === undefined)
|
||||||
channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel
|
channel = (await gateway.client.channels.fetch(d.channel_id)) as any
|
||||||
const user = new User(gateway.client, d.author)
|
const user = new User(gateway.client, d.author)
|
||||||
await gateway.client.users.set(d.author.id, d.author)
|
await gateway.client.users.set(d.author.id, d.author)
|
||||||
|
let guild
|
||||||
|
if(d.guild_id !== undefined) {
|
||||||
|
guild = await gateway.client.guilds.get(d.guild_id)
|
||||||
|
}
|
||||||
const mentions = new MessageMentions()
|
const mentions = new MessageMentions()
|
||||||
const message = new Message(gateway.client, d, channel, user, mentions)
|
const message = new Message(gateway.client, d, channel as any, user, mentions)
|
||||||
|
if (guild !== undefined) message.guild = guild
|
||||||
gateway.client.emit('messageCreate', message)
|
gateway.client.emit('messageCreate', message)
|
||||||
}
|
}
|
||||||
|
|
6
src/gateway/handlers/reconnect.ts
Normal file
6
src/gateway/handlers/reconnect.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { Gateway } from "../index.ts"
|
||||||
|
import { GatewayEventHandler } from "../index.ts"
|
||||||
|
|
||||||
|
export const reconnect: GatewayEventHandler = async (gateway: Gateway, d: any) => {
|
||||||
|
gateway.reconnect()
|
||||||
|
}
|
|
@ -1,7 +1,10 @@
|
||||||
|
import { User } from "../../structures/user.ts"
|
||||||
|
import { CLIENT_USER } from "../../types/endpoint.ts"
|
||||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||||
|
|
||||||
export const resume: GatewayEventHandler = (gateway: Gateway, d: any) => {
|
export const resume: GatewayEventHandler = async (gateway: Gateway, d: any) => {
|
||||||
gateway.debug(`Session Resumed!`)
|
gateway.debug(`Session Resumed!`)
|
||||||
gateway.client.emit('resume')
|
gateway.client.emit('resume')
|
||||||
|
if (gateway.client.user === undefined) gateway.client.user = new User(gateway.client, await gateway.client.rest.get(CLIENT_USER()) as any)
|
||||||
gateway.client.emit('ready')
|
gateway.client.emit('ready')
|
||||||
}
|
}
|
|
@ -12,7 +12,8 @@ import {
|
||||||
} from '../types/gateway.ts'
|
} from '../types/gateway.ts'
|
||||||
import { gatewayHandlers } from './handlers/index.ts'
|
import { gatewayHandlers } from './handlers/index.ts'
|
||||||
import { GATEWAY_BOT } from '../types/endpoint.ts'
|
import { GATEWAY_BOT } from '../types/endpoint.ts'
|
||||||
import { GatewayCache } from '../managers/GatewayCache.ts'
|
import { GatewayCache } from "../managers/GatewayCache.ts"
|
||||||
|
import { ClientActivityPayload } from "../structures/presence.ts"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles Discord gateway connection.
|
* Handles Discord gateway connection.
|
||||||
|
@ -85,21 +86,17 @@ class Gateway {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.websocket.send(
|
this.send({
|
||||||
JSON.stringify({
|
|
||||||
op: GatewayOpcodes.HEARTBEAT,
|
op: GatewayOpcodes.HEARTBEAT,
|
||||||
d: this.sequenceID ?? null
|
d: this.sequenceID ?? null
|
||||||
})
|
})
|
||||||
)
|
|
||||||
this.lastPingTimestamp = Date.now()
|
this.lastPingTimestamp = Date.now()
|
||||||
}, this.heartbeatInterval)
|
}, this.heartbeatInterval)
|
||||||
|
|
||||||
if (!this.initialized) {
|
if (!this.initialized) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
||||||
this.sendIdentify()
|
|
||||||
this.initialized = true
|
this.initialized = true
|
||||||
|
await this.sendIdentify(this.client.forceNewSession)
|
||||||
} else {
|
} else {
|
||||||
console.log('Calling Resume')
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.sendResume()
|
this.sendResume()
|
||||||
}
|
}
|
||||||
|
@ -224,14 +221,13 @@ class Gateway {
|
||||||
return await this.sendResume()
|
return await this.sendResume()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.websocket.send(
|
this.send({
|
||||||
JSON.stringify({
|
|
||||||
op: GatewayOpcodes.IDENTIFY,
|
op: GatewayOpcodes.IDENTIFY,
|
||||||
d: {
|
d: {
|
||||||
token: this.token,
|
token: this.token,
|
||||||
properties: {
|
properties: {
|
||||||
$os: Deno.build.os,
|
$os: Deno.build.os,
|
||||||
$browser: 'discord.deno',
|
$browser: 'discord.deno', //TODO: Change lib name
|
||||||
$device: 'discord.deno'
|
$device: 'discord.deno'
|
||||||
},
|
},
|
||||||
compress: true,
|
compress: true,
|
||||||
|
@ -240,15 +236,9 @@ class Gateway {
|
||||||
(previous, current) => previous | current,
|
(previous, current) => previous | current,
|
||||||
0
|
0
|
||||||
),
|
),
|
||||||
presence: {
|
presence: this.client.presence.create()
|
||||||
// TODO: User should can customize this
|
|
||||||
status: 'online',
|
|
||||||
since: null,
|
|
||||||
afk: false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async sendResume(): Promise<void> {
|
private async sendResume(): Promise<void> {
|
||||||
|
@ -266,7 +256,7 @@ class Gateway {
|
||||||
seq: this.sequenceID ?? null
|
seq: this.sequenceID ?? null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.websocket.send(JSON.stringify(resumePayload))
|
this.send(resumePayload)
|
||||||
}
|
}
|
||||||
|
|
||||||
debug (msg: string): void {
|
debug (msg: string): void {
|
||||||
|
@ -297,6 +287,24 @@ class Gateway {
|
||||||
close(): void {
|
close(): void {
|
||||||
this.websocket.close(1000)
|
this.websocket.close(1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
send(data: GatewayResponse): boolean {
|
||||||
|
if (this.websocket.readyState !== this.websocket.OPEN) return false
|
||||||
|
this.websocket.send(JSON.stringify({
|
||||||
|
op: data.op,
|
||||||
|
d: data.d,
|
||||||
|
s: typeof data.s === "number" ? data.s : null,
|
||||||
|
t: data.t === undefined ? null : data.t,
|
||||||
|
}))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
sendPresence(data: ClientActivityPayload): void {
|
||||||
|
this.send({
|
||||||
|
op: GatewayOpcodes.PRESENCE_UPDATE,
|
||||||
|
d: data
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GatewayEventHandler = (gateway: Gateway, d: any) => void
|
export type GatewayEventHandler = (gateway: Gateway, d: any) => void
|
||||||
|
|
40
src/managers/BaseChildManager.ts
Normal file
40
src/managers/BaseChildManager.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import { Client } from "../models/client.ts";
|
||||||
|
import { Collection } from "../utils/collection.ts";
|
||||||
|
import { BaseManager } from "./BaseManager.ts";
|
||||||
|
|
||||||
|
export class BaseChildManager<T, T2> {
|
||||||
|
client: Client
|
||||||
|
parent: BaseManager<T, T2>
|
||||||
|
|
||||||
|
constructor(client: Client, parent: BaseManager<T, T2>) {
|
||||||
|
this.client = client
|
||||||
|
this.parent = parent
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(key: string): Promise<T2 | undefined> {
|
||||||
|
return this.parent.get(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
async set(key: string, value: T): Promise<void> {
|
||||||
|
return this.parent.set(key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(key: string): Promise<any> {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async array(): Promise<any> {
|
||||||
|
return this.parent.array()
|
||||||
|
}
|
||||||
|
|
||||||
|
async collection(): Promise<Collection<string, T2>> {
|
||||||
|
const arr = await this.array() as undefined | T2[]
|
||||||
|
if (arr === undefined) return new Collection()
|
||||||
|
const collection = new Collection()
|
||||||
|
for (const elem of arr) {
|
||||||
|
// @ts-expect-error
|
||||||
|
collection.set(elem.id, elem)
|
||||||
|
}
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from "../models/client.ts";
|
||||||
|
import { Collection } from "../utils/collection.ts";
|
||||||
|
|
||||||
export class BaseManager<T, T2> {
|
export class BaseManager<T, T2> {
|
||||||
client: Client
|
client: Client
|
||||||
|
@ -28,4 +29,24 @@ export class BaseManager<T, T2> {
|
||||||
async delete (key: string): Promise<boolean> {
|
async delete (key: string): Promise<boolean> {
|
||||||
return this.client.cache.delete(this.cacheName, key)
|
return this.client.cache.delete(this.cacheName, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async array (): Promise<undefined | T2[]> {
|
||||||
|
const arr = await (this.client.cache.array(this.cacheName) as T[])
|
||||||
|
return arr.map(e => new this.DataType(this.client, e)) as any
|
||||||
|
}
|
||||||
|
|
||||||
|
async collection (): Promise<Collection<string, T2>> {
|
||||||
|
const arr = await this.array()
|
||||||
|
if (arr === undefined) return new Collection()
|
||||||
|
const collection = new Collection()
|
||||||
|
for (const elem of arr) {
|
||||||
|
// @ts-expect-error
|
||||||
|
collection.set(elem.id, elem)
|
||||||
|
}
|
||||||
|
return collection
|
||||||
|
}
|
||||||
|
|
||||||
|
flush(): any {
|
||||||
|
return this.client.cache.deleteCache(this.cacheName)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,50 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from "../models/client.ts";
|
||||||
import { Channel } from '../structures/channel.ts'
|
import { Channel } from "../structures/channel.ts";
|
||||||
import { User } from '../structures/user.ts'
|
import { ChannelPayload } from "../types/channel.ts";
|
||||||
import { ChannelPayload } from '../types/channel.ts'
|
import { CHANNEL } from "../types/endpoint.ts";
|
||||||
import { CHANNEL } from '../types/endpoint.ts'
|
import getChannelByType from "../utils/getChannelByType.ts";
|
||||||
import { BaseManager } from './BaseManager.ts'
|
import { BaseManager } from "./BaseManager.ts";
|
||||||
|
|
||||||
export class ChannelsManager extends BaseManager<ChannelPayload, Channel> {
|
export class ChannelsManager extends BaseManager<ChannelPayload, Channel> {
|
||||||
constructor(client: Client) {
|
constructor(client: Client) {
|
||||||
super(client, 'channels', User)
|
super(client, "channels", Channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override get method as Generic
|
// Override get method as Generic
|
||||||
async get<T = Channel> (key: string): Promise<T> {
|
async get<T = Channel>(key: string): Promise<T | undefined> {
|
||||||
return new this.DataType(this.client, this._get(key))
|
const data = await this._get(key)
|
||||||
|
if (data === undefined) return
|
||||||
|
let guild
|
||||||
|
if ((data as any).guild_id !== undefined) {
|
||||||
|
guild = await this.client.guilds.get((data as any).guild_id)
|
||||||
|
}
|
||||||
|
const res = getChannelByType(this.client, data, guild)
|
||||||
|
return res as any
|
||||||
|
}
|
||||||
|
|
||||||
|
async array(): Promise<undefined | Channel[]> {
|
||||||
|
const arr = await (this.client.cache.array(this.cacheName) as ChannelPayload[])
|
||||||
|
const result: any[] = []
|
||||||
|
for (const elem of arr) {
|
||||||
|
let guild
|
||||||
|
if ((elem as any).guild_id !== undefined) {
|
||||||
|
guild = await this.client.guilds.get((elem as any).guild_id)
|
||||||
|
}
|
||||||
|
result.push(getChannelByType(this.client, elem, guild))
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetch(id: string): Promise<Channel> {
|
async fetch(id: string): Promise<Channel> {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
this.client.rest
|
this.client.rest.get(CHANNEL(id)).then(async data => {
|
||||||
.get(CHANNEL(id))
|
|
||||||
.then(data => {
|
|
||||||
this.set(id, data as ChannelPayload)
|
this.set(id, data as ChannelPayload)
|
||||||
resolve(new Channel(this.client, data as ChannelPayload))
|
let guild
|
||||||
})
|
if (data.guild_id !== undefined) {
|
||||||
.catch(e => reject(e))
|
guild = await this.client.guilds.get(data.guild_id)
|
||||||
|
}
|
||||||
|
resolve(getChannelByType(this.client, data as ChannelPayload, guild))
|
||||||
|
}).catch(e => reject(e))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
45
src/managers/GuildChannelsManager.ts
Normal file
45
src/managers/GuildChannelsManager.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { Client } from "../models/client.ts";
|
||||||
|
import { Channel } from "../structures/channel.ts";
|
||||||
|
import { Guild } from "../structures/guild.ts";
|
||||||
|
import { CategoryChannel } from "../structures/guildCategoryChannel.ts";
|
||||||
|
import { GuildTextChannel } from "../structures/guildTextChannel.ts";
|
||||||
|
import { VoiceChannel } from "../structures/guildVoiceChannel.ts";
|
||||||
|
import { GuildChannelCategoryPayload, GuildTextChannelPayload, GuildVoiceChannelPayload } from "../types/channel.ts";
|
||||||
|
import { CHANNEL } from "../types/endpoint.ts";
|
||||||
|
import { BaseChildManager } from "./BaseChildManager.ts";
|
||||||
|
import { ChannelsManager } from "./ChannelsManager.ts";
|
||||||
|
|
||||||
|
export type GuildChannelPayloads = GuildTextChannelPayload | GuildVoiceChannelPayload | GuildChannelCategoryPayload
|
||||||
|
export type GuildChannel = GuildTextChannel | VoiceChannel | CategoryChannel
|
||||||
|
|
||||||
|
export class GuildChannelsManager extends BaseChildManager<GuildChannelPayloads, GuildChannel> {
|
||||||
|
guild: Guild
|
||||||
|
|
||||||
|
constructor(client: Client, parent: ChannelsManager, guild: Guild) {
|
||||||
|
super(client, parent as any)
|
||||||
|
this.guild = guild
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(id: string): Promise<GuildChannel | undefined> {
|
||||||
|
const res = await this.parent.get(id)
|
||||||
|
if (res !== undefined && res.guild.id === this.guild.id) return res
|
||||||
|
else return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string): Promise<boolean> {
|
||||||
|
return this.client.rest.delete(CHANNEL(id))
|
||||||
|
}
|
||||||
|
|
||||||
|
async array(): Promise<GuildChannel[]> {
|
||||||
|
const arr = await this.parent.array() as Channel[]
|
||||||
|
return arr.filter((c: any) => c.guild !== undefined && c.guild.id === this.guild.id) as any
|
||||||
|
}
|
||||||
|
|
||||||
|
async flush(): Promise<boolean> {
|
||||||
|
const arr = await this.array()
|
||||||
|
for (const elem of arr) {
|
||||||
|
this.parent.delete(elem.id)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from "../models/client.ts";
|
||||||
import { Guild } from '../structures/guild.ts'
|
import { Guild } from "../structures/guild.ts";
|
||||||
import { GUILD } from '../types/endpoint.ts'
|
import { GUILD } from "../types/endpoint.ts";
|
||||||
import { GuildPayload } from '../types/guild.ts'
|
import { GuildPayload, MemberPayload } from "../types/guild.ts";
|
||||||
import { BaseManager } from './BaseManager.ts'
|
import { BaseManager } from "./BaseManager.ts";
|
||||||
|
import { MembersManager } from "./MembersManager.ts";
|
||||||
|
|
||||||
export class GuildManager extends BaseManager<GuildPayload, Guild> {
|
export class GuildManager extends BaseManager<GuildPayload, Guild> {
|
||||||
constructor (client: Client) {
|
constructor (client: Client) {
|
||||||
|
@ -11,13 +12,16 @@ export class GuildManager extends BaseManager<GuildPayload, Guild> {
|
||||||
|
|
||||||
async fetch(id: string): Promise<Guild> {
|
async fetch(id: string): Promise<Guild> {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
this.client.rest
|
this.client.rest.get(GUILD(id)).then(async (data: any) => {
|
||||||
.get(GUILD(id))
|
this.set(id, data)
|
||||||
.then(data => {
|
const guild = new Guild(this.client, data)
|
||||||
this.set(id, data as GuildPayload)
|
if ((data as GuildPayload).members !== undefined) {
|
||||||
resolve(new Guild(this.client, data as GuildPayload))
|
const members = new MembersManager(this.client, guild)
|
||||||
})
|
await members.fromPayload((data as GuildPayload).members as MemberPayload[])
|
||||||
.catch(e => reject(e))
|
guild.members = members
|
||||||
|
}
|
||||||
|
resolve(guild)
|
||||||
|
}).catch(e => reject(e))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
30
src/managers/MembersManager.ts
Normal file
30
src/managers/MembersManager.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { Client } from "../models/client.ts";
|
||||||
|
import { Guild } from "../structures/guild.ts";
|
||||||
|
import { Member } from "../structures/member.ts";
|
||||||
|
import { GUILD_MEMBER } from "../types/endpoint.ts";
|
||||||
|
import { MemberPayload } from "../types/guild.ts";
|
||||||
|
import { BaseManager } from "./BaseManager.ts";
|
||||||
|
|
||||||
|
export class MembersManager extends BaseManager<MemberPayload, Member> {
|
||||||
|
guild: Guild
|
||||||
|
|
||||||
|
constructor(client: Client, guild: Guild) {
|
||||||
|
super(client, `members:${guild.id}`, Member)
|
||||||
|
this.guild = guild
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetch(id: string): Promise<Member> {
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
this.client.rest.get(GUILD_MEMBER(this.guild.id, id)).then(data => {
|
||||||
|
this.set(id, data as MemberPayload)
|
||||||
|
resolve(new Member(this.client, data as MemberPayload))
|
||||||
|
}).catch(e => reject(e))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fromPayload(members: MemberPayload[]): Promise<void> {
|
||||||
|
for (const member of members) {
|
||||||
|
await this.set(member.user.id, member)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,43 +1,40 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from "../models/client.ts";
|
||||||
import { Message } from '../structures/message.ts'
|
import { Message } from "../structures/message.ts";
|
||||||
import { MessageMentions } from '../structures/MessageMentions.ts'
|
import { MessageMentions } from "../structures/MessageMentions.ts";
|
||||||
import { User } from '../structures/user.ts'
|
import { TextChannel } from "../structures/textChannel.ts";
|
||||||
import { MessagePayload } from '../types/channel.ts'
|
import { User } from "../structures/user.ts";
|
||||||
import { CHANNEL_MESSAGE } from '../types/endpoint.ts'
|
import { MessagePayload } from "../types/channel.ts";
|
||||||
import { BaseManager } from './BaseManager.ts'
|
import { CHANNEL_MESSAGE } from "../types/endpoint.ts";
|
||||||
|
import { BaseManager } from "./BaseManager.ts";
|
||||||
|
|
||||||
export class MessagesManager extends BaseManager<MessagePayload, Message> {
|
export class MessagesManager extends BaseManager<MessagePayload, Message> {
|
||||||
constructor (client: Client) {
|
constructor (client: Client) {
|
||||||
super(client, 'messages', Message)
|
super(client, 'messages', Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async get(key: string): Promise<Message | undefined> {
|
||||||
|
const raw = await this._get(key)
|
||||||
|
if (raw === undefined) return
|
||||||
|
let channel = await this.client.channels.get(raw.channel_id)
|
||||||
|
if (channel === undefined) channel = await this.client.channels.fetch(raw.channel_id)
|
||||||
|
if (channel === undefined) return
|
||||||
|
const author = new User(this.client, raw.author)
|
||||||
|
const mentions = new MessageMentions()
|
||||||
|
return new this.DataType(this.client, raw, channel, author, mentions) as any
|
||||||
|
}
|
||||||
|
|
||||||
async fetch(channelID: string, id: string): Promise<Message> {
|
async fetch(channelID: string, id: string): Promise<Message> {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
this.client.rest
|
this.client.rest.get(CHANNEL_MESSAGE(channelID, id)).then(async data => {
|
||||||
.get(CHANNEL_MESSAGE(channelID, id))
|
|
||||||
.then(async data => {
|
|
||||||
this.set(id, data as MessagePayload)
|
this.set(id, data as MessagePayload)
|
||||||
let channel = await this.client.channels.get(channelID)
|
let channel: any = await this.client.channels.get<TextChannel>(channelID)
|
||||||
if (channel === undefined)
|
if (channel === undefined) channel = await this.client.channels.fetch(channelID)
|
||||||
channel = await this.client.channels.fetch(channelID)
|
|
||||||
const author = new User(this.client, (data as MessagePayload).author)
|
const author = new User(this.client, (data as MessagePayload).author)
|
||||||
await this.client.users.set(
|
await this.client.users.set(author.id, (data as MessagePayload).author)
|
||||||
author.id,
|
|
||||||
(data as MessagePayload).author
|
|
||||||
)
|
|
||||||
// TODO: Make this thing work (MessageMentions)
|
// TODO: Make this thing work (MessageMentions)
|
||||||
const mentions = new MessageMentions()
|
const mentions = new MessageMentions()
|
||||||
resolve(
|
resolve(new Message(this.client, data as MessagePayload, channel as TextChannel, author, mentions))
|
||||||
new Message(
|
}).catch(e => reject(e))
|
||||||
this.client,
|
|
||||||
data as MessagePayload,
|
|
||||||
channel,
|
|
||||||
author,
|
|
||||||
mentions
|
|
||||||
)
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.catch(e => reject(e))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,4 +24,11 @@ export class RolesManager extends BaseManager<RolePayload, Role> {
|
||||||
.catch(e => reject(e))
|
.catch(e => reject(e))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fromPayload(roles: RolePayload[]): Promise<boolean> {
|
||||||
|
for (const role of roles) {
|
||||||
|
await this.set(role.id, role)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@ import {
|
||||||
|
|
||||||
export interface ICacheAdapter {
|
export interface ICacheAdapter {
|
||||||
client: Client
|
client: Client
|
||||||
get: (cacheName: string, key: string) => Promise<undefined | any>
|
get: (cacheName: string, key: string) => Promise<any> | any
|
||||||
set: (cacheName: string, key: string, value: any) => Promise<any>
|
set: (cacheName: string, key: string, value: any) => Promise<any> | any
|
||||||
delete: (cacheName: string, key: string) => Promise<boolean>
|
delete: (cacheName: string, key: string) => Promise<boolean> | boolean
|
||||||
array: (cacheName: string) => Promise<any[] | undefined>
|
array: (cacheName: string) => undefined | any[] | Promise<any[] | undefined>
|
||||||
|
deleteCache: (cacheName: string) => any
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DefaultCacheAdapter implements ICacheAdapter {
|
export class DefaultCacheAdapter implements ICacheAdapter {
|
||||||
|
@ -50,6 +51,11 @@ export class DefaultCacheAdapter implements ICacheAdapter {
|
||||||
if (cache === undefined) return
|
if (cache === undefined) return
|
||||||
return cache.array()
|
return cache.array()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteCache(cacheName: string): Promise<boolean> {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||||
|
return delete this.data[cacheName]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RedisCacheAdapter implements ICacheAdapter {
|
export class RedisCacheAdapter implements ICacheAdapter {
|
||||||
|
@ -114,4 +120,9 @@ export class RedisCacheAdapter implements ICacheAdapter {
|
||||||
const data = await this.redis?.hvals(cacheName)
|
const data = await this.redis?.hvals(cacheName)
|
||||||
return data?.map((e: string) => JSON.parse(e))
|
return data?.map((e: string) => JSON.parse(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteCache(cacheName: string): Promise<boolean> {
|
||||||
|
await this._checkReady()
|
||||||
|
return await this.redis?.del(cacheName) !== 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,18 +3,21 @@ import { GatewayIntents } from '../types/gateway.ts'
|
||||||
import { Gateway } from '../gateway/index.ts'
|
import { Gateway } from '../gateway/index.ts'
|
||||||
import { RESTManager } from './rest.ts'
|
import { RESTManager } from './rest.ts'
|
||||||
import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts'
|
import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts'
|
||||||
import { DefaultCacheAdapter, ICacheAdapter } from './CacheAdapter.ts'
|
import { DefaultCacheAdapter, ICacheAdapter } from "./CacheAdapter.ts"
|
||||||
import { UserManager } from '../managers/UsersManager.ts'
|
import { UserManager } from "../managers/UsersManager.ts"
|
||||||
import { GuildManager } from '../managers/GuildsManager.ts'
|
import { GuildManager } from "../managers/GuildsManager.ts"
|
||||||
import { EmojisManager } from '../managers/EmojisManager.ts'
|
import { EmojisManager } from "../managers/EmojisManager.ts"
|
||||||
import { ChannelsManager } from '../managers/ChannelsManager.ts'
|
import { ChannelsManager } from "../managers/ChannelsManager.ts"
|
||||||
import { MessagesManager } from '../managers/MessagesManager.ts'
|
import { MessagesManager } from "../managers/MessagesManager.ts"
|
||||||
|
import { ActivityGame, ClientActivity, ClientPresence } from "../structures/presence.ts"
|
||||||
|
|
||||||
/** Some Client Options to modify behaviour */
|
/** Some Client Options to modify behaviour */
|
||||||
export interface ClientOptions {
|
export interface ClientOptions {
|
||||||
token?: string
|
token?: string
|
||||||
intents?: GatewayIntents[]
|
intents?: GatewayIntents[]
|
||||||
cache?: ICacheAdapter
|
cache?: ICacheAdapter,
|
||||||
|
forceNewSession?: boolean,
|
||||||
|
presence?: ClientPresence | ClientActivity | ActivityGame
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,18 +31,22 @@ export class Client extends EventEmitter {
|
||||||
token?: string
|
token?: string
|
||||||
cache: ICacheAdapter = new DefaultCacheAdapter(this)
|
cache: ICacheAdapter = new DefaultCacheAdapter(this)
|
||||||
intents?: GatewayIntents[]
|
intents?: GatewayIntents[]
|
||||||
|
forceNewSession?: boolean
|
||||||
users: UserManager = new UserManager(this)
|
users: UserManager = new UserManager(this)
|
||||||
guilds: GuildManager = new GuildManager(this)
|
guilds: GuildManager = new GuildManager(this)
|
||||||
channels: ChannelsManager = new ChannelsManager(this)
|
channels: ChannelsManager = new ChannelsManager(this)
|
||||||
messages: MessagesManager = new MessagesManager(this)
|
messages: MessagesManager = new MessagesManager(this)
|
||||||
emojis: EmojisManager = new EmojisManager(this)
|
emojis: EmojisManager = new EmojisManager(this)
|
||||||
|
|
||||||
|
presence: ClientPresence = new ClientPresence()
|
||||||
|
|
||||||
constructor (options: ClientOptions = {}) {
|
constructor (options: ClientOptions = {}) {
|
||||||
super()
|
super()
|
||||||
this.token = options.token
|
this.token = options.token
|
||||||
this.intents = options.intents
|
this.intents = options.intents
|
||||||
|
this.forceNewSession = options.forceNewSession
|
||||||
if (options.cache !== undefined) this.cache = options.cache
|
if (options.cache !== undefined) this.cache = options.cache
|
||||||
|
if (options.presence !== undefined) this.presence = options.presence instanceof ClientPresence ? options.presence : new ClientPresence(options.presence)
|
||||||
}
|
}
|
||||||
|
|
||||||
setAdapter (adapter: ICacheAdapter): Client {
|
setAdapter (adapter: ICacheAdapter): Client {
|
||||||
|
@ -47,8 +54,15 @@ export class Client extends EventEmitter {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPresence (presence: ClientPresence | ClientActivity | ActivityGame): void {
|
||||||
|
if (presence instanceof ClientPresence) {
|
||||||
|
this.presence = presence
|
||||||
|
} else this.presence = new ClientPresence(presence)
|
||||||
|
this.gateway?.sendPresence(this.presence.create())
|
||||||
|
}
|
||||||
|
|
||||||
debug (tag: string, msg: string): void {
|
debug (tag: string, msg: string): void {
|
||||||
this.emit('debug', `[${tag}] ${msg}`)
|
this.emit("debug", `[${tag}] ${msg}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -52,7 +52,7 @@ export class RESTManager {
|
||||||
|
|
||||||
constructor (client: Client) {
|
constructor (client: Client) {
|
||||||
this.client = client
|
this.client = client
|
||||||
setTimeout(this.processRateLimitedPaths, 1000)
|
setTimeout(() => this.processRateLimitedPaths, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
async processRateLimitedPaths (): Promise<void> {
|
async processRateLimitedPaths (): Promise<void> {
|
||||||
|
@ -158,7 +158,7 @@ export class RESTManager {
|
||||||
'User-Agent': `DiscordBot (discord.deno)`
|
'User-Agent': `DiscordBot (discord.deno)`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.client.token !== undefined) delete headers.Authorization
|
if (this.client.token === undefined) delete headers.Authorization
|
||||||
|
|
||||||
if (method === 'get') body = undefined
|
if (method === 'get') body = undefined
|
||||||
|
|
||||||
|
@ -233,9 +233,11 @@ export class RESTManager {
|
||||||
const urlToUse =
|
const urlToUse =
|
||||||
method === 'get' && query !== '' ? `${url}?${query}` : url
|
method === 'get' && query !== '' ? `${url}?${query}` : url
|
||||||
|
|
||||||
|
const requestData = this.createRequestBody(body, method)
|
||||||
|
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
urlToUse,
|
urlToUse,
|
||||||
this.createRequestBody(body, method)
|
requestData
|
||||||
)
|
)
|
||||||
const bucketIDFromHeaders = this.processHeaders(url, response.headers)
|
const bucketIDFromHeaders = this.processHeaders(url, response.headers)
|
||||||
this.handleStatusCode(response, errorStack)
|
this.handleStatusCode(response, errorStack)
|
||||||
|
@ -302,15 +304,17 @@ export class RESTManager {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.logErrors(response, errorStack)
|
this.logErrors(response, errorStack)
|
||||||
|
|
||||||
|
if(status === HttpResponseCode.Unauthorized) throw new Error("Request was not successful. Invalid Token.")
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case HttpResponseCode.BadRequest:
|
case HttpResponseCode.BadRequest:
|
||||||
case HttpResponseCode.Unauthorized:
|
case HttpResponseCode.Unauthorized:
|
||||||
case HttpResponseCode.Forbidden:
|
case HttpResponseCode.Forbidden:
|
||||||
case HttpResponseCode.NotFound:
|
case HttpResponseCode.NotFound:
|
||||||
case HttpResponseCode.MethodNotAllowed:
|
case HttpResponseCode.MethodNotAllowed:
|
||||||
throw new Error('Request Client Error')
|
throw new Error('Request Client Error.')
|
||||||
case HttpResponseCode.GatewayUnavailable:
|
case HttpResponseCode.GatewayUnavailable:
|
||||||
throw new Error('Request Server Error')
|
throw new Error('Request Server Error.')
|
||||||
}
|
}
|
||||||
|
|
||||||
// left are all unknown
|
// left are all unknown
|
||||||
|
|
|
@ -9,7 +9,6 @@ export class DMChannel extends TextChannel {
|
||||||
constructor (client: Client, data: DMChannelPayload) {
|
constructor (client: Client, data: DMChannelPayload) {
|
||||||
super(client, data)
|
super(client, data)
|
||||||
this.recipients = data.recipients
|
this.recipients = data.recipients
|
||||||
// cache.set('dmchannel', this.id, this)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readFromData (data: DMChannelPayload): void {
|
protected readFromData (data: DMChannelPayload): void {
|
||||||
|
|
|
@ -2,13 +2,12 @@ import { Client } from '../models/client.ts'
|
||||||
import { GuildFeatures, GuildPayload } from '../types/guild.ts'
|
import { GuildFeatures, GuildPayload } from '../types/guild.ts'
|
||||||
import { PresenceUpdatePayload } from '../types/gateway.ts'
|
import { PresenceUpdatePayload } from '../types/gateway.ts'
|
||||||
import { Base } from './base.ts'
|
import { Base } from './base.ts'
|
||||||
import { Channel } from './channel.ts'
|
|
||||||
import { Emoji } from './emoji.ts'
|
import { Emoji } from './emoji.ts'
|
||||||
import { Member } from './member.ts'
|
|
||||||
import { VoiceState } from './voiceState.ts'
|
import { VoiceState } from './voiceState.ts'
|
||||||
import cache from '../models/cache.ts'
|
import cache from '../models/cache.ts'
|
||||||
import getChannelByType from '../utils/getChannelByType.ts'
|
import { RolesManager } from "../managers/RolesManager.ts"
|
||||||
import { RolesManager } from '../managers/RolesManager.ts'
|
import { GuildChannelsManager } from "../managers/GuildChannelsManager.ts"
|
||||||
|
import { MembersManager } from "../managers/MembersManager.ts"
|
||||||
|
|
||||||
export class Guild extends Base {
|
export class Guild extends Base {
|
||||||
id: string
|
id: string
|
||||||
|
@ -28,7 +27,7 @@ export class Guild extends Base {
|
||||||
verificationLevel?: string
|
verificationLevel?: string
|
||||||
defaultMessageNotifications?: string
|
defaultMessageNotifications?: string
|
||||||
explicitContentFilter?: string
|
explicitContentFilter?: string
|
||||||
roles: RolesManager = new RolesManager(this.client, this)
|
roles: RolesManager
|
||||||
emojis?: Emoji[]
|
emojis?: Emoji[]
|
||||||
features?: GuildFeatures[]
|
features?: GuildFeatures[]
|
||||||
mfaLevel?: string
|
mfaLevel?: string
|
||||||
|
@ -41,8 +40,8 @@ export class Guild extends Base {
|
||||||
unavailable: boolean
|
unavailable: boolean
|
||||||
memberCount?: number
|
memberCount?: number
|
||||||
voiceStates?: VoiceState[]
|
voiceStates?: VoiceState[]
|
||||||
members?: Member[]
|
members: MembersManager
|
||||||
channels?: Channel[]
|
channels: GuildChannelsManager
|
||||||
presences?: PresenceUpdatePayload[]
|
presences?: PresenceUpdatePayload[]
|
||||||
maxPresences?: number
|
maxPresences?: number
|
||||||
maxMembers?: number
|
maxMembers?: number
|
||||||
|
@ -61,6 +60,9 @@ export class Guild extends Base {
|
||||||
super(client, data)
|
super(client, data)
|
||||||
this.id = data.id
|
this.id = data.id
|
||||||
this.unavailable = data.unavailable
|
this.unavailable = data.unavailable
|
||||||
|
this.members = new MembersManager(this.client, this)
|
||||||
|
this.channels = new GuildChannelsManager(this.client, this.client.channels, this)
|
||||||
|
this.roles = new RolesManager(this.client, this)
|
||||||
|
|
||||||
if (!this.unavailable) {
|
if (!this.unavailable) {
|
||||||
this.name = data.name
|
this.name = data.name
|
||||||
|
@ -167,22 +169,22 @@ export class Guild extends Base {
|
||||||
this.joinedAt = data.joined_at ?? this.joinedAt
|
this.joinedAt = data.joined_at ?? this.joinedAt
|
||||||
this.large = data.large ?? this.large
|
this.large = data.large ?? this.large
|
||||||
this.memberCount = data.member_count ?? this.memberCount
|
this.memberCount = data.member_count ?? this.memberCount
|
||||||
this.voiceStates =
|
// this.voiceStates =
|
||||||
data.voice_states?.map(
|
// data.voice_states?.map(
|
||||||
v =>
|
// v =>
|
||||||
cache.get('voiceState', `${v.guild_id}:${v.user_id}`) ??
|
// cache.get('voiceState', `${v.guild_id}:${v.user_id}`) ??
|
||||||
new VoiceState(this.client, v)
|
// new VoiceState(this.client, v)
|
||||||
) ?? this.voiceStates
|
// ) ?? this.voiceStates
|
||||||
this.members =
|
// this.members =
|
||||||
data.members?.map(
|
// data.members?.map(
|
||||||
v =>
|
// v =>
|
||||||
cache.get('member', `${this.id}:${v.user.id}`) ??
|
// cache.get('member', `${this.id}:${v.user.id}`) ??
|
||||||
new Member(this.client, v)
|
// new Member(this.client, v)
|
||||||
) ?? this.members
|
// ) ?? this.members
|
||||||
this.channels =
|
// this.channels =
|
||||||
data.channels?.map(
|
// data.channels?.map(
|
||||||
v => cache.get('channel', v.id) ?? getChannelByType(this.client, v)
|
// v => cache.get('channel', v.id) ?? getChannelByType(this.client, v, this)
|
||||||
) ?? this.members
|
// ) ?? this.members
|
||||||
this.presences = data.presences ?? this.presences
|
this.presences = data.presences ?? this.presences
|
||||||
this.maxPresences = data.max_presences ?? this.maxPresences
|
this.maxPresences = data.max_presences ?? this.maxPresences
|
||||||
this.maxMembers = data.max_members ?? this.maxMembers
|
this.maxMembers = data.max_members ?? this.maxMembers
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from '../models/client.ts'
|
||||||
import { Channel } from './channel.ts'
|
import { Channel } from './channel.ts'
|
||||||
import { GuildChannelCategoryPayload, Overwrite } from '../types/channel.ts'
|
import {
|
||||||
|
GuildChannelCategoryPayload,
|
||||||
|
Overwrite
|
||||||
|
} from '../types/channel.ts'
|
||||||
|
import { Guild } from "./guild.ts"
|
||||||
|
|
||||||
export class CategoryChannel extends Channel {
|
export class CategoryChannel extends Channel {
|
||||||
guildID: string
|
guildID: string
|
||||||
|
@ -8,12 +12,14 @@ export class CategoryChannel extends Channel {
|
||||||
position: number
|
position: number
|
||||||
permissionOverwrites: Overwrite[]
|
permissionOverwrites: Overwrite[]
|
||||||
nsfw: boolean
|
nsfw: boolean
|
||||||
|
guild: Guild
|
||||||
parentID?: string
|
parentID?: string
|
||||||
|
|
||||||
constructor (client: Client, data: GuildChannelCategoryPayload) {
|
constructor (client: Client, data: GuildChannelCategoryPayload, guild: Guild) {
|
||||||
super(client, data)
|
super(client, data)
|
||||||
this.guildID = data.guild_id
|
this.guildID = data.guild_id
|
||||||
this.name = data.name
|
this.name = data.name
|
||||||
|
this.guild = guild
|
||||||
this.position = data.position
|
this.position = data.position
|
||||||
this.permissionOverwrites = data.permission_overwrites
|
this.permissionOverwrites = data.permission_overwrites
|
||||||
this.nsfw = data.nsfw
|
this.nsfw = data.nsfw
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from '../models/client.ts'
|
||||||
import { GuildTextChannelPayload, Overwrite } from '../types/channel.ts'
|
import { GuildTextChannelPayload, Overwrite } from '../types/channel.ts'
|
||||||
import { TextChannel } from './textChannel.ts'
|
import { TextChannel } from './textChannel.ts'
|
||||||
|
import { Guild } from "./guild.ts"
|
||||||
|
|
||||||
export class GuildTextChannel extends TextChannel {
|
export class GuildTextChannel extends TextChannel {
|
||||||
guildID: string
|
guildID: string
|
||||||
|
@ -11,15 +12,17 @@ export class GuildTextChannel extends TextChannel {
|
||||||
parentID?: string
|
parentID?: string
|
||||||
rateLimit: number
|
rateLimit: number
|
||||||
topic?: string
|
topic?: string
|
||||||
|
guild: Guild
|
||||||
|
|
||||||
get mention (): string {
|
get mention (): string {
|
||||||
return `<#${this.id}>`
|
return `<#${this.id}>`
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (client: Client, data: GuildTextChannelPayload) {
|
constructor (client: Client, data: GuildTextChannelPayload, guild: Guild) {
|
||||||
super(client, data)
|
super(client, data)
|
||||||
this.guildID = data.guild_id
|
this.guildID = data.guild_id
|
||||||
this.name = data.name
|
this.name = data.name
|
||||||
|
this.guild = guild
|
||||||
this.position = data.position
|
this.position = data.position
|
||||||
this.permissionOverwrites = data.permission_overwrites
|
this.permissionOverwrites = data.permission_overwrites
|
||||||
this.nsfw = data.nsfw
|
this.nsfw = data.nsfw
|
||||||
|
|
|
@ -1,24 +1,27 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from '../models/client.ts'
|
||||||
import { GuildVoiceChannelPayload, Overwrite } from '../types/channel.ts'
|
import { GuildVoiceChannelPayload, Overwrite } from '../types/channel.ts'
|
||||||
import { Channel } from './channel.ts'
|
import { Channel } from './channel.ts'
|
||||||
|
import { Guild } from "./guild.ts"
|
||||||
|
|
||||||
export class VoiceChannel extends Channel {
|
export class VoiceChannel extends Channel {
|
||||||
bitrate: string
|
bitrate: string
|
||||||
userLimit: number
|
userLimit: number
|
||||||
guildID: string
|
guildID: string
|
||||||
name: string
|
name: string
|
||||||
|
guild: Guild
|
||||||
position: number
|
position: number
|
||||||
permissionOverwrites: Overwrite[]
|
permissionOverwrites: Overwrite[]
|
||||||
nsfw: boolean
|
nsfw: boolean
|
||||||
parentID?: string
|
parentID?: string
|
||||||
|
|
||||||
constructor (client: Client, data: GuildVoiceChannelPayload) {
|
constructor (client: Client, data: GuildVoiceChannelPayload, guild: Guild) {
|
||||||
super(client, data)
|
super(client, data)
|
||||||
this.bitrate = data.bitrate
|
this.bitrate = data.bitrate
|
||||||
this.userLimit = data.user_limit
|
this.userLimit = data.user_limit
|
||||||
this.guildID = data.guild_id
|
this.guildID = data.guild_id
|
||||||
this.name = data.name
|
this.name = data.name
|
||||||
this.position = data.position
|
this.position = data.position
|
||||||
|
this.guild = guild
|
||||||
this.permissionOverwrites = data.permission_overwrites
|
this.permissionOverwrites = data.permission_overwrites
|
||||||
this.nsfw = data.nsfw
|
this.nsfw = data.nsfw
|
||||||
this.parentID = data.parent_id
|
this.parentID = data.parent_id
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from '../models/client.ts'
|
||||||
import { GuildNewsChannelPayload, Overwrite } from '../types/channel.ts'
|
import { GuildNewsChannelPayload, Overwrite } from '../types/channel.ts'
|
||||||
|
import { Guild } from "./guild.ts"
|
||||||
import { TextChannel } from './textChannel.ts'
|
import { TextChannel } from './textChannel.ts'
|
||||||
|
|
||||||
export class NewsChannel extends TextChannel {
|
export class NewsChannel extends TextChannel {
|
||||||
guildID: string
|
guildID: string
|
||||||
|
guild: Guild
|
||||||
name: string
|
name: string
|
||||||
position: number
|
position: number
|
||||||
permissionOverwrites: Overwrite[]
|
permissionOverwrites: Overwrite[]
|
||||||
|
@ -11,10 +13,11 @@ export class NewsChannel extends TextChannel {
|
||||||
parentID?: string
|
parentID?: string
|
||||||
topic?: string
|
topic?: string
|
||||||
|
|
||||||
constructor (client: Client, data: GuildNewsChannelPayload) {
|
constructor (client: Client, data: GuildNewsChannelPayload, guild: Guild) {
|
||||||
super(client, data)
|
super(client, data)
|
||||||
this.guildID = data.guild_id
|
this.guildID = data.guild_id
|
||||||
this.name = data.name
|
this.name = data.name
|
||||||
|
this.guild = guild
|
||||||
this.position = data.position
|
this.position = data.position
|
||||||
this.permissionOverwrites = data.permission_overwrites
|
this.permissionOverwrites = data.permission_overwrites
|
||||||
this.nsfw = data.nsfw
|
this.nsfw = data.nsfw
|
||||||
|
|
|
@ -14,17 +14,19 @@ import { User } from './user.ts'
|
||||||
import { Member } from './member.ts'
|
import { Member } from './member.ts'
|
||||||
import { Embed } from './embed.ts'
|
import { Embed } from './embed.ts'
|
||||||
import { CHANNEL_MESSAGE } from '../types/endpoint.ts'
|
import { CHANNEL_MESSAGE } from '../types/endpoint.ts'
|
||||||
import { Channel } from './channel.ts'
|
import { MessageMentions } from "./MessageMentions.ts"
|
||||||
import { MessageMentions } from './MessageMentions.ts'
|
import { TextChannel } from "./textChannel.ts"
|
||||||
import { TextChannel } from './textChannel.ts'
|
import { DMChannel } from "./dmChannel.ts"
|
||||||
|
import { Guild } from "./guild.ts"
|
||||||
|
|
||||||
export class Message extends Base {
|
export class Message extends Base {
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-readonly
|
// eslint-disable-next-line @typescript-eslint/prefer-readonly
|
||||||
private data: MessagePayload
|
private data: MessagePayload
|
||||||
id: string
|
id: string
|
||||||
channelID: string
|
channelID: string
|
||||||
channel: Channel
|
channel: TextChannel
|
||||||
guildID?: string
|
guildID?: string
|
||||||
|
guild?: Guild
|
||||||
author: User
|
author: User
|
||||||
member?: Member
|
member?: Member
|
||||||
content: string
|
content: string
|
||||||
|
@ -50,7 +52,7 @@ export class Message extends Base {
|
||||||
constructor (
|
constructor (
|
||||||
client: Client,
|
client: Client,
|
||||||
data: MessagePayload,
|
data: MessagePayload,
|
||||||
channel: Channel,
|
channel: TextChannel,
|
||||||
author: User,
|
author: User,
|
||||||
mentions: MessageMentions
|
mentions: MessageMentions
|
||||||
) {
|
) {
|
||||||
|
@ -122,9 +124,13 @@ export class Message extends Base {
|
||||||
}
|
}
|
||||||
|
|
||||||
async edit (text?: string, option?: MessageOption): Promise<Message> {
|
async edit (text?: string, option?: MessageOption): Promise<Message> {
|
||||||
// Seriously eslint?
|
return this.channel.edit(this.id, text, option)
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
}
|
||||||
return (this.channel as TextChannel).editMessage(this.id, text, option)
|
|
||||||
|
async reply(text: string, options?: MessageOption): Promise<Message> {
|
||||||
|
// TODO: Use inline replies once they're out
|
||||||
|
if (this.channel instanceof DMChannel) return this.channel.send(text, options)
|
||||||
|
return this.channel.send(`${this.author.mention}, ${text}`, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete (): Promise<void> {
|
async delete (): Promise<void> {
|
||||||
|
|
123
src/structures/presence.ts
Normal file
123
src/structures/presence.ts
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
export type ActivityType = 'PLAYING' | 'STREAMING' | 'LISTENING' | 'WATCHING' | 'CUSTOM_STATUS' | 'COMPETING';
|
||||||
|
export type StatusType = 'online' | 'invisible' | 'offline' | 'idle' | 'dnd';
|
||||||
|
|
||||||
|
export enum ActivityTypes {
|
||||||
|
PLAYING = 0,
|
||||||
|
STREAMING = 1,
|
||||||
|
LISTENING = 2,
|
||||||
|
WATCHING = 3,
|
||||||
|
CUSTOM_STATUS = 4,
|
||||||
|
COMPETING = 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ActivityGame {
|
||||||
|
name: string;
|
||||||
|
type: 0 | 1 | 2 | 3 | 4 | 5 | ActivityType;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientActivity {
|
||||||
|
status?: StatusType
|
||||||
|
activity?: ActivityGame | ActivityGame[]
|
||||||
|
since?: number | null
|
||||||
|
afk?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClientActivityPayload {
|
||||||
|
status: StatusType
|
||||||
|
activities: ActivityGame[] | null
|
||||||
|
since: number | null
|
||||||
|
afk: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClientPresence {
|
||||||
|
status: StatusType = 'online'
|
||||||
|
activity?: ActivityGame | ActivityGame[]
|
||||||
|
since?: number | null
|
||||||
|
afk?: boolean
|
||||||
|
|
||||||
|
constructor(data?: ClientActivity | ClientActivityPayload | ActivityGame) {
|
||||||
|
if (data !== undefined) {
|
||||||
|
if ((data as ClientActivity).activity !== undefined) {
|
||||||
|
Object.assign(this, data)
|
||||||
|
} else if ((data as ClientActivityPayload).activities !== undefined) {
|
||||||
|
|
||||||
|
} else if ((data as ActivityGame).name !== undefined) {
|
||||||
|
if (this.activity === undefined) {
|
||||||
|
this.activity = data as ActivityGame
|
||||||
|
} else if (this.activity instanceof Array) {
|
||||||
|
this.activity.push(data as ActivityGame)
|
||||||
|
} else this.activity = [ this.activity, data as ActivityGame ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parse(payload: ClientActivityPayload): ClientPresence {
|
||||||
|
this.afk = payload.afk
|
||||||
|
this.activity = payload.activities ?? undefined
|
||||||
|
this.since = payload.since
|
||||||
|
this.status = payload.status
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
static parse(payload: ClientActivityPayload): ClientPresence {
|
||||||
|
return new ClientPresence().parse(payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
create(): ClientActivityPayload {
|
||||||
|
return {
|
||||||
|
afk: this.afk === undefined ? false : this.afk,
|
||||||
|
activities: this.createActivity(),
|
||||||
|
since: this.since === undefined ? null : this.since,
|
||||||
|
status: this.status === undefined ? 'online' : this.status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createActivity(): ActivityGame[] | null {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||||
|
const activity = this.activity === undefined ? null : (this.activity instanceof Array ? this.activity : [this.activity]) || null
|
||||||
|
if (activity === null) return activity
|
||||||
|
else {
|
||||||
|
activity.map(e => {
|
||||||
|
if (typeof e.type === "string") e.type = ActivityTypes[e.type]
|
||||||
|
return e
|
||||||
|
})
|
||||||
|
return activity
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setStatus(status: StatusType): ClientPresence {
|
||||||
|
this.status = status
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
setActivity(activity: ActivityGame): ClientPresence {
|
||||||
|
this.activity = activity
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
setActivities(activities: ActivityGame[]): ClientPresence {
|
||||||
|
this.activity = activities
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
setAFK(afk: boolean): ClientPresence {
|
||||||
|
this.afk = afk
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAFK(): ClientPresence {
|
||||||
|
this.afk = false
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleAFK(): ClientPresence {
|
||||||
|
this.afk = this.afk === undefined ? true : !this.afk
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
setSince(since?: number): ClientPresence {
|
||||||
|
this.since = since
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,35 +27,18 @@ export class TextChannel extends Channel {
|
||||||
if (text !== undefined && option !== undefined) {
|
if (text !== undefined && option !== undefined) {
|
||||||
throw new Error('Either text or option is necessary.')
|
throw new Error('Either text or option is necessary.')
|
||||||
}
|
}
|
||||||
if (this.client.user === undefined) {
|
const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), {
|
||||||
throw new Error('Client user has not initialized.')
|
|
||||||
}
|
|
||||||
|
|
||||||
const resp = await fetch(CHANNEL_MESSAGES(this.id), {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bot ${this.client.token}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({
|
|
||||||
content: text,
|
content: text,
|
||||||
embed: option?.embed,
|
embed: option?.embed,
|
||||||
file: option?.file,
|
file: option?.file,
|
||||||
tts: option?.tts,
|
tts: option?.tts,
|
||||||
allowed_mentions: option?.allowedMention
|
allowed_mentions: option?.allowedMention
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
return new Message(
|
return new Message(this.client, resp as any, this, this.client.user as any, new MessageMentions())
|
||||||
this.client,
|
|
||||||
await resp.json(),
|
|
||||||
this,
|
|
||||||
this.client.user,
|
|
||||||
new MessageMentions()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async editMessage (
|
async edit (
|
||||||
message: Message | string,
|
message: Message | string,
|
||||||
text?: string,
|
text?: string,
|
||||||
option?: MessageOption
|
option?: MessageOption
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
import { Client } from '../models/client.ts'
|
import { Client } from '../models/client.ts'
|
||||||
import { GatewayIntents } from '../types/gateway.ts'
|
import { GatewayIntents } from '../types/gateway.ts'
|
||||||
import { TOKEN } from './config.ts'
|
import { TOKEN } from './config.ts'
|
||||||
import { Channel } from '../structures/channel.ts'
|
|
||||||
import { GuildTextChannel } from '../structures/guildTextChannel.ts'
|
|
||||||
import { TextChannel } from '../structures/textChannel.ts'
|
|
||||||
import { Guild } from '../structures/guild.ts'
|
|
||||||
import { User } from '../structures/user.ts'
|
|
||||||
import { Message } from "../structures/message.ts"
|
import { Message } from "../structures/message.ts"
|
||||||
import { RedisCacheAdapter } from "../models/CacheAdapter.ts"
|
import { RedisCacheAdapter } from "../models/CacheAdapter.ts"
|
||||||
|
import { ClientPresence } from "../structures/presence.ts"
|
||||||
|
import { Member } from "../structures/member.ts"
|
||||||
|
import { Role } from "../structures/role.ts"
|
||||||
|
import { GuildChannel } from "../managers/GuildChannelsManager.ts"
|
||||||
|
|
||||||
const bot = new Client()
|
const bot = new Client({
|
||||||
|
presence: new ClientPresence({
|
||||||
|
activity: {
|
||||||
|
name: "Testing",
|
||||||
|
type: 'COMPETING'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
|
||||||
bot.setAdapter(new RedisCacheAdapter(bot, {
|
bot.setAdapter(new RedisCacheAdapter(bot, {
|
||||||
hostname: "127.0.0.1",
|
hostname: "127.0.0.1",
|
||||||
|
@ -18,60 +24,44 @@ bot.setAdapter(new RedisCacheAdapter(bot, {
|
||||||
|
|
||||||
bot.on('ready', () => {
|
bot.on('ready', () => {
|
||||||
console.log(`[Login] Logged in as ${bot.user?.tag}!`)
|
console.log(`[Login] Logged in as ${bot.user?.tag}!`)
|
||||||
|
bot.setPresence({
|
||||||
|
name: "Test After Ready",
|
||||||
|
type: 'COMPETING'
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
bot.on('debug', console.log)
|
bot.on('debug', console.log)
|
||||||
|
|
||||||
bot.on('channelDelete', (channel: Channel) => {
|
bot.on('messageCreate', async (msg: Message) => {
|
||||||
console.log('channelDelete', channel.id)
|
if (msg.author.bot === true) return
|
||||||
})
|
if (msg.content === "!ping") {
|
||||||
|
msg.reply(`Pong! Ping: ${bot.ping}ms`)
|
||||||
bot.on('channelUpdate', (before: Channel, after: Channel) => {
|
} else if (msg.content === "!members") {
|
||||||
if (before instanceof GuildTextChannel && after instanceof GuildTextChannel) {
|
const col = await msg.guild?.members.collection()
|
||||||
console.log('channelUpdate', before.name)
|
const data = col?.array().map((c: Member, i: number) => {
|
||||||
console.log('channelUpdate', after.name)
|
return `${i + 1}. ${c.user.tag}`
|
||||||
} else {
|
}).join("\n") as string
|
||||||
console.log('channelUpdate', before.id)
|
msg.channel.send("Member List:\n" + data)
|
||||||
console.log('channelUpdate', after.id)
|
} else if (msg.content === "!guilds") {
|
||||||
|
const guilds = await msg.client.guilds.collection()
|
||||||
|
msg.channel.send("Guild List:\n" + (guilds.array().map((c, i: number) => {
|
||||||
|
return `${i + 1}. ${c.name} - ${c.memberCount} members`
|
||||||
|
}).join("\n") as string))
|
||||||
|
} else if (msg.content === "!roles") {
|
||||||
|
const col = await msg.guild?.roles.collection()
|
||||||
|
const data = col?.array().map((c: Role, i: number) => {
|
||||||
|
return `${i + 1}. ${c.name}`
|
||||||
|
}).join("\n") as string
|
||||||
|
msg.channel.send("Roles List:\n" + data)
|
||||||
|
} else if (msg.content === "!channels") {
|
||||||
|
const col = await msg.guild?.channels.array()
|
||||||
|
const data = col?.map((c: GuildChannel, i: number) => {
|
||||||
|
return `${i + 1}. ${c.name}`
|
||||||
|
}).join("\n") as string
|
||||||
|
msg.channel.send("Channels List:\n" + data)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
bot.on('channelCreate', (channel: Channel) => {
|
|
||||||
console.log('channelCreate', channel.id)
|
|
||||||
})
|
|
||||||
|
|
||||||
bot.on('channelPinsUpdate', (before: TextChannel, after: TextChannel) => {
|
|
||||||
console.log(
|
|
||||||
'channelPinsUpdate',
|
|
||||||
before.lastPinTimestamp,
|
|
||||||
after.lastPinTimestamp
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
bot.on('guildBanAdd', (guild: Guild, user: User) => {
|
|
||||||
console.log('guildBanAdd', guild.id, user.id)
|
|
||||||
})
|
|
||||||
|
|
||||||
bot.on('guildBanRemove', (guild: Guild, user: User) => {
|
|
||||||
console.log('guildBanRemove', guild.id, user.id)
|
|
||||||
})
|
|
||||||
|
|
||||||
bot.on('guildCreate', (guild: Guild) => {
|
|
||||||
console.log('guildCreate', guild.id)
|
|
||||||
})
|
|
||||||
|
|
||||||
bot.on('guildDelete', (guild: Guild) => {
|
|
||||||
console.log('guildDelete', guild.id)
|
|
||||||
})
|
|
||||||
|
|
||||||
bot.on('guildUpdate', (before: Guild, after: Guild) => {
|
|
||||||
console.log('guildUpdate', before.name, after.name)
|
|
||||||
})
|
|
||||||
|
|
||||||
bot.on('messageCreate', (msg: Message) => {
|
|
||||||
console.log(`${msg.author.tag}: ${msg.content}`)
|
|
||||||
})
|
|
||||||
|
|
||||||
bot.connect(TOKEN, [
|
bot.connect(TOKEN, [
|
||||||
GatewayIntents.GUILD_MEMBERS,
|
GatewayIntents.GUILD_MEMBERS,
|
||||||
GatewayIntents.GUILD_PRESENCES,
|
GatewayIntents.GUILD_PRESENCES,
|
||||||
|
|
|
@ -187,6 +187,10 @@ const INVITE = (inviteCODE: string): string =>
|
||||||
const VOICE_REGIONS = (guildID: string): string =>
|
const VOICE_REGIONS = (guildID: string): string =>
|
||||||
`${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/regions`
|
`${DISCORD_API_URL}/v${DISCORD_API_VERSION}/guilds/${guildID}/regions`
|
||||||
|
|
||||||
|
// Client User Endpoint
|
||||||
|
const CLIENT_USER = (): string =>
|
||||||
|
`${DISCORD_API_URL}/v${DISCORD_API_VERSION}/users/@me`
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
GUILDS,
|
GUILDS,
|
||||||
GUILD,
|
GUILD,
|
||||||
|
@ -204,6 +208,7 @@ export default [
|
||||||
GUILD_CHANNEL,
|
GUILD_CHANNEL,
|
||||||
GUILD_CHANNELS,
|
GUILD_CHANNELS,
|
||||||
GUILD_MEMBER,
|
GUILD_MEMBER,
|
||||||
|
CLIENT_USER,
|
||||||
GUILD_MEMBERS,
|
GUILD_MEMBERS,
|
||||||
GUILD_MEMBER_ROLE,
|
GUILD_MEMBER_ROLE,
|
||||||
GUILD_INVITES,
|
GUILD_INVITES,
|
||||||
|
@ -319,6 +324,7 @@ export {
|
||||||
CUSTOM_EMOJI,
|
CUSTOM_EMOJI,
|
||||||
GUILD_ICON,
|
GUILD_ICON,
|
||||||
GUILD_SPLASH,
|
GUILD_SPLASH,
|
||||||
|
CLIENT_USER,
|
||||||
GUILD_DISCOVERY_SPLASH,
|
GUILD_DISCOVERY_SPLASH,
|
||||||
GUILD_BANNER,
|
GUILD_BANNER,
|
||||||
DEFAULT_USER_AVATAR,
|
DEFAULT_USER_AVATAR,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway
|
// https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway
|
||||||
// https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events
|
// https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events
|
||||||
|
import { StatusType } from "../../mod.ts"
|
||||||
import { EmojiPayload } from './emoji.ts'
|
import { EmojiPayload } from './emoji.ts'
|
||||||
import { MemberPayload } from './guild.ts'
|
import { MemberPayload } from './guild.ts'
|
||||||
import { ActivityPayload } from './presence.ts'
|
import { ActivityPayload } from './presence.ts'
|
||||||
|
@ -9,7 +10,7 @@ import { UserPayload } from './user.ts'
|
||||||
/**
|
/**
|
||||||
* Gateway OPcodes from Discord docs.
|
* Gateway OPcodes from Discord docs.
|
||||||
*/
|
*/
|
||||||
enum GatewayOpcodes { // 문서를 확인해본 결과 Opcode 5번은 비어있다. - UnderC -
|
export enum GatewayOpcodes { // 문서를 확인해본 결과 Opcode 5번은 비어있다. - UnderC -
|
||||||
DISPATCH = 0,
|
DISPATCH = 0,
|
||||||
HEARTBEAT = 1,
|
HEARTBEAT = 1,
|
||||||
IDENTIFY = 2,
|
IDENTIFY = 2,
|
||||||
|
@ -26,7 +27,7 @@ enum GatewayOpcodes { // 문서를 확인해본 결과 Opcode 5번은 비어있
|
||||||
/**
|
/**
|
||||||
* Gateway Close Codes from Discord docs.
|
* Gateway Close Codes from Discord docs.
|
||||||
*/
|
*/
|
||||||
enum GatewayCloseCodes {
|
export enum GatewayCloseCodes {
|
||||||
UNKNOWN_ERROR = 4000,
|
UNKNOWN_ERROR = 4000,
|
||||||
UNKNOWN_OPCODE = 4001,
|
UNKNOWN_OPCODE = 4001,
|
||||||
DECODE_ERROR = 4002,
|
DECODE_ERROR = 4002,
|
||||||
|
@ -43,7 +44,7 @@ enum GatewayCloseCodes {
|
||||||
DISALLOWED_INTENTS = 4014
|
DISALLOWED_INTENTS = 4014
|
||||||
}
|
}
|
||||||
|
|
||||||
enum GatewayIntents {
|
export enum GatewayIntents {
|
||||||
GUILDS = 1 << 0,
|
GUILDS = 1 << 0,
|
||||||
GUILD_MEMBERS = 1 << 1,
|
GUILD_MEMBERS = 1 << 1,
|
||||||
GUILD_BANS = 1 << 2,
|
GUILD_BANS = 1 << 2,
|
||||||
|
@ -61,7 +62,7 @@ enum GatewayIntents {
|
||||||
DIRECT_MESSAGE_TYPING = 1 << 13
|
DIRECT_MESSAGE_TYPING = 1 << 13
|
||||||
}
|
}
|
||||||
|
|
||||||
enum GatewayEvents {
|
export enum GatewayEvents {
|
||||||
Ready = 'READY',
|
Ready = 'READY',
|
||||||
Resumed = 'RESUMED',
|
Resumed = 'RESUMED',
|
||||||
Reconnect = 'RECONNECT',
|
Reconnect = 'RECONNECT',
|
||||||
|
@ -111,7 +112,7 @@ export interface IdentityPayload {
|
||||||
intents: number
|
intents: number
|
||||||
}
|
}
|
||||||
|
|
||||||
enum UpdateStatus {
|
export enum UpdateStatus {
|
||||||
online = 'online',
|
online = 'online',
|
||||||
dnd = 'dnd',
|
dnd = 'dnd',
|
||||||
afk = 'idle',
|
afk = 'idle',
|
||||||
|
@ -291,7 +292,7 @@ export interface MessageReactionRemoveAllPayload {
|
||||||
export interface PresenceUpdatePayload {
|
export interface PresenceUpdatePayload {
|
||||||
user: UserPayload
|
user: UserPayload
|
||||||
guild_id: string
|
guild_id: string
|
||||||
status: string
|
status: StatusType
|
||||||
activities: ActivityPayload[]
|
activities: ActivityPayload[]
|
||||||
client_status: UpdateStatus[]
|
client_status: UpdateStatus[]
|
||||||
}
|
}
|
||||||
|
@ -314,12 +315,3 @@ export interface WebhooksUpdatePayload {
|
||||||
guild_id: string
|
guild_id: string
|
||||||
channel_id: string
|
channel_id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://discord.com/developers/docs/topics/gateway#typing-start-typing-start-event-fields
|
|
||||||
export {
|
|
||||||
GatewayCloseCodes,
|
|
||||||
GatewayOpcodes,
|
|
||||||
GatewayIntents,
|
|
||||||
GatewayEvents,
|
|
||||||
UpdateStatus
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { ChannelPayload } from './channel.ts'
|
import { ChannelPayload } from './channel.ts'
|
||||||
import { EmojiPayload } from './emoji.ts'
|
import { EmojiPayload } from './emoji.ts'
|
||||||
import { PresenceUpdatePayload } from './presence.ts'
|
import { PresenceUpdatePayload } from './gateway.ts'
|
||||||
import { RolePayload } from './role.ts'
|
import { RolePayload } from './role.ts'
|
||||||
import { UserPayload } from './user.ts'
|
import { UserPayload } from './user.ts'
|
||||||
import { VoiceStatePayload } from './voice.ts'
|
import { VoiceStatePayload } from './voice.ts'
|
||||||
|
@ -63,23 +63,23 @@ export interface MemberPayload {
|
||||||
mute: boolean
|
mute: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MessageNotification {
|
export enum MessageNotification {
|
||||||
ALL_MESSAGES = 0,
|
ALL_MESSAGES = 0,
|
||||||
ONLY_MENTIONS = 1
|
ONLY_MENTIONS = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ContentFilter {
|
export enum ContentFilter {
|
||||||
DISABLED = 0,
|
DISABLED = 0,
|
||||||
MEMBERS_WITHOUT_ROLES = 1,
|
MEMBERS_WITHOUT_ROLES = 1,
|
||||||
ALL_MEMBERS = 3
|
ALL_MEMBERS = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
enum MFA {
|
export enum MFA {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
ELEVATED = 1
|
ELEVATED = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Verification {
|
export enum Verification {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
LOW = 1,
|
LOW = 1,
|
||||||
MEDIUM = 2,
|
MEDIUM = 2,
|
||||||
|
@ -87,14 +87,14 @@ enum Verification {
|
||||||
VERY_HIGH = 4
|
VERY_HIGH = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PremiumTier {
|
export enum PremiumTier {
|
||||||
NONE = 0,
|
NONE = 0,
|
||||||
TIER_1 = 1,
|
TIER_1 = 1,
|
||||||
TIER_2 = 2,
|
TIER_2 = 2,
|
||||||
TIER_3 = 3
|
TIER_3 = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
enum SystemChannelFlags {
|
export enum SystemChannelFlags {
|
||||||
SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0,
|
SUPPRESS_JOIN_NOTIFICATIONS = 1 << 0,
|
||||||
SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1
|
SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ export interface ActivitySecrets {
|
||||||
match?: string
|
match?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ActivityFlags {
|
export enum ActivityFlags {
|
||||||
INSTANCE = 1 << 0,
|
INSTANCE = 1 << 0,
|
||||||
JOIN = 1 << 1,
|
JOIN = 1 << 1,
|
||||||
SPECTATE = 1 << 2,
|
SPECTATE = 1 << 2,
|
||||||
|
@ -58,5 +58,3 @@ enum ActivityFlags {
|
||||||
SYNC = 1 << 4,
|
SYNC = 1 << 4,
|
||||||
PLAY = 1 << 5
|
PLAY = 1 << 5
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ActivityFlags }
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice
|
// https://discord.com/developers/docs/topics/opcodes-and-status-codes#voice
|
||||||
import { MemberPayload } from './guild.ts'
|
import { MemberPayload } from './guild.ts'
|
||||||
|
|
||||||
enum VoiceOpcodes { // VoiceOpcodes 추가 - UnderC -
|
export enum VoiceOpcodes { // VoiceOpcodes 추가 - UnderC -
|
||||||
IDENTIFY = 0,
|
IDENTIFY = 0,
|
||||||
SELECT_PROTOCOL = 1,
|
SELECT_PROTOCOL = 1,
|
||||||
READY = 2,
|
READY = 2,
|
||||||
|
@ -15,7 +15,7 @@ enum VoiceOpcodes { // VoiceOpcodes 추가 - UnderC -
|
||||||
CLIENT_DISCONNECT = 13
|
CLIENT_DISCONNECT = 13
|
||||||
}
|
}
|
||||||
|
|
||||||
enum VoiceCloseCodes {
|
export enum VoiceCloseCodes {
|
||||||
UNKNOWN_OPCODE = 4001,
|
UNKNOWN_OPCODE = 4001,
|
||||||
NOT_AUTHENTICATED = 4003,
|
NOT_AUTHENTICATED = 4003,
|
||||||
AUTHENTICATION_FAILED = 4004,
|
AUTHENTICATION_FAILED = 4004,
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
export class Collection<K = string, V = any> extends Map<K, V> {
|
export class Collection<K = string, V = any> extends Map<K, V> {
|
||||||
maxSize?: number;
|
set(key: K, value: V): this {
|
||||||
|
|
||||||
set(key: K, value: V) {
|
|
||||||
if (this.maxSize || this.maxSize === 0) {
|
|
||||||
if (this.size >= this.maxSize) return this
|
|
||||||
}
|
|
||||||
|
|
||||||
return super.set(key, value)
|
return super.set(key, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
array() {
|
array(): V[] {
|
||||||
return [...this.values()]
|
return [...this.values()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,53 +15,49 @@ export class Collection<K = string, V = any> extends Map<K, V> {
|
||||||
return [...this.values()][this.size - 1]
|
return [...this.values()][this.size - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
random() {
|
random(): V {
|
||||||
const arr = [...this.values()]
|
const arr = [...this.values()]
|
||||||
return arr[Math.floor(Math.random() * arr.length)]
|
return arr[Math.floor(Math.random() * arr.length)]
|
||||||
}
|
}
|
||||||
|
|
||||||
find(callback: (value: V, key: K) => boolean) {
|
find(callback: (value: V, key: K) => boolean): V | undefined {
|
||||||
for (const key of this.keys()) {
|
for (const key of this.keys()) {
|
||||||
const value = this.get(key)!
|
const value = this.get(key) as V
|
||||||
|
// eslint-disable-next-line standard/no-callback-literal
|
||||||
if (callback(value, key)) return value
|
if (callback(value, key)) return value
|
||||||
}
|
}
|
||||||
// If nothing matched
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filter(callback: (value: V, key: K) => boolean) {
|
filter(callback: (value: V, key: K) => boolean): Collection<K, V> {
|
||||||
const relevant = new Collection<K, V>()
|
const relevant = new Collection<K, V>()
|
||||||
this.forEach((value, key) => {
|
this.forEach((value, key) => {
|
||||||
if (callback(value, key)) relevant.set(key, value)
|
if (callback(value, key)) relevant.set(key, value)
|
||||||
});
|
})
|
||||||
|
return relevant
|
||||||
return relevant;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
map<T>(callback: (value: V, key: K) => T) {
|
map<T>(callback: (value: V, key: K) => T): T[] {
|
||||||
const results = []
|
const results = []
|
||||||
for (const key of this.keys()) {
|
for (const key of this.keys()) {
|
||||||
const value = this.get(key)!
|
const value = this.get(key) as V
|
||||||
results.push(callback(value, key))
|
results.push(callback(value, key))
|
||||||
}
|
}
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
some(callback: (value: V, key: K) => boolean) {
|
some(callback: (value: V, key: K) => boolean): boolean {
|
||||||
for (const key of this.keys()) {
|
for (const key of this.keys()) {
|
||||||
const value = this.get(key)!
|
const value = this.get(key) as V
|
||||||
if (callback(value, key)) return true
|
if (callback(value, key)) return true
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
every(callback: (value: V, key: K) => boolean) {
|
every(callback: (value: V, key: K) => boolean): boolean {
|
||||||
for (const key of this.keys()) {
|
for (const key of this.keys()) {
|
||||||
const value = this.get(key)!
|
const value = this.get(key) as V
|
||||||
if (!callback(value, key)) return false
|
if (!callback(value, key)) return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,21 +65,21 @@ export class Collection<K = string, V = any> extends Map<K, V> {
|
||||||
callback: (accumulator: T, value: V, key: K) => T,
|
callback: (accumulator: T, value: V, key: K) => T,
|
||||||
initialValue?: T,
|
initialValue?: T,
|
||||||
): T {
|
): T {
|
||||||
let accumulator: T = initialValue!
|
let accumulator: T = initialValue as T
|
||||||
|
|
||||||
for (const key of this.keys()) {
|
for (const key of this.keys()) {
|
||||||
const value = this.get(key)!
|
const value = this.get(key) as V
|
||||||
accumulator = callback(accumulator, value, key)
|
accumulator = callback(accumulator, value, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
return accumulator
|
return accumulator
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromObject<V>(object: { [key: string]: V }) {
|
static fromObject<V>(object: { [key: string]: V }): Collection<string, V> {
|
||||||
return new Collection<string, V>(Object.entries(object))
|
return new Collection<string, V>(Object.entries(object))
|
||||||
}
|
}
|
||||||
|
|
||||||
toObject() {
|
toObject(): { [name: string]: V } {
|
||||||
return Object.entries(this)
|
return Object.fromEntries(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
export const delay = (ms: number) => new Promise((resolve, reject) => {
|
export const delay = async (ms: number): Promise<true> => await new Promise((resolve, reject) => {
|
||||||
setTimeout(() => resolve(true), ms);
|
setTimeout(() => resolve(true), ms);
|
||||||
});
|
});
|
|
@ -14,7 +14,9 @@ import { GroupDMChannel } from '../structures/groupChannel.ts'
|
||||||
import { CategoryChannel } from '../structures/guildCategoryChannel.ts'
|
import { CategoryChannel } from '../structures/guildCategoryChannel.ts'
|
||||||
import { NewsChannel } from '../structures/guildNewsChannel.ts'
|
import { NewsChannel } from '../structures/guildNewsChannel.ts'
|
||||||
import { VoiceChannel } from '../structures/guildVoiceChannel.ts'
|
import { VoiceChannel } from '../structures/guildVoiceChannel.ts'
|
||||||
import { TextChannel } from '../structures/textChannel.ts'
|
import { Guild } from "../structures/guild.ts"
|
||||||
|
import { GuildTextChannel } from "../structures/guildTextChannel.ts"
|
||||||
|
import { TextChannel } from "../structures/textChannel.ts"
|
||||||
|
|
||||||
const getChannelByType = (
|
const getChannelByType = (
|
||||||
client: Client,
|
client: Client,
|
||||||
|
@ -25,7 +27,8 @@ const getChannelByType = (
|
||||||
| GuildVoiceChannelPayload
|
| GuildVoiceChannelPayload
|
||||||
| DMChannelPayload
|
| DMChannelPayload
|
||||||
| GroupDMChannelPayload
|
| GroupDMChannelPayload
|
||||||
| ChannelPayload
|
| ChannelPayload,
|
||||||
|
guild?: Guild
|
||||||
):
|
):
|
||||||
| CategoryChannel
|
| CategoryChannel
|
||||||
| NewsChannel
|
| NewsChannel
|
||||||
|
@ -36,13 +39,17 @@ const getChannelByType = (
|
||||||
| undefined => {
|
| undefined => {
|
||||||
switch (data.type) {
|
switch (data.type) {
|
||||||
case ChannelTypes.GUILD_CATEGORY:
|
case ChannelTypes.GUILD_CATEGORY:
|
||||||
return new CategoryChannel(client, data as GuildChannelCategoryPayload)
|
if (guild === undefined) throw new Error("No Guild was provided to construct Channel")
|
||||||
|
return new CategoryChannel(client, data as GuildChannelCategoryPayload, guild)
|
||||||
case ChannelTypes.GUILD_NEWS:
|
case ChannelTypes.GUILD_NEWS:
|
||||||
return new NewsChannel(client, data as GuildNewsChannelPayload)
|
if (guild === undefined) throw new Error("No Guild was provided to construct Channel")
|
||||||
|
return new NewsChannel(client, data as GuildNewsChannelPayload, guild)
|
||||||
case ChannelTypes.GUILD_TEXT:
|
case ChannelTypes.GUILD_TEXT:
|
||||||
return new TextChannel(client, data as GuildTextChannelPayload)
|
if (guild === undefined) throw new Error("No Guild was provided to construct Channel")
|
||||||
|
return new GuildTextChannel(client, data as GuildTextChannelPayload, guild)
|
||||||
case ChannelTypes.GUILD_VOICE:
|
case ChannelTypes.GUILD_VOICE:
|
||||||
return new VoiceChannel(client, data as GuildVoiceChannelPayload)
|
if (guild === undefined) throw new Error("No Guild was provided to construct Channel")
|
||||||
|
return new VoiceChannel(client, data as GuildVoiceChannelPayload, guild)
|
||||||
case ChannelTypes.DM:
|
case ChannelTypes.DM:
|
||||||
return new DMChannel(client, data as DMChannelPayload)
|
return new DMChannel(client, data as DMChannelPayload)
|
||||||
case ChannelTypes.GROUP_DM:
|
case ChannelTypes.GROUP_DM:
|
||||||
|
|
Loading…
Reference in a new issue