Added Presence
This commit is contained in:
		
							parent
							
								
									99630d74cf
								
							
						
					
					
						commit
						04056a7f9c
					
				
					 4 changed files with 217 additions and 64 deletions
				
			
		|  | @ -10,6 +10,7 @@ import { gatewayHandlers } from './handlers/index.ts' | |||
| import { GATEWAY_BOT } from '../types/endpoint.ts' | ||||
| import { GatewayBotPayload } from "../types/gatewayBot.ts" | ||||
| import { GatewayCache } from "../managers/GatewayCache.ts" | ||||
| import { ClientActivityPayload } from "../structures/presence.ts" | ||||
| 
 | ||||
| /** | ||||
|  * Handles Discord gateway connection. | ||||
|  | @ -79,12 +80,10 @@ class Gateway { | |||
|             return | ||||
|           } | ||||
| 
 | ||||
|           this.websocket.send( | ||||
|             JSON.stringify({ | ||||
|           this.send({ | ||||
|             op: GatewayOpcodes.HEARTBEAT, | ||||
|             d: this.sequenceID ?? null | ||||
|           }) | ||||
|           ) | ||||
|           this.lastPingTimestamp = Date.now() | ||||
|         }, this.heartbeatInterval) | ||||
| 
 | ||||
|  | @ -202,8 +201,7 @@ class Gateway { | |||
|         return this.sendResume() | ||||
|       } | ||||
|     } | ||||
|     this.websocket.send( | ||||
|       JSON.stringify({ | ||||
|     this.send({ | ||||
|       op: GatewayOpcodes.IDENTIFY, | ||||
|       d: { | ||||
|         token: this.token, | ||||
|  | @ -218,15 +216,9 @@ class Gateway { | |||
|           (previous, current) => previous | current, | ||||
|           0 | ||||
|         ), | ||||
|           presence: { | ||||
|             // TODO: User should can customize this
 | ||||
|             status: 'online', | ||||
|             since: null, | ||||
|             afk: false | ||||
|           } | ||||
|         presence: this.client.presence.create() | ||||
|       } | ||||
|     }) | ||||
|     ) | ||||
|   } | ||||
| 
 | ||||
|   private async sendResume(): Promise<void> { | ||||
|  | @ -243,9 +235,7 @@ class Gateway { | |||
|         seq: this.sequenceID || null | ||||
|       } | ||||
|     } | ||||
|     this.websocket.send( | ||||
|       JSON.stringify(resumePayload) | ||||
|     ) | ||||
|     this.send(resumePayload) | ||||
|   } | ||||
| 
 | ||||
|   debug(msg: string) { | ||||
|  | @ -275,6 +265,24 @@ class Gateway { | |||
|   close(): void { | ||||
|     this.websocket.close(1000) | ||||
|   } | ||||
| 
 | ||||
|   send(data: GatewayResponse) { | ||||
|     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 || null, | ||||
|     })) | ||||
|     return true | ||||
|   } | ||||
| 
 | ||||
|   sendPresence(data: ClientActivityPayload) { | ||||
|     this.send({ | ||||
|       op: GatewayOpcodes.PRESENCE_UPDATE, | ||||
|       d: data | ||||
|     }) | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| export type GatewayEventHandler = (gateway: Gateway, d: any) => void | ||||
|  |  | |||
|  | @ -9,13 +9,15 @@ import { GuildManager } from "../managers/GuildsManager.ts" | |||
| import { EmojisManager } from "../managers/EmojisManager.ts" | ||||
| import { ChannelsManager } from "../managers/ChannelsManager.ts" | ||||
| import { MessagesManager } from "../managers/MessagesManager.ts" | ||||
| import { ActivityGame, ClientActivity, ClientActivityPayload, ClientPresence } from "../structures/presence.ts" | ||||
| 
 | ||||
| /** Some Client Options to modify behaviour */ | ||||
| export interface ClientOptions { | ||||
|   token?: string | ||||
|   intents?: GatewayIntents[] | ||||
|   cache?: ICacheAdapter, | ||||
|   forceNewSession?: boolean | ||||
|   forceNewSession?: boolean, | ||||
|   presence?: ClientPresence | ClientActivity | ActivityGame | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  | @ -37,12 +39,15 @@ export class Client extends EventEmitter { | |||
|   messages: MessagesManager = new MessagesManager(this) | ||||
|   emojis: EmojisManager = new EmojisManager(this) | ||||
| 
 | ||||
|   presence: ClientPresence = new ClientPresence() | ||||
| 
 | ||||
|   constructor (options: ClientOptions = {}) { | ||||
|     super() | ||||
|     this.token = options.token | ||||
|     this.intents = options.intents | ||||
|     this.forceNewSession = options.forceNewSession | ||||
|     if(options.cache) this.cache = options.cache | ||||
|     if(options.presence) this.presence = options.presence instanceof ClientPresence ? options.presence : new ClientPresence(options.presence) | ||||
|   } | ||||
| 
 | ||||
|   setAdapter(adapter: ICacheAdapter) { | ||||
|  | @ -50,6 +55,13 @@ export class Client extends EventEmitter { | |||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   setPresence(presence: ClientPresence | ClientActivity | ActivityGame) { | ||||
|     if(presence instanceof ClientPresence) { | ||||
|       this.presence = presence | ||||
|     } else this.presence = new ClientPresence(presence) | ||||
|     this.gateway?.sendPresence(this.presence.create()) | ||||
|   } | ||||
| 
 | ||||
|   debug(tag: string, msg: string) { | ||||
|     this.emit("debug", `[${tag}] ${msg}`) | ||||
|   } | ||||
|  |  | |||
							
								
								
									
										120
									
								
								src/structures/presence.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/structures/presence.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,120 @@ | |||
| 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) { | ||||
|       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) { | ||||
|           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) { | ||||
|     this.afk = payload.afk | ||||
|     this.activity = payload.activities ?? undefined | ||||
|     this.since = payload.since | ||||
|     this.status = payload.status | ||||
|   } | ||||
| 
 | ||||
|   static parse(payload: ClientActivityPayload) { | ||||
|     return new ClientPresence().parse(payload) | ||||
|   } | ||||
| 
 | ||||
|   create(): ClientActivityPayload { | ||||
|     return { | ||||
|       afk: this.afk || false, | ||||
|       activities: this.createActivity(), | ||||
|       since: this.since || null, | ||||
|       status: this.status || 'online' | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   createActivity() { | ||||
|     let 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) { | ||||
|     this.status = status | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   setActivity(activity: ActivityGame) { | ||||
|     this.activity = activity | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   setActivities(activities: ActivityGame[]) { | ||||
|     this.activity = activities | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   setAFK(afk: boolean) { | ||||
|     this.afk = afk | ||||
|   } | ||||
| 
 | ||||
|   removeAFK() { | ||||
|     this.afk = false | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   toggleAFK() { | ||||
|     this.afk = !(this.afk || true) | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   setSince(since?: number) { | ||||
|     this.since = since | ||||
|     return this | ||||
|   } | ||||
| } | ||||
|  | @ -8,8 +8,17 @@ import { Guild } from '../structures/guild.ts' | |||
| import { User } from '../structures/user.ts' | ||||
| import { Message } from "../structures/message.ts" | ||||
| import { RedisCacheAdapter } from "../models/CacheAdapter.ts" | ||||
| import { ClientPresence } from "../structures/presence.ts" | ||||
| 
 | ||||
| const bot = new Client() | ||||
| const bot = new Client({ | ||||
|   presence: new ClientPresence({ | ||||
|     activity: { | ||||
|       name: "Testing", | ||||
|       type: 'COMPETING' | ||||
|     } | ||||
|   }), | ||||
|   forceNewSession: true | ||||
| }) | ||||
| 
 | ||||
| bot.setAdapter(new RedisCacheAdapter(bot, { | ||||
|   hostname: "127.0.0.1", | ||||
|  | @ -18,6 +27,10 @@ bot.setAdapter(new RedisCacheAdapter(bot, { | |||
| 
 | ||||
| bot.on('ready', () => { | ||||
|   console.log(`[Login] Logged in as ${bot.user?.tag}!`) | ||||
|   bot.setPresence({ | ||||
|     name: "Test After Ready", | ||||
|     type: 'COMPETING' | ||||
|   }) | ||||
| }) | ||||
| 
 | ||||
| bot.on('debug', console.log) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue