From c5d59e86c631ef236af1641e8d73b9c893a1bba1 Mon Sep 17 00:00:00 2001 From: Lex Lim Date: Mon, 13 Mar 2023 03:11:11 +0000 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=94=B9senderIdentity=E4=B8=BAchatId?= =?UTF-8?q?entity?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 530 ++++++++++++++++++---------- package.json | 2 +- src/App.ts | 14 + src/Config.ts | 7 + src/DatabaseManager.ts | 24 ++ src/EventManager.ts | 35 +- src/MessageStoreManager.ts | 9 + src/PluginManager.ts | 6 +- src/RobotManager.ts | 10 +- src/SessionManager.ts | 16 + src/controller/ChatGPTController.ts | 82 ++++- src/error/ConfigCheckError.ts | 1 - src/error/errors.ts | 26 ++ src/generator/TemplateFilter.ts | 2 +- src/global.d.ts | 7 + src/message/Chat.ts | 25 ++ src/message/Sender.ts | 19 +- src/orm/GroupDataModel.ts | 11 + src/orm/GroupUserDataModel.ts | 14 + src/orm/MessageLogModel.ts | 43 +++ src/orm/UserDataModel.ts | 11 + src/provider/PusherProvider.ts | 2 +- src/robot/QQRobot.ts | 23 +- src/robot/TelegramRobot.ts | 6 +- src/utils/contextHooks.ts | 26 ++ 25 files changed, 720 insertions(+), 231 deletions(-) create mode 100644 src/DatabaseManager.ts create mode 100644 src/MessageStoreManager.ts delete mode 100644 src/error/ConfigCheckError.ts create mode 100644 src/error/errors.ts create mode 100644 src/global.d.ts create mode 100644 src/message/Chat.ts create mode 100644 src/orm/GroupDataModel.ts create mode 100644 src/orm/GroupUserDataModel.ts create mode 100644 src/orm/MessageLogModel.ts create mode 100644 src/orm/UserDataModel.ts create mode 100644 src/utils/contextHooks.ts diff --git a/package-lock.json b/package-lock.json index 8ce191a..4a28086 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@waylaidwanderer/chatgpt-api": "file:../node-chatgpt-api", "cache-manager": "^5.1.7", "cache-manager-ioredis-yet": "^1.1.0", - "cache-manager-redis-yet": "^4.1.1", "chokidar": "^3.5.1", "decoders": "^1.25.3", "got": "^11.8.3", @@ -25,6 +24,7 @@ "koa-router": "^10.1.1", "lua-runner": "^2.0.3", "micromatch": "^4.0.4", + "mongoose": "^7.0.1", "node-schedule": "^2.0.0", "node-telegram-bot-api": "^0.58.0", "pusher": "^3.0.1", @@ -123,59 +123,6 @@ "resolved": "https://registry.npmmirror.com/@ioredis/commands/-/commands-1.2.0.tgz", "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" }, - "node_modules/@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/client": { - "version": "1.5.6", - "resolved": "https://registry.npmmirror.com/@redis/client/-/client-1.5.6.tgz", - "integrity": "sha512-dFD1S6je+A47Lj22jN/upVU2fj4huR7S9APd7/ziUXsIXDL+11GPYti4Suv5y8FuXaN+0ZG4JF+y1houEJ7ToA==", - "dependencies": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@redis/graph": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@redis/graph/-/graph-1.1.0.tgz", - "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/json": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@redis/json/-/json-1.0.4.tgz", - "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/search": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@redis/search/-/search-1.1.2.tgz", - "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/time-series": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.0.4.tgz", - "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz", @@ -475,6 +422,20 @@ "resolved": "https://registry.npmmirror.com/@types/triple-beam/-/triple-beam-1.3.2.tgz", "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmmirror.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "node_modules/@types/yaml": { "version": "1.9.7", "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", @@ -666,6 +627,14 @@ "node": ">=8" } }, + "node_modules/bson": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/bson/-/bson-5.0.1.tgz", + "integrity": "sha512-y09gBGusgHtinMon/GVbv1J6FrXhnr/+6hqLlSmEFzkz6PodqF6TxjyvfvY3AfO+oG1mgUtbC86xSbOlwvM62Q==", + "engines": { + "node": ">=14.20.1" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", @@ -707,24 +676,6 @@ "node": ">= 16.17.0" } }, - "node_modules/cache-manager-redis-yet": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/cache-manager-redis-yet/-/cache-manager-redis-yet-4.1.1.tgz", - "integrity": "sha512-3Mzug/4z57YXoFf8yF3U1B7Ga3ezeQR+xc1hgNVmoDk7mStdbSlnwoNSI8FoF7SBRy4MfBQXdg2zkWY7guqQzw==", - "dependencies": { - "@redis/bloom": "^1.0.2", - "@redis/client": "^1.3.0", - "@redis/graph": "^1.0.1", - "@redis/json": "^1.0.4", - "@redis/search": "^1.1.0", - "@redis/time-series": "^1.0.3", - "cache-manager": "^5.1.0", - "redis": "^4.3.1" - }, - "engines": { - "node": ">= 16.17.0" - } - }, "node_modules/cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -1309,14 +1260,6 @@ "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" }, - "node_modules/generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmmirror.com/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", - "engines": { - "node": ">= 4" - } - }, "node_modules/get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.nlark.com/get-intrinsic/download/get-intrinsic-1.1.1.tgz", @@ -1626,6 +1569,11 @@ "node": ">=12.22.0" } }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "node_modules/is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz", @@ -1871,6 +1819,14 @@ "node": ">=0.6.0" } }, + "node_modules/kareem": { + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/keygrip": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/keygrip/-/keygrip-1.1.0.tgz", @@ -2059,6 +2015,12 @@ "node": ">= 0.6" } }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", @@ -2130,6 +2092,88 @@ "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, + "node_modules/mongodb": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/mongodb/-/mongodb-5.1.0.tgz", + "integrity": "sha512-qgKb7y+EI90y4weY3z5+lIgm8wmexbonz0GalHkSElQXVKtRuwqXuhXKccyvIjXCJVy9qPV82zsinY0W1FBnJw==", + "dependencies": { + "bson": "^5.0.1", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=14.20.1" + }, + "optionalDependencies": { + "saslprep": "^1.0.3" + }, + "peerDependencies": { + "@aws-sdk/credential-providers": "^3.201.0", + "mongodb-client-encryption": "^2.3.0", + "snappy": "^7.2.2" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-providers": { + "optional": true + }, + "mongodb-client-encryption": { + "optional": true + }, + "snappy": { + "optional": true + } + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongoose": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/mongoose/-/mongoose-7.0.1.tgz", + "integrity": "sha512-fxm2bPRG457Hb8RLwN8cMCokK8HNem/7g+qp5SrHC7Pt4Z4jqn1+/3cuc8W7uqehKDWEtpirggI7uw08x2ZIjQ==", + "dependencies": { + "bson": "^5.0.1", + "kareem": "2.5.1", + "mongodb": "5.1.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/mongoose/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmmirror.com/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "dependencies": { + "debug": "4.x" + }, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", @@ -2498,22 +2542,6 @@ "node": ">=8.10.0" } }, - "node_modules/redis": { - "version": "4.6.5", - "resolved": "https://registry.npmmirror.com/redis/-/redis-4.6.5.tgz", - "integrity": "sha512-O0OWA36gDQbswOdUuAhRL6mTZpHFN525HlgZgDaVNgCJIAZR3ya06NTESb0R+TUZ+BFaDpz6NnnVvoMx9meUFg==", - "workspaces": [ - "./packages/*" - ], - "dependencies": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.5.6", - "@redis/graph": "1.1.0", - "@redis/json": "1.0.4", - "@redis/search": "1.1.2", - "@redis/time-series": "1.0.4" - } - }, "node_modules/redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/redis-errors/-/redis-errors-1.2.0.tgz", @@ -2645,6 +2673,18 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -2660,6 +2700,11 @@ "object-inspect": "^1.9.0" } }, + "node_modules/sift": { + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -2668,6 +2713,28 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmmirror.com/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, "node_modules/sorted-array-functions": { "version": "1.3.0", "resolved": "https://registry.npm.taobao.org/sorted-array-functions/download/sorted-array-functions-1.3.0.tgz", @@ -2681,6 +2748,15 @@ "node": ">=0.10.0" } }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, "node_modules/sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -2811,6 +2887,17 @@ "node": ">=0.8" } }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/triple-beam/-/triple-beam-1.3.0.tgz", @@ -2985,6 +3072,26 @@ "extsprintf": "^1.2.0" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", @@ -3067,11 +3174,6 @@ "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/yaml": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.8.3.tgz", @@ -3150,46 +3252,6 @@ "resolved": "https://registry.npmmirror.com/@ioredis/commands/-/commands-1.2.0.tgz", "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" }, - "@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "requires": {} - }, - "@redis/client": { - "version": "1.5.6", - "resolved": "https://registry.npmmirror.com/@redis/client/-/client-1.5.6.tgz", - "integrity": "sha512-dFD1S6je+A47Lj22jN/upVU2fj4huR7S9APd7/ziUXsIXDL+11GPYti4Suv5y8FuXaN+0ZG4JF+y1houEJ7ToA==", - "requires": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" - } - }, - "@redis/graph": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@redis/graph/-/graph-1.1.0.tgz", - "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", - "requires": {} - }, - "@redis/json": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@redis/json/-/json-1.0.4.tgz", - "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", - "requires": {} - }, - "@redis/search": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@redis/search/-/search-1.1.2.tgz", - "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", - "requires": {} - }, - "@redis/time-series": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@redis/time-series/-/time-series-1.0.4.tgz", - "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", - "requires": {} - }, "@sindresorhus/is": { "version": "4.6.0", "resolved": "https://registry.npmmirror.com/@sindresorhus/is/-/is-4.6.0.tgz", @@ -3482,6 +3544,20 @@ "resolved": "https://registry.npmmirror.com/@types/triple-beam/-/triple-beam-1.3.2.tgz", "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" }, + "@types/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog==" + }, + "@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmmirror.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "requires": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "@types/yaml": { "version": "1.9.7", "resolved": "https://registry.npmjs.org/@types/yaml/-/yaml-1.9.7.tgz", @@ -3658,6 +3734,11 @@ "fill-range": "^7.0.1" } }, + "bson": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/bson/-/bson-5.0.1.tgz", + "integrity": "sha512-y09gBGusgHtinMon/GVbv1J6FrXhnr/+6hqLlSmEFzkz6PodqF6TxjyvfvY3AfO+oG1mgUtbC86xSbOlwvM62Q==" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", @@ -3690,21 +3771,6 @@ "ioredis": "^5.2.3" } }, - "cache-manager-redis-yet": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/cache-manager-redis-yet/-/cache-manager-redis-yet-4.1.1.tgz", - "integrity": "sha512-3Mzug/4z57YXoFf8yF3U1B7Ga3ezeQR+xc1hgNVmoDk7mStdbSlnwoNSI8FoF7SBRy4MfBQXdg2zkWY7guqQzw==", - "requires": { - "@redis/bloom": "^1.0.2", - "@redis/client": "^1.3.0", - "@redis/graph": "^1.0.1", - "@redis/json": "^1.0.4", - "@redis/search": "^1.1.0", - "@redis/time-series": "^1.0.3", - "cache-manager": "^5.1.0", - "redis": "^4.3.1" - } - }, "cacheable-lookup": { "version": "5.0.4", "resolved": "https://registry.npmmirror.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", @@ -4184,11 +4250,6 @@ "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" }, - "generic-pool": { - "version": "3.9.0", - "resolved": "https://registry.npmmirror.com/generic-pool/-/generic-pool-3.9.0.tgz", - "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" - }, "get-intrinsic": { "version": "1.1.1", "resolved": "https://registry.nlark.com/get-intrinsic/download/get-intrinsic-1.1.1.tgz", @@ -4432,6 +4493,11 @@ "standard-as-callback": "^2.1.0" } }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, "is-arrayish": { "version": "0.3.2", "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz", @@ -4625,6 +4691,11 @@ "verror": "1.10.0" } }, + "kareem": { + "version": "2.5.1", + "resolved": "https://registry.npmmirror.com/kareem/-/kareem-2.5.1.tgz", + "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==" + }, "keygrip": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/keygrip/-/keygrip-1.1.0.tgz", @@ -4789,6 +4860,12 @@ "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmmirror.com/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz", @@ -4838,6 +4915,60 @@ "resolved": "https://registry.npmmirror.com/minimist/-/minimist-1.2.6.tgz", "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, + "mongodb": { + "version": "5.1.0", + "resolved": "https://registry.npmmirror.com/mongodb/-/mongodb-5.1.0.tgz", + "integrity": "sha512-qgKb7y+EI90y4weY3z5+lIgm8wmexbonz0GalHkSElQXVKtRuwqXuhXKccyvIjXCJVy9qPV82zsinY0W1FBnJw==", + "requires": { + "bson": "^5.0.1", + "mongodb-connection-string-url": "^2.6.0", + "saslprep": "^1.0.3", + "socks": "^2.7.1" + } + }, + "mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmmirror.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "requires": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "mongoose": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/mongoose/-/mongoose-7.0.1.tgz", + "integrity": "sha512-fxm2bPRG457Hb8RLwN8cMCokK8HNem/7g+qp5SrHC7Pt4Z4jqn1+/3cuc8W7uqehKDWEtpirggI7uw08x2ZIjQ==", + "requires": { + "bson": "^5.0.1", + "kareem": "2.5.1", + "mongodb": "5.1.0", + "mpath": "0.9.0", + "mquery": "5.0.0", + "ms": "2.1.3", + "sift": "16.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "mpath": { + "version": "0.9.0", + "resolved": "https://registry.npmmirror.com/mpath/-/mpath-0.9.0.tgz", + "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==" + }, + "mquery": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/mquery/-/mquery-5.0.0.tgz", + "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "requires": { + "debug": "4.x" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz", @@ -5144,19 +5275,6 @@ "picomatch": "^2.2.1" } }, - "redis": { - "version": "4.6.5", - "resolved": "https://registry.npmmirror.com/redis/-/redis-4.6.5.tgz", - "integrity": "sha512-O0OWA36gDQbswOdUuAhRL6mTZpHFN525HlgZgDaVNgCJIAZR3ya06NTESb0R+TUZ+BFaDpz6NnnVvoMx9meUFg==", - "requires": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.5.6", - "@redis/graph": "1.1.0", - "@redis/json": "1.0.4", - "@redis/search": "1.1.2", - "@redis/time-series": "1.0.4" - } - }, "redis-errors": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/redis-errors/-/redis-errors-1.2.0.tgz", @@ -5259,6 +5377,15 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, "setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -5274,6 +5401,11 @@ "object-inspect": "^1.9.0" } }, + "sift": { + "version": "16.0.1", + "resolved": "https://registry.npmmirror.com/sift/-/sift-16.0.1.tgz", + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + }, "simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -5282,6 +5414,20 @@ "is-arrayish": "^0.3.1" } }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmmirror.com/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, "sorted-array-functions": { "version": "1.3.0", "resolved": "https://registry.npm.taobao.org/sorted-array-functions/download/sorted-array-functions-1.3.0.tgz", @@ -5292,6 +5438,15 @@ "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", @@ -5395,6 +5550,14 @@ "punycode": "^2.1.1" } }, + "tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "requires": { + "punycode": "^2.1.1" + } + }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmmirror.com/triple-beam/-/triple-beam-1.3.0.tgz", @@ -5513,6 +5676,20 @@ "extsprintf": "^1.2.0" } }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==" + }, + "whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "requires": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + } + }, "which-boxed-primitive": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", @@ -5587,11 +5764,6 @@ "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "yaml": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.8.3.tgz", diff --git a/package.json b/package.json index ea3b8e4..ecfee24 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ "@waylaidwanderer/chatgpt-api": "file:../node-chatgpt-api", "cache-manager": "^5.1.7", "cache-manager-ioredis-yet": "^1.1.0", - "cache-manager-redis-yet": "^4.1.1", "chokidar": "^3.5.1", "decoders": "^1.25.3", "got": "^11.8.3", @@ -32,6 +31,7 @@ "koa-router": "^10.1.1", "lua-runner": "^2.0.3", "micromatch": "^4.0.4", + "mongoose": "^7.0.1", "node-schedule": "^2.0.0", "node-telegram-bot-api": "^0.58.0", "pusher": "^3.0.1", diff --git a/src/App.ts b/src/App.ts index 0f41093..ce2fe33 100644 --- a/src/App.ts +++ b/src/App.ts @@ -16,6 +16,9 @@ import { RobotManager } from './RobotManager'; import { Service, ServiceManager } from './ServiceManager'; import { SubscribeManager, Target } from './SubscribeManager'; import { SessionManager } from './SessionManager'; +import { DatabaseManager } from './DatabaseManager'; + +export * from './utils/contextHooks'; export default class App { public config: Config; @@ -28,6 +31,7 @@ export default class App { public logger!: winston.Logger; public event!: EventManager; public session!: SessionManager; + public database?: DatabaseManager; public robot!: RobotManager; public provider!: ProviderManager; public service!: ServiceManager; @@ -40,6 +44,8 @@ export default class App { this.config = Yaml.parse(fs.readFileSync(configFile, { encoding: 'utf-8' })); this.debug = this.config.debug; + (import.meta as any)._isekaiFeedbotApp = this; + this.initialize(); } @@ -48,6 +54,7 @@ export default class App { await this.initRestfulApiManager(); await this.initEventManager(); await this.initSessionManager(); + await this.initDatabaseManager(); await this.initRobot(); await this.initProviderManager(); await this.initServiceManager(); @@ -114,6 +121,13 @@ export default class App { await this.session.initialize(); } + async initDatabaseManager() { + if (this.config.db) { + this.database = new DatabaseManager(this, this.config.db); + await this.database.initialize(); + } + } + async initRobot() { this.robot = new RobotManager(this, this.config.robot); await this.robot.initialize(); diff --git a/src/Config.ts b/src/Config.ts index 01f3ad8..f2f4429 100644 --- a/src/Config.ts +++ b/src/Config.ts @@ -10,6 +10,7 @@ export type Config = { robot: Record; service: Record; session: SessionConfig; + db?: DatabaseConfig; http_api: RestfulApiConfig; command_override?: CommandOverrideConfig; focused_as_command?: true; @@ -43,6 +44,12 @@ export type SessionConfig = { ttl?: number }; +export type DatabaseConfig = { + url: string; + user?: string; + password?: string; +} + export type ChannelConfig = any; export type GeneratorConfig = { diff --git a/src/DatabaseManager.ts b/src/DatabaseManager.ts new file mode 100644 index 0000000..9f962bb --- /dev/null +++ b/src/DatabaseManager.ts @@ -0,0 +1,24 @@ +import mongoose from "mongoose"; +import App from "./App"; +import { DatabaseConfig } from "./Config"; + +export class DatabaseManager { + private app: App; + private config: DatabaseConfig; + + constructor(app: App, config: DatabaseConfig) { + this.app = app; + this.config = config; + } + + async initialize() { + let options: mongoose.ConnectOptions = {}; + if (this.config.user) { + options.auth = { + username: this.config.user, + password: this.config.password + }; + } + await mongoose.connect(this.config.url, options); + } +} \ No newline at end of file diff --git a/src/EventManager.ts b/src/EventManager.ts index 8902a49..332702d 100644 --- a/src/EventManager.ts +++ b/src/EventManager.ts @@ -1,7 +1,8 @@ import App from "./App"; import { CommandOverrideConfig } from "./Config"; +import { PermissionDeniedError, RateLimitError } from "./error/errors"; import { CommonReceivedMessage, CommonSendMessage } from "./message/Message"; -import { SenderIdentity } from "./message/Sender"; +import { ChatIdentity } from "./message/Sender"; import { CommandInfo, EventScope, MessageEventOptions, MessagePriority, PluginEvent } from "./PluginManager"; import { Robot } from "./RobotManager"; @@ -140,7 +141,7 @@ export class EventManager { } } - public async emit(eventName: string, senderInfo?: SenderIdentity | null, ...args: any[]) { + public async emit(eventName: string, senderInfo?: ChatIdentity | null, ...args: any[]) { if (this.app.debug) { if (args[0] instanceof CommonReceivedMessage) { this.app.logger.debug(`触发事件 ${eventName} ${args[0].contentText}`); @@ -160,6 +161,24 @@ export class EventManager { isResolved = true; }; + const buildOnError = (eventInfo: ControllerEventInfo) => (error: Error) => { + this.app.logger.error(`${eventInfo.eventScope.controller?.id} 处理事件 ${eventName} 时出错`, error); + console.error(error); + + for (let arg of args) { + if (arg instanceof CommonReceivedMessage) { + const msg = arg; + if (error instanceof RateLimitError) { + const retryAfterMinutes = Math.ceil(error.retryAfter / 60); + msg.sendReply(`使用太多了,${retryAfterMinutes}分钟后再试吧`); + } else if (error instanceof PermissionDeniedError) { + msg.sendReply(`使用此功能需要${error.requiredPermission}权限`); + } + break; + } + } + } + let [subscribedControllers, disabledControllers] = this.getControllerSubscribe(senderInfo); for (let eventInfo of eventList) { @@ -211,14 +230,10 @@ export class EventManager { } // detect ret is promise if (ret && typeof ret.catch === 'function') { - ret.catch((err: any) => { - this.app.logger.error(`事件 ${eventName} 处理失败: `, err); - console.error(err); - }); + ret.catch(buildOnError(eventInfo)); } } catch(err: any) { - this.app.logger.error(`事件 ${eventName} 处理失败: `, err); - console.error(err); + buildOnError(eventInfo)(err); } } @@ -304,7 +319,7 @@ export class EventManager { } - public getSenderInfo(message: CommonReceivedMessage): SenderIdentity { + public getSenderInfo(message: CommonReceivedMessage): ChatIdentity { if (message.origin === 'private') { return { type: 'private', @@ -326,7 +341,7 @@ export class EventManager { } } - public getControllerSubscribe(senderInfo?: SenderIdentity | null): [string[], string[]] { + public getControllerSubscribe(senderInfo?: ChatIdentity | null): [string[], string[]] { let subscribedCommands: string[] = []; let disabledCommands: string[] = []; diff --git a/src/MessageStoreManager.ts b/src/MessageStoreManager.ts new file mode 100644 index 0000000..d3996dc --- /dev/null +++ b/src/MessageStoreManager.ts @@ -0,0 +1,9 @@ +import App from "./App"; + +export class MessageStoreManager { + private app: App; + + constructor(app: App) { + this.app = app; + } +} \ No newline at end of file diff --git a/src/PluginManager.ts b/src/PluginManager.ts index 51ade86..a02bb05 100644 --- a/src/PluginManager.ts +++ b/src/PluginManager.ts @@ -8,7 +8,7 @@ import Yaml from 'yaml'; import App from "./App"; import EventEmitter from "events"; import path from "path"; -import { SenderIdentity } from "./message/Sender"; +import { ChatIdentity } from "./message/Sender"; import { Utils } from "./utils/Utils"; export const MessagePriority = { @@ -240,7 +240,7 @@ export class PluginManager extends EventEmitter { * @param senderInfo * @returns */ - public getSubscribedControllers(senderInfo: SenderIdentity): PluginController[] { + public getSubscribedControllers(senderInfo: ChatIdentity): PluginController[] { let [subscribedControllers, disabledControllers] = this.app.event.getControllerSubscribe(senderInfo); return Object.values(this.controllers).filter((controller) => { @@ -521,7 +521,7 @@ export class PluginEvent extends EventScope { public allowedRobotTypeList: AllowedList = '*'; - public isAllowSubscribe: (source: SenderIdentity) => boolean = (source) => { + public isAllowSubscribe: (source: ChatIdentity) => boolean = (source) => { if (this.allowedRobotTypeList !== '*' && !this.allowedRobotTypeList.includes(source.robot.type)) { return false; } diff --git a/src/RobotManager.ts b/src/RobotManager.ts index 294f9f6..c01f067 100644 --- a/src/RobotManager.ts +++ b/src/RobotManager.ts @@ -5,7 +5,7 @@ import App from "./App"; import { MultipleMessage } from "./base/provider/BaseProvider"; import { RobotConfig } from "./Config"; import { CommonGroupMessage, CommonPrivateMessage, CommonReceivedMessage, CommonSendMessage } from "./message/Message"; -import { GroupSender, SenderIdentity, UserSender } from "./message/Sender"; +import { GroupSender, ChatIdentity, UserSender } from "./message/Sender"; import { CommandInfo } from "./PluginManager"; import { RestfulApiManager, RestfulContext, RestfulRouter } from "./RestfulApiManager"; import { SessionStore } from "./SessionManager"; @@ -19,9 +19,11 @@ export interface Robot { initialize?: () => Promise; initRestfulApi?: (router: RestfulRouter, api: RestfulApiManager) => Promise; setCommands?(commands: CommandInfo[]): Promise; + sendTyping?(chatIdentity: ChatIdentity): Promise; sendMessage(message: CommonSendMessage): Promise; sendPushMessage(targets: Target[], message: string): Promise; - getSession(senderIdentity: SenderIdentity, type: string): SessionStore; + deleteMessage?(chatIdentity: ChatIdentity, messageId: string): Promise; + getSession(chatIdentity: ChatIdentity, type: string): SessionStore; } export class RobotManager { @@ -116,7 +118,7 @@ export class RobotManager { } public getSenderIdentity(robot: Robot, message: CommonReceivedMessage) { - let sender: SenderIdentity = { + let sender: ChatIdentity = { robot: robot, type: 'raw', }; @@ -135,7 +137,7 @@ export class RobotManager { return sender; } - public getSessionPath(sender: SenderIdentity, type: string = 'chat'): string[] { + public getSessionPath(sender: ChatIdentity, type: string = 'chat'): string[] { if (type === 'global') { // 全局Session return ['global']; } diff --git a/src/SessionManager.ts b/src/SessionManager.ts index 48a0cb0..78b08cc 100644 --- a/src/SessionManager.ts +++ b/src/SessionManager.ts @@ -3,6 +3,7 @@ import { redisStore } from "cache-manager-ioredis-yet"; import App from "./App"; import { SessionConfig } from "./Config"; +import { RateLimitError } from "./error/errors"; export class SessionManager { private app: App; @@ -133,4 +134,19 @@ export class SessionStore implements Cache { await this.set(key, requestCountData, Math.max(1, requestCountData.startTime + ttl - currentTime)); } + + /** + * 限流,如果超过限制则抛出异常 + * @param key + * @param limit + * @param ttl + * @param readOnly 仅读取,不记录请求 + */ + public async rateLimit(key: string, limit: number, ttl: number, readOnly = false): Promise { + const waitTime = await this.getRateLimit(key, limit, ttl); + if (waitTime) { + throw new RateLimitError(waitTime); + } + await this.addRequestCount(key, ttl); + } } \ No newline at end of file diff --git a/src/controller/ChatGPTController.ts b/src/controller/ChatGPTController.ts index 907b4e1..6eacae1 100644 --- a/src/controller/ChatGPTController.ts +++ b/src/controller/ChatGPTController.ts @@ -51,6 +51,7 @@ export default class ChatGPTController implements PluginController { browser_api: { token: '', cookies: '', + buffer_size: 100, }, openai_api: { token: '', @@ -66,6 +67,7 @@ export default class ChatGPTController implements PluginController { max_input_tokens: 1000, } }, + gatekeeper_url: '', rate_limit: 2, rate_limit_minutes: 5, } @@ -145,6 +147,21 @@ export default class ChatGPTController implements PluginController { await message.sendReply('说点什么啊', true); return; } + if (this.config.gatekeeper_url) { + try { + let response = await got.post(this.config.gatekeeper_url, { + json: { + text: content, + }, + }).json(); + if (response.status == 1) { + await message.sendReply(response.message, true); + return; + } + } catch (e) { + console.error(e); + } + } const sessionStore = shareWithGroup ? message.session.group : message.session.chat; const userSessionStore = message.session.user; @@ -169,16 +186,44 @@ export default class ChatGPTController implements PluginController { this.app.logger.debug('ChatGPT chatSession', chatSession); - const lowSpeedTimer = setTimeout(() => { + let lowSpeedTimer: NodeJS.Timeout | null = setTimeout(() => { message.sendReply('生成对话速度较慢,请耐心等待', true); }, 10 * 1000); this.chatGenerating = true; try { + let buffer: string[] = []; + const flushBuffer = (force: boolean = false) => { + if (force || buffer.length > this.config.browser_api.buffer_size) { + if (lowSpeedTimer) { + clearInterval(lowSpeedTimer); + lowSpeedTimer = null; + } + + let content = buffer.join('').replace(/\n\n/g, '\n').trim(); + message.sendReply(content, true); + buffer = []; + } + } + const onProgress = (text: string) => { + if (text.includes('\n')) { + buffer.push(text); + flushBuffer(); + } else if (text === '[DONE]') { + flushBuffer(true); + } else { + buffer.push(text); + } + } if (!chatSession.conversationId) { - response = await this.chatGPTClient.sendMessage(this.DEFAULT_PROMPT + content); + response = await this.chatGPTClient.sendMessage(this.DEFAULT_PROMPT + content, { + onProgress + }); } else { - response = await this.chatGPTClient.sendMessage(content, chatSession); + response = await this.chatGPTClient.sendMessage(content, { + ...chatSession, + onProgress + }); } } catch (err: any) { this.app.logger.error('ChatGPT error', err); @@ -196,7 +241,11 @@ export default class ChatGPTController implements PluginController { await message.sendReply('生成对话失败: ' + err.toString(), true); return; } finally { - clearTimeout(lowSpeedTimer); + if (lowSpeedTimer) { + clearInterval(lowSpeedTimer); + lowSpeedTimer = null; + } + this.chatGenerating = false; } @@ -205,20 +254,10 @@ export default class ChatGPTController implements PluginController { } if (response.response) { - let reply: string = response.response ?? ''; - reply = reply.replace(/\n\n/g, '\n'); - /* - if (isFirstMessage) { - reply += '\n\n接下来的对话可以直接回复我。'; - } - */ - chatSession.conversationId = response.conversationId; chatSession.parentMessageId = response.messageId; await sessionStore.set(this.SESSION_KEY_CHAT_SESSION, chatSession, 600); - - await message.sendReply(reply, true); } } @@ -371,6 +410,21 @@ export default class ChatGPTController implements PluginController { await message.sendReply('说点什么啊', true); return; } + if (this.config.gatekeeper_url) { + try { + let response = await got.post(this.config.gatekeeper_url, { + json: { + text: content, + }, + }).json(); + if (response.status == 1) { + await message.sendReply(response.message, true); + return; + } + } catch (e) { + console.error(e); + } + } const userSessionStore = message.session.user; // 使用频率限制 diff --git a/src/error/ConfigCheckError.ts b/src/error/ConfigCheckError.ts deleted file mode 100644 index 4d6ea91..0000000 --- a/src/error/ConfigCheckError.ts +++ /dev/null @@ -1 +0,0 @@ -export class ConfigCheckError extends Error { } \ No newline at end of file diff --git a/src/error/errors.ts b/src/error/errors.ts new file mode 100644 index 0000000..08d42f0 --- /dev/null +++ b/src/error/errors.ts @@ -0,0 +1,26 @@ +export class ConfigCheckError extends Error { + constructor(message: string) { + super(message); + this.name = 'ConfigCheckError'; + } +} + +export class RateLimitError extends Error { + public readonly retryAfter: number; + + constructor(retryAfter: number) { + super('Rate limit exceeded'); + this.name = 'RateLimitError'; + this.retryAfter = retryAfter; + } +} + +export class PermissionDeniedError extends Error { + public readonly requiredPermission: string; + + constructor(requiredPermission: string) { + super('Permission denied'); + this.name = 'PermissionDeniedError'; + this.requiredPermission = requiredPermission; + } +} \ No newline at end of file diff --git a/src/generator/TemplateFilter.ts b/src/generator/TemplateFilter.ts index cdb5d55..4dacab1 100644 --- a/src/generator/TemplateFilter.ts +++ b/src/generator/TemplateFilter.ts @@ -2,7 +2,7 @@ import Handlebars from "handlebars"; import App from "../App"; import { MultipleMessage } from "../base/provider/BaseProvider"; -import { ConfigCheckError } from "../error/ConfigCheckError"; +import { ConfigCheckError } from "../error/errors"; export type TemplateFilterConfig = { [key: string]: string }; diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..e2e838d --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,7 @@ +import App from "./App"; + +interface ImportMeta { + context: { + isekaiFeedbotApp: App; + } +} \ No newline at end of file diff --git a/src/message/Chat.ts b/src/message/Chat.ts new file mode 100644 index 0000000..5cc68c8 --- /dev/null +++ b/src/message/Chat.ts @@ -0,0 +1,25 @@ +import App from "../App"; +import { Robot } from "../RobotManager"; + +export class ChatThread { + private app: App; + private robot: Robot; + + public type: string; + public targetId: string; + + constructor(app: App, robot: Robot, type: string, targetId: string) { + this.app = app; + this.robot = robot; + this.type = type; + this.targetId = targetId; + } + + async sendTyping(isTyping: boolean): Promise { + return false; + } + + async deleteMessage(messageId: string): Promise { + return false; + } +} \ No newline at end of file diff --git a/src/message/Sender.ts b/src/message/Sender.ts index f2c3048..9ee806f 100644 --- a/src/message/Sender.ts +++ b/src/message/Sender.ts @@ -15,6 +15,8 @@ export class UserSender implements BaseSender { public userName?: string; public nickName?: string; + public accessGroup: string[] = []; + constructor(robot: Robot, uid: string) { this.robot = robot; this.uid = uid; @@ -24,15 +26,14 @@ export class UserSender implements BaseSender { return new UserSender(robot, ''); } - - get identity(): SenderIdentity { - let senderIdentity: SenderIdentity = { + get identity(): ChatIdentity { + let chatIdentity: ChatIdentity = { type: 'private', robot: this.robot, userId: this.uid, }; - return senderIdentity; + return chatIdentity; } get targetId() { @@ -66,8 +67,8 @@ export class GroupSender { this.uid = uid; } - get identity(): SenderIdentity { - let senderIdentity: SenderIdentity = { + get identity(): ChatIdentity { + let chatIdentity: ChatIdentity = { type: 'group', robot: this.robot, groupId: this.groupId, @@ -75,10 +76,10 @@ export class GroupSender { }; if (this.rootGroupId) { - senderIdentity.rootGroupId = this.rootGroupId; + chatIdentity.rootGroupId = this.rootGroupId; } - return senderIdentity; + return chatIdentity; } get targetId() { @@ -102,7 +103,7 @@ export class GroupSender { } } -export type SenderIdentity = { +export type ChatIdentity = { type: 'private' | 'group' | 'channel' | 'raw' | string, robot: Robot, rootGroupId?: string, diff --git a/src/orm/GroupDataModel.ts b/src/orm/GroupDataModel.ts new file mode 100644 index 0000000..bb8c2bd --- /dev/null +++ b/src/orm/GroupDataModel.ts @@ -0,0 +1,11 @@ +import { Schema } from "mongoose"; +import { ObjectId } from "mongodb"; + +export const GroupDataModel = new Schema({ + id: ObjectId, + groupId: String, + parentId: ObjectId, + name: String, + image: String, + extra: Object, +}); \ No newline at end of file diff --git a/src/orm/GroupUserDataModel.ts b/src/orm/GroupUserDataModel.ts new file mode 100644 index 0000000..efad0df --- /dev/null +++ b/src/orm/GroupUserDataModel.ts @@ -0,0 +1,14 @@ +import { Schema } from "mongoose"; +import { ObjectId } from "mongodb"; + +export const GroupUserDataModel = new Schema({ + id: ObjectId, + groupId: String, + uid: String, + userName: String, + nickName: String, + title: String, + role: String, + image: String, + extra: Object, +}); \ No newline at end of file diff --git a/src/orm/MessageLogModel.ts b/src/orm/MessageLogModel.ts new file mode 100644 index 0000000..a0e5d8f --- /dev/null +++ b/src/orm/MessageLogModel.ts @@ -0,0 +1,43 @@ +import { Schema } from "mongoose"; +import { ObjectId } from "mongodb"; + +export const MessageLogModel = new Schema({ + id: ObjectId, + messageId: String, + type: String, + origin: String, + chatIdentity: { + robotId: String, + uid: String, + groupId: String, + rootGroupId: String, + channelId: String, + }, + meta: { + repliedId: ObjectId, + repliedMessageId: String, + mentionedUsers: { + type: [ObjectId], + default: [] + }, + mentionedUids: { + type: [String], + default: [] + } + }, + isSend: Boolean, + contentText: String, + content: Object, + time: { + type: Date, + default: Date.now + }, + deleted: { + type: Boolean, + default: false + }, + extra: { + type: Object, + default: {}, + }, +}); \ No newline at end of file diff --git a/src/orm/UserDataModel.ts b/src/orm/UserDataModel.ts new file mode 100644 index 0000000..13aaa94 --- /dev/null +++ b/src/orm/UserDataModel.ts @@ -0,0 +1,11 @@ +import { Schema } from "mongoose"; +import { ObjectId } from "mongodb"; + +export const UserDataModel = new Schema({ + id: ObjectId, + uid: String, + userName: String, + nickName: String, + image: String, + extra: Object, +}); \ No newline at end of file diff --git a/src/provider/PusherProvider.ts b/src/provider/PusherProvider.ts index b56bb17..e823c0b 100644 --- a/src/provider/PusherProvider.ts +++ b/src/provider/PusherProvider.ts @@ -1,7 +1,7 @@ import App from "../App"; import { BaseProvider, MultipleMessage } from "../base/provider/BaseProvider"; import { ChannelConfig } from "../Config"; -import { ConfigCheckError } from "../error/ConfigCheckError"; +import { ConfigCheckError } from "../error/errors"; import PusherService from "../service/PusherService"; import { string, optional, object, guard } from "decoders"; diff --git a/src/robot/QQRobot.ts b/src/robot/QQRobot.ts index 3b1cbe7..bb207b7 100644 --- a/src/robot/QQRobot.ts +++ b/src/robot/QQRobot.ts @@ -10,7 +10,7 @@ import { convertMessageToQQChunk, parseQQMessageChunk, QQGroupMessage, QQGroupSe import { CommonReceivedMessage, CommonSendMessage } from "../message/Message"; import { PluginController } from "../PluginManager"; import { RobotConfig } from "../Config"; -import { SenderIdentity } from "../message/Sender"; +import { ChatIdentity } from "../message/Sender"; export type QQRobotConfig = RobotConfig & { uid: string; @@ -211,8 +211,8 @@ export default class QQRobot implements Robot { return null; } - getSession(senderIdentity: SenderIdentity, type: string) { - const sessionPath = this.app.robot.getSessionPath(senderIdentity, type); + getSession(chatIdentity: ChatIdentity, type: string) { + const sessionPath = this.app.robot.getSessionPath(chatIdentity, type); return this.app.session.getStore(sessionPath); } @@ -268,12 +268,18 @@ export default class QQRobot implements Robot { let msgData = await convertMessageToQQChunk(message); + let res: any = {}; if (message.origin === 'private') { this.app.logger.debug('[DEBUG] 发送私聊消息', message.targetId, msgData); - await this.sendToUser(message.targetId, msgData); + res = await this.sendToUser(message.targetId, msgData); } else if (message.origin === 'group') { this.app.logger.debug('[DEBUG] 发送群消息', message.targetId, msgData); - await this.sendToGroup(message.targetId, msgData); + res = await this.sendToGroup(message.targetId, msgData); + } + + // 保存 Message ID + if (res?.data?.message_id) { + message.id = res.data.message_id; } return message; @@ -301,6 +307,13 @@ export default class QQRobot implements Robot { } } + async deleteMessage(chatIdentity: ChatIdentity, messageId: string): Promise { + await this.doApiRequest('delete_msg', { + message_id: messageId + }); + return true; + } + async getGroupList(): Promise { const res = await this.doApiRequest('get_group_list', {}); if (res && res.status === 'ok') { diff --git a/src/robot/TelegramRobot.ts b/src/robot/TelegramRobot.ts index 6f4fa42..49145cb 100644 --- a/src/robot/TelegramRobot.ts +++ b/src/robot/TelegramRobot.ts @@ -2,7 +2,7 @@ import TelegramBot from "node-telegram-bot-api"; import App from "../App"; import { RobotConfig } from "../Config"; import { CommonSendMessage } from "../message/Message"; -import { SenderIdentity } from "../message/Sender"; +import { ChatIdentity } from "../message/Sender"; import { CommandInfo } from "../PluginManager"; import { Robot } from "../RobotManager"; import { Target } from "../SubscribeManager"; @@ -77,8 +77,8 @@ export default class TelegramRobot implements Robot { */ } - getSession(senderIdentity: SenderIdentity, type: string) { - const sessionPath = this.app.robot.getSessionPath(senderIdentity, type); + getSession(chatIdentity: ChatIdentity, type: string) { + const sessionPath = this.app.robot.getSessionPath(chatIdentity, type); return this.app.session.getStore(sessionPath); } diff --git a/src/utils/contextHooks.ts b/src/utils/contextHooks.ts new file mode 100644 index 0000000..01e581e --- /dev/null +++ b/src/utils/contextHooks.ts @@ -0,0 +1,26 @@ +import winston from "winston"; +import App from "../App"; + +export function useApp(): App { + return (import.meta as any)._isekaiFeedbotApp; +} + +export function useLogger(): winston.Logger { + return useApp().logger; +} + +export function useEventManager() { + return useApp().event; +} + +export function useSessionManager() { + return useApp().session; +} + +export function useRobotManager() { + return useApp().robot; +} + +export function useRestfulApiManager() { + return useApp().restfulApi; +} \ No newline at end of file