From 950243af5c2cfd6b035657f652d32e6b93c5d7f1 Mon Sep 17 00:00:00 2001 From: DjDeveloperr Date: Sat, 6 Feb 2021 19:25:45 +0530 Subject: [PATCH] add updateRefs --- src/managers/messageReactions.ts | 9 +++ src/managers/messages.ts | 10 +-- src/models/voice.ts | 102 +++++++++++++++++++++++++--- src/structures/guildVoiceChannel.ts | 30 ++++++-- src/structures/message.ts | 19 +++++- 5 files changed, 146 insertions(+), 24 deletions(-) diff --git a/src/managers/messageReactions.ts b/src/managers/messageReactions.ts index 30c0672..531c18a 100644 --- a/src/managers/messageReactions.ts +++ b/src/managers/messageReactions.ts @@ -23,6 +23,14 @@ export class MessageReactionsManager extends BaseManager< this.message = message } + async updateRefs(): Promise { + const newVal = await this.message.channel.messages.get(this.message.id) + if (newVal !== undefined) { + this.message = newVal + } + await this.message.updateRefs() + } + async get(id: string): Promise { const raw = await this._get(id) if (raw === undefined) return @@ -32,6 +40,7 @@ export class MessageReactionsManager extends BaseManager< let emoji = await this.client.emojis.get(emojiID as string) if (emoji === undefined) emoji = new Emoji(this.client, raw.emoji) + await this.updateRefs() const reaction = new MessageReaction(this.client, raw, this.message, emoji) return reaction } diff --git a/src/managers/messages.ts b/src/managers/messages.ts index f9daf5a..4c1cfc1 100644 --- a/src/managers/messages.ts +++ b/src/managers/messages.ts @@ -93,18 +93,12 @@ export class MessagesManager extends BaseManager { if (channel === undefined) channel = await this.client.channels.fetch(this.channel.id) - const author = new User(this.client, (data as MessagePayload).author) await this.client.users.set( - author.id, + data.author.id, (data as MessagePayload).author ) - const res = new Message( - this.client, - data as MessagePayload, - channel as TextChannel, - author - ) + const res = (await this.get(data.id)) as Message await res.mentions.fromPayload(data) diff --git a/src/models/voice.ts b/src/models/voice.ts index 65c63e8..ec9c9b5 100644 --- a/src/models/voice.ts +++ b/src/models/voice.ts @@ -1,26 +1,112 @@ import { Guild } from '../structures/guild.ts' -import { VoiceChannel } from '../structures/guildVoiceChannel.ts' +import { + VoiceChannel, + VoiceServerData +} from '../structures/guildVoiceChannel.ts' +import { VoiceOpcodes } from '../types/voice.ts' +import { Collection } from '../utils/collection.ts' +import { HarmonyEventEmitter } from '../utils/events.ts' import { Client } from './client.ts' export interface VoiceOptions { - guild: Guild channel: VoiceChannel + data: VoiceServerData + manager: VoiceConnectionsManager } -export class VoiceClient { +export class VoiceConnectionsManager { + client: Client + connections: Collection = new Collection() + + constructor(client: Client) { + this.client = client + } + + async establish(options: VoiceOptions): Promise { + if (this.connections.has(options.channel.guild.id) === true) + throw new Error('Voice Connection already established') + const conn = new VoiceConnection(this, options) + this.connections.set(options.channel.guild.id, conn) + await conn.connect() + return conn + } +} + +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions +export type VoiceConnectionEvents = { + ready: [] +} + +/** Represents a Voice Connection made through a Voice Channel */ +export class VoiceConnection extends HarmonyEventEmitter { client: Client ws?: WebSocket guild: Guild channel: VoiceChannel + data: VoiceServerData + manager: VoiceConnectionsManager + ssrc?: number + ip?: string + port?: number - constructor(client: Client, options: VoiceOptions) { - this.client = client - this.guild = options.guild + constructor(manager: VoiceConnectionsManager, options: VoiceOptions) { + super() + this.client = manager.client + this.manager = manager this.channel = options.channel + this.guild = options.channel.guild + this.data = options.data } - async connect(): Promise { - // TODO(DjDeveloperr): understand docs + /** Connect to Voice Server */ + async connect(): Promise { + this.ws = new WebSocket(`wss://${this.data.endpoint}`) + this.ws.binaryType = 'arraybuffer' + this.ws.onopen = this.onopen.bind(this) + this.ws.onclose = this.onclose.bind(this) + this.ws.onmessage = this.onmessage.bind(this) + this.ws.onerror = this.onerror.bind(this) return this } + + private send(data: { op: VoiceOpcodes; d: any }): void { + this.ws?.send(JSON.stringify(data)) + } + + private sendIdentify(): void { + this.send({ + op: VoiceOpcodes.IDENTIFY, + d: { + server_id: this.guild.id, + user_id: this.client.user?.id, + session_id: this.data.sessionID, + token: this.data.token + } + }) + } + + private onopen(): void { + this.sendIdentify() + } + + private onclose(): void {} + + private onmessage(e: MessageEvent): void { + const data = JSON.parse(e.data) + if (typeof data !== 'object') return + + switch (data.op) { + case VoiceOpcodes.READY: + this.ssrc = data.d.ssrc + this.ip = data.d.ip + this.port = data.d.port + this.emit('ready') + break + + default: + break + } + } + + private onerror(): void {} } diff --git a/src/structures/guildVoiceChannel.ts b/src/structures/guildVoiceChannel.ts index 49dcd2a..0e452dc 100644 --- a/src/structures/guildVoiceChannel.ts +++ b/src/structures/guildVoiceChannel.ts @@ -12,6 +12,10 @@ import { Channel } from './channel.ts' import { Guild } from './guild.ts' import { VoiceState } from './voiceState.ts' +export interface VoiceServerData extends VoiceServerUpdateData { + sessionID: string +} + export class VoiceChannel extends Channel { bitrate: string userLimit: number @@ -32,13 +36,15 @@ export class VoiceChannel extends Channel { this.guild = guild this.permissionOverwrites = data.permission_overwrites this.parentID = data.parent_id - // TODO: Cache in Gateway Event Code - // cache.set('guildvoicechannel', this.id, this) } - async join(options?: VoiceStateOptions): Promise { + /** Join the Voice Channel */ + async join( + options?: VoiceStateOptions & { onlyJoin?: boolean } + ): Promise { return await new Promise((resolve, reject) => { - let vcdata: VoiceServerUpdateData | undefined + let vcdata: VoiceServerData + let sessionID: string let done = 0 const onVoiceStateAdd = (state: VoiceState): void => { @@ -46,15 +52,24 @@ export class VoiceChannel extends Channel { if (state.channel?.id !== this.id) return this.client.off('voiceStateAdd', onVoiceStateAdd) done++ - if (done >= 2) resolve((vcdata as unknown) as VoiceServerUpdateData) + sessionID = state.sessionID + if (done >= 2) { + vcdata.sessionID = sessionID + if (options?.onlyJoin !== true) { + } + resolve(vcdata) + } } const onVoiceServerUpdate = (data: VoiceServerUpdateData): void => { if (data.guild.id !== this.guild.id) return - vcdata = data + vcdata = (data as unknown) as VoiceServerData this.client.off('voiceServerUpdate', onVoiceServerUpdate) done++ - if (done >= 2) resolve(vcdata) + if (done >= 2) { + vcdata.sessionID = sessionID + resolve(vcdata) + } } this.client.shards @@ -78,6 +93,7 @@ export class VoiceChannel extends Channel { }) } + /** Leave the Voice Channel */ leave(): void { this.client.shards .get(this.guild.shardID) diff --git a/src/structures/message.ts b/src/structures/message.ts index b697220..2b387c8 100644 --- a/src/structures/message.ts +++ b/src/structures/message.ts @@ -13,7 +13,7 @@ import { Member } from './member.ts' import { Embed } from './embed.ts' import { CHANNEL_MESSAGE } from '../types/endpoint.ts' import { MessageMentions } from './messageMentions.ts' -import { TextChannel } from './textChannel.ts' +import { GuildTextChannel, TextChannel } from './textChannel.ts' import { Guild } from './guild.ts' import { MessageReactionsManager } from '../managers/messageReactions.ts' import { MessageSticker } from './messageSticker.ts' @@ -115,6 +115,23 @@ export class Message extends SnowflakeBase { : this.stickers } + async updateRefs(): Promise { + if (this.guildID !== undefined) + this.guild = await this.client.guilds.get(this.guildID) + const newVal = await this.client.channels.get(this.channelID) + if (newVal !== undefined) this.channel = newVal + const newUser = await this.client.users.get(this.author.id) + if (newUser !== undefined) this.author = newUser + if (this.member !== undefined) { + const newMember = await this.guild?.members.get(this.member?.id) + if (newMember !== undefined) this.member = newMember + } + if (((this.channel as unknown) as GuildTextChannel).guild !== undefined) + this.guild = ((this.channel as unknown) as GuildTextChannel).guild + if (this.guild !== undefined && this.guildID === undefined) + this.guildID = this.guild.id + } + /** Edits this message. */ async edit( content?: string | AllMessageOptions,