MASSIVE UPDATE NOW WITH EVENTS
Co-Authored-By: Y <8479056+yky4589@users.noreply.github.com> Co-Authored-By: Aki <71239005+AkiaCode@users.noreply.github.com>
This commit is contained in:
parent
e899738b55
commit
f319e0df91
42 changed files with 641 additions and 483 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -110,5 +110,3 @@ yarn.lock
|
|||
# PRIVACY XDDDD
|
||||
src/test/config.ts
|
||||
.vscode
|
||||
|
||||
src/test/
|
13
src/gateway/handlers/channelCreate.ts
Normal file
13
src/gateway/handlers/channelCreate.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
import getChannelByType from '../../utils/getChannelByType.ts'
|
||||
|
||||
export const channelCreate: GatewayEventHandler = (
|
||||
gateway: Gateway,
|
||||
d: any
|
||||
) => {
|
||||
const channel = getChannelByType(gateway.client, d)
|
||||
|
||||
if (channel !== undefined) {
|
||||
gateway.client.emit('channelCreate', channel)
|
||||
}
|
||||
}
|
14
src/gateway/handlers/channelDelete.ts
Normal file
14
src/gateway/handlers/channelDelete.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
import cache from '../../models/cache.ts'
|
||||
import { Channel } from '../../structures/channel.ts'
|
||||
|
||||
export const channelDelete: GatewayEventHandler = (
|
||||
gateway: Gateway,
|
||||
d: any
|
||||
) => {
|
||||
const channel: Channel = cache.get('channel', d.id)
|
||||
if (channel !== undefined) {
|
||||
cache.del('channel', d.id)
|
||||
gateway.client.emit('channelDelete', channel)
|
||||
}
|
||||
}
|
16
src/gateway/handlers/channelPinsUpdate.ts
Normal file
16
src/gateway/handlers/channelPinsUpdate.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
import cache from '../../models/cache.ts'
|
||||
import { TextChannel } from '../../structures/textChannel.ts'
|
||||
|
||||
export const channelPinsUpdate: GatewayEventHandler = (
|
||||
gateway: Gateway,
|
||||
d: any
|
||||
) => {
|
||||
const after: TextChannel = cache.get('textchannel', d.channel_id)
|
||||
if (after !== undefined) {
|
||||
const before = after.refreshFromData({
|
||||
last_pin_timestamp: d.last_pin_timestamp
|
||||
})
|
||||
gateway.client.emit('channelPinsUpdate', before, after)
|
||||
}
|
||||
}
|
21
src/gateway/handlers/channelUpdate.ts
Normal file
21
src/gateway/handlers/channelUpdate.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import cache from '../../models/cache.ts'
|
||||
import { Channel } from '../../structures/channel.ts'
|
||||
import getChannelByType from '../../utils/getChannelByType.ts'
|
||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
|
||||
export const channelUpdate: GatewayEventHandler = (
|
||||
gateway: Gateway,
|
||||
d: any
|
||||
) => {
|
||||
const oldChannel: Channel = cache.get('channel', d.id)
|
||||
|
||||
if (oldChannel !== undefined) {
|
||||
if (oldChannel.type !== d.type) {
|
||||
const channel: Channel = getChannelByType(gateway.client, d) ?? oldChannel
|
||||
gateway.client.emit('channelUpdate', oldChannel, channel)
|
||||
} else {
|
||||
const before = oldChannel.refreshFromData(d)
|
||||
gateway.client.emit('channelUpdate', before, oldChannel)
|
||||
}
|
||||
}
|
||||
}
|
14
src/gateway/handlers/guildBanAdd.ts
Normal file
14
src/gateway/handlers/guildBanAdd.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
import cache from '../../models/cache.ts'
|
||||
import { Guild } from '../../structures/guild.ts'
|
||||
import { User } from '../../structures/user.ts'
|
||||
|
||||
export const guildBanAdd: GatewayEventHandler = (gateway: Gateway, d: any) => {
|
||||
const guild: Guild = cache.get('guild', d.guild_id)
|
||||
const user: User =
|
||||
cache.get('user', d.user.id) ?? new User(gateway.client, d.user)
|
||||
|
||||
if (guild !== undefined) {
|
||||
gateway.client.emit('guildBanAdd', guild, user)
|
||||
}
|
||||
}
|
17
src/gateway/handlers/guildBanRemove.ts
Normal file
17
src/gateway/handlers/guildBanRemove.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
import cache from '../../models/cache.ts'
|
||||
import { Guild } from '../../structures/guild.ts'
|
||||
import { User } from '../../structures/user.ts'
|
||||
|
||||
export const guildBanRemove: GatewayEventHandler = (
|
||||
gateway: Gateway,
|
||||
d: any
|
||||
) => {
|
||||
const guild: Guild = cache.get('guild', d.guild_id)
|
||||
const user: User =
|
||||
cache.get('user', d.user.id) ?? new User(gateway.client, d.user)
|
||||
|
||||
if (guild !== undefined) {
|
||||
gateway.client.emit('guildBanRemove', guild, user)
|
||||
}
|
||||
}
|
14
src/gateway/handlers/guildCreate.ts
Normal file
14
src/gateway/handlers/guildCreate.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
import cache from '../../models/cache.ts'
|
||||
import { Guild } from '../../structures/guild.ts'
|
||||
|
||||
export const guildCreate: GatewayEventHandler = (gateway: Gateway, d: any) => {
|
||||
let guild: Guild = cache.get('guild', d.id)
|
||||
if (guild !== undefined) {
|
||||
guild.refreshFromData(d)
|
||||
} else {
|
||||
guild = new Guild(gateway.client, d)
|
||||
}
|
||||
|
||||
gateway.client.emit('guildCreate', guild)
|
||||
}
|
13
src/gateway/handlers/guildDelete.ts
Normal file
13
src/gateway/handlers/guildDelete.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
import cache from '../../models/cache.ts'
|
||||
import { Guild } from '../../structures/guild.ts'
|
||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
|
||||
export const guildDelte: GatewayEventHandler = (gateway: Gateway, d: any) => {
|
||||
const guild: Guild = cache.get('guild', d.id)
|
||||
|
||||
if (guild !== undefined) {
|
||||
guild.refreshFromData(d)
|
||||
cache.del('guild', d.id)
|
||||
gateway.client.emit('guildDelete', guild)
|
||||
}
|
||||
}
|
11
src/gateway/handlers/guildUpdate.ts
Normal file
11
src/gateway/handlers/guildUpdate.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
import cache from '../../models/cache.ts'
|
||||
import { Guild } from '../../structures/guild.ts'
|
||||
|
||||
export const guildUpdate: GatewayEventHandler = (gateway: Gateway, d: any) => {
|
||||
const after: Guild = cache.get('guild', d.id)
|
||||
if (after !== undefined) {
|
||||
const before: Guild = after.refreshFromData(d)
|
||||
gateway.client.emit('guildUpdate', before, after)
|
||||
}
|
||||
}
|
53
src/gateway/handlers/index.ts
Normal file
53
src/gateway/handlers/index.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { GatewayEventHandler } from '../index.ts'
|
||||
import { GatewayEvents } from '../../types/gatewayTypes.ts'
|
||||
import { channelCreate } from './channelCreate.ts'
|
||||
import { channelDelete } from './channelDelete.ts'
|
||||
import { channelUpdate } from './channelUpdate.ts'
|
||||
import { channelPinsUpdate } from './channelPinsUpdate.ts'
|
||||
import { guildCreate } from './guildCreate.ts'
|
||||
import { guildDelte as guildDelete } from './guildDelete.ts'
|
||||
import { guildUpdate } from './guildUpdate.ts'
|
||||
import { guildBanAdd } from './guildBanAdd.ts'
|
||||
import { ready } from './ready.ts'
|
||||
import { guildBanRemove } from './guildBanRemove.ts'
|
||||
|
||||
export const gatewayHandlers: {
|
||||
[eventCode in GatewayEvents]: GatewayEventHandler | undefined
|
||||
} = {
|
||||
READY: ready,
|
||||
RECONNECT: undefined,
|
||||
RESUMED: undefined,
|
||||
CHANNEL_CREATE: channelCreate,
|
||||
CHANNEL_DELETE: channelDelete,
|
||||
CHANNEL_UPDATE: channelUpdate,
|
||||
CHANNEL_PINS_UPDATE: channelPinsUpdate,
|
||||
GUILD_CREATE: guildCreate,
|
||||
GUILD_DELETE: guildDelete,
|
||||
GUILD_UPDATE: guildUpdate,
|
||||
GUILD_BAN_ADD: guildBanAdd,
|
||||
GUILD_BAN_REMOVE: guildBanRemove,
|
||||
GUILD_EMOJIS_UPDATE: undefined,
|
||||
GUILD_INTEGRATIONS_UPDATE: undefined,
|
||||
GUILD_MEMBER_ADD: undefined,
|
||||
GUILD_MEMBER_REMOVE: undefined,
|
||||
GUILD_MEMBER_UPDATE: undefined,
|
||||
GUILD_MEMBERS_CHUNK: undefined,
|
||||
GUILD_ROLE_CREATE: undefined,
|
||||
GUILD_ROLE_UPDATE: undefined,
|
||||
GUILD_ROLE_DELETE: undefined,
|
||||
INVITE_CREATE: undefined,
|
||||
INVITE_DELETE: undefined,
|
||||
MESSAGE_CREATE: undefined,
|
||||
MESSAGE_UPDATE: undefined,
|
||||
MESSAGE_DELETE: undefined,
|
||||
MESSAGE_DELETE_BULK: undefined,
|
||||
MESSAGE_REACTION_ADD: undefined,
|
||||
MESSAGE_REACTION_REMOVE: undefined,
|
||||
MESSAGE_REACTION_REMOVE_ALL: undefined,
|
||||
MESSAGE_REACTION_REMOVE_EMOJI: undefined,
|
||||
PRESENCE_UPDATE: undefined,
|
||||
TYPING_START: undefined,
|
||||
USER_UPDATE: undefined,
|
||||
VOICE_SERVER_UPDATE: undefined,
|
||||
WEBHOOKS_UPDATE: undefined
|
||||
}
|
11
src/gateway/handlers/ready.ts
Normal file
11
src/gateway/handlers/ready.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { Guild } from '../../structures/guild.ts'
|
||||
import { User } from '../../structures/user.ts'
|
||||
import { GuildPayload } from '../../types/guildTypes.ts'
|
||||
import { Gateway, GatewayEventHandler } from '../index.ts'
|
||||
|
||||
export const ready: GatewayEventHandler = (gateway: Gateway, d: any) => {
|
||||
gateway.client.user = new User(gateway.client, d.user)
|
||||
gateway.sessionID = d.session_id
|
||||
d.guilds.forEach((guild: GuildPayload) => new Guild(gateway.client, guild))
|
||||
gateway.client.emit('ready')
|
||||
}
|
199
src/gateway/index.ts
Normal file
199
src/gateway/index.ts
Normal file
|
@ -0,0 +1,199 @@
|
|||
import { unzlib } from 'https://deno.land/x/denoflate/mod.ts'
|
||||
import { Client } from '../models/client.ts'
|
||||
import {
|
||||
DISCORD_GATEWAY_URL,
|
||||
DISCORD_API_VERSION
|
||||
} from '../consts/urlsAndVersions.ts'
|
||||
import { GatewayResponse } from '../types/gatewayResponse.ts'
|
||||
import { GatewayOpcodes, GatewayIntents } from '../types/gatewayTypes.ts'
|
||||
import { gatewayHandlers } from './handlers/index.ts'
|
||||
|
||||
/**
|
||||
* Handles Discord gateway connection.
|
||||
* You should not use this and rather use Client class.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
class Gateway {
|
||||
websocket: WebSocket
|
||||
token: string
|
||||
intents: GatewayIntents[]
|
||||
connected = false
|
||||
initialized = false
|
||||
heartbeatInterval = 0
|
||||
heartbeatIntervalID?: number
|
||||
sequenceID?: number
|
||||
sessionID?: string
|
||||
lastPingTimestemp = 0
|
||||
private heartbeatServerResponded = false
|
||||
client: Client
|
||||
|
||||
constructor (client: Client, token: string, intents: GatewayIntents[]) {
|
||||
this.token = token
|
||||
this.intents = intents
|
||||
this.client = client
|
||||
this.websocket = new WebSocket(
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
`${DISCORD_GATEWAY_URL}/?v=${DISCORD_API_VERSION}&encoding=json`,
|
||||
[]
|
||||
)
|
||||
this.websocket.binaryType = 'arraybuffer'
|
||||
this.websocket.onopen = this.onopen.bind(this)
|
||||
this.websocket.onmessage = this.onmessage.bind(this)
|
||||
this.websocket.onclose = this.onclose.bind(this)
|
||||
this.websocket.onerror = this.onerror.bind(this)
|
||||
}
|
||||
|
||||
private onopen (): void {
|
||||
this.connected = true
|
||||
}
|
||||
|
||||
private onmessage (event: MessageEvent): void {
|
||||
let data = event.data
|
||||
if (data instanceof ArrayBuffer) {
|
||||
data = new Uint8Array(data)
|
||||
}
|
||||
if (data instanceof Uint8Array) {
|
||||
data = unzlib(data)
|
||||
data = new TextDecoder('utf-8').decode(data)
|
||||
}
|
||||
|
||||
const { op, d, s, t }: GatewayResponse = JSON.parse(data)
|
||||
|
||||
switch (op) {
|
||||
case GatewayOpcodes.HELLO:
|
||||
this.heartbeatInterval = d.heartbeat_interval
|
||||
this.heartbeatIntervalID = setInterval(() => {
|
||||
if (this.heartbeatServerResponded) {
|
||||
this.heartbeatServerResponded = false
|
||||
} else {
|
||||
clearInterval(this.heartbeatIntervalID)
|
||||
this.websocket.close()
|
||||
this.initWebsocket()
|
||||
return
|
||||
}
|
||||
|
||||
this.websocket.send(
|
||||
JSON.stringify({
|
||||
op: GatewayOpcodes.HEARTBEAT,
|
||||
d: this.sequenceID ?? null
|
||||
})
|
||||
)
|
||||
this.lastPingTimestemp = Date.now()
|
||||
}, this.heartbeatInterval)
|
||||
|
||||
if (!this.initialized) {
|
||||
this.sendIdentify()
|
||||
this.initialized = true
|
||||
} else {
|
||||
this.sendResume()
|
||||
}
|
||||
break
|
||||
|
||||
case GatewayOpcodes.HEARTBEAT_ACK:
|
||||
this.heartbeatServerResponded = true
|
||||
this.client.ping = Date.now() - this.lastPingTimestemp
|
||||
break
|
||||
|
||||
case GatewayOpcodes.INVALID_SESSION:
|
||||
// Because we know this gonna be bool
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (!d) {
|
||||
setTimeout(this.sendResume, 3000)
|
||||
} else {
|
||||
setTimeout(this.sendIdentify, 3000)
|
||||
}
|
||||
break
|
||||
|
||||
case GatewayOpcodes.DISPATCH: {
|
||||
this.heartbeatServerResponded = true
|
||||
if (s !== null) {
|
||||
this.sequenceID = s
|
||||
}
|
||||
if (t !== null && t !== undefined) {
|
||||
const handler = gatewayHandlers[t]
|
||||
|
||||
if (handler !== undefined) {
|
||||
handler(this, d)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private onclose (event: CloseEvent): void {
|
||||
console.log(event.code)
|
||||
// TODO: Handle close event codes.
|
||||
}
|
||||
|
||||
private onerror (event: Event | ErrorEvent): void {
|
||||
const eventError = event as ErrorEvent
|
||||
|
||||
console.log(eventError)
|
||||
}
|
||||
|
||||
private sendIdentify (): void {
|
||||
this.websocket.send(
|
||||
JSON.stringify({
|
||||
op: GatewayOpcodes.IDENTIFY,
|
||||
d: {
|
||||
token: this.token,
|
||||
properties: {
|
||||
$os: Deno.build.os,
|
||||
$browser: 'discord.deno',
|
||||
$device: 'discord.deno'
|
||||
},
|
||||
compress: true,
|
||||
shard: [0, 1], // TODO: Make sharding possible
|
||||
intents: this.intents.reduce(
|
||||
(previous, current) => previous | current,
|
||||
0
|
||||
),
|
||||
presence: {
|
||||
// TODO: User should can customize this
|
||||
status: 'online',
|
||||
since: null,
|
||||
afk: false
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private sendResume (): void {
|
||||
this.websocket.send(
|
||||
JSON.stringify({
|
||||
op: GatewayOpcodes.RESUME,
|
||||
d: {
|
||||
token: this.token,
|
||||
session_id: this.sessionID,
|
||||
seq: this.sequenceID
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
initWebsocket (): void {
|
||||
this.websocket = new WebSocket(
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
`${DISCORD_GATEWAY_URL}/?v=${DISCORD_API_VERSION}&encoding=json`,
|
||||
[]
|
||||
)
|
||||
this.websocket.binaryType = 'arraybuffer'
|
||||
this.websocket.onopen = this.onopen.bind(this)
|
||||
this.websocket.onmessage = this.onmessage.bind(this)
|
||||
this.websocket.onclose = this.onclose.bind(this)
|
||||
this.websocket.onerror = this.onerror.bind(this)
|
||||
}
|
||||
|
||||
close (): void {
|
||||
this.websocket.close(1000)
|
||||
}
|
||||
}
|
||||
|
||||
export type GatewayEventHandler = (gateway: Gateway, d: any) => void
|
||||
|
||||
export { Gateway }
|
|
@ -1,8 +1,9 @@
|
|||
import { User } from '../structures/user.ts'
|
||||
import { GatewayIntents } from '../types/gatewayTypes.ts'
|
||||
import { Gateway } from './gateway.ts'
|
||||
import { Gateway } from '../gateway/index.ts'
|
||||
import { Rest } from './rest.ts'
|
||||
import EventEmitter from 'https://deno.land/std@0.74.0/node/events.ts'
|
||||
|
||||
/**
|
||||
* Discord Client.
|
||||
*/
|
||||
|
|
|
@ -1,309 +0,0 @@
|
|||
import { unzlib } from 'https://deno.land/x/denoflate/mod.ts'
|
||||
import { Client } from './client.ts'
|
||||
import {
|
||||
DISCORD_GATEWAY_URL,
|
||||
DISCORD_API_VERSION
|
||||
} from '../consts/urlsAndVersions.ts'
|
||||
import { GatewayResponse } from '../types/gatewayResponse.ts'
|
||||
import {
|
||||
GatewayOpcodes,
|
||||
GatewayIntents,
|
||||
GatewayEvents
|
||||
} from '../types/gatewayTypes.ts'
|
||||
import { GuildPayload } from '../types/guildTypes.ts'
|
||||
import { User } from '../structures/user.ts'
|
||||
import * as cache from './cache.ts'
|
||||
import { Guild } from '../structures/guild.ts'
|
||||
import { Channel } from '../structures/channel.ts'
|
||||
import { ChannelTypes } from '../types/channelTypes.ts'
|
||||
import { DMChannel } from '../structures/dmChannel.ts'
|
||||
import { GroupDMChannel } from '../structures/groupChannel.ts'
|
||||
import { GuildTextChannel } from '../structures/guildTextChannel.ts'
|
||||
import { VoiceChannel } from '../structures/guildVoiceChannel.ts'
|
||||
import { CategoryChannel } from '../structures/guildCategoryChannel.ts'
|
||||
import { NewsChannel } from '../structures/guildNewsChannel.ts'
|
||||
|
||||
/**
|
||||
* Handles Discord gateway connection.
|
||||
* You should not use this and rather use Client class.
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
class Gateway {
|
||||
websocket: WebSocket
|
||||
token: string
|
||||
intents: GatewayIntents[]
|
||||
connected = false
|
||||
initialized = false
|
||||
private heartbeatInterval = 0
|
||||
private heartbeatIntervalID?: number
|
||||
private sequenceID?: number
|
||||
private sessionID?: string
|
||||
lastPingTimestemp = 0
|
||||
private heartbeatServerResponded = false
|
||||
client: Client
|
||||
|
||||
constructor (client: Client, token: string, intents: GatewayIntents[]) {
|
||||
this.token = token
|
||||
this.intents = intents
|
||||
this.client = client
|
||||
this.websocket = new WebSocket(
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
`${DISCORD_GATEWAY_URL}/?v=${DISCORD_API_VERSION}&encoding=json`,
|
||||
[]
|
||||
)
|
||||
this.websocket.binaryType = 'arraybuffer'
|
||||
this.websocket.onopen = this.onopen.bind(this)
|
||||
this.websocket.onmessage = this.onmessage.bind(this)
|
||||
this.websocket.onclose = this.onclose.bind(this)
|
||||
this.websocket.onerror = this.onerror.bind(this)
|
||||
}
|
||||
|
||||
private onopen (): void {
|
||||
this.connected = true
|
||||
}
|
||||
|
||||
private onmessage (event: MessageEvent): void {
|
||||
let data = event.data
|
||||
if (data instanceof ArrayBuffer) {
|
||||
data = new Uint8Array(data)
|
||||
}
|
||||
if (data instanceof Uint8Array) {
|
||||
data = unzlib(data)
|
||||
data = new TextDecoder('utf-8').decode(data)
|
||||
}
|
||||
|
||||
const { op, d, s, t }: GatewayResponse = JSON.parse(data)
|
||||
|
||||
switch (op) {
|
||||
case GatewayOpcodes.HELLO:
|
||||
this.heartbeatInterval = d.heartbeat_interval
|
||||
this.heartbeatIntervalID = setInterval(() => {
|
||||
if (this.heartbeatServerResponded) {
|
||||
this.heartbeatServerResponded = false
|
||||
} else {
|
||||
clearInterval(this.heartbeatIntervalID)
|
||||
this.websocket.close()
|
||||
this.initWebsocket()
|
||||
return
|
||||
}
|
||||
|
||||
this.websocket.send(
|
||||
JSON.stringify({
|
||||
op: GatewayOpcodes.HEARTBEAT,
|
||||
d: this.sequenceID ?? null
|
||||
})
|
||||
)
|
||||
this.lastPingTimestemp = Date.now()
|
||||
}, this.heartbeatInterval)
|
||||
|
||||
if (!this.initialized) {
|
||||
this.sendIdentify()
|
||||
this.initialized = true
|
||||
} else {
|
||||
this.sendResume()
|
||||
}
|
||||
break
|
||||
|
||||
case GatewayOpcodes.HEARTBEAT_ACK:
|
||||
this.heartbeatServerResponded = true
|
||||
this.client.ping = Date.now() - this.lastPingTimestemp
|
||||
break
|
||||
|
||||
case GatewayOpcodes.INVALID_SESSION:
|
||||
// Because we know this gonna be bool
|
||||
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
|
||||
if (!d) {
|
||||
setTimeout(this.sendResume, 3000)
|
||||
} else {
|
||||
setTimeout(this.sendIdentify, 3000)
|
||||
}
|
||||
break
|
||||
|
||||
case GatewayOpcodes.DISPATCH:
|
||||
this.heartbeatServerResponded = true
|
||||
if (s !== null) {
|
||||
this.sequenceID = s
|
||||
}
|
||||
switch (t) {
|
||||
case GatewayEvents.Ready:
|
||||
this.client.user = new User(this.client, d.user)
|
||||
this.sessionID = d.session_id
|
||||
d.guilds.forEach((guild: GuildPayload) => {
|
||||
cache.set('guild', guild.id, new Guild(this.client, guild))
|
||||
})
|
||||
this.client.emit('ready')
|
||||
break
|
||||
case GatewayEvents.Channel_Create: {
|
||||
let channel: Channel | undefined
|
||||
switch (d.type) {
|
||||
case ChannelTypes.DM:
|
||||
channel = new DMChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GROUP_DM:
|
||||
channel = new GroupDMChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GUILD_TEXT:
|
||||
channel = new GuildTextChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GUILD_VOICE:
|
||||
channel = new VoiceChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GUILD_CATEGORY:
|
||||
channel = new CategoryChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GUILD_NEWS:
|
||||
channel = new NewsChannel(this.client, d)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
if (channel !== undefined) {
|
||||
cache.set('channel', channel.id, channel)
|
||||
this.client.emit('channelCreate', channel)
|
||||
}
|
||||
break
|
||||
}
|
||||
case GatewayEvents.Channel_Update: {
|
||||
const oldChannel: Channel = cache.get('channel', d.id)
|
||||
|
||||
if (oldChannel !== undefined) {
|
||||
if (oldChannel.type !== d.type) {
|
||||
let channel: Channel = oldChannel
|
||||
switch (d.type) {
|
||||
case ChannelTypes.DM:
|
||||
channel = new DMChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GROUP_DM:
|
||||
channel = new GroupDMChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GUILD_TEXT:
|
||||
channel = new GuildTextChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GUILD_VOICE:
|
||||
channel = new VoiceChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GUILD_CATEGORY:
|
||||
channel = new CategoryChannel(this.client, d)
|
||||
break
|
||||
case ChannelTypes.GUILD_NEWS:
|
||||
channel = new NewsChannel(this.client, d)
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
cache.set('channel', channel.id, channel)
|
||||
this.client.emit('channelUpdate', oldChannel, channel)
|
||||
} else {
|
||||
const before = oldChannel.refreshFromData(d)
|
||||
this.client.emit('channelUpdate', before, oldChannel)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
case GatewayEvents.Channel_Delete: {
|
||||
const channel: Channel = cache.get('channel', d.id)
|
||||
if (channel !== undefined) {
|
||||
cache.del('channel', d.id)
|
||||
this.client.emit('channelDelete', channel)
|
||||
}
|
||||
break
|
||||
}
|
||||
case GatewayEvents.Channel_Pins_Update: {
|
||||
const channel: Channel = cache.get('channel', d.channel_id)
|
||||
if (channel !== undefined && d.last_pin_timestamp !== null) {
|
||||
channel.refreshFromData({
|
||||
last_pin_timestamp: d.last_pin_timestamp
|
||||
})
|
||||
this.client.emit('channelPinsUpdate', channel)
|
||||
}
|
||||
break
|
||||
}
|
||||
case GatewayEvents.Guild_Create: {
|
||||
const guild: Guild = cache.get('guild', d.id)
|
||||
if (guild !== undefined) {
|
||||
guild.refreshFromData(guild)
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
private onclose (event: CloseEvent): void {
|
||||
console.log(event.code)
|
||||
// TODO: Handle close event codes.
|
||||
}
|
||||
|
||||
private onerror (event: Event | ErrorEvent): void {
|
||||
const eventError = event as ErrorEvent
|
||||
|
||||
console.log(eventError)
|
||||
}
|
||||
|
||||
private sendIdentify (): void {
|
||||
this.websocket.send(
|
||||
JSON.stringify({
|
||||
op: GatewayOpcodes.IDENTIFY,
|
||||
d: {
|
||||
token: this.token,
|
||||
properties: {
|
||||
$os: Deno.build.os,
|
||||
$browser: 'discord.deno',
|
||||
$device: 'discord.deno'
|
||||
},
|
||||
compress: true,
|
||||
shard: [0, 1], // TODO: Make sharding possible
|
||||
intents: this.intents.reduce(
|
||||
(previous, current) => previous | current,
|
||||
0
|
||||
),
|
||||
presence: {
|
||||
// TODO: User should can customize this
|
||||
status: 'online',
|
||||
since: null,
|
||||
afk: false
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
private sendResume (): void {
|
||||
this.websocket.send(
|
||||
JSON.stringify({
|
||||
op: GatewayOpcodes.RESUME,
|
||||
d: {
|
||||
token: this.token,
|
||||
session_id: this.sessionID,
|
||||
seq: this.sequenceID
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
initWebsocket (): void {
|
||||
this.websocket = new WebSocket(
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
`${DISCORD_GATEWAY_URL}/?v=${DISCORD_API_VERSION}&encoding=json`,
|
||||
[]
|
||||
)
|
||||
this.websocket.binaryType = 'arraybuffer'
|
||||
this.websocket.onopen = this.onopen.bind(this)
|
||||
this.websocket.onmessage = this.onmessage.bind(this)
|
||||
this.websocket.onclose = this.onclose.bind(this)
|
||||
this.websocket.onerror = this.onerror.bind(this)
|
||||
}
|
||||
|
||||
close (): void {
|
||||
this.websocket.close(1000)
|
||||
}
|
||||
}
|
||||
|
||||
export { Gateway }
|
|
@ -65,7 +65,7 @@ export class Base {
|
|||
return oldOne
|
||||
}
|
||||
|
||||
readFromData (data: { [k: string]: any }): void {}
|
||||
protected readFromData (data: { [k: string]: any }): void {}
|
||||
|
||||
// toJSON() {}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ export class Channel extends Base {
|
|||
cache.set('channel', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: ChannelPayload): void {
|
||||
protected readFromData (data: ChannelPayload): void {
|
||||
super.readFromData(data)
|
||||
this.type = data.type ?? this.type
|
||||
this.id = data.id ?? this.id
|
||||
|
|
|
@ -13,7 +13,7 @@ export class DMChannel extends TextChannel {
|
|||
cache.set('dmchannel', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: DMChannelPayload): void {
|
||||
protected readFromData (data: DMChannelPayload): void {
|
||||
super.readFromData(data)
|
||||
this.recipients = data.recipients ?? this.recipients
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ export class Emoji extends Base {
|
|||
this.available = data.available
|
||||
}
|
||||
|
||||
readFromData (data: EmojiPayload): void {
|
||||
protected readFromData (data: EmojiPayload): void {
|
||||
super.readFromData(data)
|
||||
this.id = data.id ?? this.id
|
||||
this.name = data.name ?? this.name
|
||||
|
|
|
@ -17,7 +17,7 @@ export class GroupDMChannel extends Channel {
|
|||
cache.set('groupchannel', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: GroupDMChannelPayload): void {
|
||||
protected readFromData (data: GroupDMChannelPayload): void {
|
||||
super.readFromData(data)
|
||||
this.name = data.name ?? this.name
|
||||
this.icon = data.icon ?? this.icon
|
||||
|
|
|
@ -8,6 +8,7 @@ import { Member } from './member.ts'
|
|||
import { Role } from './role.ts'
|
||||
import { VoiceState } from './voiceState.ts'
|
||||
import cache from '../models/cache.ts'
|
||||
import getChannelByType from '../utils/getChannelByType.ts'
|
||||
|
||||
export class Guild extends Base {
|
||||
id: string
|
||||
|
@ -103,7 +104,7 @@ export class Guild extends Base {
|
|||
new Member(client, v)
|
||||
)
|
||||
this.channels = data.channels?.map(
|
||||
v => cache.get('channel', v.id) ?? new Channel(client, v)
|
||||
v => cache.get('channel', v.id) ?? getChannelByType(this.client, v)
|
||||
)
|
||||
this.presences = data.presences
|
||||
this.maxPresences = data.max_presences
|
||||
|
@ -122,7 +123,7 @@ export class Guild extends Base {
|
|||
cache.set('guild', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: GuildPayload): void {
|
||||
protected readFromData (data: GuildPayload): void {
|
||||
super.readFromData(data)
|
||||
this.id = data.id ?? this.id
|
||||
this.unavailable = data.unavailable ?? this.unavailable
|
||||
|
@ -177,7 +178,7 @@ export class Guild extends Base {
|
|||
) ?? this.members
|
||||
this.channels =
|
||||
data.channels?.map(
|
||||
v => cache.get('channel', v.id) ?? new Channel(this.client, v)
|
||||
v => cache.get('channel', v.id) ?? getChannelByType(this.client, v)
|
||||
) ?? this.members
|
||||
this.presences = data.presences ?? this.presences
|
||||
this.maxPresences = data.max_presences ?? this.maxPresences
|
||||
|
|
|
@ -25,7 +25,7 @@ export class CategoryChannel extends Channel {
|
|||
cache.set('guildcategorychannel', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: GuildChannelCategoryPayload): void {
|
||||
protected readFromData (data: GuildChannelCategoryPayload): void {
|
||||
super.readFromData(data)
|
||||
this.guildID = data.guild_id ?? this.guildID
|
||||
this.name = data.name ?? this.name
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
import cache from '../models/cache.ts'
|
||||
import { Client } from '../models/client.ts'
|
||||
import { GuildChannelPayload, Overwrite } from '../types/channelTypes.ts'
|
||||
import { Channel } from './channel.ts'
|
||||
|
||||
export class GuildChannel extends Channel {
|
||||
guildID: string
|
||||
name: string
|
||||
position: number
|
||||
permissionOverwrites: Overwrite[]
|
||||
nsfw: boolean
|
||||
parentID?: string
|
||||
|
||||
constructor (client: Client, data: GuildChannelPayload) {
|
||||
super(client, data)
|
||||
this.guildID = data.guild_id
|
||||
this.name = data.name
|
||||
this.position = data.position
|
||||
this.permissionOverwrites = data.permission_overwrites
|
||||
this.nsfw = data.nsfw
|
||||
this.parentID = data.parent_id
|
||||
cache.set('guildchannel', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: GuildChannelPayload): void {
|
||||
super.readFromData(data)
|
||||
this.guildID = data.guild_id ?? this.guildID
|
||||
this.name = data.name ?? this.name
|
||||
this.position = data.position ?? this.position
|
||||
this.permissionOverwrites =
|
||||
data.permission_overwrites ?? this.permissionOverwrites
|
||||
this.nsfw = data.nsfw ?? this.nsfw
|
||||
this.parentID = data.parent_id ?? this.parentID
|
||||
}
|
||||
}
|
|
@ -1,9 +1,15 @@
|
|||
import { Client } from '../models/client.ts'
|
||||
import { GuildChannel } from './guildChannel.ts'
|
||||
import { GuildTextChannelPayload } from '../types/channelTypes.ts'
|
||||
import { GuildTextChannelPayload, Overwrite } from '../types/channelTypes.ts'
|
||||
import cache from '../models/cache.ts'
|
||||
import { TextChannel } from './textChannel.ts'
|
||||
|
||||
export class GuildTextChannel extends GuildChannel {
|
||||
export class GuildTextChannel extends TextChannel {
|
||||
guildID: string
|
||||
name: string
|
||||
position: number
|
||||
permissionOverwrites: Overwrite[]
|
||||
nsfw: boolean
|
||||
parentID?: string
|
||||
rateLimit: number
|
||||
topic?: string
|
||||
|
||||
|
@ -13,13 +19,26 @@ export class GuildTextChannel extends GuildChannel {
|
|||
|
||||
constructor (client: Client, data: GuildTextChannelPayload) {
|
||||
super(client, data)
|
||||
this.guildID = data.guild_id
|
||||
this.name = data.name
|
||||
this.position = data.position
|
||||
this.permissionOverwrites = data.permission_overwrites
|
||||
this.nsfw = data.nsfw
|
||||
this.parentID = data.parent_id
|
||||
this.topic = data.topic
|
||||
this.rateLimit = data.rate_limit_per_user
|
||||
cache.set('guildtextchannel', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: GuildTextChannelPayload): void {
|
||||
protected readFromData (data: GuildTextChannelPayload): void {
|
||||
super.readFromData(data)
|
||||
this.guildID = data.guild_id ?? this.guildID
|
||||
this.name = data.name ?? this.name
|
||||
this.position = data.position ?? this.position
|
||||
this.permissionOverwrites =
|
||||
data.permission_overwrites ?? this.permissionOverwrites
|
||||
this.nsfw = data.nsfw ?? this.nsfw
|
||||
this.parentID = data.parent_id ?? this.parentID
|
||||
this.topic = data.topic ?? this.topic
|
||||
this.rateLimit = data.rate_limit_per_user ?? this.rateLimit
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ export class VoiceChannel extends Channel {
|
|||
cache.set('guildvoicechannel', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: GuildVoiceChannelPayload): void {
|
||||
protected readFromData (data: GuildVoiceChannelPayload): void {
|
||||
super.readFromData(data)
|
||||
this.bitrate = data.bitrate ?? this.bitrate
|
||||
this.userLimit = data.user_limit ?? this.userLimit
|
||||
|
|
|
@ -1,10 +1,36 @@
|
|||
import { Client } from '../models/client.ts'
|
||||
import { Channel } from './channel.ts'
|
||||
import { GuildNewsChannelPayload } from '../types/channelTypes.ts'
|
||||
import { GuildNewsChannelPayload, Overwrite } from '../types/channelTypes.ts'
|
||||
import { TextChannel } from './textChannel.ts'
|
||||
|
||||
export class NewsChannel extends TextChannel {
|
||||
guildID: string
|
||||
name: string
|
||||
position: number
|
||||
permissionOverwrites: Overwrite[]
|
||||
nsfw: boolean
|
||||
parentID?: string
|
||||
topic?: string
|
||||
|
||||
export class NewsChannel extends Channel {
|
||||
// eslint-disable-next-line @typescript-eslint/no-useless-constructor
|
||||
constructor (client: Client, data: GuildNewsChannelPayload) {
|
||||
super(client, data)
|
||||
this.guildID = data.guild_id
|
||||
this.name = data.name
|
||||
this.position = data.position
|
||||
this.permissionOverwrites = data.permission_overwrites
|
||||
this.nsfw = data.nsfw
|
||||
this.parentID = data.parent_id
|
||||
this.topic = data.topic
|
||||
}
|
||||
|
||||
protected readFromData (data: GuildNewsChannelPayload): void {
|
||||
super.readFromData(data)
|
||||
this.guildID = data.guild_id ?? this.guildID
|
||||
this.name = data.name ?? this.name
|
||||
this.position = data.position ?? this.position
|
||||
this.permissionOverwrites =
|
||||
data.permission_overwrites ?? this.permissionOverwrites
|
||||
this.nsfw = data.nsfw ?? this.nsfw
|
||||
this.parentID = data.parent_id ?? this.parentID
|
||||
this.topic = data.topic ?? this.topic
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ export class Invite extends Base {
|
|||
this.approximatePresenceCount = data.approximate_presence_count
|
||||
}
|
||||
|
||||
readFromData (data: InvitePayload): void {
|
||||
protected readFromData (data: InvitePayload): void {
|
||||
super.readFromData(data)
|
||||
this.code = data.code ?? this.code
|
||||
this.guild = data.guild ?? this.guild
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
import cache from '../models/cache.ts'
|
||||
import { Client } from '../models/client.ts'
|
||||
import { MemberPayload } from '../types/guildTypes.ts'
|
||||
import { Base } from './base.ts'
|
||||
import { User } from './user.ts'
|
||||
|
||||
export class Member extends User {
|
||||
export class Member extends Base {
|
||||
id: string
|
||||
user: User
|
||||
nick?: string
|
||||
roles: string[]
|
||||
joinedAt: string
|
||||
|
@ -12,7 +15,10 @@ export class Member extends User {
|
|||
mute: boolean
|
||||
|
||||
constructor (client: Client, data: MemberPayload) {
|
||||
super(client, data.user)
|
||||
super(client)
|
||||
this.id = data.user.id
|
||||
this.user =
|
||||
cache.get('user', data.user.id) ?? new User(this.client, data.user)
|
||||
this.nick = data.nick
|
||||
this.roles = data.roles
|
||||
this.joinedAt = data.joined_at
|
||||
|
@ -22,8 +28,8 @@ export class Member extends User {
|
|||
cache.set('member', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: MemberPayload): void {
|
||||
super.readFromData(data)
|
||||
protected readFromData (data: MemberPayload): void {
|
||||
super.readFromData(data.user)
|
||||
this.nick = data.nick ?? this.nick
|
||||
this.roles = data.roles ?? this.roles
|
||||
this.joinedAt = data.joined_at ?? this.joinedAt
|
||||
|
|
|
@ -76,14 +76,14 @@ export class Message extends Base {
|
|||
cache.set('message', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: MessagePayload): void {
|
||||
protected readFromData (data: MessagePayload): void {
|
||||
super.readFromData(data)
|
||||
this.channelID = data.channel_id ?? this.channelID
|
||||
this.guildID = data.guild_id ?? this.guildID
|
||||
this.author =
|
||||
cache.get('user', data.author.id) ??
|
||||
new User(this.client, data.author) ??
|
||||
this.author
|
||||
this.author ??
|
||||
new User(this.client, data.author)
|
||||
this.content = data.content ?? this.content
|
||||
this.timestamp = data.timestamp ?? this.timestamp
|
||||
this.editedTimestamp = data.edited_timestamp ?? this.editedTimestamp
|
||||
|
|
|
@ -30,7 +30,7 @@ export class Role extends Base {
|
|||
cache.set('role', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: RolePayload): void {
|
||||
protected readFromData (data: RolePayload): void {
|
||||
super.readFromData(data)
|
||||
this.name = data.name ?? this.name
|
||||
this.color = data.color ?? this.color
|
||||
|
|
|
@ -16,7 +16,7 @@ export class TextChannel extends Channel {
|
|||
cache.set('textchannel', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: TextChannelPayload): void {
|
||||
protected readFromData (data: TextChannelPayload): void {
|
||||
super.readFromData(data)
|
||||
this.lastMessageID = data.last_message_id ?? this.lastMessageID
|
||||
this.lastPinTimestamp = data.last_pin_timestamp ?? this.lastPinTimestamp
|
||||
|
|
|
@ -44,7 +44,7 @@ export class User extends Base {
|
|||
cache.set('user', this.id, this)
|
||||
}
|
||||
|
||||
readFromData (data: UserPayload): void {
|
||||
protected readFromData (data: UserPayload): void {
|
||||
super.readFromData(data)
|
||||
this.username = data.username ?? this.username
|
||||
this.discriminator = data.discriminator ?? this.discriminator
|
||||
|
|
|
@ -33,7 +33,7 @@ export class VoiceState extends Base {
|
|||
cache.set('voiceState', `${this.guildID}:${this.userID}`, this)
|
||||
}
|
||||
|
||||
readFromData (data: VoiceStatePayload): void {
|
||||
protected readFromData (data: VoiceStatePayload): void {
|
||||
super.readFromData(data)
|
||||
this.channelID = data.channel_id ?? this.channelID
|
||||
this.sessionID = data.session_id ?? this.sessionID
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { Client } from '../models/client.ts'
|
||||
import { GatewayIntents } from '../types/gatewayTypes.ts'
|
||||
import { TOKEN } from './config.ts'
|
||||
import * as cache from '../models/cache.ts'
|
||||
import { Member } from '../structures/member.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'
|
||||
|
||||
const bot = new Client()
|
||||
|
||||
|
@ -12,18 +13,66 @@ bot.on('ready', () => {
|
|||
console.log('READY!')
|
||||
})
|
||||
|
||||
bot.on('channelDelete', (channel: Channel) => {
|
||||
console.log('channelDelete', channel.id)
|
||||
})
|
||||
|
||||
bot.on('channelUpdate', (before: Channel, after: Channel) => {
|
||||
if (before instanceof GuildTextChannel && after instanceof GuildTextChannel) {
|
||||
console.log(before.name)
|
||||
console.log(after.name)
|
||||
console.log('channelUpdate', before.name)
|
||||
console.log('channelUpdate', after.name)
|
||||
} else {
|
||||
console.log(before)
|
||||
console.log(after)
|
||||
console.log('channelUpdate', before.id)
|
||||
console.log('channelUpdate', after.id)
|
||||
}
|
||||
})
|
||||
|
||||
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.connect(TOKEN, [
|
||||
GatewayIntents.GUILD_MEMBERS,
|
||||
GatewayIntents.GUILD_PRESENCES,
|
||||
GatewayIntents.GUILD_MESSAGES
|
||||
GatewayIntents.GUILD_MESSAGES,
|
||||
GatewayIntents.DIRECT_MESSAGES,
|
||||
GatewayIntents.DIRECT_MESSAGE_REACTIONS,
|
||||
GatewayIntents.DIRECT_MESSAGE_TYPING,
|
||||
GatewayIntents.GUILDS,
|
||||
GatewayIntents.GUILD_BANS,
|
||||
GatewayIntents.GUILD_EMOJIS,
|
||||
GatewayIntents.GUILD_INTEGRATIONS,
|
||||
GatewayIntents.GUILD_INVITES,
|
||||
GatewayIntents.GUILD_MESSAGE_REACTIONS,
|
||||
GatewayIntents.GUILD_MESSAGE_TYPING,
|
||||
GatewayIntents.GUILD_VOICE_STATES,
|
||||
GatewayIntents.GUILD_WEBHOOKS
|
||||
])
|
||||
|
|
|
@ -3,17 +3,17 @@ import { EmojiPayload } from './emojiTypes.ts'
|
|||
import { MemberPayload } from './guildTypes.ts'
|
||||
import { UserPayload } from './userTypes.ts'
|
||||
|
||||
interface ChannelPayload {
|
||||
export interface ChannelPayload {
|
||||
id: string
|
||||
type: ChannelTypes
|
||||
}
|
||||
|
||||
interface TextChannelPayload extends ChannelPayload {
|
||||
export interface TextChannelPayload extends ChannelPayload {
|
||||
last_message_id?: string
|
||||
last_pin_timestamp?: string
|
||||
}
|
||||
|
||||
interface GuildChannelPayload extends ChannelPayload {
|
||||
export interface GuildChannelPayload extends ChannelPayload {
|
||||
guild_id: string
|
||||
name: string
|
||||
position: number
|
||||
|
@ -22,46 +22,46 @@ interface GuildChannelPayload extends ChannelPayload {
|
|||
parent_id?: string
|
||||
}
|
||||
|
||||
interface GuildTextChannelPayload
|
||||
export interface GuildTextChannelPayload
|
||||
extends TextChannelPayload,
|
||||
GuildChannelPayload {
|
||||
rate_limit_per_user: number
|
||||
topic?: string
|
||||
}
|
||||
|
||||
interface GuildNewsChannelPayload
|
||||
export interface GuildNewsChannelPayload
|
||||
extends TextChannelPayload,
|
||||
GuildChannelPayload {
|
||||
topic?: string
|
||||
}
|
||||
|
||||
interface GuildVoiceChannelPayload extends GuildChannelPayload {
|
||||
export interface GuildVoiceChannelPayload extends GuildChannelPayload {
|
||||
bitrate: string
|
||||
user_limit: number
|
||||
}
|
||||
|
||||
interface DMChannelPayload extends TextChannelPayload {
|
||||
export interface DMChannelPayload extends TextChannelPayload {
|
||||
recipients: UserPayload[]
|
||||
}
|
||||
|
||||
interface GroupDMChannelPayload extends DMChannelPayload {
|
||||
export interface GroupDMChannelPayload extends DMChannelPayload {
|
||||
name: string
|
||||
icon?: string
|
||||
owner_id: string
|
||||
}
|
||||
|
||||
interface GuildChannelCategoryPayload
|
||||
export interface GuildChannelCategoryPayload
|
||||
extends ChannelPayload,
|
||||
GuildChannelPayload {}
|
||||
|
||||
interface Overwrite {
|
||||
export interface Overwrite {
|
||||
id: string
|
||||
type: number
|
||||
allow: string
|
||||
deny: string
|
||||
}
|
||||
|
||||
enum ChannelTypes {
|
||||
export enum ChannelTypes {
|
||||
GUILD_TEXT = 0,
|
||||
DM = 1,
|
||||
GUILD_VOICE = 2,
|
||||
|
@ -71,7 +71,7 @@ enum ChannelTypes {
|
|||
GUILD_STORE = 6
|
||||
}
|
||||
|
||||
interface MessagePayload {
|
||||
export interface MessagePayload {
|
||||
id: string
|
||||
channel_id: string
|
||||
guild_id?: string
|
||||
|
@ -98,7 +98,7 @@ interface MessagePayload {
|
|||
flags?: number
|
||||
}
|
||||
|
||||
interface MessageOption {
|
||||
export interface MessageOption {
|
||||
tts: boolean
|
||||
embed: Embed
|
||||
file: Attachment
|
||||
|
@ -109,14 +109,14 @@ interface MessageOption {
|
|||
}
|
||||
}
|
||||
|
||||
interface ChannelMention {
|
||||
export interface ChannelMention {
|
||||
id: string
|
||||
guild_id: string
|
||||
type: ChannelTypes
|
||||
name: string
|
||||
}
|
||||
|
||||
interface Attachment {
|
||||
export interface Attachment {
|
||||
id: string
|
||||
filename: string
|
||||
size: number
|
||||
|
@ -126,7 +126,7 @@ interface Attachment {
|
|||
width: number | undefined
|
||||
}
|
||||
|
||||
interface EmbedPayload {
|
||||
export interface EmbedPayload {
|
||||
title?: string
|
||||
type?: EmbedTypes
|
||||
description?: string
|
||||
|
@ -142,64 +142,70 @@ interface EmbedPayload {
|
|||
fields?: EmbedField[]
|
||||
}
|
||||
|
||||
type EmbedTypes = 'rich' | 'image' | 'video' | 'gifv' | 'article' | 'link'
|
||||
export type EmbedTypes =
|
||||
| 'rich'
|
||||
| 'image'
|
||||
| 'video'
|
||||
| 'gifv'
|
||||
| 'article'
|
||||
| 'link'
|
||||
|
||||
interface EmbedField {
|
||||
export interface EmbedField {
|
||||
name: string
|
||||
value: string
|
||||
inline?: boolean
|
||||
}
|
||||
|
||||
interface EmbedAuthor {
|
||||
export interface EmbedAuthor {
|
||||
name?: string
|
||||
url?: string
|
||||
icon_url?: string
|
||||
proxy_icon_url?: string
|
||||
}
|
||||
|
||||
interface EmbedFooter {
|
||||
export interface EmbedFooter {
|
||||
text: string
|
||||
icon_url?: string
|
||||
proxy_icon_url?: string
|
||||
}
|
||||
|
||||
interface EmbedImage {
|
||||
export interface EmbedImage {
|
||||
url?: string
|
||||
proxy_url?: string
|
||||
height?: number
|
||||
width?: number
|
||||
}
|
||||
|
||||
interface EmbedProvider {
|
||||
export interface EmbedProvider {
|
||||
name?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
interface EmbedVideo {
|
||||
export interface EmbedVideo {
|
||||
url?: string
|
||||
height?: number
|
||||
width?: number
|
||||
}
|
||||
|
||||
interface EmbedThumbnail {
|
||||
export interface EmbedThumbnail {
|
||||
url?: string
|
||||
proxy_url?: string
|
||||
height?: number
|
||||
width?: number
|
||||
}
|
||||
|
||||
interface Reaction {
|
||||
export interface Reaction {
|
||||
count: number
|
||||
me: boolean
|
||||
emoji: EmojiPayload
|
||||
}
|
||||
|
||||
interface MessageActivity {
|
||||
export interface MessageActivity {
|
||||
type: MessageTypes
|
||||
party_id?: string
|
||||
}
|
||||
|
||||
interface MessageApplication {
|
||||
export interface MessageApplication {
|
||||
id: string
|
||||
cover_image?: string
|
||||
desription: string
|
||||
|
@ -207,13 +213,13 @@ interface MessageApplication {
|
|||
name: string
|
||||
}
|
||||
|
||||
interface MessageReference {
|
||||
export interface MessageReference {
|
||||
message_id?: string
|
||||
channel_id?: string
|
||||
guild_id?: string
|
||||
}
|
||||
|
||||
enum MessageTypes {
|
||||
export enum MessageTypes {
|
||||
DEFAULT = 0,
|
||||
RECIPIENT_ADD = 1,
|
||||
RECIPIENT_REMOVE = 2,
|
||||
|
@ -231,14 +237,14 @@ enum MessageTypes {
|
|||
GUILD_DISCOVERY_REQUALIFIED = 15
|
||||
}
|
||||
|
||||
enum MessageActivityTypes {
|
||||
export enum MessageActivityTypes {
|
||||
JOIN = 1,
|
||||
SPECTATE = 2,
|
||||
LISTEN = 3,
|
||||
JOIN_REQUEST = 4
|
||||
}
|
||||
|
||||
enum MessageFlags {
|
||||
export enum MessageFlags {
|
||||
CROSSPOSTED = 1 << 0,
|
||||
IS_CROSSPOST = 1 << 1,
|
||||
SUPPRESS_EMBEDS = 1 << 2,
|
||||
|
@ -246,54 +252,7 @@ enum MessageFlags {
|
|||
URGENT = 1 << 4
|
||||
}
|
||||
|
||||
interface FollowedChannel {
|
||||
export interface FollowedChannel {
|
||||
channel_id: string
|
||||
webhook_id: string
|
||||
}
|
||||
|
||||
interface Overwrite {
|
||||
id: string
|
||||
type: number
|
||||
allow: string
|
||||
deny: string
|
||||
}
|
||||
interface ChannelMention {
|
||||
id: string
|
||||
guild_id: string
|
||||
type: ChannelTypes
|
||||
name: string
|
||||
}
|
||||
|
||||
export {
|
||||
ChannelPayload,
|
||||
TextChannelPayload,
|
||||
GuildChannelPayload,
|
||||
GuildNewsChannelPayload,
|
||||
GuildTextChannelPayload,
|
||||
GuildVoiceChannelPayload,
|
||||
GuildChannelCategoryPayload,
|
||||
DMChannelPayload,
|
||||
GroupDMChannelPayload,
|
||||
Overwrite,
|
||||
ChannelTypes,
|
||||
ChannelMention,
|
||||
Attachment,
|
||||
Reaction,
|
||||
MessageActivity,
|
||||
MessageActivityTypes,
|
||||
MessageFlags,
|
||||
FollowedChannel,
|
||||
MessageApplication,
|
||||
MessageReference,
|
||||
MessagePayload,
|
||||
MessageOption,
|
||||
EmbedPayload,
|
||||
EmbedTypes,
|
||||
EmbedFooter,
|
||||
EmbedImage,
|
||||
EmbedThumbnail,
|
||||
EmbedVideo,
|
||||
EmbedProvider,
|
||||
EmbedAuthor,
|
||||
EmbedField
|
||||
}
|
||||
|
|
|
@ -4,11 +4,9 @@ import { GatewayOpcodes, GatewayEvents } from '../types/gatewayTypes.ts'
|
|||
* Gateway response from Discord.
|
||||
*
|
||||
*/
|
||||
interface GatewayResponse {
|
||||
export interface GatewayResponse {
|
||||
op: GatewayOpcodes
|
||||
d: any
|
||||
s?: number
|
||||
t?: GatewayEvents
|
||||
}
|
||||
|
||||
export { GatewayResponse }
|
||||
|
|
|
@ -62,11 +62,9 @@ enum GatewayIntents {
|
|||
}
|
||||
|
||||
enum GatewayEvents {
|
||||
Hello = 'HELLO',
|
||||
Ready = 'READY',
|
||||
Resumed = 'RESUMED',
|
||||
Reconnect = 'RECONNECT',
|
||||
Invalid_Session = 'INVALID_SESSION',
|
||||
Channel_Create = 'CHANNEL_CREATE',
|
||||
Channel_Update = 'CHANNEL_UPDATE',
|
||||
Channel_Delete = 'CHANNEL_DELETE',
|
||||
|
@ -89,7 +87,7 @@ enum GatewayEvents {
|
|||
Invite_Delete = 'INVITE_DELETE',
|
||||
Message_Create = 'MESSAGE_CREATE',
|
||||
Message_Update = 'MESSAGE_UPDATE',
|
||||
Message_Delete = 'MESSAG_DELETE',
|
||||
Message_Delete = 'MESSAGE_DELETE',
|
||||
Message_Delete_Bulk = 'MESSAGE_DELETE_BULK',
|
||||
Message_Reaction_Add = 'MESSAGE_REACTION_ADD',
|
||||
Message_Reaction_Remove = 'MESSAGE_REACTION_REMOVE',
|
||||
|
@ -98,7 +96,6 @@ enum GatewayEvents {
|
|||
Presence_Update = 'PRESENCE_UPDATE',
|
||||
Typing_Start = 'TYPING_START',
|
||||
User_Update = 'USER_UPDATE',
|
||||
Voice_State_Update = 'VOICE_STATE_UPDATE',
|
||||
Voice_Server_Update = 'VOICE_SERVER_UPDATE',
|
||||
Webhooks_Update = 'WEBHOOKS_UPDATE'
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import { RolePayload } from './roleTypes.ts'
|
|||
import { UserPayload } from './userTypes.ts'
|
||||
import { VoiceStatePayload } from './voiceTypes.ts'
|
||||
|
||||
interface GuildPayload {
|
||||
export interface GuildPayload {
|
||||
id: string
|
||||
name: string
|
||||
icon?: string
|
||||
|
@ -53,7 +53,7 @@ interface GuildPayload {
|
|||
approximate_presence_count?: number
|
||||
}
|
||||
|
||||
interface MemberPayload {
|
||||
export interface MemberPayload {
|
||||
user: UserPayload
|
||||
nick?: string
|
||||
roles: string[]
|
||||
|
@ -99,7 +99,7 @@ enum SystemChannelFlags {
|
|||
SUPPRESS_PREMIUM_SUBSCRIPTIONS = 1 << 1
|
||||
}
|
||||
|
||||
type GuildFeatures =
|
||||
export type GuildFeatures =
|
||||
| 'INVITE_SPLASH'
|
||||
| 'VIP_REGIONS'
|
||||
| 'VANITY_URL'
|
||||
|
@ -112,5 +112,3 @@ type GuildFeatures =
|
|||
| 'FEATURABLE'
|
||||
| 'ANIMATED_ICON'
|
||||
| 'BANNER'
|
||||
|
||||
export { MemberPayload, GuildPayload, GuildFeatures }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { UserPayload } from './userTypes.ts'
|
||||
|
||||
interface PresenceUpdatePayload {
|
||||
export interface PresenceUpdatePayload {
|
||||
user: UserPayload
|
||||
guild_id: string
|
||||
status: string
|
||||
|
@ -14,7 +14,7 @@ interface ClientStatus {
|
|||
web?: string
|
||||
}
|
||||
|
||||
interface ActivityPayload {
|
||||
export interface ActivityPayload {
|
||||
name: string
|
||||
type: 0 | 1 | 2 | 3 | 4 | 5
|
||||
url?: string | undefined
|
||||
|
@ -68,5 +68,3 @@ enum ActivityFlags {
|
|||
SYNC = 1 << 4,
|
||||
PLAY = 1 << 5
|
||||
}
|
||||
|
||||
export { ActivityPayload, PresenceUpdatePayload }
|
||||
|
|
53
src/utils/getChannelByType.ts
Normal file
53
src/utils/getChannelByType.ts
Normal file
|
@ -0,0 +1,53 @@
|
|||
import { Client } from '../models/client.ts'
|
||||
import {
|
||||
ChannelPayload,
|
||||
ChannelTypes,
|
||||
DMChannelPayload,
|
||||
GroupDMChannelPayload,
|
||||
GuildChannelCategoryPayload,
|
||||
GuildNewsChannelPayload,
|
||||
GuildTextChannelPayload,
|
||||
GuildVoiceChannelPayload
|
||||
} from '../types/channelTypes.ts'
|
||||
import { DMChannel } from '../structures/dmChannel.ts'
|
||||
import { GroupDMChannel } from '../structures/groupChannel.ts'
|
||||
import { CategoryChannel } from '../structures/guildCategoryChannel.ts'
|
||||
import { NewsChannel } from '../structures/guildNewsChannel.ts'
|
||||
import { VoiceChannel } from '../structures/guildVoiceChannel.ts'
|
||||
import { TextChannel } from '../structures/textChannel.ts'
|
||||
|
||||
const getChannelByType = (
|
||||
client: Client,
|
||||
data:
|
||||
| GuildChannelCategoryPayload
|
||||
| GuildNewsChannelPayload
|
||||
| GuildTextChannelPayload
|
||||
| GuildVoiceChannelPayload
|
||||
| DMChannelPayload
|
||||
| GroupDMChannelPayload
|
||||
| ChannelPayload
|
||||
):
|
||||
| CategoryChannel
|
||||
| NewsChannel
|
||||
| TextChannel
|
||||
| VoiceChannel
|
||||
| DMChannel
|
||||
| GroupDMChannel
|
||||
| undefined => {
|
||||
switch (data.type) {
|
||||
case ChannelTypes.GUILD_CATEGORY:
|
||||
return new CategoryChannel(client, data as GuildChannelCategoryPayload)
|
||||
case ChannelTypes.GUILD_NEWS:
|
||||
return new NewsChannel(client, data as GuildNewsChannelPayload)
|
||||
case ChannelTypes.GUILD_TEXT:
|
||||
return new TextChannel(client, data as GuildTextChannelPayload)
|
||||
case ChannelTypes.GUILD_VOICE:
|
||||
return new VoiceChannel(client, data as GuildVoiceChannelPayload)
|
||||
case ChannelTypes.DM:
|
||||
return new DMChannel(client, data as DMChannelPayload)
|
||||
case ChannelTypes.GROUP_DM:
|
||||
return new GroupDMChannel(client, data as GroupDMChannelPayload)
|
||||
}
|
||||
}
|
||||
|
||||
export default getChannelByType
|
3
src/utils/index.ts
Normal file
3
src/utils/index.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import getChannelByType from './getChannelByType.ts'
|
||||
|
||||
export default { getChannelByType }
|
|
@ -25,7 +25,7 @@
|
|||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
"isolatedModules": true /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */,
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true,
|
||||
/* Enable all strict type-checking options. */
|
||||
|
@ -61,7 +61,7 @@
|
|||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
"emitDecoratorMetadata": false /* Enables experimental support for emitting type metadata for decorators. */,
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true,
|
||||
/* Skip type checking of declaration files. */
|
||||
|
|
Loading…
Reference in a new issue