feat: void -- start work
This commit is contained in:
		
							parent
							
								
									6f60bd5040
								
							
						
					
					
						commit
						a6697a75a7
					
				
					 13 changed files with 485 additions and 365 deletions
				
			
		|  | @ -5,3 +5,5 @@ export const DISCORD_GATEWAY_URL: string = 'wss://gateway.discord.gg' | ||||||
| export const DISCORD_CDN_URL: string = 'https://cdn.discordapp.com' | export const DISCORD_CDN_URL: string = 'https://cdn.discordapp.com' | ||||||
| 
 | 
 | ||||||
| export const DISCORD_API_VERSION: number = 8 | export const DISCORD_API_VERSION: number = 8 | ||||||
|  | 
 | ||||||
|  | export const DISCORD_VOICE_VERSION: number = 4 | ||||||
|  | @ -36,6 +36,9 @@ import { Member } from "../../structures/member.ts" | ||||||
| import { Role } from "../../structures/role.ts" | import { Role } from "../../structures/role.ts" | ||||||
| import { Message } from "../../structures/message.ts" | import { Message } from "../../structures/message.ts" | ||||||
| import { Collection } from "../../utils/collection.ts" | import { Collection } from "../../utils/collection.ts" | ||||||
|  | import { voiceServerUpdate } from "./voiceServerUpdate.ts" | ||||||
|  | import { voiceStateUpdate } from "./voiceStateUpdate.ts" | ||||||
|  | import { VoiceState } from "../../structures/voiceState.ts" | ||||||
| 
 | 
 | ||||||
| export const gatewayHandlers: { | export const gatewayHandlers: { | ||||||
|   [eventCode in GatewayEvents]: GatewayEventHandler | undefined |   [eventCode in GatewayEvents]: GatewayEventHandler | undefined | ||||||
|  | @ -74,7 +77,8 @@ export const gatewayHandlers: { | ||||||
|   PRESENCE_UPDATE: undefined, |   PRESENCE_UPDATE: undefined, | ||||||
|   TYPING_START: typingStart, |   TYPING_START: typingStart, | ||||||
|   USER_UPDATE: userUpdate, |   USER_UPDATE: userUpdate, | ||||||
|   VOICE_SERVER_UPDATE: undefined, |   VOICE_STATE_UPDATE: voiceStateUpdate, | ||||||
|  |   VOICE_SERVER_UPDATE: voiceServerUpdate, | ||||||
|   WEBHOOKS_UPDATE: webhooksUpdate |   WEBHOOKS_UPDATE: webhooksUpdate | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -82,6 +86,12 @@ export interface EventTypes { | ||||||
|   [name: string]: (...args: any[]) => void |   [name: string]: (...args: any[]) => void | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface VoiceServerUpdateData { | ||||||
|  |   token: string | ||||||
|  |   endpoint: string | ||||||
|  |   guild: Guild | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export interface ClientEvents extends EventTypes { | export interface ClientEvents extends EventTypes { | ||||||
|   'ready': () => void |   'ready': () => void | ||||||
|   'reconnect': () => void |   'reconnect': () => void | ||||||
|  | @ -111,5 +121,9 @@ export interface ClientEvents extends EventTypes { | ||||||
|   'messageUpdate': (before: Message, after: Message) => void |   'messageUpdate': (before: Message, after: Message) => void | ||||||
|   'typingStart': (user: User, channel: TextChannel, at: Date, guildData?: TypingStartGuildData) => void |   'typingStart': (user: User, channel: TextChannel, at: Date, guildData?: TypingStartGuildData) => void | ||||||
|   'userUpdate': (before: User, after: User) => void |   'userUpdate': (before: User, after: User) => void | ||||||
|  |   'voiceServerUpdate': (data: VoiceServerUpdateData) => void | ||||||
|  |   'voiceStateAdd': (state: VoiceState) => void | ||||||
|  |   'voiceStateRemove': (state: VoiceState) => void | ||||||
|  |   'voiceStateUpdate': (state: VoiceState, after: VoiceState) => void | ||||||
|   'webhooksUpdate': (guild: Guild, channel: GuildTextChannel) => void |   'webhooksUpdate': (guild: Guild, channel: GuildTextChannel) => void | ||||||
| } | } | ||||||
							
								
								
									
										14
									
								
								src/gateway/handlers/voiceServerUpdate.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/gateway/handlers/voiceServerUpdate.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | ||||||
|  | import { Guild } from "../../structures/guild.ts" | ||||||
|  | import { VoiceServerUpdatePayload } from "../../types/gateway.ts" | ||||||
|  | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
|  | 
 | ||||||
|  | export const voiceServerUpdate: GatewayEventHandler = async ( | ||||||
|  |   gateway: Gateway, | ||||||
|  |   d: VoiceServerUpdatePayload | ||||||
|  | ) => { | ||||||
|  |   gateway.client.emit('voiceServerUpdate', { | ||||||
|  |     token: d.token, | ||||||
|  |     endpoint: d.endpoint, | ||||||
|  |     guild: (await gateway.client.guilds.get(d.guild_id) as unknown) as Guild | ||||||
|  |   }) | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								src/gateway/handlers/voiceStateUpdate.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/gateway/handlers/voiceStateUpdate.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | import { Guild } from "../../structures/guild.ts" | ||||||
|  | import { VoiceState } from "../../structures/voiceState.ts" | ||||||
|  | import { VoiceStatePayload } from "../../types/voice.ts" | ||||||
|  | import { Gateway, GatewayEventHandler } from '../index.ts' | ||||||
|  | 
 | ||||||
|  | export const voiceStateUpdate: GatewayEventHandler = async ( | ||||||
|  |   gateway: Gateway, | ||||||
|  |   d: VoiceStatePayload | ||||||
|  | ) => { | ||||||
|  |   // TODO(DjDeveloperr): Support self-bot here; they can be in DMs (Call)
 | ||||||
|  |   if (d.guild_id === undefined) return | ||||||
|  |   const guild = (await gateway.client.guilds.get(d.guild_id) as unknown) as Guild | ||||||
|  | 
 | ||||||
|  |   const voiceState = await guild.voiceStates.get(d.user_id) | ||||||
|  | 
 | ||||||
|  |   if (d.channel_id === null) { | ||||||
|  |     // No longer in the channel, so delete
 | ||||||
|  |     await guild.voiceStates.delete(d.user_id) | ||||||
|  |     gateway.client.emit('voiceStateRemove', (voiceState as unknown) as VoiceState) | ||||||
|  |     return | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   await guild.voiceStates.set(d.user_id, d) | ||||||
|  |   const newVoiceState = await guild.voiceStates.get(d.user_id) | ||||||
|  |   if (voiceState === undefined) { | ||||||
|  |     gateway.client.emit('voiceStateAdd', (newVoiceState as unknown) as VoiceState) | ||||||
|  |   } else { | ||||||
|  |     gateway.client.emit('voiceStateUpdate', voiceState, (newVoiceState as unknown) as VoiceState) | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								src/managers/guildVoiceStates.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/managers/guildVoiceStates.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | import { Client } from '../models/client.ts' | ||||||
|  | import { Guild } from "../structures/guild.ts" | ||||||
|  | import { VoiceChannel } from "../structures/guildVoiceChannel.ts" | ||||||
|  | import { User } from "../structures/user.ts" | ||||||
|  | import { VoiceState } from "../structures/voiceState.ts" | ||||||
|  | import { VoiceStatePayload } from "../types/voice.ts" | ||||||
|  | import { BaseManager } from './base.ts' | ||||||
|  | 
 | ||||||
|  | export class GuildVoiceStatesManager extends BaseManager<VoiceStatePayload, VoiceState> { | ||||||
|  |   guild: Guild | ||||||
|  | 
 | ||||||
|  |   async get (key: string): Promise<VoiceState | undefined> { | ||||||
|  |     const raw = await this._get(key) | ||||||
|  |     if (raw === undefined) return | ||||||
|  | 
 | ||||||
|  |     const guild = raw.guild_id === undefined ? undefined : await this.client.guilds.get(raw.guild_id) | ||||||
|  | 
 | ||||||
|  |     return new VoiceState(this.client, raw, { | ||||||
|  |       user: (await this.client.users.get(raw.user_id) as unknown) as User, | ||||||
|  |       channel: raw.channel_id == null ? null : (await this.client.channels.get<VoiceChannel>(raw.channel_id) as unknown) as VoiceChannel, | ||||||
|  |       guild, | ||||||
|  |       member: guild === undefined ? undefined : await guild.members.get(raw.user_id)  | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   constructor (client: Client, guild: Guild) { | ||||||
|  |     super(client, `vs:${guild.id}`, VoiceState) | ||||||
|  |     this.guild = guild | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | @ -1,10 +1,26 @@ | ||||||
|  | import { Guild } from "../structures/guild.ts" | ||||||
|  | import { VoiceChannel } from "../structures/guildVoiceChannel.ts" | ||||||
| import { Client } from './client.ts' | import { Client } from './client.ts' | ||||||
| 
 | 
 | ||||||
|  | export interface VoiceOptions { | ||||||
|  |   guild: Guild, | ||||||
|  |   channel: VoiceChannel | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export class VoiceClient { | export class VoiceClient { | ||||||
|   client: Client |   client: Client | ||||||
|  |   ws?: WebSocket | ||||||
|  |   guild: Guild | ||||||
|  |   channel: VoiceChannel | ||||||
| 
 | 
 | ||||||
|   constructor(client: Client) { |   constructor(client: Client, options: VoiceOptions) { | ||||||
|     this.client = client |     this.client = client | ||||||
|  |     this.guild = options.guild | ||||||
|  |     this.channel = options.channel | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|  |   async connect(): Promise<VoiceClient> { | ||||||
|  |      | ||||||
|  |     return this | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -2,7 +2,6 @@ import { Client } from '../models/client.ts' | ||||||
| import { GuildFeatures, GuildIntegrationPayload, GuildPayload, IntegrationAccountPayload, IntegrationExpireBehavior } from '../types/guild.ts' | import { GuildFeatures, GuildIntegrationPayload, GuildPayload, IntegrationAccountPayload, IntegrationExpireBehavior } 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 { VoiceState } from './voiceState.ts' |  | ||||||
| import { RolesManager } from '../managers/roles.ts' | import { RolesManager } from '../managers/roles.ts' | ||||||
| import { GuildChannelsManager } from '../managers/guildChannels.ts' | import { GuildChannelsManager } from '../managers/guildChannels.ts' | ||||||
| import { MembersManager } from '../managers/members.ts' | import { MembersManager } from '../managers/members.ts' | ||||||
|  | @ -12,6 +11,7 @@ import { Member } from "./member.ts" | ||||||
| import { User } from "./user.ts" | import { User } from "./user.ts" | ||||||
| import { Application } from "./application.ts" | import { Application } from "./application.ts" | ||||||
| import { GUILD_INTEGRATIONS } from "../types/endpoint.ts" | import { GUILD_INTEGRATIONS } from "../types/endpoint.ts" | ||||||
|  | import { GuildVoiceStatesManager } from "../managers/guildVoiceStates.ts" | ||||||
| 
 | 
 | ||||||
| export class Guild extends Base { | export class Guild extends Base { | ||||||
|   id: string |   id: string | ||||||
|  | @ -43,7 +43,7 @@ export class Guild extends Base { | ||||||
|   large?: boolean |   large?: boolean | ||||||
|   unavailable: boolean |   unavailable: boolean | ||||||
|   memberCount?: number |   memberCount?: number | ||||||
|   voiceStates?: VoiceState[] |   voiceStates: GuildVoiceStatesManager | ||||||
|   members: MembersManager |   members: MembersManager | ||||||
|   channels: GuildChannelsManager |   channels: GuildChannelsManager | ||||||
|   presences?: PresenceUpdatePayload[] |   presences?: PresenceUpdatePayload[] | ||||||
|  | @ -65,6 +65,7 @@ export class Guild extends Base { | ||||||
|     this.id = data.id |     this.id = data.id | ||||||
|     this.unavailable = data.unavailable |     this.unavailable = data.unavailable | ||||||
|     this.members = new MembersManager(this.client, this) |     this.members = new MembersManager(this.client, this) | ||||||
|  |     this.voiceStates = new GuildVoiceStatesManager(client, this) | ||||||
|     this.channels = new GuildChannelsManager( |     this.channels = new GuildChannelsManager( | ||||||
|       this.client,  |       this.client,  | ||||||
|       this.client.channels,  |       this.client.channels,  | ||||||
|  |  | ||||||
|  | @ -1,49 +1,53 @@ | ||||||
| import { Client } from '../models/client.ts' | import { Client } from '../models/client.ts' | ||||||
| import { MemberPayload } from '../types/guild.ts' |  | ||||||
| import { VoiceStatePayload } from '../types/voice.ts' | import { VoiceStatePayload } from '../types/voice.ts' | ||||||
| import { Base } from './base.ts' | import { Base } from './base.ts' | ||||||
|  | import { Guild } from "./guild.ts" | ||||||
|  | import { VoiceChannel } from "./guildVoiceChannel.ts" | ||||||
|  | import { Member } from "./member.ts" | ||||||
|  | import { User } from "./user.ts" | ||||||
| 
 | 
 | ||||||
| export class VoiceState extends Base { | export class VoiceState extends Base { | ||||||
|   guildID?: string |   guild?: Guild | ||||||
|   channelID?: string |   channel: VoiceChannel | null | ||||||
|   userID: string |   user: User | ||||||
|   member?: MemberPayload |   member?: Member | ||||||
|   sessionID: string |   sessionID: string | ||||||
|   deaf: boolean |   deaf: boolean | ||||||
|   mute: boolean |   mute: boolean | ||||||
|   selfDeaf: boolean |   stream?: boolean | ||||||
|   selfMute: boolean |   video: boolean | ||||||
|   selfStream?: boolean |  | ||||||
|   selfVideo: boolean |  | ||||||
|   suppress: boolean |   suppress: boolean | ||||||
| 
 | 
 | ||||||
|   constructor (client: Client, data: VoiceStatePayload) { |   constructor (client: Client, data: VoiceStatePayload, _data: { | ||||||
|  |     user: User, | ||||||
|  |     channel: VoiceChannel | null, | ||||||
|  |     member?: Member, | ||||||
|  |     guild?: Guild | ||||||
|  |   }) { | ||||||
|     super(client, data) |     super(client, data) | ||||||
|     this.channelID = data.channel_id |     this.channel = _data.channel | ||||||
|     this.sessionID = data.session_id |     this.sessionID = data.session_id | ||||||
|     this.userID = data.user_id |     this.user = _data.user | ||||||
|  |     this.member = _data.member | ||||||
|  |     this.guild = _data.guild | ||||||
|     this.deaf = data.deaf |     this.deaf = data.deaf | ||||||
|     this.mute = data.mute |     this.mute = data.mute | ||||||
|     this.selfDeaf = data.self_deaf |     this.deaf = data.self_deaf | ||||||
|     this.selfMute = data.self_mute |     this.mute = data.self_mute | ||||||
|     this.selfStream = data.self_stream |     this.stream = data.self_stream | ||||||
|     this.selfVideo = data.self_video |     this.video = data.self_video | ||||||
|     this.suppress = data.suppress |     this.suppress = data.suppress | ||||||
|     // TODO: Cache in Gateway Event Code
 |  | ||||||
|     // cache.set('voiceState', `${this.guildID}:${this.userID}`, this)
 |  | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   protected readFromData (data: VoiceStatePayload): void { |   protected readFromData (data: VoiceStatePayload): void { | ||||||
|     super.readFromData(data) |     super.readFromData(data) | ||||||
|     this.channelID = data.channel_id ?? this.channelID |  | ||||||
|     this.sessionID = data.session_id ?? this.sessionID |     this.sessionID = data.session_id ?? this.sessionID | ||||||
|     this.userID = data.user_id ?? this.userID |  | ||||||
|     this.deaf = data.deaf ?? this.deaf |     this.deaf = data.deaf ?? this.deaf | ||||||
|     this.mute = data.mute ?? this.mute |     this.mute = data.mute ?? this.mute | ||||||
|     this.selfDeaf = data.self_deaf ?? this.selfDeaf |     this.deaf = data.self_deaf ?? this.deaf | ||||||
|     this.selfMute = data.self_mute ?? this.selfMute |     this.mute = data.self_mute ?? this.mute | ||||||
|     this.selfStream = data.self_stream ?? this.selfStream |     this.stream = data.self_stream ?? this.stream | ||||||
|     this.selfVideo = data.self_video ?? this.selfVideo |     this.video = data.self_video ?? this.video | ||||||
|     this.suppress = data.suppress ?? this.suppress |     this.suppress = data.suppress ?? this.suppress | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -92,6 +92,14 @@ client.on('typingStart', (user, channel, at, guildData) => { | ||||||
|   console.log(`${user.tag} started typing in ${channel.id} at ${at}${guildData !== undefined ? `\nGuild: ${guildData.guild.name}` : ''}`) |   console.log(`${user.tag} started typing in ${channel.id} at ${at}${guildData !== undefined ? `\nGuild: ${guildData.guild.name}` : ''}`) | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  | client.on('voiceStateAdd', (state) => { | ||||||
|  |   console.log('VC Join', state) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
|  | client.on('voiceStateRemove', (state) => { | ||||||
|  |   console.log('VC Leave', state) | ||||||
|  | }) | ||||||
|  | 
 | ||||||
| // client.on('raw', (evt: string) => console.log(`EVENT: ${evt}`))
 | // client.on('raw', (evt: string) => console.log(`EVENT: ${evt}`))
 | ||||||
| 
 | 
 | ||||||
| const files = Deno.readDirSync('./src/test/cmds') | const files = Deno.readDirSync('./src/test/cmds') | ||||||
|  |  | ||||||
|  | @ -104,6 +104,7 @@ export enum GatewayEvents { | ||||||
|   Typing_Start = 'TYPING_START', |   Typing_Start = 'TYPING_START', | ||||||
|   User_Update = 'USER_UPDATE', |   User_Update = 'USER_UPDATE', | ||||||
|   Voice_Server_Update = 'VOICE_SERVER_UPDATE', |   Voice_Server_Update = 'VOICE_SERVER_UPDATE', | ||||||
|  |   Voice_State_Update = 'VOICE_STATE_UPDATE', | ||||||
|   Webhooks_Update = 'WEBHOOKS_UPDATE' |   Webhooks_Update = 'WEBHOOKS_UPDATE' | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ export enum VoiceCloseCodes { | ||||||
| 
 | 
 | ||||||
| export interface VoiceStatePayload { | export interface VoiceStatePayload { | ||||||
|   guild_id?: string |   guild_id?: string | ||||||
|   channel_id?: string |   channel_id: string | null | ||||||
|   user_id: string |   user_id: string | ||||||
|   member?: MemberPayload |   member?: MemberPayload | ||||||
|   session_id: string |   session_id: string | ||||||
|  |  | ||||||
|  | @ -60,7 +60,7 @@ | ||||||
|     // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */ |     // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */ | ||||||
|     // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ |     // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ | ||||||
|     /* Experimental Options */ |     /* Experimental Options */ | ||||||
|     // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */ |     "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */ | ||||||
|     "emitDecoratorMetadata": false /* Enables experimental support for emitting type metadata for decorators. */, |     "emitDecoratorMetadata": false /* Enables experimental support for emitting type metadata for decorators. */, | ||||||
|     /* Advanced Options */ |     /* Advanced Options */ | ||||||
|     "skipLibCheck": true, |     "skipLibCheck": true, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue