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 arr = (await this.array()) ?? []
const { readable, writable } = new TransformStream() const { readable, writable } = new TransformStream()
arr.forEach((el) => writable.getWriter().write(el)) 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 */ /** Deletes everything from Cache */

View File

@ -44,6 +44,20 @@ export class BaseChildManager<T, T2> {
const arr = (await this.array()) ?? [] const arr = (await this.array()) ?? []
const { readable, writable } = new TransformStream() const { readable, writable } = new TransformStream()
arr.forEach((el: unknown) => writable.getWriter().write(el)) 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 { Client } from '../models/client.ts'
import { Channel } from '../structures/channel.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 { CHANNEL } from '../types/endpoint.ts'
import getChannelByType from '../utils/getChannelByType.ts' import getChannelByType from '../utils/getChannelByType.ts'
import { BaseManager } from './base.ts' import { BaseManager } from './base.ts'
export type AllMessageOptions = MessageOptions | Embed
export class ChannelsManager extends BaseManager<ChannelPayload, Channel> { export class ChannelsManager extends BaseManager<ChannelPayload, Channel> {
constructor(client: Client) { constructor(client: Client) {
super(client, 'channels', Channel) super(client, 'channels', Channel)
@ -66,4 +75,105 @@ export class ChannelsManager extends BaseManager<ChannelPayload, Channel> {
.catch((e) => reject(e)) .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 dmOnly?: boolean
ownerOnly?: 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) */ /** Method executed before executing actual command. Returns bool value - whether to continue or not (optional) */
beforeExecute(ctx: CommandContext): boolean | Promise<boolean> { beforeExecute(ctx: CommandContext): boolean | Promise<boolean> {
return true return true

View File

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

View File

@ -5,7 +5,6 @@ import {
GuildTextChannelPayload, GuildTextChannelPayload,
MessageOptions, MessageOptions,
MessagePayload, MessagePayload,
MessageReference,
ModifyGuildTextChannelOption, ModifyGuildTextChannelOption,
ModifyGuildTextChannelPayload, ModifyGuildTextChannelPayload,
Overwrite, Overwrite,
@ -13,8 +12,6 @@ import {
} from '../types/channel.ts' } from '../types/channel.ts'
import { import {
CHANNEL, CHANNEL,
CHANNEL_MESSAGE,
CHANNEL_MESSAGES,
MESSAGE_REACTION_ME, MESSAGE_REACTION_ME,
MESSAGE_REACTION_USER MESSAGE_REACTION_USER
} from '../types/endpoint.ts' } from '../types/endpoint.ts'
@ -62,42 +59,11 @@ export class TextChannel extends Channel {
option?: AllMessageOptions, option?: AllMessageOptions,
reply?: Message reply?: Message
): Promise<Message> { ): Promise<Message> {
if (typeof content === 'object') { return this.client.channels.sendMessage(
option = content this,
content = undefined content,
} Object.assign(option ?? {}, { reply })
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
} }
/** /**
@ -111,32 +77,7 @@ export class TextChannel extends Channel {
text?: string, text?: string,
option?: MessageOptions option?: MessageOptions
): Promise<Message> { ): Promise<Message> {
if (text === undefined && option === undefined) { return this.client.channels.editMessage(this, message, text, option)
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
} }
/** Add a reaction to a Message in this Channel */ /** 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}` buf += `\n${role.name}`
} }
msg.reply(buf) 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 { 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 { EmojiPayload } from './emoji.ts'
import { MemberPayload } from './guild.ts' import { MemberPayload } from './guild.ts'
import { UserPayload } from './user.ts' import { UserPayload } from './user.ts'
@ -156,16 +156,26 @@ export interface MessagePayload {
stickers?: MessageStickerPayload[] 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 { export interface MessageOptions {
tts?: boolean tts?: boolean
embed?: Embed embed?: Embed
file?: MessageAttachment file?: MessageAttachment
files?: MessageAttachment[] files?: MessageAttachment[]
allowedMentions?: { allowedMentions?: AllowedMentionsPayload
parse?: 'everyone' | 'users' | 'roles' reply?: Message | MessageReference | string
roles?: string[]
users?: string[]
}
} }
export interface ChannelMention { export interface ChannelMention {