From 02b1d28a6bfd15837238af2335b13f8650346fd2 Mon Sep 17 00:00:00 2001 From: CrescentLeaf Date: Fri, 28 Nov 2025 23:10:20 +0800 Subject: [PATCH] =?UTF-8?q?feat(client-protocol):=20=E5=8F=AF=E4=BB=A5?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E6=B6=88=E6=81=AF=E5=95=A6=20*=20=E4=B8=BA?= =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E9=87=8D=E6=9E=84=E5=A5=A0=E5=AE=9A?= =?UTF-8?q?=E5=BA=93=E5=9F=BA=E7=A1=80=20*=20=E5=AF=B9=E5=A4=96=E6=8F=90?= =?UTF-8?q?=E4=BE=9B=E4=BA=86=E6=AF=94=E8=BE=83=E6=96=B9=E4=BE=BF=E7=9A=84?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E6=B6=88=E6=81=AF=E9=99=84=E4=BB=B6=E5=8F=8A?= =?UTF-8?q?=E6=8F=90=E5=8F=8A=E7=9A=84=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client-protocol/Message.ts | 114 +++++++++++++++++++++++++++++++++++++ client-protocol/deno.jsonc | 3 +- 2 files changed, 116 insertions(+), 1 deletion(-) diff --git a/client-protocol/Message.ts b/client-protocol/Message.ts index 57dc679..1f4c571 100644 --- a/client-protocol/Message.ts +++ b/client-protocol/Message.ts @@ -3,6 +3,63 @@ import MessageBean from "./bean/MessageBean.ts" import LingChairClient from "./LingChairClient.ts" import Chat from "./Chat.ts" import User from "./User.ts" +import CallbackError from "./CallbackError.ts" +import ApiCallbackMessage from "./ApiCallbackMessage.ts" + +import marked from 'marked' + +class ChatMention extends BaseClientObject { + declare chat_id?: string + declare user_id?: string + constructor(client: LingChairClient, { + user_id, + chat_id, + }: { + user_id?: string, + chat_id?: string, + }) { + super(client) + this.user_id = user_id + this.chat_id = chat_id + } + async getChat() { + return await Chat.getById(this.client, this.chat_id as string) + } + async getUser() { + return await User.getById(this.client, this.user_id as string) + } +} + +type FileType = 'Video' | 'Image' | 'File' +type MentionType = 'ChatMention' | 'UserMention' + +class ChatAttachment extends BaseClientObject { + declare file_hash: string + constructor(client: LingChairClient, file_hash: string) { + super(client) + this.file_hash = file_hash + } + async blob() { + try { + return await this.blobOrThrow() + } catch (_) { + return null + } + } + async blobOrThrow() { + const url = this.client.getUrlForFileByHash(this.file_hash) + const re = await fetch(url!) + const blob = await re.blob() + if (!re.ok) throw new CallbackError({ + msg: await blob.text(), + code: re.status, + } as ApiCallbackMessage) + return blob + } + getFileHash() { + return this.file_hash + } +} export default class Message extends BaseClientObject { declare bean: MessageBean @@ -27,6 +84,63 @@ export default class Message extends BaseClientObject { getText() { return this.bean.text } + parseWithTransformers({ + attachment, + mention, + }: { + attachment?: ({ text, fileType, attachment }: { text: string, fileType: FileType, attachment: ChatAttachment }) => string, + mention?: ({ text, mentionType, mention }: { text: string, mentionType: MentionType, mention: ChatMention }) => string, + }) { + new marked.Marked({ + extensions: [ + { + name: 'image', + renderer: ({ text, href }) => { + const mentionType = /^(UserMention|ChatMention)=.*/.exec(text)?.[1] as MentionType + const fileType = (/^(Video|File|Image)=.*/.exec(text)?.[1] || 'Image') as FileType + + if (fileType != null && /tws:\/\/file\?hash=[A-Za-z0-9]+$/.test(href)) { + const file_hash = /^tws:\/\/file\?hash=(.*)/.exec(href)?.[1]! + return attachment ? attachment({ text: text, attachment: new ChatAttachment(this.client, file_hash), fileType: fileType, }) : text + } + if (mentionType != null && /^tws:\/\/chat\?id=[A-Za-z0-9]+/.test(href)) { + const id = /^tws:\/\/chat\?id=(.*)/.exec(href)?.[1]! + return mention ? mention({ + text: text, + mention: new ChatMention(this.client, { + [({ + ChatMention: 'chat_id', + UserMention: 'user_id', + })[mentionType]]: id + }), + mentionType: mentionType, + }) : text + } + }, + } + ] + }).parse(this.getText()) + } + getAttachments() { + const attachments: ChatAttachment[] = [] + this.parseWithTransformers({ + attachment({ attachment }) { + attachments.push(attachment) + return '' + } + }) + return attachments + } + getMentions() { + const mentions: ChatMention[] = [] + this.parseWithTransformers({ + mention({ mention }) { + mentions.push(mention) + return '' + } + }) + return mentions + } getUserId() { return this.bean.user_id } diff --git a/client-protocol/deno.jsonc b/client-protocol/deno.jsonc index 818504e..7b07fb4 100644 --- a/client-protocol/deno.jsonc +++ b/client-protocol/deno.jsonc @@ -1,6 +1,7 @@ { "imports": { "socket.io-client": "npm:socket.io-client@4.8.1", - "lingchair-internal-shared": "../internal-shared/mod.ts" + "lingchair-internal-shared": "../internal-shared/mod.ts", + "marked": "npm:marked@16.3.0" } } \ No newline at end of file