Fixed Member Caching, Message#member, Member#roles

This commit is contained in:
DjDeveloperr 2020-11-07 18:35:37 +05:30
parent 71c1499c1d
commit 70824135a7
13 changed files with 103 additions and 85 deletions

View File

@ -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)

View File

@ -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)
}

View File

@ -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) {

View File

@ -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))
})
}

View File

@ -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 }

View File

@ -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)
/** 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}`)
}

View File

@ -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 })
}
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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
View 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)
}
}