Fixed Member Caching, Message#member, Member#roles
This commit is contained in:
		
							parent
							
								
									71c1499c1d
								
							
						
					
					
						commit
						70824135a7
					
				
					 13 changed files with 103 additions and 85 deletions
				
			
		|  | @ -1,16 +1,15 @@ | |||
| import { Gateway, GatewayEventHandler } from '../index.ts' | ||||
| import cache from '../../models/cache.ts' | ||||
| import { Guild } from '../../structures/guild.ts' | ||||
| import { User } from '../../structures/user.ts' | ||||
| import { GuildBanRemovePayload } from '../../types/gateway.ts' | ||||
| 
 | ||||
| export const guildBanRemove: GatewayEventHandler = ( | ||||
| export const guildBanRemove: GatewayEventHandler = async ( | ||||
|   gateway: Gateway, | ||||
|   d: GuildBanRemovePayload | ||||
| ) => { | ||||
|   const guild: Guild = cache.get('guild', d.guild_id) | ||||
|   const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id) | ||||
|   const user: User = | ||||
|     cache.get('user', d.user.id) ?? new User(gateway.client, d.user) | ||||
|     await gateway.client.users.get(d.user.id) ?? new User(gateway.client, d.user) | ||||
| 
 | ||||
|   if (guild !== undefined) { | ||||
|     gateway.client.emit('guildBanRemove', guild, user) | ||||
|  |  | |||
|  | @ -17,11 +17,26 @@ export const messageCreate: GatewayEventHandler = async ( | |||
|   const user = new User(gateway.client, d.author) | ||||
|   await gateway.client.users.set(d.author.id, d.author) | ||||
|   let guild | ||||
|   let member | ||||
|   if (d.guild_id !== undefined) { | ||||
|     guild = await gateway.client.guilds.get(d.guild_id) | ||||
|   } | ||||
|   if (guild !== undefined && d.member !== undefined) { | ||||
|     d.member.user = d.author | ||||
|     await guild.members.set(d.author.id, d.member) | ||||
|     member = await guild.members.get(d.author.id) | ||||
|   } | ||||
|   const mentions = new MessageMentions() | ||||
|   const message = new Message(gateway.client, d, channel as any, user, mentions) | ||||
|   message.member = member | ||||
|   if (guild !== undefined) message.guild = guild | ||||
|   if (message.member !== undefined) { | ||||
|     if(message.member.user === undefined) { | ||||
|       const user = await gateway.client.users.get(message.member.id) | ||||
|       if(user !== undefined) { | ||||
|         message.member.user = user | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   gateway.client.emit('messageCreate', message) | ||||
| } | ||||
|  |  | |||
|  | @ -3,7 +3,9 @@ import { Collection } from "../utils/collection.ts"; | |||
| 
 | ||||
| export class BaseManager<T, T2> { | ||||
|   client: Client | ||||
|   /** Cache Name or Key used to differentiate caches */ | ||||
|   cacheName: string | ||||
|   /** Which data type does this cache have */ | ||||
|   DataType: any | ||||
| 
 | ||||
|   constructor (client: Client, cacheName: string, DataType: any) { | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| import { User } from "../structures/user.ts"; | ||||
| import { Client } from "../models/client.ts"; | ||||
| import { Guild } from "../structures/guild.ts"; | ||||
| import { Member } from "../structures/member.ts"; | ||||
|  | @ -13,11 +14,29 @@ export class MembersManager extends BaseManager<MemberPayload, Member> { | |||
|     this.guild = guild | ||||
|   } | ||||
| 
 | ||||
|   async get (key: string): Promise<Member | undefined> { | ||||
|     const raw = await this._get(key) | ||||
|     if (raw === undefined) return | ||||
|     const user = new User(this.client, raw.user) | ||||
|     const res = new this.DataType(this.client, raw, user) | ||||
|     for (const roleid of res.roleIDs as string[]) { | ||||
|       const role = await this.guild.roles.get(roleid) | ||||
|       if(role !== undefined) res.roles.push(role) | ||||
|     } | ||||
|     return res | ||||
|   } | ||||
| 
 | ||||
|   async fetch(id: string): Promise<Member> { | ||||
|     return await new Promise((resolve, reject) => { | ||||
|       this.client.rest.get(GUILD_MEMBER(this.guild.id, id)).then(data => { | ||||
|         this.set(id, data as MemberPayload) | ||||
|         resolve(new Member(this.client, data as MemberPayload)) | ||||
|       this.client.rest.get(GUILD_MEMBER(this.guild.id, id)).then(async data => { | ||||
|         await this.set(id, data as MemberPayload) | ||||
|         const user: User = new User(this.client, data.user) | ||||
|         const res = new Member(this.client, data as MemberPayload, user) | ||||
|         for (const roleid of res.roleIDs as string[]) { | ||||
|           const role = await this.guild.roles.get(roleid) | ||||
|           if(role !== undefined) res.roles.push(role) | ||||
|         } | ||||
|         resolve(res) | ||||
|       }).catch(e => reject(e)) | ||||
|     }) | ||||
|   } | ||||
|  |  | |||
|  | @ -1,48 +0,0 @@ | |||
| let caches: any = {} | ||||
| 
 | ||||
| const get = (cacheName: string, key: string): any => { | ||||
|   const gotCache: Map<string, any> = caches[cacheName] | ||||
|   if (gotCache === undefined || !(gotCache instanceof Map)) { | ||||
|     return undefined | ||||
|   } | ||||
| 
 | ||||
|   const gotMap = gotCache.get(key) | ||||
|   return gotMap | ||||
| } | ||||
| 
 | ||||
| const set = (cacheName: string, key: string, value: any): any => { | ||||
|   let gotCache: Map<string, any> = caches[cacheName] | ||||
|   if (gotCache === undefined || !(gotCache instanceof Map)) { | ||||
|     gotCache = caches[cacheName] = new Map<string, any>() | ||||
|   } | ||||
| 
 | ||||
|   gotCache.set(key, value) | ||||
| 
 | ||||
|   return value | ||||
| } | ||||
| 
 | ||||
| const del = (cacheName: string, key: string): boolean | undefined => { | ||||
|   const gotCache: Map<string, any> = caches[cacheName] | ||||
|   if (gotCache === undefined || !(gotCache instanceof Map)) { | ||||
|     return | ||||
|   } | ||||
| 
 | ||||
|   return gotCache.delete(key) | ||||
| } | ||||
| 
 | ||||
| const deleteCache = (cacheName: string): void => { | ||||
|   const gotCache = caches[cacheName] | ||||
|   if (gotCache === undefined) { | ||||
|     return | ||||
|   } | ||||
| 
 | ||||
|   // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
 | ||||
|   delete caches[cacheName] | ||||
| } | ||||
| 
 | ||||
| const resetCaches = (): void => { | ||||
|   caches = {} | ||||
| } | ||||
| 
 | ||||
| export default { get, set, del, deleteCache, resetCaches } | ||||
| export { get, set, del, deleteCache, resetCaches } | ||||
|  | @ -13,12 +13,19 @@ import { ActivityGame, ClientActivity, ClientPresence } from "../structures/pres | |||
| 
 | ||||
| /** Some Client Options to modify behaviour */ | ||||
| export interface ClientOptions { | ||||
|   /** Token of the Bot/User */ | ||||
|   token?: string | ||||
|   /** Gateway Intents */ | ||||
|   intents?: GatewayIntents[] | ||||
|   /** Cache Adapter to use, defaults to Collections one */ | ||||
|   cache?: ICacheAdapter, | ||||
|   /** Force New Session and don't use cached Session (by persistent caching) */ | ||||
|   forceNewSession?: boolean, | ||||
|   /** Startup presence of client */ | ||||
|   presence?: ClientPresence | ClientActivity | ActivityGame | ||||
|   /** Whether it's a bot user or not? Use this if selfbot! */ | ||||
|   bot?: boolean | ||||
|   /** Force all requests to Canary API */ | ||||
|   canary?: boolean | ||||
| } | ||||
| 
 | ||||
|  | @ -26,22 +33,34 @@ export interface ClientOptions { | |||
|  * Discord Client. | ||||
|  */ | ||||
| export class Client extends EventEmitter { | ||||
|   /** Gateway object */ | ||||
|   gateway?: Gateway | ||||
|   /** REST Manager - used to make all requests */ | ||||
|   rest: RESTManager = new RESTManager(this) | ||||
|   /** User which Client logs in to, undefined until logs in */ | ||||
|   user?: User | ||||
|   /** WebSocket ping of Client */ | ||||
|   ping = 0 | ||||
|   /** Token of the Bot/User */ | ||||
|   token?: string | ||||
|   /** Cache Adapter */ | ||||
|   cache: ICacheAdapter = new DefaultCacheAdapter() | ||||
|   /** Gateway Intents */ | ||||
|   intents?: GatewayIntents[] | ||||
|   /** Whether to force new session or not */ | ||||
|   forceNewSession?: boolean | ||||
| 
 | ||||
|   users: UserManager = new UserManager(this) | ||||
|   guilds: GuildManager = new GuildManager(this) | ||||
|   channels: ChannelsManager = new ChannelsManager(this) | ||||
|   messages: MessagesManager = new MessagesManager(this) | ||||
|   emojis: EmojisManager = new EmojisManager(this) | ||||
|   bot: boolean = true | ||||
|   canary: boolean = false | ||||
|    | ||||
|   /** Whether this client will login as bot user or not */ | ||||
|   bot: boolean = true | ||||
|   /** Whether the REST Manager will use Canary API or not */ | ||||
|   canary: boolean = false | ||||
|   /** Client's presence. Startup one if set before connecting */ | ||||
|   presence: ClientPresence = new ClientPresence() | ||||
| 
 | ||||
|   constructor (options: ClientOptions = {}) { | ||||
|  | @ -55,11 +74,13 @@ export class Client extends EventEmitter { | |||
|     if (options.canary === true) this.canary = true | ||||
|   } | ||||
| 
 | ||||
|   /** Set Cache Adapter */ | ||||
|   setAdapter (adapter: ICacheAdapter): Client { | ||||
|     this.cache = adapter | ||||
|     return this | ||||
|   } | ||||
| 
 | ||||
|   /** Change Presence of Client */ | ||||
|   setPresence (presence: ClientPresence | ClientActivity | ActivityGame): void { | ||||
|     if (presence instanceof ClientPresence) { | ||||
|       this.presence = presence | ||||
|  | @ -67,6 +88,7 @@ export class Client extends EventEmitter { | |||
|     this.gateway?.sendPresence(this.presence.create()) | ||||
|   } | ||||
| 
 | ||||
|   /** Emit debug event */ | ||||
|   debug (tag: string, msg: string): void { | ||||
|     this.emit("debug", `[${tag}] ${msg}`) | ||||
|   } | ||||
|  |  | |||
|  | @ -141,7 +141,7 @@ export class CommandClient extends Client { | |||
|       this.emit('commandUsed', { context: ctx }) | ||||
|       command.execute(ctx) | ||||
|     } catch (e) { | ||||
|       if (this.texts.ERROR !== undefined) return this.sendProcessedText(msg, this.texts.ERROR, Object.assign(baseReplaces, { error: e.message })) | ||||
|       if (this.texts.ERROR !== undefined) this.sendProcessedText(msg, this.texts.ERROR, Object.assign(baseReplaces, { error: e.message })) | ||||
|       this.emit('commandError', { command, parsed, error: e }) | ||||
|     } | ||||
|   } | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| import { Client } from '../models/client.ts' | ||||
| import * as cache from '../models/cache.ts' | ||||
| 
 | ||||
| interface IInit { | ||||
|   useCache?: boolean | ||||
|  | @ -25,18 +24,13 @@ export class Base { | |||
|     this.useCache = useCache | ||||
|     const cacheID = restURLfuncArgs.join(':') | ||||
|     if (this.useCache !== undefined) { | ||||
|       const cached = cache.get(this.cacheName ?? this.name, cacheID) | ||||
|       const cached = await client.cache.get(this.cacheName ?? this.name, cacheID) | ||||
|       if (cached !== undefined) { | ||||
|         return cached | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     const resp = await fetch(endpoint(...restURLfuncArgs), { | ||||
|       headers: { | ||||
|         Authorization: `Bot ${client.token}` | ||||
|       } | ||||
|     }) | ||||
|     const jsonParsed = await resp.json() | ||||
|     const jsonParsed = await client.rest.get(endpoint(...restURLfuncArgs)) | ||||
| 
 | ||||
|     return new this(client, jsonParsed) | ||||
|   } | ||||
|  | @ -47,12 +41,7 @@ export class Base { | |||
|   ): Promise<this> { | ||||
|     const oldOne = Object.assign(Object.create(this), this) | ||||
| 
 | ||||
|     const resp = await fetch(endpoint(...restURLfuncArgs), { | ||||
|       headers: { | ||||
|         Authorization: `Bot ${client.token}` | ||||
|       } | ||||
|     }) | ||||
|     const jsonParsed = await resp.json() | ||||
|     const jsonParsed = await client.rest.get(endpoint(...restURLfuncArgs)) | ||||
| 
 | ||||
|     this.readFromData(jsonParsed) | ||||
| 
 | ||||
|  |  | |||
|  | @ -4,7 +4,6 @@ import { PresenceUpdatePayload } from '../types/gateway.ts' | |||
| import { Base } from './base.ts' | ||||
| import { Emoji } from './emoji.ts' | ||||
| import { VoiceState } from './voiceState.ts' | ||||
| import cache from '../models/cache.ts' | ||||
| import { RolesManager } from "../managers/roles.ts" | ||||
| import { GuildChannelsManager } from "../managers/guildChannels.ts" | ||||
| import { MembersManager } from "../managers/members.ts" | ||||
|  | @ -156,10 +155,10 @@ export class Guild extends Base { | |||
|       //   data.roles.map(
 | ||||
|       //     v => cache.get('role', v.id) ?? new Role(this.client, v)
 | ||||
|       //   ) ?? this.roles
 | ||||
|       this.emojis = | ||||
|         data.emojis.map( | ||||
|           v => cache.get('emoji', v.id) ?? new Emoji(this.client, v) | ||||
|         ) ?? this.emojis | ||||
|       // this.emojis =
 | ||||
|       //   data.emojis.map(
 | ||||
|       //     v => cache.get('emoji', v.id) ?? new Emoji(this.client, v)
 | ||||
|       //   ) ?? this.emojis
 | ||||
|       this.features = data.features ?? this.features | ||||
|       this.mfaLevel = data.mfa_level ?? this.mfaLevel | ||||
|       this.systemChannelID = data.system_channel_id ?? this.systemChannelID | ||||
|  |  | |||
|  | @ -1,26 +1,28 @@ | |||
| import cache from '../models/cache.ts' | ||||
| import { Client } from '../models/client.ts' | ||||
| import { MemberPayload } from '../types/guild.ts' | ||||
| import { Base } from './base.ts' | ||||
| import { Role } from "./role.ts" | ||||
| import { User } from './user.ts' | ||||
| 
 | ||||
| export class Member extends Base { | ||||
|   id: string | ||||
|   user: User | ||||
|   nick?: string | ||||
|   roles: string[] | ||||
|   roleIDs: string[] | ||||
|   roles: Role[] = [] | ||||
|   joinedAt: string | ||||
|   premiumSince?: string | ||||
|   deaf: boolean | ||||
|   mute: boolean | ||||
| 
 | ||||
|   constructor (client: Client, data: MemberPayload) { | ||||
|   constructor (client: Client, data: MemberPayload, user: User) { | ||||
|     super(client) | ||||
|     this.id = data.user.id | ||||
|     this.user = | ||||
|       cache.get('user', data.user.id) ?? new User(this.client, data.user) | ||||
|     this.user = user | ||||
|     // this.user =
 | ||||
|     //   cache.get('user', data.user.id) ?? new User(this.client, data.user)
 | ||||
|     this.nick = data.nick | ||||
|     this.roles = data.roles | ||||
|     this.roleIDs = data.roles | ||||
|     this.joinedAt = data.joined_at | ||||
|     this.premiumSince = data.premium_since | ||||
|     this.deaf = data.deaf | ||||
|  | @ -32,7 +34,7 @@ export class Member extends Base { | |||
|   protected readFromData (data: MemberPayload): void { | ||||
|     super.readFromData(data.user) | ||||
|     this.nick = data.nick ?? this.nick | ||||
|     this.roles = data.roles ?? this.roles | ||||
|     this.roleIDs = data.roles ?? this.roles | ||||
|     this.joinedAt = data.joined_at ?? this.joinedAt | ||||
|     this.premiumSince = data.premium_since ?? this.premiumSince | ||||
|     this.deaf = data.deaf ?? this.deaf | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| import { CommandClient, Intents } from '../../mod.ts'; | ||||
| import PingCommand from "./cmds/ping.ts"; | ||||
| import UserinfoCommand from "./cmds/userinfo.ts"; | ||||
| import { TOKEN } from './config.ts' | ||||
| 
 | ||||
| const client = new CommandClient({ | ||||
|  | @ -13,6 +14,9 @@ client.on('ready', () => { | |||
|   console.log(`[Login] Logged in as ${client.user?.tag}!`) | ||||
| }) | ||||
| 
 | ||||
| client.on("commandError", console.log) | ||||
| 
 | ||||
| client.commands.add(PingCommand) | ||||
| client.commands.add(UserinfoCommand) | ||||
| 
 | ||||
| client.connect(TOKEN, Intents.All) | ||||
|  | @ -3,9 +3,8 @@ import { CommandContext } from "../../models/command.ts"; | |||
| 
 | ||||
| export default class PingCommand extends Command { | ||||
|   name = "ping" | ||||
|   dmOnly = true | ||||
| 
 | ||||
|   execute(ctx: CommandContext): void { | ||||
|     ctx.message.reply(`pong! Latency: ${ctx.client.ping}ms`) | ||||
|     ctx.message.reply(`Pong! Latency: ${ctx.client.ping}ms`) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										16
									
								
								src/test/cmds/userinfo.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/test/cmds/userinfo.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| import { Command, Member, CommandContext, Embed } from "../../../mod.ts"; | ||||
| 
 | ||||
| export default class UserinfoCommand extends Command { | ||||
|     name = "userinfo" | ||||
|     guildOnly = true | ||||
| 
 | ||||
|     execute(ctx: CommandContext): void { | ||||
|         const member: Member = ctx.message.member as any | ||||
|         const embed = new Embed() | ||||
|         .setTitle(`User Info`) | ||||
|         .setAuthor({ name: member.user.tag }) | ||||
|         .addField("ID", member.id) | ||||
|         .addField("Roles", member.roles.map(r => r.name).join(", ")) | ||||
|         ctx.channel.send(embed) | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue