From c342756e780cd3d0616695b27d821ed56a053f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=8B=E6=B4=9B=E4=BC=8A=E5=B0=94?= Date: Mon, 4 Nov 2024 14:59:23 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A1=A5=E9=BD=90=E4=BA=86=E7=A7=81?= =?UTF-8?q?=E8=81=8A=E4=BA=8B=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 3 +- package.json | 6 ++-- src/index.ts | 20 +++++++---- src/qqhook/api.ts | 17 --------- src/qqhook/api/index.ts | 78 +++++++++++++++++++++++++++++++++++++++++ src/qqhook/index.ts | 6 ++-- 6 files changed, 98 insertions(+), 32 deletions(-) delete mode 100644 src/qqhook/api.ts create mode 100644 src/qqhook/api/index.ts diff --git a/Dockerfile b/Dockerfile index 00ac5b1..b8534cc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ # 使用官方 Node.js 20.18.0 版本的 slim 镜像作为基础镜像 FROM node:20.18.0 -# 安装 Deno +# 安装 Deno (国内镜像加速) RUN curl -fsSL https://x.deno.js.cn/install.sh | sh # 将 Deno 的可执行文件路径添加到 PATH 环境变量中 @@ -15,7 +15,6 @@ WORKDIR /app COPY . . RUN npm config set registry https://registry.npmmirror.com -RUN npm install # 运行您的应用 CMD ["npm", "run", "dev"] diff --git a/package.json b/package.json index e813c0f..9c12249 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,10 @@ "scripts": { "dev": "deno run -A src/index.ts", "dev:linux": "/root/.deno/bin/deno run -A ./src/index.ts", - "nodemon": "deno run -A --watch src/index.ts", - "nodemon:linux": "/root/.deno/bin/deno run -A --watch ./src/index.ts", - "build:linux": "deno compile --no-check -o dist/test --target x86_64-unknown-linux-gnu -A src/index.ts", + "watch": "deno run -A --watch src/index.ts", + "watch:linux": "/root/.deno/bin/deno run -A --watch ./src/index.ts", "build:win": "deno compile --no-check -o dist/test --target x86_64-pc-windows-msvc -A src/index.ts", + "build:linux": "deno compile --no-check -o dist/test --target x86_64-unknown-linux-gnu -A src/index.ts", "docker": "docker build -t qqbot-image .", "docker:run": "docker run -d --rm --name qqbot-image-app -v ./db:/app/db -p 3000:3000 qqbot-image" }, diff --git a/src/index.ts b/src/index.ts index fef3990..5596717 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,7 +4,7 @@ import chalk from "chalk"; const config = await db_config_get(); -type T = 'GROUP_AT_MESSAGE_CREATE' | 'MESSAGE_CREATE'; +type T = 'C2C_MESSAGE_CREATE' | 'GROUP_AT_MESSAGE_CREATE' | 'MESSAGE_CREATE'; const app = new QQHook({ host: '127.0.0.1', @@ -14,21 +14,27 @@ const app = new QQHook({ path: '/webhook/qqbot' }); +app.on('C2C_MESSAGE_CREATE', data => { + console.log(chalk.red('私聊:'), data.content); + app.axios.post_msg_user(data.author.user_openid, { + msg_id: data.id, + content: `😅` + }) +}) + app.on('GROUP_AT_MESSAGE_CREATE', data => { // 用户在群聊@机器人发送消息 - // console.log(chalk.red('[还没打算做群聊]')); - // console.log(data); console.log(chalk.yellow('群聊:'), data.content); - app.axios.post(`/v2/groups/${data.group_openid}/messages`, { + + app.axios.post_msg_group(data.group_openid, { content: `😅`, msg_id: data.id - }) + }); }) app.on('MESSAGE_CREATE', data => { // 用户在文字子频道内发送的所有聊天消息(私域) console.log(chalk.yellow('文字子频道:'), data.content); - const reply = (res: string) => app.axios.post( - `/channels/${data.channel_id}/messages`, { + const reply = (res: string) => app.axios.post_msg_channel(data.channel_id, { content: res, msg_id: data.id }); diff --git a/src/qqhook/api.ts b/src/qqhook/api.ts deleted file mode 100644 index b8b6c6c..0000000 --- a/src/qqhook/api.ts +++ /dev/null @@ -1,17 +0,0 @@ -import axios from "axios"; - -export async function getAppAccessToken(appId: string, clientSecret: string) { - const ans = await axios.post('https://bots.qq.com/app/getAppAccessToken', { - appId, clientSecret - }).then(res => { - if (res.status === 200) { - const { access_token, expires_in } = res.data; - return { access_token, expires_in }; - } - throw new Error('Failed to get access token'); - }); - return ans as { - access_token: string; - expires_in: string; - }; -} diff --git a/src/qqhook/api/index.ts b/src/qqhook/api/index.ts new file mode 100644 index 0000000..33154d0 --- /dev/null +++ b/src/qqhook/api/index.ts @@ -0,0 +1,78 @@ +import axios, { AxiosHeaderValue, AxiosInstance, AxiosResponse, HeadersDefaults } from "axios"; + +export enum msg_type { + text = 0, + markdown = 2, + ark = 3, + embed = 4, + media = 7 +} + +export type post_msg_type = { + content?: string, + msg_type?: msg_type, + markdown?: Object, + keyboard?: Object, + ark?: Object, + media?: Object, + event_id?: string, + msg_id?: string, + msg_seq?: number, + embed?: Object +}; + +export type post_msg_type2 = { + content?: string, + embed?: Object, + ark?: Object, + message_reference?: Object, + image?: string, + msg_id?: string, + event_id?: string, + markdown?: Object +}; + +export class QQAxios { + private _axios: AxiosInstance = axios.create({ baseURL: 'https://api.sgroup.qq.com' }); + + public get defaults() { return this._axios.defaults; } + public get post() { return this._axios.post; } + + public static async getAppAccessToken(appId: string, clientSecret: string) { + const ans = await axios.post('https://bots.qq.com/app/getAppAccessToken', { + appId, clientSecret + }).then(res => { + if (res.status === 200) { + const { access_token, expires_in } = res.data; + return { access_token, expires_in }; + } + throw new Error('Failed to get access token'); + }); + return ans as { + access_token: string; + expires_in: string; + }; + } + + /** 单聊 */ + public async post_msg_user(openid: string, content: post_msg_type): Promise<{ + id: string, timestamp: number + }> { + return (await this._axios.post(`/v2/users/${openid}/messages`, content)).data; + } + + public async post_msg_group(group_openid: string, content: post_msg_type): Promise<{ + id: string, timestamp: number + }> { + return (await this._axios.post(`/v2/groups/${group_openid}/messages`, content)).data; + } + + public async post_msg_channel(channel_id: string, content: post_msg_type2): Promise { + return (await this._axios.post(`/channels/${channel_id}/messages`, content)).data; + } + + public async post_msg_dms(guild_id: string, content: post_msg_type2): Promise { + return (await this._axios.post(`/dms/${guild_id}/messages`, content)).data; + } + +} \ No newline at end of file diff --git a/src/qqhook/index.ts b/src/qqhook/index.ts index e7f928e..19e30f1 100644 --- a/src/qqhook/index.ts +++ b/src/qqhook/index.ts @@ -1,8 +1,8 @@ import Koa from "koa"; import { createRouter } from "./router/index.ts"; import axios, { type AxiosInstance } from "axios"; -import { getAppAccessToken } from "./api.ts"; import chalk from "chalk"; +import { QQAxios } from "./api/index.ts"; export type QQHookConfigType = { "account": string, @@ -26,7 +26,7 @@ export class QQHook extends Koa { qqbot: QQHookConfigType, path: string; }; - private _qqAxios: AxiosInstance = axios.create({ baseURL: 'https://api.sgroup.qq.com' }); + private _qqAxios: QQAxios = new QQAxios(); public get host() { return this._config.host; } public get port() { return this._config.port; } @@ -36,7 +36,7 @@ export class QQHook extends Koa { private async authFlushed() { try { const config = this._config.qqbot; - const auth = await getAppAccessToken(config.appId, config.secret); + const auth = await QQAxios.getAppAccessToken(config.appId, config.secret); this._qqAxios.defaults.headers.common['Authorization'] = `QQBot ${auth.access_token}`; this.context.log(chalk.yellow('[鉴权: 成功]'), auth.expires_in);