Merge pull request #115 from DjDeveloperr/catch
add ChannelsManager#{sendMessage, editMessage} and Command#onError
			
			
This commit is contained in:
		
						commit
						b532a99eb4
					
				
					 8 changed files with 189 additions and 78 deletions
				
			
		|  | @ -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 */ | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -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 | ||||||
|  |  | ||||||
|  | @ -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() | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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 */ | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  |     }) | ||||||
|   } |   } | ||||||
| }) | }) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -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 { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue