harmony/src/structures/message.ts

233 lines
6.9 KiB
TypeScript

import { SnowflakeBase } from './base.ts'
import {
Attachment,
MessageActivity,
MessageApplication,
MessageOptions,
MessagePayload,
MessageReference
} from '../types/channel.ts'
import { Client } from '../models/client.ts'
import { User } from './user.ts'
import { Member } from './member.ts'
import { Embed } from './embed.ts'
import { CHANNEL_MESSAGE } from '../types/endpoint.ts'
import { MessageMentions } from './messageMentions.ts'
import { TextChannel } from './textChannel.ts'
import { GuildTextBasedChannel } from './guildTextChannel.ts'
import { Guild } from './guild.ts'
import { MessageReactionsManager } from '../managers/messageReactions.ts'
import { MessageSticker } from './messageSticker.ts'
import { Emoji } from './emoji.ts'
type AllMessageOptions = MessageOptions | Embed
export class Message extends SnowflakeBase {
id: string
channelID: string
channel: TextChannel
guildID?: string
guild?: Guild
author: User
member?: Member
content: string
editedTimestamp?: Date
tts: boolean
mentions: MessageMentions
attachments: Attachment[]
embeds: Embed[]
reactions: MessageReactionsManager
nonce?: string | number
pinned: boolean
webhookID?: string
type: number
activity?: MessageActivity
application?: MessageApplication
messageReference?: MessageReference
flags?: number
stickers?: MessageSticker[]
get createdAt(): Date {
return new Date(this.timestamp)
}
constructor(
client: Client,
data: MessagePayload,
channel: TextChannel,
author: User
) {
super(client)
this.id = data.id
this.channelID = data.channel_id
this.guildID = data.guild_id
this.author = author
this.content = data.content
this.editedTimestamp =
data.edited_timestamp === undefined
? undefined
: new Date(data.edited_timestamp)
this.tts = data.tts
this.mentions = new MessageMentions(this.client, this)
this.attachments = data.attachments
this.embeds = data.embeds.map((v) => new Embed(v))
this.reactions = new MessageReactionsManager(this.client, this)
this.nonce = data.nonce
this.pinned = data.pinned
this.webhookID = data.webhook_id
this.type = data.type
this.activity = data.activity
this.application = data.application
this.messageReference = data.message_reference
this.flags = data.flags
this.channel = channel
this.stickers =
data.stickers !== undefined
? data.stickers.map(
(payload) => new MessageSticker(this.client, payload)
)
: undefined
}
readFromData(data: MessagePayload): void {
this.channelID = data.channel_id ?? this.channelID
this.guildID = data.guild_id ?? this.guildID
this.content = data.content ?? this.content
this.editedTimestamp =
data.edited_timestamp === undefined
? this.editedTimestamp
: new Date(data.edited_timestamp)
this.tts = data.tts ?? this.tts
this.attachments = data.attachments ?? this.attachments
this.embeds = data.embeds.map((v) => new Embed(v)) ?? this.embeds
this.nonce = data.nonce ?? this.nonce
this.pinned = data.pinned ?? this.pinned
this.webhookID = data.webhook_id ?? this.webhookID
this.type = data.type ?? this.type
this.activity = data.activity ?? this.activity
this.application = data.application ?? this.application
this.messageReference = data.message_reference ?? this.messageReference
this.flags = data.flags ?? this.flags
this.stickers =
data.stickers !== undefined
? data.stickers.map(
(payload) => new MessageSticker(this.client, payload)
)
: this.stickers
}
async updateRefs(): Promise<void> {
if (this.guildID !== undefined)
this.guild = await this.client.guilds.get(this.guildID)
const newVal = await this.client.channels.get<TextChannel>(this.channelID)
if (newVal !== undefined) this.channel = newVal
const newUser = await this.client.users.get(this.author.id)
if (newUser !== undefined) this.author = newUser
if (this.member !== undefined) {
const newMember = await this.guild?.members.get(this.member?.id)
if (newMember !== undefined) this.member = newMember
}
if (
((this.channel as unknown) as GuildTextBasedChannel).guild !== undefined
)
this.guild = ((this.channel as unknown) as GuildTextBasedChannel).guild
if (this.guild !== undefined && this.guildID === undefined)
this.guildID = this.guild.id
}
/** Edits this message. */
async edit(
content?: string | AllMessageOptions,
option?: AllMessageOptions
): 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
}
}
if (
this.client.user !== undefined &&
this.author.id !== this.client.user?.id
) {
throw new Error("Cannot edit other users' messages")
}
return this.channel.editMessage(this.id, content, option)
}
/** Creates a Reply to this Message. */
async reply(
content?: string | AllMessageOptions,
option?: AllMessageOptions
): Promise<Message> {
return this.channel.send(content, option, this)
}
/** Deletes the Message. */
async delete(): Promise<void> {
return this.client.rest.delete(CHANNEL_MESSAGE(this.channelID, this.id))
}
/**
* Adds a reaction to the message.
* @param emoji Emoji in string or object
*/
async addReaction(emoji: string | Emoji): Promise<void> {
return this.channel.addReaction(this, emoji)
}
/**
* Removes a reaction to the message.
* @param emoji Emoji in string or object
* @param user User or Member or user id
*/
async removeReaction(
emoji: string | Emoji,
user?: User | Member | string
): Promise<void> {
return this.channel.removeReaction(this, emoji, user)
}
}
const encoder = new TextEncoder()
/** Message Attachment that can be sent while Creating Message */
export class MessageAttachment {
name: string
blob: Blob
constructor(name: string, blob: Blob | Uint8Array | string) {
this.name = name
this.blob =
typeof blob === 'string'
? new Blob([encoder.encode(blob)])
: blob instanceof Uint8Array
? new Blob([blob])
: blob
}
/** Load an Message Attachment from local file or URL */
static async load(
path: string,
filename?: string
): Promise<MessageAttachment> {
const blob = path.startsWith('http')
? await fetch(path).then((res) => res.blob())
: await Deno.readFile(path)
if (filename === undefined) {
const split = path.replaceAll('\\', '/').split('/').pop()
if (split !== undefined) filename = split.split('?')[0].split('#')[0]
else filename = 'unnamed_attachment'
}
return new MessageAttachment(filename, blob)
}
}