增加消息接收的功能

main
落雨楓 2 years ago
parent 992d1655f4
commit 484bc90692

@ -0,0 +1,20 @@
{
// 使 IntelliSense
//
// 访: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "启动程序",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceFolder}/index.js",
"outFiles": [
"${workspaceFolder}/**/*.js"
]
}
]
}

374
package-lock.json generated

@ -14,6 +14,7 @@
"decoders": "^1.25.3",
"handlebars": "^4.7.7",
"koa": "^2.13.4",
"koa-body": "^6.0.1",
"koa-router": "^10.1.1",
"lua-runner": "^2.0.3",
"micromatch": "^4.0.4",
@ -96,7 +97,6 @@
"version": "1.3.5",
"resolved": "https://registry.npmmirror.com/@types/accepts/-/accepts-1.3.5.tgz",
"integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
@ -120,7 +120,6 @@
"version": "1.19.2",
"resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.2.tgz",
"integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
"dev": true,
"dependencies": {
"@types/connect": "*",
"@types/node": "*"
@ -137,11 +136,19 @@
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
},
"node_modules/@types/co-body": {
"version": "6.1.0",
"resolved": "https://registry.npmmirror.com/@types/co-body/-/co-body-6.1.0.tgz",
"integrity": "sha512-3e0q2jyDAnx/DSZi0z2H0yoZ2wt5yRDZ+P7ymcMObvq0ufWRT4tsajyO+Q1VwVWiv9PRR4W3YEjEzBjeZlhF+w==",
"dependencies": {
"@types/node": "*",
"@types/qs": "*"
}
},
"node_modules/@types/connect": {
"version": "3.4.35",
"resolved": "https://registry.npmmirror.com/@types/connect/-/connect-3.4.35.tgz",
"integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
@ -149,14 +156,12 @@
"node_modules/@types/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmmirror.com/@types/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ==",
"dev": true
"integrity": "sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ=="
},
"node_modules/@types/cookies": {
"version": "0.7.7",
"resolved": "https://registry.npmmirror.com/@types/cookies/-/cookies-0.7.7.tgz",
"integrity": "sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==",
"dev": true,
"dependencies": {
"@types/connect": "*",
"@types/express": "*",
@ -168,7 +173,6 @@
"version": "4.17.13",
"resolved": "https://registry.npmmirror.com/@types/express/-/express-4.17.13.tgz",
"integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
"dev": true,
"dependencies": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
@ -180,36 +184,39 @@
"version": "4.17.28",
"resolved": "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
"integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
"dev": true,
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"node_modules/@types/formidable": {
"version": "2.0.5",
"resolved": "https://registry.npmmirror.com/@types/formidable/-/formidable-2.0.5.tgz",
"integrity": "sha512-uvMcdn/KK3maPOaVUAc3HEYbCEhjaGFwww4EsX6IJfWIJ1tzHtDHczuImH3GKdusPnAAmzB07St90uabZeCKPA==",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/http-assert": {
"version": "1.5.3",
"resolved": "https://registry.npmmirror.com/@types/http-assert/-/http-assert-1.5.3.tgz",
"integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==",
"dev": true
"integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA=="
},
"node_modules/@types/http-errors": {
"version": "1.8.2",
"resolved": "https://registry.npmmirror.com/@types/http-errors/-/http-errors-1.8.2.tgz",
"integrity": "sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==",
"dev": true
"integrity": "sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w=="
},
"node_modules/@types/keygrip": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/@types/keygrip/-/keygrip-1.0.2.tgz",
"integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==",
"dev": true
"integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw=="
},
"node_modules/@types/koa": {
"version": "2.13.4",
"resolved": "https://registry.npmmirror.com/@types/koa/-/koa-2.13.4.tgz",
"integrity": "sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw==",
"dev": true,
"version": "2.13.5",
"resolved": "https://registry.npmmirror.com/@types/koa/-/koa-2.13.5.tgz",
"integrity": "sha512-HSUOdzKz3by4fnqagwthW/1w/yJspTgppyyalPVbgZf8jQWvdIXcVW5h2DGtw4zYntOaeRGx49r1hxoPWrD4aA==",
"dependencies": {
"@types/accepts": "*",
"@types/content-disposition": "*",
@ -225,7 +232,6 @@
"version": "3.2.5",
"resolved": "https://registry.npmmirror.com/@types/koa-compose/-/koa-compose-3.2.5.tgz",
"integrity": "sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==",
"dev": true,
"dependencies": {
"@types/koa": "*"
}
@ -251,8 +257,7 @@
"node_modules/@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.2.tgz",
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
"dev": true
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
},
"node_modules/@types/node": {
"version": "17.0.8",
@ -271,14 +276,12 @@
"node_modules/@types/qs": {
"version": "6.9.7",
"resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
},
"node_modules/@types/range-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmmirror.com/@types/range-parser/-/range-parser-1.2.4.tgz",
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
"dev": true
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
},
"node_modules/@types/request": {
"version": "2.48.4",
@ -318,7 +321,6 @@
"version": "1.13.10",
"resolved": "https://registry.npmmirror.com/@types/serve-static/-/serve-static-1.13.10.tgz",
"integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
"dev": true,
"dependencies": {
"@types/mime": "^1",
"@types/node": "*"
@ -437,6 +439,11 @@
"es-shim-unscopables": "^1.0.0"
}
},
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmmirror.com/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"node_modules/asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@ -512,6 +519,14 @@
"node": ">=8"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/cache-content-type": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/cache-content-type/-/cache-content-type-1.0.1.tgz",
@ -567,6 +582,17 @@
"node": ">= 0.12.0"
}
},
"node_modules/co-body": {
"version": "6.1.0",
"resolved": "https://registry.npmmirror.com/co-body/-/co-body-6.1.0.tgz",
"integrity": "sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==",
"dependencies": {
"inflation": "^2.0.0",
"qs": "^6.5.2",
"raw-body": "^2.3.3",
"type-is": "^1.6.16"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -725,6 +751,15 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/dezalgo": {
"version": "1.0.4",
"resolved": "https://registry.npmmirror.com/dezalgo/-/dezalgo-1.0.4.tgz",
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
"dependencies": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@ -891,6 +926,28 @@
"node": ">= 0.12"
}
},
"node_modules/formidable": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/formidable/-/formidable-2.1.1.tgz",
"integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==",
"dependencies": {
"dezalgo": "^1.0.4",
"hexoid": "^1.0.0",
"once": "^1.4.0",
"qs": "^6.11.0"
}
},
"node_modules/formidable/node_modules/qs": {
"version": "6.11.0",
"resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"dependencies": {
"side-channel": "^1.0.4"
},
"engines": {
"node": ">=0.6"
}
},
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz",
@ -1060,6 +1117,14 @@
"node": ">= 0.4"
}
},
"node_modules/hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==",
"engines": {
"node": ">=8"
}
},
"node_modules/http-assert": {
"version": "1.5.0",
"resolved": "https://registry.npmmirror.com/http-assert/-/http-assert-1.5.0.tgz",
@ -1109,6 +1174,25 @@
"npm": ">=1.3.7"
}
},
"node_modules/iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inflation": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/inflation/-/inflation-2.0.0.tgz",
"integrity": "sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw==",
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
@ -1398,6 +1482,19 @@
"node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4"
}
},
"node_modules/koa-body": {
"version": "6.0.1",
"resolved": "https://registry.npmmirror.com/koa-body/-/koa-body-6.0.1.tgz",
"integrity": "sha512-M8ZvMD8r+kPHy28aWP9VxL7kY8oPWA+C7ZgCljrCMeaU7uX6wsIQgDHskyrAr9sw+jqnIXyv4Mlxri5R4InIJg==",
"dependencies": {
"@types/co-body": "^6.1.0",
"@types/formidable": "^2.0.5",
"@types/koa": "^2.13.5",
"co-body": "^6.1.0",
"formidable": "^2.0.1",
"zod": "^3.19.1"
}
},
"node_modules/koa-compose": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/koa-compose/-/koa-compose-4.1.0.tgz",
@ -1804,6 +1901,43 @@
"node": ">=0.6"
}
},
"node_modules/raw-body": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz",
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/raw-body/node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/raw-body/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.7.tgz",
@ -2183,6 +2317,14 @@
"which-boxed-primitive": "^1.0.2"
}
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@ -2275,6 +2417,11 @@
"engines": {
"node": ">=6"
}
},
"node_modules/zod": {
"version": "3.20.5",
"resolved": "https://registry.npmmirror.com/zod/-/zod-3.20.5.tgz",
"integrity": "sha512-BTAAliwfoB9dWf2hC+TXlyWKk/YTqRGZjHQR0WLC2A2pzierWo7KuQ1ebjS4SNaFaxg/lDItzl9/QTgLjcHbgw=="
}
},
"dependencies": {
@ -2329,7 +2476,6 @@
"version": "1.3.5",
"resolved": "https://registry.npmmirror.com/@types/accepts/-/accepts-1.3.5.tgz",
"integrity": "sha512-jOdnI/3qTpHABjM5cx1Hc0sKsPoYCp+DP/GJRGtDlPd7fiV9oXGGIcjW/ZOxLIvjGz8MA+uMZI9metHlgqbgwQ==",
"dev": true,
"requires": {
"@types/node": "*"
}
@ -2353,7 +2499,6 @@
"version": "1.19.2",
"resolved": "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.2.tgz",
"integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
"dev": true,
"requires": {
"@types/connect": "*",
"@types/node": "*"
@ -2370,11 +2515,19 @@
"resolved": "https://registry.npmjs.org/@types/caseless/-/caseless-0.12.2.tgz",
"integrity": "sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w=="
},
"@types/co-body": {
"version": "6.1.0",
"resolved": "https://registry.npmmirror.com/@types/co-body/-/co-body-6.1.0.tgz",
"integrity": "sha512-3e0q2jyDAnx/DSZi0z2H0yoZ2wt5yRDZ+P7ymcMObvq0ufWRT4tsajyO+Q1VwVWiv9PRR4W3YEjEzBjeZlhF+w==",
"requires": {
"@types/node": "*",
"@types/qs": "*"
}
},
"@types/connect": {
"version": "3.4.35",
"resolved": "https://registry.npmmirror.com/@types/connect/-/connect-3.4.35.tgz",
"integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
"dev": true,
"requires": {
"@types/node": "*"
}
@ -2382,14 +2535,12 @@
"@types/content-disposition": {
"version": "0.5.4",
"resolved": "https://registry.npmmirror.com/@types/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ==",
"dev": true
"integrity": "sha512-0mPF08jn9zYI0n0Q/Pnz7C4kThdSt+6LD4amsrYDDpgBfrVWa3TcCOxKX1zkGgYniGagRv8heN2cbh+CAn+uuQ=="
},
"@types/cookies": {
"version": "0.7.7",
"resolved": "https://registry.npmmirror.com/@types/cookies/-/cookies-0.7.7.tgz",
"integrity": "sha512-h7BcvPUogWbKCzBR2lY4oqaZbO3jXZksexYJVFvkrFeLgbZjQkU4x8pRq6eg2MHXQhY0McQdqmmsxRWlVAHooA==",
"dev": true,
"requires": {
"@types/connect": "*",
"@types/express": "*",
@ -2401,7 +2552,6 @@
"version": "4.17.13",
"resolved": "https://registry.npmmirror.com/@types/express/-/express-4.17.13.tgz",
"integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==",
"dev": true,
"requires": {
"@types/body-parser": "*",
"@types/express-serve-static-core": "^4.17.18",
@ -2413,36 +2563,39 @@
"version": "4.17.28",
"resolved": "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz",
"integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*"
}
},
"@types/formidable": {
"version": "2.0.5",
"resolved": "https://registry.npmmirror.com/@types/formidable/-/formidable-2.0.5.tgz",
"integrity": "sha512-uvMcdn/KK3maPOaVUAc3HEYbCEhjaGFwww4EsX6IJfWIJ1tzHtDHczuImH3GKdusPnAAmzB07St90uabZeCKPA==",
"requires": {
"@types/node": "*"
}
},
"@types/http-assert": {
"version": "1.5.3",
"resolved": "https://registry.npmmirror.com/@types/http-assert/-/http-assert-1.5.3.tgz",
"integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA==",
"dev": true
"integrity": "sha512-FyAOrDuQmBi8/or3ns4rwPno7/9tJTijVW6aQQjK02+kOQ8zmoNg2XJtAuQhvQcy1ASJq38wirX5//9J1EqoUA=="
},
"@types/http-errors": {
"version": "1.8.2",
"resolved": "https://registry.npmmirror.com/@types/http-errors/-/http-errors-1.8.2.tgz",
"integrity": "sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w==",
"dev": true
"integrity": "sha512-EqX+YQxINb+MeXaIqYDASb6U6FCHbWjkj4a1CKDBks3d/QiB2+PqBLyO72vLDgAO1wUI4O+9gweRcQK11bTL/w=="
},
"@types/keygrip": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/@types/keygrip/-/keygrip-1.0.2.tgz",
"integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw==",
"dev": true
"integrity": "sha512-GJhpTepz2udxGexqos8wgaBx4I/zWIDPh/KOGEwAqtuGDkOUJu5eFvwmdBX4AmB8Odsr+9pHCQqiAqDL/yKMKw=="
},
"@types/koa": {
"version": "2.13.4",
"resolved": "https://registry.npmmirror.com/@types/koa/-/koa-2.13.4.tgz",
"integrity": "sha512-dfHYMfU+z/vKtQB7NUrthdAEiSvnLebvBjwHtfFmpZmB7em2N3WVQdHgnFq+xvyVgxW5jKDmjWfLD3lw4g4uTw==",
"dev": true,
"version": "2.13.5",
"resolved": "https://registry.npmmirror.com/@types/koa/-/koa-2.13.5.tgz",
"integrity": "sha512-HSUOdzKz3by4fnqagwthW/1w/yJspTgppyyalPVbgZf8jQWvdIXcVW5h2DGtw4zYntOaeRGx49r1hxoPWrD4aA==",
"requires": {
"@types/accepts": "*",
"@types/content-disposition": "*",
@ -2458,7 +2611,6 @@
"version": "3.2.5",
"resolved": "https://registry.npmmirror.com/@types/koa-compose/-/koa-compose-3.2.5.tgz",
"integrity": "sha512-B8nG/OoE1ORZqCkBVsup/AKcvjdgoHnfi4pZMn5UwAPCbhk/96xyv284eBYW8JlQbQ7zDmnpFr68I/40mFoIBQ==",
"dev": true,
"requires": {
"@types/koa": "*"
}
@ -2484,8 +2636,7 @@
"@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmmirror.com/@types/mime/-/mime-1.3.2.tgz",
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==",
"dev": true
"integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
},
"@types/node": {
"version": "17.0.8",
@ -2504,14 +2655,12 @@
"@types/qs": {
"version": "6.9.7",
"resolved": "https://registry.npmmirror.com/@types/qs/-/qs-6.9.7.tgz",
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
"dev": true
"integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
},
"@types/range-parser": {
"version": "1.2.4",
"resolved": "https://registry.npmmirror.com/@types/range-parser/-/range-parser-1.2.4.tgz",
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
"dev": true
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
},
"@types/request": {
"version": "2.48.4",
@ -2550,7 +2699,6 @@
"version": "1.13.10",
"resolved": "https://registry.npmmirror.com/@types/serve-static/-/serve-static-1.13.10.tgz",
"integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==",
"dev": true,
"requires": {
"@types/mime": "^1",
"@types/node": "*"
@ -2649,6 +2797,11 @@
"es-shim-unscopables": "^1.0.0"
}
},
"asap": {
"version": "2.0.6",
"resolved": "https://registry.npmmirror.com/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA=="
},
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@ -2712,6 +2865,11 @@
"fill-range": "^7.0.1"
}
},
"bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="
},
"cache-content-type": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/cache-content-type/-/cache-content-type-1.0.1.tgz",
@ -2755,6 +2913,17 @@
"resolved": "https://registry.npmmirror.com/co/-/co-4.6.0.tgz",
"integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ=="
},
"co-body": {
"version": "6.1.0",
"resolved": "https://registry.npmmirror.com/co-body/-/co-body-6.1.0.tgz",
"integrity": "sha512-m7pOT6CdLN7FuXUcpuz/8lfQ/L77x8SchHCF4G0RBTJO20Wzmhn5Sp4/5WsKy8OSpifBSUrmg83qEqaDHdyFuQ==",
"requires": {
"inflation": "^2.0.0",
"qs": "^6.5.2",
"raw-body": "^2.3.3",
"type-is": "^1.6.16"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@ -2876,6 +3045,15 @@
"resolved": "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg=="
},
"dezalgo": {
"version": "1.0.4",
"resolved": "https://registry.npmmirror.com/dezalgo/-/dezalgo-1.0.4.tgz",
"integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==",
"requires": {
"asap": "^2.0.0",
"wrappy": "1"
}
},
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
@ -3015,6 +3193,27 @@
"mime-types": "^2.1.12"
}
},
"formidable": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/formidable/-/formidable-2.1.1.tgz",
"integrity": "sha512-0EcS9wCFEzLvfiks7omJ+SiYJAiD+TzK4Pcw1UlUoGnhUxDcMKjt0P7x8wEb0u6OHu8Nb98WG3nxtlF5C7bvUQ==",
"requires": {
"dezalgo": "^1.0.4",
"hexoid": "^1.0.0",
"once": "^1.4.0",
"qs": "^6.11.0"
},
"dependencies": {
"qs": {
"version": "6.11.0",
"resolved": "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz",
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
"requires": {
"side-channel": "^1.0.4"
}
}
}
},
"fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz",
@ -3142,6 +3341,11 @@
"has-symbols": "^1.0.2"
}
},
"hexoid": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="
},
"http-assert": {
"version": "1.5.0",
"resolved": "https://registry.npmmirror.com/http-assert/-/http-assert-1.5.0.tgz",
@ -3180,6 +3384,19 @@
"sshpk": "^1.7.0"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
}
},
"inflation": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/inflation/-/inflation-2.0.0.tgz",
"integrity": "sha512-m3xv4hJYR2oXw4o4Y5l6P5P16WYmazYof+el6Al3f+YlggGj6qT9kImBAnzDelRALnP5d3h4jGBPKzYCizjZZw=="
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz",
@ -3411,6 +3628,19 @@
"vary": "^1.1.2"
}
},
"koa-body": {
"version": "6.0.1",
"resolved": "https://registry.npmmirror.com/koa-body/-/koa-body-6.0.1.tgz",
"integrity": "sha512-M8ZvMD8r+kPHy28aWP9VxL7kY8oPWA+C7ZgCljrCMeaU7uX6wsIQgDHskyrAr9sw+jqnIXyv4Mlxri5R4InIJg==",
"requires": {
"@types/co-body": "^6.1.0",
"@types/formidable": "^2.0.5",
"@types/koa": "^2.13.5",
"co-body": "^6.1.0",
"formidable": "^2.0.1",
"zod": "^3.19.1"
}
},
"koa-compose": {
"version": "4.1.0",
"resolved": "https://registry.npmmirror.com/koa-compose/-/koa-compose-4.1.0.tgz",
@ -3741,6 +3971,36 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
"raw-body": {
"version": "2.5.1",
"resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz",
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
"requires": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"dependencies": {
"http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"requires": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
}
},
"statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="
}
}
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.7.tgz",
@ -4029,6 +4289,11 @@
"which-boxed-primitive": "^1.0.2"
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="
},
"uri-js": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
@ -4102,6 +4367,11 @@
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true
},
"zod": {
"version": "3.20.5",
"resolved": "https://registry.npmmirror.com/zod/-/zod-3.20.5.tgz",
"integrity": "sha512-BTAAliwfoB9dWf2hC+TXlyWKk/YTqRGZjHQR0WLC2A2pzierWo7KuQ1ebjS4SNaFaxg/lDItzl9/QTgLjcHbgw=="
}
}
}

@ -5,7 +5,7 @@
"main": "index.js",
"scripts": {
"start": "node index.js",
"start-dev": "tsc && node index.js",
"dev": "tsc && node index.js",
"build": "tsc"
},
"author": {
@ -20,6 +20,7 @@
"decoders": "^1.25.3",
"handlebars": "^4.7.7",
"koa": "^2.13.4",
"koa-body": "^6.0.1",
"koa-router": "^10.1.1",
"lua-runner": "^2.0.3",
"micromatch": "^4.0.4",

@ -5,6 +5,8 @@ import { BaseProvider, MultipleMessage } from './base/provider/BaseProvider';
import { ChannelManager } from './ChannelManager';
import { ChannelConfig, Config } from './Config';
import { EventManager } from './EventManager';
import { CommonSendMessage } from './message/Message';
import { ProviderManager } from './ProviderManager';
import { RestfulApiManager } from './RestfulApiManager';
import { RobotManager } from './RobotManager';
@ -16,6 +18,7 @@ export default class App {
public config: Config;
public srcPath: string = __dirname;
public event!: EventManager;
public robot!: RobotManager;
public provider!: ProviderManager;
public service!: ServiceManager;
@ -30,6 +33,8 @@ export default class App {
async initialize() {
await this.initModules();
await this.initRestfulApiManager();
await this.initEventManager();
await this.initRobot();
await this.initProviderManager();
await this.initServiceManager();
@ -42,6 +47,16 @@ export default class App {
await Setup.initHandlebars();
}
async initRestfulApiManager() {
this.restfulApi = new RestfulApiManager(this, this.config.http_api);
await this.restfulApi.initialize();
}
async initEventManager() {
this.event = new EventManager(this);
await this.event.initialize();
}
async initRobot() {
this.robot = new RobotManager(this, this.config.robot);
await this.robot.initialize();
@ -79,11 +94,6 @@ export default class App {
await this.channel.initialize();
}
async initRestfulApiManager() {
this.restfulApi = new RestfulApiManager(this, this.config.http_api);
await this.restfulApi.initialize();
}
/**
*
* @param serviceName
@ -102,14 +112,22 @@ export default class App {
}
/**
*
*
* @param channelId Channel ID
* @param messages
* @returns
*/
async sendMessage(channelId: string, messages: MultipleMessage): Promise<void> {
async sendPushMessage(channelId: string, messages: MultipleMessage): Promise<void> {
console.log(`[${channelId}] 消息: `, messages);
this.robot.sendMessage(channelId, messages);
this.robot.sendPushMessage(channelId, messages);
}
/**
*
* @param message
*/
async sendMessage(message: CommonSendMessage) {
}
require(file: string): any {

@ -0,0 +1,253 @@
import EventEmitter from "events";
import { debounce } from "throttle-debounce";
import App from "./App";
import { CommonReceivedMessage } from "./message/Message";
import { GroupSender, UserSender } from "./message/Sender";
import { Robot } from "./RobotManager";
export class EventManager {
private app: App;
private eventEmitter: EventEmitter;
private eventGroup: Record<string, EventGroup> = {};
private eventHandlerList: Record<string, EventGroup[]> = {};
constructor(app: App) {
this.app = app;
this.eventEmitter = new EventEmitter;
}
public async initialize() {
}
public getEventGroup() {
}
}
export const MessagePriority = {
LOWEST: 0,
LOW: 20,
DEFAULT: 40,
/**
*
*
*/
TEMP_HANDLER: 60,
HIGH: 80,
/**
*
*/
SYSTEM: 90,
/**
*
*/
HIGHEST: 100
};
export type MessageEventOptions = {
priority?: number,
/** Base sources: private, group, channel */
source?: string[],
robotApi?: string[],
};
export type CommandInfo = {
command: string,
name: string,
alias?: string[],
help?: string,
};
export type EventListenerInfo = {
priority: number;
callback: CallableFunction;
}
export type MessageCallback = (message: CommonReceivedMessage, resolved: VoidFunction) => any;
export type CommandCallback = (argv: string[], message: CommonReceivedMessage, resolved: VoidFunction) => any;
export type RawEventCallback = (robot: Robot, event: any, resolved: VoidFunction) => any;
export type AllowedList = string[] | '*';
export class EventGroup {
readonly id: string;
public allowPrivate = true;
public allowGroup = true;
public allowedGroupList: AllowedList = '*';
private commandList: CommandInfo[] = [];
private eventList: Record<string, EventListenerInfo[]> = {};
constructor(id: string) {
this.id = id;
}
public shouldAllowSource: (sender: any) => boolean = (sender) => {
if (sender instanceof UserSender) {
if (this.allowPrivate) {
return true;
}
} else if (sender instanceof GroupSender) {
if (this.allowedGroupList === '*') {
return true;
} else if (this.allowedGroupList.includes(sender.groupId)) {
return true;
}
}
return false;
}
public emit(eventName: string, ...args: any[]) {
const eventList = this.eventList[eventName];
let isResolved = false;
let isBreakAll = false;
const resolved = (breakAll: boolean = false) => {
isResolved = true;
if (breakAll) {
isBreakAll = true;
}
};
for (let eventInfo of eventList) {
eventInfo.callback(...args, resolved);
if (isResolved) {
break;
}
}
return !isBreakAll;
}
on(event: string, callback: CallableFunction, options?: MessageEventOptions) {
if (!(event in this.eventList)) {
this.eventList[event] = [];
}
let defaultOptions: MessageEventOptions = {
priority: MessagePriority.DEFAULT
};
if (!options) {
options = defaultOptions;
} else {
options = {
...defaultOptions,
...options
};
}
const eventInfo = {
callback: callback,
priority: options.priority!
};
const singleEventList = this.eventList[event];
const priority = options.priority!;
// Add event to specified position
if (singleEventList.length === 0) {
singleEventList.push(eventInfo);
} else {
for (let i = 0; i < singleEventList.length; i++) {
if (singleEventList[i].priority < priority) {
const target = i - 1;
if (target === 0) {
singleEventList.unshift(eventInfo);
} else {
this.eventList[event] = [
...singleEventList.slice(0, target),
eventInfo,
...singleEventList.slice(target)
];
}
}
}
}
}
addCommand(command: string, name: string, callback: MessageCallback, options?: MessageEventOptions): void
addCommand(commandInfo: CommandInfo, callback: MessageCallback, options?: MessageEventOptions): void
addCommand(...args: any[]): void {
// 处理传入参数
let commandInfo: Partial<CommandInfo> = {};
let callback: MessageCallback;
let options: MessageEventOptions;
if (typeof args[0] === 'string' && typeof args[1] === 'string') {
commandInfo = {
command: args[0],
name: args[1]
};
callback = args[2];
options = args[3] ?? {};
} else {
commandInfo = args[0];
callback = args[1];
options = args[2] ?? {};
}
// 注册消息
this.commandList.push(commandInfo as any);
this.on(`command/${commandInfo.command}`, callback, options);
if (Array.isArray(commandInfo.alias)) { // Add event for alias
commandInfo.alias.forEach((cmd) => {
this.on(`command/${cmd}`, callback, options);
});
}
}
/**
* Add message handle.
* will be trigger on private message or group message with mentions to robot
* @param callback
* @param options
*/
onMentionedMessage(callback: MessageCallback, options?: MessageEventOptions) {
this.on('mentionedMessage', callback, options);
this.on('privateMessage', callback, options);
}
/**
* Add private message handle.
* @param callback
* @param options
*/
onPrivateMessage(callback: MessageCallback, options?: MessageEventOptions) {
this.on('privateMessage', callback, options);
}
/**
* Add group message handle.
* @param callback
* @param options
*/
onGroupMessage(callback: MessageCallback, options?: MessageEventOptions) {
this.on('groupMessage', callback, options);
}
/**
* Add message handle.
* Will handle all messages in group
* @param callback
* @param options
*/
onMessage(callback: MessageCallback, options?: MessageEventOptions) {
this.on('message', callback, options);
}
/**
* Add raw message handle.
* Will be triggered even when the message is a command.
* @param callback
* @param options
*/
onRawMessage(callback: MessageCallback, options?: MessageEventOptions) {
this.on('rawMessage', callback, options);
}
onRawEvent(callback: RawEventCallback, options?: MessageEventOptions) {
this.on('rawEvent', callback, options);
}
}

@ -3,19 +3,22 @@ import Koa from 'koa';
import { RestfulApiConfig } from "./Config";
import Router from "koa-router";
import { makeRoutes } from "./restful/routes";
import koaBody from "koa-body";
export interface RestfulContext {
app: App
feedbot: App,
request: Koa.Request,
}
export type FullRestfulContext = RestfulContext & Koa.BaseContext;
export type RestfulRouter = Router<any, RestfulContext>;
export class RestfulApiManager {
private app: App;
private config: RestfulApiConfig;
private koa: Koa;
private router: Router<any, RestfulContext>;
public koa: Koa;
public router: RestfulRouter;
constructor(app: App, config: Pick<RestfulApiConfig, any>) {
this.app = app;
@ -33,12 +36,17 @@ export class RestfulApiManager {
public initialize(): Promise<void> {
makeRoutes(this.router, this, this.app);
this.koa.use(koaBody());
this.koa.use(this.globalMiddleware);
this.koa.on("error", (err, ctx) => {
console.error(err);
});
return new Promise((resolve) => {
this.koa.use(this.router.routes());
this.koa.listen(this.config.port, () => {
console.log(`Restful API 启动于:${this.config.port}`);
console.log(`Restful API 启动于:http://${this.config.host}:${this.config.port}`);
resolve();
});
});
@ -50,7 +58,7 @@ export class RestfulApiManager {
* @param next
*/
public globalMiddleware = async (ctx: FullRestfulContext, next: () => Promise<any>) => {
ctx.app = this.app; // 注入全局app
ctx.feedbot = this.app; // 注入全局app
await next();
}
@ -135,4 +143,8 @@ export class RestfulApiManager {
}
return false;
}
public getRobotRouter(robotId: string) {
return this.router.prefix('/' + robotId);
}
}

@ -4,24 +4,30 @@ import path from "path";
import App from "./App";
import { MultipleMessage } from "./base/provider/BaseProvider";
import { RobotConfig } from "./Config";
import { CommonSendMessage } from "./message/Message";
import { RestfulApiManager, RestfulContext, RestfulRouter } from "./RestfulApiManager";
import { Target } from "./SubscribeManager";
const ROBOT_PATH = __dirname + "/robot";
export interface Robot {
initialize(): Promise<void>;
sendMessage(targets: Target[], message: string): Promise<void>;
baseId?: string;
type: string;
robotId?: string;
uid?: string;
initialize?: () => Promise<any>;
initRestfulApi?: (router: RestfulRouter, api: RestfulApiManager) => Promise<any>;
sendMessage(message: CommonSendMessage): Promise<CommonSendMessage>;
sendPushMessage(targets: Target[], message: string): Promise<any>;
}
export class RobotManager {
private app: App;
private config: { [key: string]: RobotConfig };
private config: Record<string, RobotConfig>;
private robotClasses: { [key: string]: any };
private robots: { [key: string]: Robot };
private robotClasses: Record<string, any>;
private robots: Record<string, Robot>;
constructor(app: App, config: { [key: string]: RobotConfig }) {
constructor(app: App, config: Record<string, RobotConfig>) {
this.app = app;
this.config = config;
@ -59,7 +65,10 @@ export class RobotManager {
let robotClass = this.robotClasses[robotType];
try {
let robotObject: Robot = new robotClass(this.app, robotId, robotConfig);
await robotObject.initialize();
await robotObject.initialize?.();
await robotObject.initRestfulApi?.(this.app.restfulApi.getRobotRouter(robotId), this.app.restfulApi);
this.robots[robotId] = robotObject;
console.log(`已加载Robot: ${robotId}`);
} catch(err) {
@ -71,15 +80,15 @@ export class RobotManager {
}
}
public async sendMessage(channelId: string, messages: MultipleMessage) {
public async sendPushMessage(channelId: string, messages: MultipleMessage) {
for (let robotId in this.robots) {
let robot = this.robots[robotId];
let baseId = robot.baseId;
let robotType = robot.type;
let currentMsg: string | null = null;
if (robotId in messages) {
currentMsg = messages[robotId];
} else if (baseId && baseId in messages) {
currentMsg = messages[baseId];
} else if (robotType && robotType in messages) {
currentMsg = messages[robotType];
} else if ("base" in messages) {
currentMsg = messages["base"];
}
@ -93,7 +102,7 @@ export class RobotManager {
}
try {
await robot.sendMessage(targets, currentMsg);
await robot.sendPushMessage(targets, currentMsg);
} catch(err) {
console.error(`[${channelId}] 无法发送消息到 ${robotId} : `, err);
}

@ -1,5 +1,5 @@
import Handlebars from "handlebars";
import { Utils } from "./Utils";
import { Utils } from "./utils/Utils";
export class Setup {
public static initHandlebars() {

@ -42,7 +42,7 @@ export class BaseProvider {
*
*/
sendMessage(messages: MultipleMessage) {
this.app.sendMessage(this.channelId, messages)
this.app.sendPushMessage(this.channelId, messages)
.then(() => {})
.catch((err) => {
this.error('无法发送消息', err);
@ -53,7 +53,7 @@ export class BaseProvider {
*
*/
sendMessageAsync(messages: MultipleMessage): Promise<void> {
return this.app.sendMessage(this.channelId, messages);
return this.app.sendPushMessage(this.channelId, messages);
}
/**

@ -0,0 +1,21 @@
import { CommonGroupMessage, CommonReceivedMessage, CommonSendMessage } from "../message/Message";
import { GroupSender } from "../message/Sender";
export class EchoController {
fliterBotGroupMessage(message: CommonGroupMessage) {
let newMsg = message.content.map((chunk) => {
if (chunk.type === 'text') {
return {
type: 'text',
data: {
text: chunk.data.text.replace(/^[ ]*说[:, ]*/, '').replace(/我/g, '你'),
}
};
} else {
return chunk;
}
});
message.sendReply(newMsg);
}
}

@ -0,0 +1,184 @@
import { Robot } from "../RobotManager";
import { BaseSender, GroupSender, UserSender } from "./Sender";
export interface MessageChunk {
type: string;
baseType?: string;
data: any;
}
export interface TextMessage extends MessageChunk {
type: 'text';
data: {
text: string;
};
}
export interface ImageMessage extends MessageChunk {
type: 'image';
data: {
url: string;
alt?: string;
};
}
export interface VoiceMessage extends MessageChunk {
type: 'voice';
data: {
url: string;
text?: string;
};
}
export interface AttachmentMessage extends MessageChunk {
type: 'attachment';
data: {
url: string;
fileName: string;
};
}
export interface MentionMessage extends MessageChunk {
type: 'mention';
data: {
uid: string;
text?: string;
};
}
export type CommonMessageType = "text" | "combine" | "image" | "media" | "toast";
export type CommonMessageOrigin = "private" | "group" | "channel";
/** 基本消息 */
export class CommonMessage {
/** 消息ID */
id?: string;
/** 消息内容 */
content: MessageChunk[] = [];
/** 主类型 */
type: string | CommonMessageType = "text";
origin: string | CommonMessageOrigin = "private";
/** 回复的消息ID */
replyId?: string;
/** 提到的人 */
mentions?: { uid: string, text?: string }[];
/**
*
* @param uid ID
* @param text
* @returns
*/
public mention(uid: string, text?: string) {
// 私聊消息不支持
if (this.origin === 'private') {
return false;
}
if (typeof this.mentions === 'undefined') {
this.mentions = [];
} else if (this.mentions!.find((u) => u.uid === uid)) {
return true;
}
this.mentions.push({ uid, text });
this.content.unshift({
type: 'mention',
data: { uid, text }
});
return true;
}
/**
*
* @param uid ID
* @returns
*/
public removeMention(uid: string) {
// 私聊消息不支持
if (this.origin === 'private') {
return false;
}
if (typeof this.mentions === 'undefined') {
return true;
} else {
this.mentions = this.mentions.filter((u) => u.uid !== uid);
if (this.mentions.length === 0) {
delete this.mentions;
}
this.content = this.content.filter((msg) => msg.type !== 'mention' || msg.data?.uid !== uid);
return true;
}
}
}
/** 基本发送的消息 */
export class CommonSendMessage extends CommonMessage {
sender: Robot;
targetId: string;
constructor(sender: Robot, targetType: string, targetId: string, content?: MessageChunk[]) {
super();
this.sender = sender;
this.type = targetType;
this.targetId = targetId;
if (Array.isArray(content)) this.content = content;
}
}
export class CommonReceivedMessage extends CommonMessage {
// 接收时间
time: Date = new Date();
// 接收者
receiver: Robot;
// 发送者
sender: any;
constructor(receiver: Robot, messageId?: string) {
super();
this.receiver = receiver;
this.id = messageId;
}
public async sendReply(message: string | MessageChunk[], addReply: boolean = false): Promise<CommonSendMessage | null> {
const sender = this.sender as BaseSender;
let newMessage = new CommonSendMessage(this.receiver!, sender.type, sender.targetId);
if (typeof message === 'string') {
let msgContent: MessageChunk[] = [{
type: 'text',
data: { text: message }
}];
newMessage.content = msgContent;
} else if (Array.isArray(message)) {
newMessage.content = message;
} else {
return null;
}
newMessage = await this.receiver.sendMessage(newMessage);
return newMessage;
}
}
export class CommonPrivateMessage<US extends UserSender> extends CommonReceivedMessage {
sender: US;
constructor(sender: US, receiver: Robot, messageId?: string) {
super(receiver, messageId);
this.sender = sender;
}
}
export class CommonGroupMessage<GS extends GroupSender = GroupSender> extends CommonReceivedMessage {
sender: GS;
constructor(sender: GS, receiver: Robot, messageId?: string) {
super(receiver, messageId);
this.sender = sender;
}
}

@ -0,0 +1,66 @@
export type BaseSenderType = "user" | "group" | "channel";
export interface BaseSender {
readonly type: string | BaseSenderType;
readonly targetId: string;
}
export class UserSender implements BaseSender {
public readonly type = "user";
public uid: string;
public userName?: string;
public nickName?: string;
constructor(uid: string) {
this.uid = uid;
}
static newAnonymous() {
return new UserSender('');
}
get targetId() {
return this.uid;
}
get displayName() {
return this.nickName ?? this.userName ?? this.uid;
}
}
export class GroupSender {
public readonly type = "group";
public groupId: string;
public groupName?: string;
public uid: string;
public userName?: string;
public globalNickName?: string;
public nickName?: string;
constructor(groupId: string, uid: string) {
this.groupId = groupId;
this.uid = uid;
}
get targetId() {
return this.groupId;
}
get groupDisplayName() {
return this.groupName ?? this.groupId;
}
get displayName() {
return this.nickName ?? this.globalNickName ?? this.userName ?? this.uid;
}
get userSender() {
let sender = new UserSender(this.uid);
sender.userName = this.userName;
sender.nickName = this.globalNickName;
return sender;
}
}

@ -2,7 +2,11 @@ import App from "../App";
import { Robot } from "../RobotManager";
import { Target } from "../SubscribeManager";
import request from "request-promise";
import { Utils } from "../Utils";
import { Utils } from "../utils/Utils";
import { FullRestfulContext, RestfulApiManager, RestfulRouter } from "../RestfulApiManager";
import koa from "koa";
import { convertMessageToQQChunk, parseQQMessageChunk, QQFaceMessage, QQGroupMessage, QQGroupSender, QQImageMessage, QQPrivateMessage, QQUserSender, QQVoiceMessage } from "./qq/Message";
import { CommonReceivedMessage, CommonSendMessage, MentionMessage, TextMessage } from "../message/Message";
export type QQRobotConfig = {
user: string;
@ -10,23 +14,109 @@ export type QQRobotConfig = {
baseId?: string;
}
export type QQGroupInfo = {
groupId: string,
groupName?: string,
memberCount?: number,
memberLimit?: number
};
export default class QQRobot implements Robot {
private robotId: string;
public type = 'qq';
public uid: string;
public robotId: string;
private app: App;
private endpoint: string;
private botQQ: number;
public baseId?: string;
private taskId?: NodeJS.Timer;
private groupList: QQGroupInfo[] = [];
constructor(app: App, robotId: string, config: QQRobotConfig) {
this.app = app;
this.robotId = robotId;
this.endpoint = 'http://' + config.host;
this.botQQ = parseInt(config.user);
this.baseId = config.baseId;
this.uid = config.user;
}
async initialize() {
this.refreshRobotInfo();
// 每30分钟刷新一次信息
this.taskId = setInterval(() => {
this.refreshRobotInfo();
}, 30 * 60 * 1000);
}
async refreshRobotInfo() {
// 刷新群信息
let remoteGroupList = await this.getGroupList();
remoteGroupList.forEach((groupInfo) => {
if (groupInfo.group_id) {
this.groupList.push({
groupId: groupInfo.group_id,
groupName: groupInfo.group_name,
memberCount: groupInfo.member_count,
memberLimit: groupInfo.max_member_count
});
}
});
}
async initRestfulApi(router: RestfulRouter, api: RestfulApiManager) {
api.router.post(`/event`, this.handlePostEvent.bind(this));
}
async handlePostEvent(ctx: FullRestfulContext, next: koa.Next) {
if (ctx.request.body?.post_type) {
const postData = ctx.request.body;
switch (postData.post_type) {
case 'message':
this.handleMessage(postData);
break;
}
}
ctx.body = 'OK';
await next();
}
/**
*
* @param postData
*/
async handleMessage(postData: any) {
if (postData.message_id) {
if (postData.message_type === 'group') {
// 处理群消息
let groupInfo = this.groupList.find((info) => info.groupId === postData.group_id);
let groupSender = new QQGroupSender(postData.group_id, postData.user_id);
groupSender.groupInfo = groupInfo;
groupSender.groupName = groupInfo?.groupName;
groupSender.globalNickName = postData.sender?.nickname;
groupSender.nickName = postData.sender?.card;
groupSender.role = postData.sender?.role ?? 'member';
groupSender.level = postData.sender?.level;
groupSender.title = postData.sender?.title;
let message = new QQGroupMessage(groupSender, this, postData.message_id.toString());
message.time = new Date(postData.time * 1000);
message = await parseQQMessageChunk(postData.message ?? [], message);
} else if (postData.message_type === 'private') {
// 处理私聊消息
let userSender = new QQUserSender(postData.user_id);
userSender.nickName = postData.sender?.nickname;
let message = new QQPrivateMessage(userSender, this, postData.message_id.toString());
message.time = new Date(postData.time * 1000);
message = await parseQQMessageChunk(postData.message ?? [], message);
}
}
}
/**
@ -35,8 +125,8 @@ export default class QQRobot implements Robot {
* @param message -
* @returns
*/
async sendToUser(user: number|number[], message: string) {
if(Array.isArray(user)){ //发送给多个用户的处理
async sendToUser(user: string | string[], message: string | any[]) {
if (Array.isArray(user)) { //发送给多个用户的处理
for (let one of user) {
await this.sendToUser(one, message);
await Utils.sleep(100);
@ -53,8 +143,8 @@ export default class QQRobot implements Robot {
/**
*
*/
async sendToGroup(group: number|number[], message: string) {
if(Array.isArray(group)){ //发送给多个群组的处理
async sendToGroup(group: string | string[], message: string | any[]) {
if (Array.isArray(group)) { //发送给多个群组的处理
for (let one of group) {
await this.sendToGroup(one, message);
await Utils.sleep(100);
@ -70,15 +160,31 @@ export default class QQRobot implements Robot {
/**
*
* @param message
*/
async sendMessage(targets: Target[], message: string) {
let groupList: number[] = [];
let userList: number[] = [];
async sendMessage(message: CommonSendMessage): Promise<CommonSendMessage> {
let msgData = await convertMessageToQQChunk(message);
if (message.origin === 'private') {
await this.sendToUser(message.targetId, msgData);
} else if (message.origin === 'group') {
await this.sendToGroup(message.targetId, msgData);
}
return message;
}
/**
*
*/
async sendPushMessage(targets: Target[], message: string) {
let groupList: string[] = [];
let userList: string[] = [];
for (let target of targets) {
if (target.type === "group") {
groupList.push(parseInt(target.identity));
groupList.push(target.identity);
} else if (target.type === "user") {
userList.push(parseInt(target.identity));
userList.push(target.identity);
}
}
@ -90,6 +196,15 @@ export default class QQRobot implements Robot {
}
}
async getGroupList(): Promise<any[]> {
const res = await this.doApiRequest('get_group_list', {});
if (res && res.status === 'ok') {
return res.data;
} else {
return [];
}
}
/**
* API
*/

@ -1,8 +1,9 @@
import TelegramBot from "node-telegram-bot-api";
import App from "../App";
import { CommonSendMessage } from "../message/Message";
import { Robot } from "../RobotManager";
import { Target } from "../SubscribeManager";
import { Utils } from "../Utils";
import { Utils } from "../utils/Utils";
export type TelegramRobotConfig = {
token: string;
@ -11,13 +12,14 @@ export type TelegramRobotConfig = {
}
export default class TelegramRobot implements Robot {
private robotId: string;
bot: TelegramBot;
baseId?: string | undefined;
public type = 'telegram';
public robotId: string;
public uid?: string;
private bot: TelegramBot;
constructor(app: App, robotId: string, config: TelegramRobotConfig) {
this.robotId = robotId;
this.baseId = config.baseId;
let botOptions: any = {
polling: true
@ -69,12 +71,20 @@ export default class TelegramRobot implements Robot {
return await this.bot.sendMessage(chatId, message);
}
/**
*
* @param message
*/
async sendMessage(message: CommonSendMessage): Promise<CommonSendMessage> {
return message;
}
/**
*
* @param targets
* @param message
*/
async sendMessage(targets: Target[], message: string): Promise<void> {
async sendPushMessage(targets: Target[], message: string): Promise<void> {
let chatIdList: number[] = [];
for (let target of targets) {
chatIdList.push(parseInt(target.identity));

@ -0,0 +1,223 @@
import { CommonGroupMessage, CommonPrivateMessage, CommonReceivedMessage, CommonSendMessage, MentionMessage, MessageChunk, TextMessage } from "../../message/Message";
import { GroupSender, UserSender } from "../../message/Sender";
import { QQGroupInfo } from "../QQRobot";
export interface QQFaceMessage extends MessageChunk {
type: 'qqface';
data: {
id: string
};
}
export interface QQImageMessage extends MessageChunk {
type: 'qqimage';
data: {
url: string;
alt?: string;
subType?: string;
};
}
export interface QQVoiceMessage extends MessageChunk {
type: 'qqvoice';
data: {
url: string;
};
}
export interface QQUrlMessage extends MessageChunk {
type: 'qqurl';
data: {
url: string;
title: string;
};
}
export class QQUserSender extends UserSender {
constructor(uid: string) {
super(uid);
this.userName = uid;
}
}
export class QQGroupSender extends GroupSender {
public role: "owner" | "admin" | "member" = 'member';
public level?: string;
public title?: string;
public groupInfo?: QQGroupInfo;
constructor(groupId: string, uid: string) {
super(groupId, uid);
this.userName = uid;
}
get userSender() {
let sender = new QQUserSender(this.uid);
sender.userName = this.userName;
sender.nickName = this.globalNickName;
return sender;
}
}
/**
*
* @param messageData
* @param message
* @returns
*/
export async function parseQQMessageChunk(messageData: any[], message: CommonReceivedMessage): Promise<CommonReceivedMessage> {
let willIgnoreMention = false;
messageData.forEach((chunkData) => {
if (chunkData.type) {
switch (chunkData.type) {
case 'text':
message.content.push({
type: 'text',
data: {
text: chunkData.data?.text ?? ''
}
} as TextMessage);
break;
case 'image':
message.content.push({
type: 'qqimage',
baseType: 'image',
data: {
url: chunkData.data?.url ?? '',
alt: chunkData.data?.file,
subType: chunkData.data?.subType
}
} as QQImageMessage);
break;
case 'record':
message.content.push({
type: 'qqvoice',
baseType: 'voice',
data: {
url: chunkData.data?.url ?? '',
}
} as QQVoiceMessage);
break;
case 'face':
message.content.push({
type: 'qqface',
data: {
id: chunkData.data?.id ?? '',
}
} as QQFaceMessage);
break;
case 'at':
if (chunkData.data?.qq) {
if (!willIgnoreMention) {
message.mention(chunkData.data.qq);
message.content.push({
type: 'mention',
data: {
uid: chunkData.data.qq
}
} as MentionMessage);
} else {
willIgnoreMention = false;
}
}
break;
case 'reply':
if (chunkData.data?.id) {
message.replyId = chunkData.data.id;
willIgnoreMention = true; // 忽略下一个“@”
}
break;
}
}
});
if (message.content.length === 1) {
// 检查单一消息的类型
switch (message.content[0].type) {
case 'qqimage':
message.type = 'image';
break;
case 'qqvoice':
message.type = 'voice';
break;
}
}
return message;
}
export async function convertMessageToQQChunk(message: CommonSendMessage) {
let msgChunk: any[] = [];
message.content.forEach((rawChunk) => {
let chunk = rawChunk;
if (rawChunk.baseType && !rawChunk.type.startsWith('qq')) {
chunk = {
...rawChunk,
type: rawChunk.baseType,
};
}
switch (chunk.type) {
case 'text':
msgChunk.push({
type: 'text',
data: {
url: chunk.data.url
}
});
break;
case 'qqface':
msgChunk.push({
type: 'face',
data: { id: chunk.data.id }
});
break;
case 'image':
case 'qqimage':
msgChunk.push({
type: 'image',
data: {
file: chunk.data.url,
subType: chunk.data.subType ?? 0
}
});
break;
case 'voice':
case 'qqvoice':
msgChunk.push({
type: 'record',
data: {
file: chunk.data.url
}
});
break;
case 'mention':
msgChunk.push({
type: 'at',
data: {
qq: chunk.data.uid
}
});
break;
}
})
if (message.replyId) {
msgChunk.unshift({
type: 'reply',
data: { id: message.replyId }
});
}
return msgChunk;
}
export class QQPrivateMessage extends CommonPrivateMessage<QQUserSender> {
}
export class QQGroupMessage extends CommonGroupMessage<QQGroupSender> {
}

@ -1,7 +1,7 @@
import App from "../App";
import { Service } from "../ServiceManager";
import Pusher, { Channel } from 'pusher-js';
import { Utils } from "../Utils";
import { Utils } from "../utils/Utils";
export type PusherServiceConfig = {
app_id: string;

@ -10,7 +10,7 @@ export class Utils {
static getCurrentDate(): string {
let date = new Date();
return date.getFullYear() + '年' + date.getMonth() + '月' + date.getDate() + '日';
return date.getFullYear() + '年' + (date.getMonth() + 1) + '月' + date.getDate() + '日';
}
static count(dict: { [key: string]: any }): number {

@ -0,0 +1 @@
export type AnyFunction = (...args: any) => any;
Loading…
Cancel
Save