Merge pull request #115 from DjDeveloperr/catch

add ChannelsManager#{sendMessage, editMessage} and Command#onError
This commit is contained in:
DjDeveloper 2021-03-19 17:33:39 +05:30 committed by GitHub
commit b532a99eb4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 189 additions and 78 deletions

View File

@ -64,7 +64,21 @@ export class BaseManager<T, T2> {
const arr = (await this.array()) ?? []
const { readable, writable } = new TransformStream()
arr.forEach((el) => writable.getWriter().write(el))
yield* readable.getIterator()
yield* readable
}
async fetch(...args: unknown[]): Promise<T2 | undefined> {
return undefined
}
/** Try to get value from cache, if not found then fetch */
async resolve(key: string): Promise<T2 | undefined> {
const cacheValue = await this.get(key)
if (cacheValue !== undefined) return cacheValue
else {
const fetchValue = await this.fetch(key).catch(() => undefined)
if (fetchValue !== undefined) return fetchValue
}
}
/** Deletes everything from Cache */

View File

@ -44,6 +44,20 @@ export class BaseChildManager<T, T2> {
const arr = (await this.array()) ?? []
const { readable, writable } = new TransformStream()
arr.forEach((el: unknown) => writable.getWriter().write(el))
yield* readable.getIterator()
yield* readable
}
async fetch(...args: unknown[]): Promise<T2 | undefined> {
return this.parent.fetch(...args)
}
/** Try to get value from cache, if not found then fetch */
async resolve(key: string): Promise<T2 | undefined> {
const cacheValue = await this.get(key)
if (cacheValue !== undefined) return cacheValue
else {
const fetchValue = await this.fetch(key).catch(() => undefined)
if (fetchValue !== undefined) return fetchValue
}
}
}

View File

@ -1,10 +1,19 @@
import { Client } from '../models/client.ts'
import { Channel } from '../structures/channel.ts'
import { ChannelPayload, GuildChannelPayload } from '../types/channel.ts'
import { Embed } from '../structures/embed.ts'
import { Message } from '../structures/message.ts'
import { TextChannel } from '../structures/textChannel.ts'
import {
ChannelPayload,
GuildChannelPayload,
MessageOptions
} from '../types/channel.ts'
import { CHANNEL } from '../types/endpoint.ts'
import getChannelByType from '../utils/getChannelByType.ts'
import { BaseManager } from './base.ts'
export type AllMessageOptions = MessageOptions | Embed
export class ChannelsManager extends BaseManager<ChannelPayload, Channel> {
constructor(client: Client) {
super(client, 'channels', Channel)
@ -66,4 +75,105 @@ export class ChannelsManager extends BaseManager<ChannelPayload, Channel> {
.catch((e) => reject(e))
})
}
async sendMessage(
channel: string | TextChannel,
content?: string | AllMessageOptions,
option?: AllMessageOptions
): Promise<Message> {
const channelID = typeof channel === 'string' ? channel : channel.id
if (typeof content === 'object') {
option = content
content = undefined
}
if (content === undefined && option === undefined) {
throw new Error('Either text or option is necessary.')
}
if (option instanceof Embed) {
option = {
embed: option
}
}
const payload: any = {
content: content,
embed: option?.embed,
file: option?.file,
files: option?.files,
tts: option?.tts,
allowed_mentions: option?.allowedMentions,
message_reference:
option?.reply === undefined
? undefined
: typeof option.reply === 'string'
? {
message_id: option.reply
}
: typeof option.reply === 'object'
? option.reply instanceof Message
? {
message_id: option.reply.id,
channel_id: option.reply.channel.id,
guild_id: option.reply.guild?.id
}
: option.reply
: undefined
}
const resp = await this.client.rest.api.channels[channelID].messages.post(
payload
)
const chan =
typeof channel === 'string'
? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(await this.get<TextChannel>(channel))!
: channel
const res = new Message(this.client, resp, chan, this.client.user as any)
await res.mentions.fromPayload(resp)
return res
}
async editMessage(
channel: string | TextChannel,
message: Message | string,
text?: string | MessageOptions,
option?: MessageOptions
): Promise<Message> {
const channelID = typeof channel === 'string' ? channel : channel.id
if (text === undefined && option === undefined) {
throw new Error('Either text or option is necessary.')
}
if (this.client.user === undefined) {
throw new Error('Client user has not initialized.')
}
if (typeof text === 'object') {
if (typeof option === 'object') Object.assign(option, text)
else option = text
text = undefined
}
const newMsg = await this.client.rest.api.channels[channelID].messages[
typeof message === 'string' ? message : message.id
].patch({
content: text,
embed: option?.embed !== undefined ? option.embed.toJSON() : undefined,
// Cannot upload new files with Message
// file: option?.file,
tts: option?.tts,
allowed_mentions: option?.allowedMentions
})
const chan =
typeof channel === 'string'
? // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
(await this.get<TextChannel>(channel))!
: channel
const res = new Message(this.client, newMsg, chan, this.client.user)
await res.mentions.fromPayload(newMsg)
return res
}
}

View File

@ -92,6 +92,9 @@ export class Command implements CommandOptions {
dmOnly?: boolean
ownerOnly?: boolean
/** Method called when the command errors */
onError(ctx: CommandContext, error: Error): any {}
/** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */
beforeExecute(ctx: CommandContext): boolean | Promise<boolean> {
return true

View File

@ -286,7 +286,8 @@ export class CommandClient extends Client implements CommandClientOptions {
if (
(command.botPermissions !== undefined ||
category?.permissions !== undefined) &&
category?.botPermissions !== undefined ||
allPermissions !== undefined) &&
msg.guild !== undefined
) {
// TODO: Check Overwrites too
@ -315,7 +316,8 @@ export class CommandClient extends Client implements CommandClientOptions {
if (
(command.userPermissions !== undefined ||
category?.userPermissions !== undefined) &&
category?.userPermissions !== undefined ||
allPermissions !== undefined) &&
msg.guild !== undefined
) {
let permissions =
@ -358,8 +360,11 @@ export class CommandClient extends Client implements CommandClientOptions {
if (beforeExecute === false) return
const result = await command.execute(ctx)
command.afterExecute(ctx, result)
await command.afterExecute(ctx, result)
} catch (e) {
await command
.onError(ctx, e)
.catch((e: Error) => this.emit('commandError', ctx, e))
this.emit('commandError', ctx, e)
}
}
@ -375,7 +380,7 @@ export function command(options?: CommandOptions) {
})[name]
if (typeof prop !== 'function')
throw new Error('@command decorator can only be used on functions')
throw new Error('@command decorator can only be used on class methods')
const command = new Command()

View File

@ -5,7 +5,6 @@ import {
GuildTextChannelPayload,
MessageOptions,
MessagePayload,
MessageReference,
ModifyGuildTextChannelOption,
ModifyGuildTextChannelPayload,
Overwrite,
@ -13,8 +12,6 @@ import {
} from '../types/channel.ts'
import {
CHANNEL,
CHANNEL_MESSAGE,
CHANNEL_MESSAGES,
MESSAGE_REACTION_ME,
MESSAGE_REACTION_USER
} from '../types/endpoint.ts'
@ -62,42 +59,11 @@ export class TextChannel extends Channel {
option?: AllMessageOptions,
reply?: Message
): Promise<Message> {
if (typeof content === 'object') {
option = content
content = undefined
}
if (content === undefined && option === undefined) {
throw new Error('Either text or option is necessary.')
}
if (option instanceof Embed) {
option = {
embed: option
}
}
const payload: any = {
content: content,
embed: option?.embed,
file: option?.file,
files: option?.files,
tts: option?.tts,
allowed_mentions: option?.allowedMentions
}
if (reply !== undefined) {
const reference: MessageReference = {
message_id: reply.id,
channel_id: reply.channel.id,
guild_id: reply.guild?.id
}
payload.message_reference = reference
}
const resp = await this.client.rest.post(CHANNEL_MESSAGES(this.id), payload)
const res = new Message(this.client, resp, this, this.client.user as any)
await res.mentions.fromPayload(resp)
return res
return this.client.channels.sendMessage(
this,
content,
Object.assign(option ?? {}, { reply })
)
}
/**
@ -111,32 +77,7 @@ export class TextChannel extends Channel {
text?: string,
option?: MessageOptions
): Promise<Message> {
if (text === undefined && option === undefined) {
throw new Error('Either text or option is necessary.')
}
if (this.client.user === undefined) {
throw new Error('Client user has not initialized.')
}
const newMsg = await this.client.rest.patch(
CHANNEL_MESSAGE(
this.id,
typeof message === 'string' ? message : message.id
),
{
content: text,
embed: option?.embed !== undefined ? option.embed.toJSON() : undefined,
// Cannot upload new files with Message
// file: option?.file,
tts: option?.tts,
allowed_mentions: option?.allowedMentions
}
)
const res = new Message(this.client, newMsg, this, this.client.user)
await res.mentions.fromPayload(newMsg)
return res
return this.client.channels.editMessage(this, message, text, option)
}
/** Add a reaction to a Message in this Channel */

View File

@ -243,6 +243,20 @@ client.on('messageCreate', async (msg: Message) => {
buf += `\n${role.name}`
}
msg.reply(buf)
} else if (msg.content === '!timer') {
msg.channel.send('3...').then((msg) => {
setTimeout(() => {
msg.edit('2...').then((msg) => {
setTimeout(() => {
msg.edit('1...').then((msg) => {
setTimeout(() => {
msg.edit('ok wut')
}, 1000)
})
}, 1000)
})
}, 1000)
})
}
})

View File

@ -1,5 +1,5 @@
import { Embed } from '../structures/embed.ts'
import { MessageAttachment } from '../structures/message.ts'
import type { Message, MessageAttachment } from '../structures/message.ts'
import { EmojiPayload } from './emoji.ts'
import { MemberPayload } from './guild.ts'
import { UserPayload } from './user.ts'
@ -156,16 +156,26 @@ export interface MessagePayload {
stickers?: MessageStickerPayload[]
}
export enum AllowedMentionType {
Roles = 'roles',
Users = 'users',
Everyone = 'everyone'
}
export interface AllowedMentionsPayload {
parse?: AllowedMentionType[]
users?: string[]
roles?: string[]
replied_user?: boolean
}
export interface MessageOptions {
tts?: boolean
embed?: Embed
file?: MessageAttachment
files?: MessageAttachment[]
allowedMentions?: {
parse?: 'everyone' | 'users' | 'roles'
roles?: string[]
users?: string[]
}
allowedMentions?: AllowedMentionsPayload
reply?: Message | MessageReference | string
}
export interface ChannelMention {