diff --git a/.gitignore b/.gitignore index 2576880..0332118 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ node_modules/ dist/ -.idea/ \ No newline at end of file +.idea/ +.DS_Store \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 3b11f41..19da495 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "llonebot", "version": "1.0.0", + "hasInstallScript": true, "license": "ISC", "dependencies": { "express": "^4.18.2", @@ -18,7 +19,6 @@ "@types/express": "^4.17.20", "@types/uuid": "^9.0.8", "babel-loader": "^9.1.3", - "electron": "^27.0.2", "ts-loader": "^9.5.0", "typescript": "^5.2.2", "webpack": "^5.89.0", @@ -2006,59 +2006,6 @@ "node": ">=10.0.0" } }, - "node_modules/@electron/get": { - "version": "2.0.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/@electron/get/-/get-2.0.3.tgz", - "integrity": "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/@electron/get/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@electron/get/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/@electron/get/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", @@ -2117,30 +2064,6 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://mirrors.cloud.tencent.com/npm/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@types/body-parser": { "version": "1.19.4", "resolved": "https://mirrors.cloud.tencent.com/npm/@types/body-parser/-/body-parser-1.19.4.tgz", @@ -2151,18 +2074,6 @@ "@types/node": "*" } }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, "node_modules/@types/connect": { "version": "3.4.37", "resolved": "https://mirrors.cloud.tencent.com/npm/@types/connect/-/connect-3.4.37.tgz", @@ -2222,12 +2133,6 @@ "@types/send": "*" } }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/@types/http-cache-semantics/-/http-cache-semantics-4.0.3.tgz", - "integrity": "sha512-V46MYLFp08Wf2mmaBhvgjStM3tPa+2GAdy/iqoX+noX1//zje2x4XmrIU0cAwyClATsTmahbtoQ2EwP7I5WSiA==", - "dev": true - }, "node_modules/@types/http-errors": { "version": "2.0.3", "resolved": "https://mirrors.cloud.tencent.com/npm/@types/http-errors/-/http-errors-2.0.3.tgz", @@ -2240,15 +2145,6 @@ "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", "dev": true }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/mime": { "version": "1.3.4", "resolved": "https://mirrors.cloud.tencent.com/npm/@types/mime/-/mime-1.3.4.tgz", @@ -2276,15 +2172,6 @@ "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==", "dev": true }, - "node_modules/@types/responselike": { - "version": "1.0.2", - "resolved": "https://mirrors.cloud.tencent.com/npm/@types/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/4YQT5Kp6HxUDb4yhRkm0bJ7TbjvTddqX7PZ5hz6qV3pxSo72f/6YPRo+Mu2DU307tm9IioO69l7uAwn5XNcFA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/send": { "version": "0.17.3", "resolved": "https://mirrors.cloud.tencent.com/npm/@types/send/-/send-0.17.3.tgz", @@ -2312,16 +2199,6 @@ "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", "dev": true }, - "node_modules/@types/yauzl": { - "version": "2.10.2", - "resolved": "https://mirrors.cloud.tencent.com/npm/@types/yauzl/-/yauzl-2.10.2.tgz", - "integrity": "sha512-Km7XAtUIduROw7QPgvcft0lIupeG8a8rdKL8RiSyKvlE7dYY31fEn41HVuQsRFDuROA8tA4K2UVL+WdfFmErBA==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@webassemblyjs/ast": { "version": "1.11.6", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", @@ -2790,13 +2667,6 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/boolean": { - "version": "3.2.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/boolean/-/boolean-3.2.0.tgz", - "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", - "dev": true, - "optional": true - }, "node_modules/braces": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", @@ -2841,15 +2711,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://mirrors.cloud.tencent.com/npm/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2864,33 +2725,6 @@ "node": ">= 0.8" } }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/call-bind": { "version": "1.0.5", "resolved": "https://mirrors.cloud.tencent.com/npm/call-bind/-/call-bind-1.0.5.tgz", @@ -2975,18 +2809,6 @@ "node": ">=6" } }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3097,42 +2919,6 @@ "ms": "2.0.0" } }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/define-data-property": { "version": "1.1.1", "resolved": "https://mirrors.cloud.tencent.com/npm/define-data-property/-/define-data-property-1.1.1.tgz", @@ -3146,24 +2932,6 @@ "node": ">= 0.4" } }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "optional": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/depd/-/depd-2.0.0.tgz", @@ -3181,51 +2949,17 @@ "npm": "1.2.8000 || >= 1.4.16" } }, - "node_modules/detect-node": { - "version": "2.1.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/detect-node/-/detect-node-2.1.0.tgz", - "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", - "dev": true, - "optional": true - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://mirrors.cloud.tencent.com/npm/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, - "node_modules/electron": { - "version": "27.0.2", - "resolved": "https://mirrors.cloud.tencent.com/npm/electron/-/electron-27.0.2.tgz", - "integrity": "sha512-4fbcHQ40ZDlqhr5Pamm+M5BF7ry2lGqjFTWTJ/mrBwuiPWu6xhV/RWgUhKBaLqKNfAaNl3eMxV3Jc82gv6JauQ==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@electron/get": "^2.0.0", - "@types/node": "^18.11.18", - "extract-zip": "^2.0.1" - }, - "bin": { - "electron": "cli.js" - }, - "engines": { - "node": ">= 12.20.55" - } - }, "node_modules/electron-to-chromium": { "version": "1.4.567", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.567.tgz", "integrity": "sha512-8KR114CAYQ4/r5EIEsOmOMqQ9j0MRbJZR3aXD/KFA8RuKzyoUB4XrUCg+l8RUGqTVQgKNIgTpjaG8YHRPAbX2w==", "dev": true }, - "node_modules/electron/node_modules/@types/node": { - "version": "18.18.7", - "resolved": "https://mirrors.cloud.tencent.com/npm/@types/node/-/node-18.18.7.tgz", - "integrity": "sha512-bw+lEsxis6eqJYW8Ql6+yTqkE6RuFtsQPSe5JxXbqYRFQEER5aJA9a5UH9igqDWm3X4iLHIKOHlnAXLM4mi7uQ==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://mirrors.cloud.tencent.com/npm/encodeurl/-/encodeurl-1.0.2.tgz", @@ -3234,15 +2968,6 @@ "node": ">= 0.8" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/enhanced-resolve": { "version": "5.15.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", @@ -3256,15 +2981,6 @@ "node": ">=10.13.0" } }, - "node_modules/env-paths": { - "version": "2.2.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/env-paths/-/env-paths-2.2.1.tgz", - "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/envinfo": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.10.0.tgz", @@ -3283,13 +2999,6 @@ "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==", "dev": true }, - "node_modules/es6-error": { - "version": "4.1.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/es6-error/-/es6-error-4.1.1.tgz", - "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", - "dev": true, - "optional": true - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3304,19 +3013,6 @@ "resolved": "https://mirrors.cloud.tencent.com/npm/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -3427,49 +3123,6 @@ "node": ">= 0.10.0" } }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extract-zip/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3491,15 +3144,6 @@ "node": ">= 4.9.1" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -3668,20 +3312,6 @@ "node": ">= 0.6" } }, - "node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://mirrors.cloud.tencent.com/npm/function-bind/-/function-bind-1.1.2.tgz", @@ -3714,61 +3344,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "node_modules/global-agent": { - "version": "3.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/global-agent/-/global-agent-3.0.0.tgz", - "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", - "dev": true, - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "es6-error": "^4.1.1", - "matcher": "^3.0.0", - "roarr": "^2.15.3", - "semver": "^7.3.2", - "serialize-error": "^7.0.1" - }, - "engines": { - "node": ">=10.0" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "optional": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/gopd/-/gopd-1.0.1.tgz", @@ -3780,31 +3361,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://mirrors.cloud.tencent.com/npm/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", @@ -3864,12 +3420,6 @@ "node": ">= 0.4" } }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/http-errors/-/http-errors-2.0.0.tgz", @@ -3885,19 +3435,6 @@ "node": ">= 0.8" } }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://mirrors.cloud.tencent.com/npm/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -4033,12 +3570,6 @@ "bignumber.js": "^9.0.0" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -4051,13 +3582,6 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true, - "optional": true - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://mirrors.cloud.tencent.com/npm/json5/-/json5-2.2.3.tgz", @@ -4071,24 +3595,6 @@ "node": ">=6" } }, - "node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "dev": true, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -4125,15 +3631,6 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -4146,19 +3643,6 @@ "node": ">=10" } }, - "node_modules/matcher": { - "version": "3.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/matcher/-/matcher-3.0.0.tgz", - "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", - "dev": true, - "optional": true, - "dependencies": { - "escape-string-regexp": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://mirrors.cloud.tencent.com/npm/media-typer/-/media-typer-0.3.0.tgz", @@ -4229,15 +3713,6 @@ "node": ">= 0.6" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.0.0.tgz", @@ -4263,18 +3738,6 @@ "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/object-inspect": { "version": "1.13.1", "resolved": "https://mirrors.cloud.tencent.com/npm/object-inspect/-/object-inspect-1.13.1.tgz", @@ -4283,16 +3746,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "optional": true, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://mirrors.cloud.tencent.com/npm/on-finished/-/on-finished-2.4.1.tgz", @@ -4304,24 +3757,6 @@ "node": ">= 0.8" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -4395,12 +3830,6 @@ "resolved": "https://mirrors.cloud.tencent.com/npm/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/picocolors/-/picocolors-1.0.0.tgz", @@ -4431,15 +3860,6 @@ "node": ">=8" } }, - "node_modules/progress": { - "version": "2.0.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://mirrors.cloud.tencent.com/npm/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -4452,16 +3872,6 @@ "node": ">= 0.10" } }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", @@ -4485,18 +3895,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/quick-lru": { - "version": "5.1.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/quick-lru/-/quick-lru-5.1.1.tgz", - "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -4631,12 +4029,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -4658,36 +4050,6 @@ "node": ">=8" } }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/roarr": { - "version": "2.15.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/roarr/-/roarr-2.15.4.tgz", - "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", - "dev": true, - "optional": true, - "dependencies": { - "boolean": "^3.0.1", - "detect-node": "^2.0.4", - "globalthis": "^1.0.1", - "json-stringify-safe": "^5.0.1", - "semver-compare": "^1.0.0", - "sprintf-js": "^1.1.2" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://mirrors.cloud.tencent.com/npm/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4745,13 +4107,6 @@ "node": ">=10" } }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true, - "optional": true - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://mirrors.cloud.tencent.com/npm/send/-/send-0.18.0.tgz", @@ -4780,22 +4135,6 @@ "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, - "node_modules/serialize-error": { - "version": "7.0.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/serialize-error/-/serialize-error-7.0.1.tgz", - "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", - "dev": true, - "optional": true, - "dependencies": { - "type-fest": "^0.13.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/serialize-javascript": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", @@ -4903,13 +4242,6 @@ "source-map": "^0.6.0" } }, - "node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://mirrors.cloud.tencent.com/npm/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "dev": true, - "optional": true - }, "node_modules/statuses": { "version": "2.0.1", "resolved": "https://mirrors.cloud.tencent.com/npm/statuses/-/statuses-2.0.1.tgz", @@ -4918,41 +4250,6 @@ "node": ">= 0.8" } }, - "node_modules/sumchecker": { - "version": "3.0.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/sumchecker/-/sumchecker-3.0.1.tgz", - "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", - "dev": true, - "dependencies": { - "debug": "^4.1.0" - }, - "engines": { - "node": ">= 8.0" - } - }, - "node_modules/sumchecker/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://mirrors.cloud.tencent.com/npm/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/sumchecker/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://mirrors.cloud.tencent.com/npm/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", @@ -5090,19 +4387,6 @@ "node": ">= 8" } }, - "node_modules/type-fest": { - "version": "0.13.1", - "resolved": "https://mirrors.cloud.tencent.com/npm/type-fest/-/type-fest-0.13.1.tgz", - "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://mirrors.cloud.tencent.com/npm/type-is/-/type-is-1.6.18.tgz", @@ -5174,15 +4458,6 @@ "node": ">=4" } }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://mirrors.cloud.tencent.com/npm/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/unpipe/-/unpipe-1.0.0.tgz", @@ -5416,28 +4691,12 @@ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", "dev": true }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://mirrors.cloud.tencent.com/npm/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://mirrors.cloud.tencent.com/npm/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, "node_modules/yocto-queue": { "version": "1.0.0", "resolved": "https://mirrors.cloud.tencent.com/npm/yocto-queue/-/yocto-queue-1.0.0.tgz", diff --git a/package.json b/package.json index f3327b2..1ec8b58 100644 --- a/package.json +++ b/package.json @@ -5,12 +5,13 @@ "main": "dist/main.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", + "postinstall": "ELECTRON_SKIP_BINARY_DOWNLOAD=1 npm install electron --no-save", "build": "npm run build-main && npm run build-preload && npm run build-renderer", "build-main": "webpack --config webpack.main.config.js", "build-preload": "webpack --config webpack.preload.config.js", "build-renderer": "webpack --config webpack.renderer.config.js", "build-mac": "npm run build && cp manifest.json dist/ && npm run deploy-mac", - "deploy-mac": "cp dist/* ~/Library/Containers/com.tencent.qq/Data/Documents/LiteLoaderQQNT/plugins/LLOnebot/", + "deploy-mac": "cp dist/* ~/Library/Containers/com.tencent.qq/Data/LiteLoaderQQNT/plugins/LLOnebot/", "build-win": "npm run build && cp manifest.json dist/ && npm run deploy-win", "deploy-win": "cmd /c \"copy dist\\* %USERPROFILE%\\documents\\LiteLoaderQQNT\\plugins\\LLOnebot\\\"" }, @@ -26,7 +27,6 @@ "@types/express": "^4.17.20", "@types/uuid": "^9.0.8", "babel-loader": "^9.1.3", - "electron": "^27.0.2", "ts-loader": "^9.5.0", "typescript": "^5.2.2", "webpack": "^5.89.0", diff --git a/src/common/data.ts b/src/common/data.ts index 8c7606c..bd4fcd0 100644 --- a/src/common/data.ts +++ b/src/common/data.ts @@ -1,21 +1,38 @@ -import {Group, MessageElement, RawMessage, SelfInfo, User} from "./types"; +import {SelfInfo} from "./types"; +import { NTQQApi } from '../ntqqapi/ntcall'; +import { Group, RawMessage, User } from "../ntqqapi/types"; export let groups: Group[] = [] export let friends: User[] = [] export let msgHistory: Record = {} // msgId: RawMessage -export function getFriend(qq: string): User | undefined { - return friends.find(friend => friend.uin === qq) +export async function getFriend(qq: string): Promise { + let friend = friends.find(friend => friend.uin === qq) + if (!friend){ + friends = await NTQQApi.getFriends(true) + friend = friends.find(friend => friend.uin === qq) + } + return friend } -export function getGroup(qq: string): Group | undefined { - return groups.find(group => group.uid === qq) +export async function getGroup(qq: string): Promise { + let group = groups.find(group => group.groupCode === qq) + if (!group){ + groups = await NTQQApi.getGroups(true); + group = groups.find(group => group.groupCode === qq) + } + return group } -export function getGroupMember(groupQQ: string, memberQQ: string) { - const group = getGroup(groupQQ) +export async function getGroupMember(groupQQ: string, memberQQ: string) { + const group = await getGroup(groupQQ) if (group) { - return group.members?.find(member => member.uin === memberQQ) + let member = group.members?.find(member => member.uin === memberQQ) + if (!member){ + group.members = await NTQQApi.getGroupMembers(groupQQ) + member = group.members?.find(member => member.uin === memberQQ) + } + return member } } @@ -28,3 +45,14 @@ export let selfInfo: SelfInfo = { export function getHistoryMsgBySeq(seq: string) { return Object.values(msgHistory).find(msg => msg.msgSeq === seq) } + + +export let uidMaps:Record = {} // 一串加密的字符串(uid) -> qq号 + +export function getStrangerByUin(uin: string) { + for (const key in uidMaps) { + if (uidMaps[key].uin === uin) { + return uidMaps[key]; + } + } +} \ No newline at end of file diff --git a/src/common/types.ts b/src/common/types.ts index ceb6c92..0a9d7b2 100644 --- a/src/common/types.ts +++ b/src/common/types.ts @@ -1,143 +1,10 @@ import {OB11ApiName, OB11MessageData} from "../onebot11/types"; -export enum AtType { - notAt = 0, - atAll = 1, - atUser = 2 -} - -export enum ChatType { - friend = 1, - group = 2, - temp = 100 -} - -export interface GroupMember { - avatarPath: string; - cardName: string; - cardType: number; - isDelete: boolean; - nick: string; - qid: string; - remark: string; - role: number; // 群主:4, 管理员:3,群员:2 - shutUpTime: number; // 禁言时间,单位是什么暂时不清楚 - uid: string; // 加密的字符串 - uin: string; // QQ号 -} - - export interface SelfInfo { user_id: string; nickname: string; } -export interface User { - avatarUrl?: string; - bio?: string; // 签名 - nickName: string; - uid?: string; // 加密的字符串 - uin: string; // QQ号 -} - -export interface Group { - uid: string; // 群号 - name: string; - members?: GroupMember[]; -} - -export interface Peer { - chatType: ChatType - name: string - uid: string // qq号 -} - -export interface PttElement { - canConvert2Text: boolean - duration: number // 秒数 - fileBizId: null - fileId: number // 0 - fileName: string // "e4d09c784d5a2abcb2f9980bdc7acfe6.amr" - filePath: string // "/Users//Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/nt_qq_a6b15c9820595d25a56c1633ce19ad40/nt_data/Ptt/2023-11/Ori/e4d09c784d5a2abcb2f9980bdc7acfe6.amr" - fileSize: string // "4261" - fileSubId: string // "0" - fileUuid: string // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV" - formatType: string // 1 - invalidState: number // 0 - md5HexStr: string // "e4d09c784d5a2abcb2f9980bdc7acfe6" - playState: number // 0 - progress: number // 0 - text: string // "" - transferStatus: number // 0 - translateStatus: number // 0 - voiceChangeType: number // 0 - voiceType: number // 0 - waveAmplitudes: number[] -} - -export interface ArkElement { - bytesData: string -} - -export interface RawMessage { - msgId: string, - msgTime: string, - msgSeq: string, - senderUin: string; // 发送者QQ号 - peerUid: string; // 群号 或者 QQ uid - peerUin: string; // 群号 或者 发送者QQ号 - sendNickName: string; - sendMemberName?: string; // 发送者群名片 - chatType: ChatType, - elements: { - replyElement: { - senderUid: string, // 原消息发送者QQ号 - sourceMsgIsIncPic: boolean; // 原消息是否有图片 - sourceMsgText: string; - replayMsgSeq: string; // 源消息的msgSeq,可以通过这个找到源消息的msgId - }, - textElement: { - atType: AtType - atUid: string, - content: string, - atNtUid: string - }, - picElement: { - sourcePath: string // 图片本地路径 - picWidth: number - picHeight: number - fileSize: number - fileName: string - fileUuid: string - }, - pttElement: PttElement, - arkElement: ArkElement - }[] -} - -export interface MessageElement { - raw: RawMessage - peer: Peer, - sender: { - uid: string // 一串加密的字符串 - memberName: string - nickname: string - } -} - -export interface PostDataSendMsg { - action: OB11ApiName - message_type?: "private" | "group" - params?: { - user_id: string, - group_id: string, - message: OB11MessageData[]; - }, - user_id: string, - group_id: string, - message?: OB11MessageData[]; -} - export interface Config { port: number hosts: string[] diff --git a/src/global.d.ts b/src/global.d.ts index b792d3d..0cdba03 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,13 +1,12 @@ import { Config, - Group, - GroupMember, - MessageElement, Peer, - PostDataSendMsg, PttElement, RawMessage, - SelfInfo, - User -} from "./common/types"; + PostDataSendMsg, + SelfInfo} from "./common/types"; +import { Group } from "./ntqqapi/types"; +import { GroupMember } from "./ntqqapi/types"; +import { MessageElement, PttElement, RawMessage } from "./ntqqapi/types"; +import { User } from "./ntqqapi/types"; import { SendIPCMsgSession } from "./main/ipcsend"; diff --git a/src/main/ipcsend.ts b/src/main/ipcsend.ts index db640c3..34c4016 100644 --- a/src/main/ipcsend.ts +++ b/src/main/ipcsend.ts @@ -1,5 +1,5 @@ import {ipcMain, webContents} from 'electron'; -import {PostDataSendMsg} from "../common/types"; +import {OB11PostSendMsg} from "../onebot11/types" import {CHANNEL_RECALL_MSG, CHANNEL_SEND_MSG,CHANNEL_SEND_BACK_MSG} from "../common/channels"; import {v4 as uuid4} from "uuid"; import {log} from "../common/utils"; @@ -23,7 +23,7 @@ export interface SendIPCMsgSession { data: T } -export function sendIPCSendQQMsg(postData: PostDataSendMsg, handleSendResult: (data: OB11Return) => void) { +export function sendIPCSendQQMsg(postData: OB11PostSendMsg, handleSendResult: (data: OB11Return) => void) { const onceSessionId = uuid4(); const handler = (event: any, session: SendIPCMsgSession>) => { // log("llonebot send msg ipcMain.once:" + JSON.stringify(sendResult)); diff --git a/src/main/main.ts b/src/main/main.ts index e62bfa7..254ce51 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -43,134 +43,14 @@ function onLoad() { ipcMain.handle(CHANNEL_GET_CONFIG, (event: any, arg: any) => { return getConfigUtil().getConfig() }) - ipcMain.handle(CHANNEL_DOWNLOAD_FILE, async (event: any, arg: { uri: string, fileName: string }): Promise<{ - success: boolean, - errMsg: string, - path: string - }> => { - let filePath = path.join(CONFIG_DIR, arg.fileName) - let url = new URL(arg.uri); - if (url.protocol == "base64:") { - // base64转成文件 - let base64Data = arg.uri.split("base64://")[1] - try { - const buffer = Buffer.from(base64Data, 'base64'); - fs.writeFileSync(filePath, buffer); - } catch (e: any) { - return { - success: false, - errMsg: `base64文件下载失败,` + e.toString(), - path: "" - } - } - } else if (url.protocol == "http:" || url.protocol == "https:") { - // 下载文件 - let res = await fetch(url) - if (!res.ok) { - return { - success: false, - errMsg: `${url}下载失败,` + res.statusText, - path: "" - } - } - let blob = await res.blob(); - let buffer = await blob.arrayBuffer(); - try { - fs.writeFileSync(filePath, Buffer.from(buffer)); - } catch (e: any) { - return { - success: false, - errMsg: `${url}下载失败,` + e.toString(), - path: "" - } - } - } - else{ - return { - success: false, - errMsg: `不支持的file协议,` + url.protocol, - path: "" - } - } - if (isGIF(filePath)) { - fs.renameSync(filePath, filePath + ".gif"); - filePath += ".gif"; - } - return { - success: true, - errMsg: "", - path: filePath - }; - }) ipcMain.on(CHANNEL_SET_CONFIG, (event: any, arg: Config) => { getConfigUtil().setConfig(arg) }) - ipcMain.on(CHANNEL_START_HTTP_SERVER, (event: any, arg: any) => { - startExpress(getConfigUtil().getConfig().port) - }) - - ipcMain.on(CHANNEL_UPDATE_GROUPS, (event: any, arg: Group[]) => { - for (const group of arg) { - let existGroup = groups.find(g => g.uid == group.uid) - if (existGroup) { - if (!existGroup.members) { - existGroup.members = [] - } - existGroup.name = group.name - for (const member of group.members || []) { - let existMember = existGroup.members?.find(m => m.uin == member.uin) - if (existMember) { - existMember.nick = member.nick - existMember.cardName = member.cardName - } else { - existGroup.members?.push(member) - } - } - } else { - groups.push(group) - } - } - groups.length = 0 - groups.push(...arg) - }) - - ipcMain.on(CHANNEL_UPDATE_FRIENDS, (event: any, arg: User[]) => { - friends.length = 0 - friends.push(...arg) - }) - - ipcMain.on(CHANNEL_POST_ONEBOT_DATA, (event: any, arg: any) => { - postMsg(arg); - }) - ipcMain.on(CHANNEL_LOG, (event: any, arg: any) => { log(arg) }) - ipcMain.handle(CHANNEL_SET_SELF_INFO, (event: any, arg: SelfInfo) => { - selfInfo.user_id = arg.user_id; - selfInfo.nickname = arg.nickname; - running = true; - }) - - ipcMain.on(CHANNEL_DELETE_FILE, (event: any, arg: string[]) => { - for (const path of arg) { - fs.unlinkSync(path); - } - }) - - ipcMain.handle(CHANNEL_GET_RUNNING_STATUS, (event: any, arg: any) => { - return running; - }) - - ipcMain.handle(CHANNEL_FILE2BASE64, async (event: any, path: string): Promise<{err: string, data: string}> => { - return await file2base64(path); - }) - - ipcMain.handle(CHANNEL_GET_HISTORY_MSG, (event: any, arg: string): RawMessage | undefined => { - return msgHistory[arg] || null; - }) function postRawMsg(msgList:RawMessage[]) { const {debug, reportSelfMessage} = getConfigUtil().getConfig(); @@ -207,12 +87,48 @@ function onLoad() { log("report self message error: ", e.toString()) } }) + + async function getSelfInfo(){ + if (!selfInfo.user_id){ + setTimeout(()=>{ + getSelfInfo().then() + }) + } + const _ = await NTQQApi.getSelfInfo() + if (_.uin){ + log("get self info success", _) + selfInfo.user_id = _.uin + let nickName = _.uin + try{ + const userInfo = (await NTQQApi.getUserInfo(_.uid)) + if (userInfo){ + nickName = userInfo.nickName + } + } + catch(e){ + log("get self nickname failed", e.toString()) + } + selfInfo.nickname = nickName + try{ + // let _friends = await NTQQApi.getFriends(true) + // log("friends api:", _friends) + // for (let f of _friends){ + // friends.push(f) + // } + let _groups = await NTQQApi.getGroups(true) + log("groups api:", _groups) + for (let g of _groups){ + g.members = (await NTQQApi.getGroupMembers(g.uid)) + groups.push(g) + } - setTimeout(()=>{ - NTQQApi.getSelfInfo().then(r=>{ - log(r); - }) - }, 10000) + }catch(e){ + log("!!!初始化失败", e.stack.toString()) + } + startExpress(getConfigUtil().getConfig().port) + } + } + getSelfInfo().then() } diff --git a/src/ntqqapi/constructor.ts b/src/ntqqapi/constructor.ts index b20a854..d140385 100644 --- a/src/ntqqapi/constructor.ts +++ b/src/ntqqapi/constructor.ts @@ -32,7 +32,7 @@ export class SendMsgElementConstructor { }; } - reply(msgSeq: string, msgId: string, senderUin: string, senderUinStr: string): SendReplyElement { + static reply(msgSeq: string, msgId: string, senderUin: string, senderUinStr: string): SendReplyElement { return { elementType: ElementType.REPLY, elementId: "", @@ -45,7 +45,7 @@ export class SendMsgElementConstructor { } } - async pic(picPath: string): Promise{ + static async pic(picPath: string): Promise{ const {md5, fileName, path, fileSize} = await NTQQApi.uploadFile(picPath); const imageSize = await NTQQApi.getImageSize(picPath); const picElement = { @@ -71,7 +71,7 @@ export class SendMsgElementConstructor { }; } - async ptt(pttPath: string):Promise { + static async ptt(pttPath: string):Promise { const {md5, fileName, path, fileSize} = await NTQQApi.uploadFile(pttPath); return { elementType: ElementType.PTT, diff --git a/src/ntqqapi/hook.ts b/src/ntqqapi/hook.ts index b55e307..fc3cba7 100644 --- a/src/ntqqapi/hook.ts +++ b/src/ntqqapi/hook.ts @@ -1,15 +1,19 @@ import {BrowserWindow} from 'electron'; import {getConfigUtil, log} from "../common/utils"; -import {NTQQApiClass} from "./ntcall"; -import {RawMessage} from "../common/types"; -import {msgHistory} from "../common/data"; +import {NTQQApiClass, sendMessagePool} from "./ntcall"; +import { Group } from "./types"; +import { RawMessage } from "./types"; +import {groups, msgHistory} from "../common/data"; export let hookApiCallbacks: Recordvoid>={} export enum ReceiveCmd { UPDATE_MSG = "nodeIKernelMsgListener/onMsgInfoListUpdate", NEW_MSG = "nodeIKernelMsgListener/onRecvMsg", - SELF_SEND_MSG = "nodeIKernelMsgListener/onAddSendMsg" + SELF_SEND_MSG = "nodeIKernelMsgListener/onAddSendMsg", + USER_INFO = "nodeIKernelProfileListener/onProfileDetailInfoChanged", + GROUPS = "nodeIKernelGroupListener/onGroupListUpdate", + GROUPS_UNIX = "onGroupListUpdate" } interface NTQQApiReturnData extends Array { @@ -28,13 +32,14 @@ interface NTQQApiReturnData extends Array { let receiveHooks: Array<{ method: ReceiveCmd, - hookFunc: (payload: unknown) => void + hookFunc: (payload: any) => void }> = [] export function hookNTQQApiReceive(window: BrowserWindow) { const originalSend = window.webContents.send; const patchSend = (channel: string, ...args: NTQQApiReturnData) => { // 判断是否是列表 + log(`received ntqq api message: ${channel}`, JSON.stringify(args)) if (args?.[1] instanceof Array) { for (let receiveData of args?.[1]) { const ntQQApiMethodName = receiveData.cmdName; @@ -75,6 +80,25 @@ export function registerReceiveHook(method: ReceiveCmd, hookFunc: ( }) } +function updateGroups(_groups: Group[]){ + for(let group of _groups){ + let existGroup = groups.find(g=>g.groupCode == group.groupCode) + if (!existGroup){ + groups.push(group) + } + else{ + Object.assign(existGroup, group); + } + } +} + +registerReceiveHook<{groupList: Group[]}>(ReceiveCmd.GROUPS, (payload)=>updateGroups(payload.groupList)) +registerReceiveHook<{groupList: Group[]}>(ReceiveCmd.GROUPS_UNIX, (payload)=>updateGroups(payload.groupList)) + +registerReceiveHook(ReceiveCmd.USER_INFO, (payload)=>{ + log("user info", payload); +}) + registerReceiveHook<{ msgList: Array }>(ReceiveCmd.UPDATE_MSG, (payload) => { for (const message of payload.msgList) { msgHistory[message.msgId] = message; @@ -84,7 +108,25 @@ registerReceiveHook<{ msgList: Array }>(ReceiveCmd.UPDATE_MSG, (payl registerReceiveHook<{ msgList: Array }>(ReceiveCmd.NEW_MSG, (payload) => { for (const message of payload.msgList) { log("收到新消息,push到历史记录", message) - msgHistory[message.msgId] = message; + if (!msgHistory[message.msgId]){ + msgHistory[message.msgId] = message + } + else{ + Object.assign(msgHistory[message.msgId], message) + } } }) +registerReceiveHook<{msgRecord: RawMessage}>(ReceiveCmd.SELF_SEND_MSG, ({msgRecord})=>{ + const message = msgRecord; + const peerUid = message.peerUid; + // log("收到自己发送成功的消息", Object.keys(sendMessagePool), message); + const sendCallback = sendMessagePool[peerUid]; + if (sendCallback){ + try{ + sendCallback(message); + }catch(e){ + log("receive self msg error", e.stack) + } + } +}) diff --git a/src/ntqqapi/ntcall.ts b/src/ntqqapi/ntcall.ts index 52aeb40..0b9ed34 100644 --- a/src/ntqqapi/ntcall.ts +++ b/src/ntqqapi/ntcall.ts @@ -2,7 +2,11 @@ import {ipcMain} from "electron"; import {v4 as uuidv4} from "uuid"; import {hookApiCallbacks} from "./hook"; import {log} from "../common/utils"; -import {ChatType, Group, GroupMember, User} from "../common/types"; +import { ChatType } from "./types"; +import { Group } from "./types"; +import { GroupMember } from "./types"; +import { RawMessage } from "./types"; +import { User } from "./types"; import {SendMessageElement} from "./types"; interface IPCReceiveEvent { @@ -48,9 +52,9 @@ enum NTQQApiChannel { IPC_UP_1 = "IPC_UP_1", } -interface Peer { +export interface Peer { chatType: ChatType - peerUid: string // 是uid还是QQ号 + peerUid: string // 如果是群聊uid为群号,私聊uid就是加密的字符串 guildId?: "" } @@ -70,6 +74,13 @@ function callNTQQApi(channel: NTQQApiChannel, className: NTQQApiClas }) } +export let sendMessagePool: Recordvoid) | null> = {}// peerUid: callbackFunnc + +interface GeneralCallResult{ + result:0, + errMsg: string +} + export class NTQQApi { // static likeFriend = defineNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.LIKE_FRIEND) @@ -91,14 +102,14 @@ export class NTQQApi { } static getFriends(forced = false) { - return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.FRIENDS, [{force_update: forced}, undefined]) + return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.FRIENDS, [{force_update: forced}, undefined]) } static getGroups(forced = false) { - return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUPS, [{force_update: forced}, undefined]) + return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUPS, [{force_update: forced}, undefined]) } - static async getGroupMembers(groupQQ: string, num = 3000) { + static async getGroupMembers(groupQQ: string, num = 5000) { const sceneId = callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.GROUP_MEMBER_SCENE, [{ groupCode: groupQQ, scene: "groupMemberList_MainWindow" @@ -114,13 +125,11 @@ export class NTQQApi { } static async getUserInfo(uid: string) { - const result = await callNTQQApi<[{ - payload: { profiles: Map } - }]>(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.USER_INFO, + const result = await callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.USER_INFO, [{force: true, uids: [uid]}, undefined]) - return new Promise(resolve => { - resolve(result[0].payload.profiles.get(uid)) - }) + log("get user info result", result); + return result[0].payload.profiles.get(uid); + } static getFileType(filePath: string) { @@ -134,7 +143,7 @@ export class NTQQApi { } static copyFile(filePath: string, destPath: string) { - return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.FS_API, NTQQApiMethod.FILE_COPY, [filePath, destPath]) + return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.FS_API, NTQQApiMethod.FILE_COPY, [{ fromPath: filePath, toPath: destPath }]) } static getImageSize(filePath: string) { @@ -152,7 +161,7 @@ export class NTQQApi { static async uploadFile(filePath: string) { const md5 = await NTQQApi.getFileMd5(filePath); const fileName = `${md5}.${(await NTQQApi.getFileType(filePath)).ext}`; - const mediaPath = await callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.FS_API, NTQQApiMethod.MEDIA_FILE_PATH, [{ + const mediaPath = await callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.MEDIA_FILE_PATH, [{ path_info: { md5HexStr: md5, fileName: fileName, @@ -164,6 +173,7 @@ export class NTQQApi { file_uuid: "" } }]) + log("media path", mediaPath) await NTQQApi.copyFile(filePath, mediaPath); const fileSize = await NTQQApi.getFileSize(filePath); return { @@ -178,11 +188,49 @@ export class NTQQApi { return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.RECALL_MSG, [{peer, msgIds}, null]) } - static sendMsg(peer: Peer, msgElements: SendMessageElement){ - return callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.SEND_MSG, [{ - msgId: "0", - peer, msgElements, - msgAttributeInfos: new Map(), - }, null]) + static sendMsg(peer: Peer, msgElements: SendMessageElement[]){ + const sendTimeout = 10 * 1000 + + return new Promise((resolve, reject)=>{ + const peerUid = peer.peerUid; + let usingTime = 0; + let success = false; + + const checkSuccess = ()=>{ + if (!success){ + sendMessagePool[peerUid] = null; + reject("发送超时") + } + } + setTimeout(checkSuccess, sendTimeout); + + const checkLastSend = ()=>{ + let lastSending = sendMessagePool[peerUid] + if (sendTimeout < usingTime){ + sendMessagePool[peerUid] = null; + reject("发送超时") + } + if (!!lastSending){ + // log("有正在发送的消息,等待中...") + usingTime += 100; + setTimeout(checkLastSend, 100); + } + else{ + log("可以进行发送消息,设置发送成功回调", sendMessagePool) + sendMessagePool[peerUid] = (rawMessage: RawMessage)=>{ + success = true; + sendMessagePool[peerUid] = null; + resolve(rawMessage); + } + } + } + checkLastSend() + callNTQQApi(NTQQApiChannel.IPC_UP_2, NTQQApiClass.NT_API, NTQQApiMethod.SEND_MSG, [{ + msgId: "0", + peer, msgElements, + msgAttributeInfos: new Map(), + }, null]).then() + }) + } } \ No newline at end of file diff --git a/src/ntqqapi/types.ts b/src/ntqqapi/types.ts index 3ca483a..fa32cd0 100644 --- a/src/ntqqapi/types.ts +++ b/src/ntqqapi/types.ts @@ -1,3 +1,60 @@ + +export interface User { + uid: string; // 加密的字符串 + uin: string; // QQ号 + nick: string; + avatarUrl?: string; + longNick: string; // 签名 + raw: { + remark: string; + }; +} + +export interface Group{ + groupCode: string, + maxMember: number, + memberCount: number, + groupName: string, + groupStatus: 0, + memberRole: 2, + isTop: boolean, + toppedTimestamp: "0", + privilegeFlag: number, //65760 + isConf: boolean, + hasModifyConfGroupFace: boolean, + hasModifyConfGroupName: boolean, + remarkName: string, + hasMemo: boolean, + groupShutupExpireTime: string, //"0", + personShutupExpireTime: string, //"0", + discussToGroupUin: string, //"0", + discussToGroupMaxMsgSeq: number, + discussToGroupTime: number, + groupFlagExt: number, //1073938496, + authGroupType: number, //0, + groupCreditLevel: number, //0, + groupFlagExt3: number, //0, + groupOwnerId: { + "memberUin": string, //"0", + "memberUid": string, //"u_fbf8N7aeuZEnUiJAbQ9R8Q" + }, + members: GroupMember[] // 原始数据是没有这个的,为了方便自己加了这个字段 +} + +export interface GroupMember { + avatarPath: string; + cardName: string; + cardType: number; + isDelete: boolean; + nick: string; + qid: string; + remark: string; + role: number; // 群主:4, 管理员:3,群员:2 + shutUpTime: number; // 禁言时间,单位是什么暂时不清楚 + uid: string; // 加密的字符串 + uin: string; // QQ号 +} + export enum ElementType { TEXT = 1, PIC = 2, @@ -67,4 +124,90 @@ export interface SendReplyElement { } } -export type SendMessageElement = SendTextElement | SendPttElement | SendPicElement | SendReplyElement \ No newline at end of file +export type SendMessageElement = SendTextElement | SendPttElement | SendPicElement | SendReplyElement + +export enum AtType { + notAt = 0, + atAll = 1, + atUser = 2 +} + +export enum ChatType { + friend = 1, + group = 2, + temp = 100 +} +export interface PttElement { + canConvert2Text: boolean; + duration: number; // 秒数 + fileBizId: null; + fileId: number; // 0 + fileName: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6.amr" + filePath: string; // "/Users//Library/Containers/com.tencent.qq/Data/Library/Application Support/QQ/nt_qq_a6b15c9820595d25a56c1633ce19ad40/nt_data/Ptt/2023-11/Ori/e4d09c784d5a2abcb2f9980bdc7acfe6.amr" + fileSize: string; // "4261" + fileSubId: string; // "0" + fileUuid: string; // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV" + formatType: string; // 1 + invalidState: number; // 0 + md5HexStr: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6" + playState: number; // 0 + progress: number; // 0 + text: string; // "" + transferStatus: number; // 0 + translateStatus: number; // 0 + voiceChangeType: number; // 0 + voiceType: number; // 0 + waveAmplitudes: number[]; +} + +export interface ArkElement { + bytesData: string; +} + +export interface RawMessage { + msgId: string; + msgTime: string; + msgSeq: string; + senderUin: string; // 发送者QQ号 + peerUid: string; // 群号 或者 QQ uid + peerUin: string; // 群号 或者 发送者QQ号 + sendNickName: string; + sendMemberName?: string; // 发送者群名片 + chatType: ChatType; + elements: { + replyElement: { + senderUid: string; // 原消息发送者QQ号 + sourceMsgIsIncPic: boolean; // 原消息是否有图片 + sourceMsgText: string; + replayMsgSeq: string; // 源消息的msgSeq,可以通过这个找到源消息的msgId + }; + textElement: { + atType: AtType; + atUid: string; + content: string; + atNtUid: string; + }; + picElement: { + sourcePath: string; // 图片本地路径 + picWidth: number; + picHeight: number; + fileSize: number; + fileName: string; + fileUuid: string; + }; + pttElement: PttElement; + arkElement: ArkElement; + }[]; +} + +export interface MessageElement { + raw: RawMessage; + peer: any; + sender: { + uid: string; // 一串加密的字符串 + memberName: string; + nickname: string; + }; +} + + diff --git a/src/onebot11/constructor.ts b/src/onebot11/constructor.ts index cab642b..2b5e1a0 100644 --- a/src/onebot11/constructor.ts +++ b/src/onebot11/constructor.ts @@ -1,5 +1,5 @@ -import {OB11MessageDataType, OB11GroupMemberRole, OB11Message, OB11MessageData} from "./types"; -import {AtType, ChatType, RawMessage} from "../common/types"; +import {OB11MessageDataType, OB11GroupMemberRole, OB11Message, OB11MessageData, OB11Group, OB11GroupMember, Friend} from "./types"; +import { AtType, ChatType, Group, GroupMember, RawMessage, User } from '../ntqqapi/types'; import {getFriend, getGroupMember, getHistoryMsgBySeq, msgHistory, selfInfo} from "../common/data"; import {file2base64, getConfigUtil} from "../common/utils"; @@ -28,13 +28,13 @@ export class OB11Constructor { } if (msg.chatType == ChatType.group) { resMsg.group_id = msg.peerUin - const member = getGroupMember(msg.peerUin, msg.senderUin); + const member = await getGroupMember(msg.peerUin, msg.senderUin); if (member) { resMsg.sender.role = OB11Constructor.groupMemberRole(member.role); } } else if (msg.chatType == ChatType.friend) { resMsg.sub_type = "friend" - const friend = getFriend(msg.senderUin); + const friend = await getFriend(msg.senderUin); if (friend) { resMsg.sender.nickname = friend.nickName; } @@ -54,7 +54,7 @@ export class OB11Constructor { message_data["data"]["qq"] = "all" } else { let uid = element.textElement.atUid - let atMember = getGroupMember(msg.peerUin, uid) + let atMember = await getGroupMember(msg.peerUin, uid) message_data["data"]["mention"] = atMember?.uin message_data["data"]["qq"] = atMember?.uin } @@ -118,12 +118,49 @@ export class OB11Constructor { // } return resMsg; } + + static friend(friend: User): Friend{ + return { + user_id: friend.uin, + nickname: friend.nickName, + remark: friend.raw.remark + } + + } - static groupMemberRole(role: number): OB11GroupMemberRole { + static friends(friends: User[]): Friend[]{ + return friends.map(OB11Constructor.friend) + } + + static groupMemberRole(role: number): OB11GroupMemberRole | undefined { return { 4: OB11GroupMemberRole.owner, 3: OB11GroupMemberRole.admin, 2: OB11GroupMemberRole.member }[role] } + + static groupMember(group_id: string, member: GroupMember): OB11GroupMember{ + return { + group_id, + user_id: member.uin, + nickname: member.nick, + card: member.cardName + } + } + + static groupMembers(group: Group): OB11GroupMember[]{ + return group.members.map(m=>OB11Constructor.groupMember(group.groupCode, m)) + } + + static group(group: Group): OB11Group{ + return { + group_id: group.groupCode, + group_name: group.groupName + } + } + + static groups(groups: Group[]): OB11Group[]{ + return groups.map(OB11Constructor.group) + } } \ No newline at end of file diff --git a/src/onebot11/types.ts b/src/onebot11/types.ts index 34975d6..2d719c6 100644 --- a/src/onebot11/types.ts +++ b/src/onebot11/types.ts @@ -1,4 +1,11 @@ -import {AtType, RawMessage} from "../common/types"; +import {SelfInfo} from "../common/types"; +import { AtType } from "../ntqqapi/types"; +import { RawMessage } from "../ntqqapi/types"; +import { User } from "../ntqqapi/types"; + +export interface Friend extends SelfInfo{ + remark?: string +} export enum OB11UserSex{ male = "male", @@ -12,6 +19,27 @@ export enum OB11GroupMemberRole{ member = "member", } +export interface OB11GroupMember { + group_id: string + user_id: string + nickname: string + card?: string + sex?: OB11UserSex + age?: number + join_time?: number + last_sent_time?: number + level?: number + role?: OB11GroupMemberRole + title?: string +} + +export interface OB11Group{ + group_id: string + group_name: string + member_count?: number + max_member_count?: number +} + interface OB11Sender { user_id: string, nickname: string, @@ -45,9 +73,11 @@ export interface OB11Message { } export type OB11ApiName = - "send_private_msg" + "send_msg" + | "send_private_msg" | "send_group_msg" | "get_group_list" + | "get_group_info" | "get_friend_list" | "delete_msg" | "get_login_info" @@ -102,4 +132,11 @@ export type OB11MessageData = { data: { id: string, } +} + +export interface OB11PostSendMsg { + message_type?: "private" | "group" + user_id: string, + group_id?: string, + message: OB11MessageData[] | string | OB11MessageData; } \ No newline at end of file diff --git a/src/onebot11/utils.ts b/src/onebot11/utils.ts new file mode 100644 index 0000000..67d5931 --- /dev/null +++ b/src/onebot11/utils.ts @@ -0,0 +1,63 @@ +import { CONFIG_DIR, isGIF } from "../common/utils"; +import * as path from 'path'; +import { NTQQApi } from '../ntqqapi/ntcall'; +const fs = require("fs").promises; + +export async function uri2local(fileName: string, uri: string){ + let filePath = path.join(CONFIG_DIR, fileName) + let url = new URL(uri); + if (url.protocol == "base64:") { + // base64转成文件 + let base64Data = uri.split("base64://")[1] + try { + const buffer = Buffer.from(base64Data, 'base64'); + await fs.writeFile(filePath, buffer); + } catch (e: any) { + return { + success: false, + errMsg: `base64文件下载失败,` + e.toString(), + path: "" + } + } + } else if (url.protocol == "http:" || url.protocol == "https:") { + // 下载文件 + let res = await fetch(url) + if (!res.ok) { + return { + success: false, + errMsg: `${url}下载失败,` + res.statusText, + path: "" + } + } + let blob = await res.blob(); + let buffer = await blob.arrayBuffer(); + try { + await fs.writeFile(filePath, Buffer.from(buffer)); + } catch (e: any) { + return { + success: false, + errMsg: `${url}下载失败,` + e.toString(), + path: "" + } + } + } else if (url.protocol === "file:"){ + await fs.copyFile(url.pathname, filePath); + // filePath = (await NTQQApi.uploadFile(url.pathname)).path; + } + else{ + return { + success: false, + errMsg: `不支持的file协议,` + url.protocol, + path: "" + } + } + if (isGIF(filePath)) { + await fs.rename(filePath, filePath + ".gif"); + filePath += ".gif"; + } + return { + success: true, + errMsg: "", + path: filePath + }; +} \ No newline at end of file diff --git a/src/preload.ts b/src/preload.ts index 438a141..3fc8bcc 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -1,6 +1,9 @@ // Electron 主进程 与 渲染进程 交互的桥梁 -import {Config, Group, PostDataSendMsg, RawMessage, SelfInfo, User} from "./common/types"; +import {Config, SelfInfo} from "./common/types"; +import { Group } from "./ntqqapi/types"; +import { RawMessage } from "./ntqqapi/types"; +import { User } from "./ntqqapi/types"; import { CHANNEL_DOWNLOAD_FILE, CHANNEL_GET_CONFIG, @@ -46,12 +49,7 @@ contextBridge.exposeInMainWorld("llonebot", { data: msgResult, }); }, - listenSendMessage: (handle: (jsonData: SendIPCMsgSession) => void) => { - ipcRenderer.send(CHANNEL_LOG, "发送消息API已注册"); - ipcRenderer.on(CHANNEL_SEND_MSG, (event: any, args: SendIPCMsgSession) => { - handle(args) - }) - }, + listenRecallMessage: (handle: (jsonData: {message_id: string}) => void) => { ipcRenderer.on(CHANNEL_RECALL_MSG, (event: any, args: {message_id: string}) => { handle(args) diff --git a/src/renderer.ts b/src/renderer.ts index 914e409..83651f1 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -1,440 +1,5 @@ /// -import {AtType, ChatType, Group, MessageElement, Peer, PostDataSendMsg, RawMessage, User} from "./common/types"; - - -import {OB11SendMsgReturn} from "./onebot11/types"; -import {ipcRenderer} from "electron"; -import {CHANNEL_GET_HISTORY_MSG} from "./common/channels"; -import { SendIPCMsgSession } from "./main/ipcsend"; - -let groups: Group[] = [] -let friends: User[] = [] -let uid_maps: Record = {} // 一串加密的字符串 -> qq号 - -function getStrangerByUin(uin: string) { - for (const key in uid_maps) { - if (uid_maps[key].uin === uin) { - return uid_maps[key]; - } - } -} - -async function getHistoryMsg(msgId: string) { - return await window.llonebot.getHistoryMsg(msgId); -} - -async function getUserInfo(uid: string): Promise { - let user = uid_maps[uid] - if (!user) { - // 从服务器获取用户信息 - user = await window.LLAPI.getUserInfo(uid) - uid_maps[uid] = user - } - return user -} - -async function getFriends() { - let _friends = await window.LLAPI.getFriendsList(false) - for (let friend of _friends) { - let existFriend = friends.find(f => f.uin == friend.uin) - if (!existFriend) { - friends.push(friend) - } - } - window.llonebot.updateFriends(friends) - return friends -} - -async function getFriend(qq: string) { - let friend = friends.find(friend => friend.uin == qq) - if (!friend) { - await getFriends(); - friend = friends.find(friend => friend.uin == qq); - } - return friend; -} - -async function getGroup(qq: string) { - let group = groups.find(group => group.uid == qq) - if (!group) { - await getGroups(); - group = groups.find(group => group.uid == qq) - } - return group -} - -async function getGroups() { - let __groups = await window.LLAPI.getGroupsList(false) - for (let group of __groups) { - group.members = []; - let existGroup = groups.find(g => g.uid == group.uid) - if (!existGroup) { - // console.log("更新群列表", groups) - groups.push(group) - } - } - window.llonebot.updateGroups(groups) - return groups -} - -async function getGroupMembers(group_qq: string, forced: boolean = false) { - let group = await getGroup(group_qq) - if (!group?.members || group!.members!.length == 0 || forced) { - let res = (await window.LLAPI.getGroupMemberList(group_qq, 5000)) - // console.log(`更新群${group}成员列表 await`, _res) - // window.LLAPI.getGroupMemberList(group_qq + "_groupMemberList_MainWindow", 5000).then(res =>{ - let members = res.result.infos.values(); - console.log("getGroupMemberList api response:", res) - if (members && forced) { - group.members = [] - } - for (const member of members) { - if (!group!.members!.find(m => m.uid == member.uid)) { - group!.members!.push(member) - } - uid_maps[member.uid] = { - uin: member.uin, - uid: member.uid, - nickName: member.nick - }; - } - window.llonebot.updateGroups(groups) - console.log(`更新群${group.name}成员列表`, group) - // }) - } - return group?.members -} - -async function getGroupMember(group_qq: string, member_uid: string) { - let members = await getGroupMembers(group_qq) - if (members) { - let member = members.find(member => member.uid == member_uid) - if (!member) { - members = await getGroupMembers(group_qq, true) - member = members?.find(member => member.uid == member_uid) - } - return member - } -} - - -async function listenSendMessage(session: SendIPCMsgSession) { - const postData = session.data - console.log("收到发送消息请求", postData); - let sendMsgResult: OB11SendMsgReturn = { - retcode: 0, - status: 0, - data: { - message_id: "" - }, - message: "发送成功" - } - if (postData.action == "send_private_msg" || postData.action == "send_group_msg") { - let peer: Peer | null = null; - if (!postData.params) { - postData.params = { - message: postData.message, - user_id: postData.user_id, - group_id: postData.group_id - } - } - if (postData.action == "send_private_msg") { - let friend = await getFriend(postData.params.user_id) - if (friend) { - console.log("好友消息", postData) - peer = { - chatType: ChatType.friend, - name: friend.nickName, - uid: friend.uid - } - } else { - // 临时消息 - console.log("发送临时消息", postData) - let receiver = getStrangerByUin(postData.params.user_id); - if (receiver) { - peer = { - chatType: ChatType.temp, - name: receiver.nickName, - uid: receiver.uid - } - } else { - sendMsgResult.status = -1; - sendMsgResult.retcode = -1; - sendMsgResult.message = `发送失败,未找到对象${postData.params.user_id},检查他是否为好友或是群友`; - } - } - } else if (postData.action == "send_group_msg") { - let group = await getGroup(postData.params.group_id) - if (group) { - peer = { - chatType: ChatType.group, - name: group.name, - uid: group.uid - } - } else { - sendMsgResult.status = -1; - sendMsgResult.retcode = -1; - sendMsgResult.message = `发送失败,未找到群${postData.params.group_id}`; - console.log("未找到群, 发送群消息失败", postData) - } - } - if (peer) { - let sendFiles: string[] = []; - for (let message of postData.params.message) { - if (message.type == "at") { - // @ts-ignore - message.type = "text" - message.atType = AtType.atUser - let atUid = message.data?.qq || message.atUid - if (atUid == "all") { - message.atType = AtType.atAll - atUid = "0"; - message.content = `@全体成员` - } else { - let group = await getGroup(postData.params.group_id) - let atMember = group.members.find(member => member.uin == atUid) - message.atNtUid = atMember.uid - message.atUid = atUid - message.content = `@${atMember.cardName || atMember.nick}` - } - } else if (message.type == "text") { - message.content = message.data?.text || message.content - } else if (message.type == "image" || message.type == "voice" || message.type == "record") { - // 收到的是uri格式的,需要转成本地的, uri格式有三种,http, file, base64 - let url = message.data?.file || message.file - let uri = new URL(url); - let ext: string; - if (message.type == "image") { - ext = ".png" - } - if (message.type == "voice" || message.type == "record") { - message.type = "voice" - ext = ".amr" - } - let localFilePath = `${Date.now()}${ext}` - if (uri.protocol == "file:") { - localFilePath = url.split("file://")[1] - } else { - const {errMsg, path} = await window.llonebot.downloadFile({ - uri: url, - fileName: `${Date.now()}${ext}` - }) - console.log("下载文件结果", errMsg, path) - if (errMsg) { - console.log("下载文件失败", errMsg); - sendMsgResult.status = -1; - sendMsgResult.retcode = -1; - sendMsgResult.message = `发送失败,下载文件失败,${errMsg}`; - break; - } else { - localFilePath = path; - } - sendFiles.push(localFilePath); - } - message.file = localFilePath - } else if (message.type == "reply") { - let msgId = message.data?.id || message.msgId - const rawMsg: RawMessage = await getHistoryMsg(msgId) - if (rawMsg){ - message.msgId = msgId - message.msgSeq = rawMsg.msgSeq - } - } - } - console.log("发送消息", postData) - if (sendMsgResult.status !== 0) { - window.llonebot.sendSendMsgResult(session.id, sendMsgResult) - return; - } - window.LLAPI.sendMessage(peer, postData.params.message).then( - (res: MessageElement) => { - console.log("消息发送成功:", res, peer, postData.params.message) - if (sendFiles.length) { - window.llonebot.deleteFile(sendFiles); - } - sendMsgResult.data.message_id = res.raw.msgId; - window.llonebot.sendSendMsgResult(session.id, sendMsgResult) - }, - err => { - sendMsgResult.status = -1; - sendMsgResult.retcode = -1; - sendMsgResult.message = `发送失败,${err}`; - window.llonebot.sendSendMsgResult(session.id, sendMsgResult) - console.log("消息发送失败", postData, err) - }) - } else { - console.log(sendMsgResult, postData); - window.llonebot.sendSendMsgResult(session.id, sendMsgResult) - } - } -} - -function recallMessage(msgId: string) { - getHistoryMsg(msgId).then((msg: RawMessage)=>{ - const peer: Peer ={ - chatType: msg.chatType, - name: "", - uid: msg.peerUin - } - window.LLAPI.recallMessage(peer, [msgId]).then() - }) - -} - -let chatListEle: HTMLCollectionOf - -async function getGroupsMembers(groupsArg: Group[]) { - // 批量获取群成员列表 - let failedGroups: Group[] = [] - for (const group of groupsArg) { - let handledGroup = await getGroupMembers(group.uid, true) - if (handledGroup.length == 0) { - failedGroups.push(group) - } - } - if (failedGroups.length > 0) { - console.log("获取群成员列表失败,重试", failedGroups.map(group => group.name)) - setTimeout(() => { - getGroupsMembers(failedGroups).then() - }, 1000) - } else { - window.llonebot.log("全部群成员获取完毕") - } -} - - -async function initAccountInfo() { - let accountInfo = await window.LLAPI.getAccountInfo(); - window.llonebot.log("getAccountInfo " + JSON.stringify(accountInfo)); - if (!accountInfo.uid) { - return false; - } - let selfInfo = await window.LLAPI.getUserInfo(accountInfo.uid); - window.llonebot.setSelfInfo({ - user_id: accountInfo.uin, - nickname: selfInfo.nickName - }); - window.llonebot.log("selfInfo " + JSON.stringify(selfInfo)); - return true; -} - -function onLoad() { - window.llonebot.log("llonebot render onLoad"); - window.llonebot.getRunningStatus().then(running => { - if (running) { - return; - } - initAccountInfo().then( - (initSuccess) => { - if (!initSuccess) { - return; - } - if (friends.length == 0) { - getFriends().then(() => { - }); - } - if (groups.length == 0) { - getGroups().then(() => { - getGroupsMembers(groups).then(() => { - }); - }); - } - window.llonebot.log("llonebot render start"); - window.llonebot.startExpress(); - - window.llonebot.listenSendMessage((session: SendIPCMsgSession) => { - listenSendMessage(session).then().catch(err => console.log("listenSendMessage err", err)) - }) - window.llonebot.listenRecallMessage((arg: { message_id: string }) => { - // console.log("listenRecallMessage", arg) - recallMessage(arg.message_id) - }) - window.llonebot.log("llonebot loaded"); - // window.LLAPI.add_qmenu((qContextMenu: Node) => { - // let btn = document.createElement("a") - // btn.className = "q-context-menu-item q-context-menu-item--normal vue-component" - // btn.setAttribute("aria-disabled", "false") - // btn.setAttribute("role", "menuitem") - // btn.setAttribute("tabindex", "-1") - // btn.onclick = () => { - // // window.LLAPI.getPeer().then(peer => { - // // // console.log("current peer", peer) - // // if (peer && peer.chatType == "group") { - // // getGroupMembers(peer.uid, true).then(()=> { - // // console.log("获取群成员列表成功", groups); - // // alert("获取群成员列表成功") - // // }) - // // } - // // }) - // async function func() { - // for (const group of groups) { - // await getGroupMembers(group.uid, true) - // } - // } - // - // func().then(() => { - // console.log("获取群成员列表结果", groups); - // // 找到members数量为空的群 - // groups.map(group => { - // if (group.members.length == 0) { - // console.log(`${group.name}群成员为空`) - // } - // }) - // window.llonebot.updateGroups(groups) - // }) - // } - // btn.innerText = "获取群成员列表" - // console.log(qContextMenu) - // // qContextMenu.appendChild(btn) - // }) - // - // window.LLAPI.on("context-msg-menu", (event, target, msgIds) => { - // console.log("msg menu", event, target, msgIds); - // }) - // - // // console.log("getAccountInfo", LLAPI.getAccountInfo()); - // function getChatListEle() { - // chatListEle = document.getElementsByClassName("viewport-list__inner") - // console.log("chatListEle", chatListEle) - // if (chatListEle.length == 0) { - // setTimeout(getChatListEle, 500) - // } else { - // try { - // // 选择要观察的目标节点 - // const targetNode = chatListEle[0]; - // - // // 创建一个观察器实例并传入回调函数 - // const observer = new MutationObserver(function (mutations) { - // mutations.forEach(function (mutation) { - // // console.log("chat list changed", mutation.type); // 输出 mutation 的类型 - // // 获得当前聊天窗口 - // window.LLAPI.getPeer().then(peer => { - // // console.log("current peer", peer) - // if (peer && peer.chatType == "group") { - // getGroupMembers(peer.uid, false).then() - // } - // }) - // }); - // }); - // - // // 配置观察选项 - // const config = {attributes: true, childList: true, subtree: true}; - // - // // 传入目标节点和观察选项 - // observer.observe(targetNode, config); - // - // } catch (e) { - // window.llonebot.log(e) - // } - // } - // } - // - // // getChatListEle(); - } - ); - }); -} // 打开设置界面时触发 async function onSettingWindowCreated(view: Element) { @@ -584,7 +149,6 @@ async function onSettingWindowCreated(view: Element) { } -setTimeout(onLoad, 5000) export { onSettingWindowCreated diff --git a/src/server/httpserver.ts b/src/server/httpserver.ts index 1c269c3..ea4006b 100644 --- a/src/server/httpserver.ts +++ b/src/server/httpserver.ts @@ -1,16 +1,21 @@ import {getConfigUtil, log} from "../common/utils"; -// const express = require("express"); -import express = require("express"); -import {Request} from 'express'; +const express = require("express"); +import {Request, text} from 'express'; import {Response} from 'express'; -const JSONbig = require('json-bigint'); +const JSONbig = require('json-bigint')({storeAsString: true}); import {sendIPCRecallQQMsg, sendIPCSendQQMsg} from "../main/ipcsend"; -import {PostDataSendMsg} from "../common/types"; -import {friends, groups, msgHistory, selfInfo} from "../common/data"; -import {OB11ApiName, OB11Message, OB11Return, OB11MessageData} from "../onebot11/types"; +import {AtType, ChatType, Group, SelfInfo} from "../common/types"; +import {friends, getGroup, getGroupMember, getStrangerByUin, groups, msgHistory, selfInfo} from "../common/data"; +import { OB11ApiName, OB11Message, OB11Return, OB11MessageData, OB11Group, OB11GroupMember, OB11PostSendMsg, OB11MessageDataType, Friend } from '../onebot11/types'; import {OB11Constructor} from "../onebot11/constructor"; +import { NTQQApi } from "../ntqqapi/ntcall"; +import { Peer } from "../ntqqapi/ntcall"; +import { ElementType, SendMessageElement } from "../ntqqapi/types"; +import { SendMsgElementConstructor } from "../ntqqapi/constructor"; +import { uri2local } from "../onebot11/utils"; +import { v4 as uuid4 } from 'uuid'; // @SiberianHusky 2021-08-15 @@ -51,16 +56,20 @@ function checkSendMessage(sendMsgList: OB11MessageData[]) { // ==end== -function constructReturnData(status: number, data: any = {}, message: string = "") { +function constructReturnData(data: T, status: number=0, message: string = ""): OB11Return { return { status: status, retcode: status, data: data, message: message } - } +function constructErrorReturn(err: string){ + return constructReturnData(null, -1, err); +} + + function handlePost(jsonData: any, handleSendResult: (data: OB11Return) => void) { log("API receive post:" + JSON.stringify(jsonData)) if (!jsonData.params) { @@ -74,9 +83,7 @@ function handlePost(jsonData: any, handleSendResult: (data: OB11Return) => message: '' } - if (jsonData.action == "get_login_info") { - resData["data"] = selfInfo - } else if (jsonData.action == "send_private_msg" || jsonData.action == "send_group_msg") { + if (jsonData.action == "send_private_msg" || jsonData.action == "send_group_msg") { if (jsonData.action == "send_private_msg") { jsonData.message_type = "private" } else { @@ -99,8 +106,8 @@ function handlePost(jsonData: any, handleSendResult: (data: OB11Return) => return { group_id: group.uid, group_name: group.name, - member_count: group.members.length, - group_members: group.members.map(member => { + member_count: group.members?.length, + group_members: group.members?.map(member => { return { user_id: member.uin, user_name: member.cardName || member.nick, @@ -115,18 +122,18 @@ function handlePost(jsonData: any, handleSendResult: (data: OB11Return) => resData["data"] = { group_id: group.uid, group_name: group.name, - member_count: group.members.length, + member_count: group.members?.length, } } } else if (jsonData.action == "get_group_member_info") { let member = groups.find(group => group.uid == jsonData.params.group_id)?.members?.find(member => member.uin == jsonData.params.user_id) resData["data"] = { - user_id: member.uin, - user_name: member.nick, - user_display_name: member.cardName || member.nick, - nickname: member.nick, - card: member.cardName, - role: OB11Constructor.groupMemberRole(member.role), + user_id: member?.uin, + user_name: member?.nick, + user_display_name: member?.cardName || member?.nick, + nickname: member?.nick, + card: member?.cardName, + role: member && OB11Constructor.groupMemberRole(member.role), } } else if (jsonData.action == "get_group_member_list") { let group = groups.find(group => group.uid == jsonData.params.group_id) @@ -159,112 +166,93 @@ function handlePost(jsonData: any, handleSendResult: (data: OB11Return) => } -export function startExpress(port: number) { - const app = express(); - // 中间件,用于解析POST请求的请求体 - app.use(express.urlencoded({extended: true, limit: "500mb"})); - app.use(express.json({ - limit: '500mb', - verify: (req: any, res: any, buf: any, encoding: any) => { - req.rawBody = buf; - } - })); - app.use((req: any, res: any, next: any) => { - try { - req.body = JSONbig.parse(req.rawBody.toString()); - next(); - } catch (error) { - // next(error); - next(); - } +const expressAPP = express(); +expressAPP.use(express.urlencoded({extended: true, limit: "500mb"})); + +expressAPP.use((req, res, next) => { + let data = ''; + req.on('data', chunk => { + data += chunk.toString(); }); - - async function registerRouter(action: OB11ApiName, handle: (payload: PayloadType) => Promise>) { - let url = action.toString() - if (!action.startsWith("/")){ - url = "/" + action - } - async function _handle(res: Response, payload: PayloadType) { - res.send(await handle(payload)) + req.on('end', () => { + if (data) { + try { + // log("receive raw", data) + req.body = JSONbig.parse(data); + } catch (e) { + return next(e); } + } + next(); + }); + }); +// expressAPP.use(express.json({ +// limit: '500mb', +// verify: (req: any, res: any, buf: any, encoding: any) => { +// req.rawBody = buf; +// } +// })); - app.post(url, (req: Request, res: Response) => { - _handle(res, req.body).then() - }); - app.get(url, (req: Request, res: Response) => { - _handle(res, req.query as any).then() - }); - } +export function startExpress(port: number) { - function parseToOnebot12(action: OB11ApiName) { - app.post('/' + action, (req: Request, res: Response) => { - let jsonData: PostDataSendMsg = req.body; - jsonData.action = action - let resData = handlePost(jsonData, (data: OB11Return) => { - res.send(data) - }) - if (resData) { - res.send(resData) - } - }); - } + + // function parseToOnebot12(action: OB11ApiName) { + // expressAPP.post('/' + action, (req: Request, res: Response) => { + // let jsonData: PostDataSendMsg = req.body; + // jsonData.action = action + // let resData = handlePost(jsonData, (data: OB11Return) => { + // res.send(data) + // }) + // if (resData) { + // res.send(resData) + // } + // }); + // } const actionList: OB11ApiName[] = ["get_login_info", "send_private_msg", "send_group_msg", "get_group_list", "get_friend_list", "delete_msg", "get_group_member_list", "get_group_member_info"] - for (const action of actionList) { - parseToOnebot12(action as OB11ApiName) - } + // for (const action of actionList) { + // parseToOnebot12(action as OB11ApiName) + // } - app.get('/', (req: Request, res: Response) => { + expressAPP.get('/', (req: Request, res: Response) => { res.send('llonebot已启动'); }) // 处理POST请求的路由 - app.post('/', (req: Request, res: Response) => { - let jsonData: PostDataSendMsg = req.body; - let resData = handlePost(jsonData, (data: OB11Return) => { - res.send(data) - }) - if (resData) { - res.send(resData) - } - }); - app.post('/send_msg', (req: Request, res: Response) => { - let jsonData: PostDataSendMsg = req.body; - if (jsonData.message_type == "private") { - jsonData.action = "send_private_msg" - } else if (jsonData.message_type == "group") { - jsonData.action = "send_group_msg" - } else { - if (jsonData.params.group_id) { - jsonData.action = "send_group_msg" - } else { - jsonData.action = "send_private_msg" - } - } - let resData = handlePost(jsonData, (data: OB11Return) => { - res.send(data) - }) - if (resData) { - res.send(resData) - } - }) + // expressAPP.post('/', (req: Request, res: Response) => { + // let jsonData: PostDataSendMsg = req.body; + // let resData = handlePost(jsonData, (data: OB11Return) => { + // res.send(data) + // }) + // if (resData) { + // res.send(resData) + // } + // }); + // expressAPP.post('/send_msg', (req: Request, res: Response) => { + // let jsonData: PostDataSendMsg = req.body; + // if (jsonData.message_type == "private") { + // jsonData.action = "send_private_msg" + // } else if (jsonData.message_type == "group") { + // jsonData.action = "send_group_msg" + // } else { + // if (jsonData.params?.group_id) { + // jsonData.action = "send_group_msg" + // } else { + // jsonData.action = "send_private_msg" + // } + // } + // let resData = handlePost(jsonData, (data: OB11Return) => { + // res.send(data) + // }) + // if (resData) { + // res.send(resData) + // } + // }) - registerRouter<{ message_id: string }, OB11Message>("get_msg", async (payload) => { - const msg = msgHistory[payload.message_id.toString()] - if (msg) { - const msgData = await OB11Constructor.message(msg); - return constructReturnData(0, msgData) - } else { - return constructReturnData(1, {}, "消息不存在") - } - }).then(()=>{ - - }) - - app.listen(port, "0.0.0.0", () => { + expressAPP.listen(port, "0.0.0.0", () => { console.log(`llonebot started 0.0.0.0:${port}`); }); } @@ -291,4 +279,196 @@ export function postMsg(msg: OB11Message) { log(`新消息事件上报失败: ${host} ` + err + JSON.stringify(msg)); }); } -} \ No newline at end of file +} + +let routers: RecordPromise>> = {}; + +function registerRouter(action: OB11ApiName, handle: (payload: PayloadType) => Promise>) { + let url = action.toString() + if (!action.startsWith("/")){ + url = "/" + action + } + async function _handle(res: Response, payload: PayloadType) { + log("receive post data", url, payload) + try{ + const result = await handle(payload) + res.send(result) + } + catch(e){ + log(e.stack); + res.send(constructErrorReturn(e.stack.toString())) + } + } + + expressAPP.post(url, (req: Request, res: Response) => { + _handle(res, req.body).then() + }); + expressAPP.get(url, (req: Request, res: Response) => { + _handle(res, req.query as any).then() + }); + routers[url] = handle +} + +registerRouter<{ message_id: string }, OB11Message>("get_msg", async (payload) => { + log("history msg ids", Object.keys(msgHistory)); + const msg = msgHistory[payload.message_id.toString()] + if (msg) { + const msgData = await OB11Constructor.message(msg); + return constructReturnData(msgData) + } else { + return constructErrorReturn("消息不存在") + } +}) + +registerRouter<{}, SelfInfo>("get_login_info", async (payload)=>{ + return constructReturnData(selfInfo); +}) + +registerRouter<{}, Friend[]>("get_friend_list", async (payload)=>{ + return constructReturnData(OB11Constructor.friends(friends)); +}) + +registerRouter<{}, OB11Group[]>("get_group_list", async (payload)=>{ + return constructReturnData(OB11Constructor.groups(groups)); +}) + + +registerRouter<{group_id: number}, OB11Group[]>("get_group_info", async (payload)=>{ + const group = await getGroup(payload.group_id.toString()) + if (group){ + return constructReturnData(OB11Constructor.groups(groups)); + } + else{ + return constructErrorReturn(`群${payload.group_id}不存在`) + } +}) + +registerRouter<{group_id: number}, OB11GroupMember[]>("get_group_member_list", async (payload)=>{ + + const group = await getGroup(payload.group_id.toString()); + if (group){ + return constructReturnData(OB11Constructor.groupMembers(group)); + } + else{ + return constructErrorReturn(`群${payload.group_id}不存在`) + } +}) + +registerRouter<{group_id: number, user_id: number}, OB11GroupMember>("get_group_member_info", async (payload)=>{ + const member = await getGroupMember(payload.group_id.toString(), payload.user_id.toString()) + if (member){ + return constructReturnData(OB11Constructor.groupMember(payload.group_id.toString(), member)) + } + else{ + return constructErrorReturn(`群成员${payload.user_id}不存在`) + } +}) + +const handleSendMsg = async (payload)=>{ + const peer: Peer = { + chatType: ChatType.friend, + peerUid: "" + } + let group: Group | undefined = undefined; + if(payload?.group_id){ + group = groups.find(g=>g.uid == payload.group_id?.toString()) + if (!group){ + return constructErrorReturn(`群${payload.group_id}不存在`) + } + peer.chatType = ChatType.group + // peer.name = group.name + peer.peerUid = group.uid + } + else if (payload?.user_id){ + const friend = friends.find(f=>f.uin == payload.user_id.toString()) + if (friend){ + // peer.name = friend.nickName + peer.peerUid = friend.uid + } + else{ + peer.chatType = ChatType.temp + const tempUser = getStrangerByUin(payload.user_id.toString()) + if (!tempUser){ + return constructErrorReturn(`找不到私聊对象${payload.user_id}`) + } + // peer.name = tempUser.nickName + peer.peerUid = tempUser.uid + } + } + if (typeof payload.message === "string"){ + payload.message = [{ + type: OB11MessageDataType.text, + data: { + text: payload.message + } + }] as OB11MessageData[] + } + else if (!Array.isArray(payload.message)){ + payload.message = [payload.message] + } + const sendElements: SendMessageElement[] = [] + for (let sendMsg of payload.message){ + switch(sendMsg.type){ + case OB11MessageDataType.text: { + const text = sendMsg.data?.text; + if (text){ + sendElements.push(SendMsgElementConstructor.text(sendMsg.data!.text)) + } + }break; + case OB11MessageDataType.at: { + let atQQ = sendMsg.data?.qq; + if (atQQ){ + atQQ = atQQ.toString() + if (atQQ === "all"){ + sendElements.push(SendMsgElementConstructor.at(atQQ, atQQ, AtType.atAll, "全体成员")) + } + else{ + const atMember = group?.members.find(m=>m.uin == atQQ) + if (atMember){ + sendElements.push(SendMsgElementConstructor.at(atQQ, atMember.uid, AtType.atUser, atMember.cardName || atMember.nick)) + } + } + } + }break; + case OB11MessageDataType.reply: { + let replyMsgId = sendMsg.data.id; + if (replyMsgId){ + replyMsgId = replyMsgId.toString() + const replyMsg = msgHistory[replyMsgId] + if (replyMsg){ + sendElements.push(SendMsgElementConstructor.reply(replyMsg.msgSeq, replyMsgId, replyMsg.senderUin, replyMsg.senderUin)) + } + } + }break; + case OB11MessageDataType.image: { + const file = sendMsg.data?.file + if (file){ + const picPath = await (await uri2local(uuid4(), file)).path + if (picPath){ + sendElements.push(await SendMsgElementConstructor.pic(picPath)) + } + } + }break; + case OB11MessageDataType.voice: { + const file = sendMsg.data?.file + if (file){ + const voicePath = await (await uri2local(uuid4(), file)).path + if (voicePath){ + sendElements.push(await SendMsgElementConstructor.ptt(voicePath)) + } + } + } + } + } + log("send msg:", peer, sendElements) + try{ + const returnMsg = await NTQQApi.sendMsg(peer, sendElements) + return constructReturnData({message_id: returnMsg.msgId}) + }catch(e){ + return constructErrorReturn(e.toString()) + } +} + +registerRouter("send_msg", handleSendMsg) +registerRouter("send_private_msg", handleSendMsg) +registerRouter("send_group_msg", handleSendMsg) \ No newline at end of file diff --git a/webpack.base.config.js b/webpack.base.config.js index c08821c..0e33688 100644 --- a/webpack.base.config.js +++ b/webpack.base.config.js @@ -50,7 +50,7 @@ module.exports = { ] }, optimization: { - minimize: true, + minimize: false, minimizer: [ new TerserPlugin({ extractComments: false,