diff --git a/README.md b/README.md index 6e5f26e414..cfaeca8906 100644 --- a/README.md +++ b/README.md @@ -66,10 +66,10 @@ Koishi 在开发时借助了下面的工具: ### 对比 -| 特性 | [koishi
1.3.0](https://www.npmjs.com/package/koishi/v/1.3.0) | [cqhttp
1.2.0](https://www.npmjs.com/package/cqhttp/v/1.2.0) | [cq-websocket
2.0.2](https://www.npmjs.com/package/cq-websocket/v/2.0.2) | [lemon-bot
0.6.0](https://www.npmjs.com/package/lemon-bot/v/0.6.0) | [@ionjs/core
0.6.5](https://www.npmjs.com/package/@ionjs/core/v/0.6.5) | +| 特性 | [koishi
1.10.0](https://www.npmjs.com/package/koishi/v/1.10.0) | [cqhttp
1.2.0](https://www.npmjs.com/package/cqhttp/v/1.2.0) | [cq-websocket
2.0.2](https://www.npmjs.com/package/cq-websocket/v/2.0.2) | [lemon-bot
0.6.0](https://www.npmjs.com/package/lemon-bot/v/0.6.0) | [@ionjs/core
0.6.5](https://www.npmjs.com/package/@ionjs/core/v/0.6.5) | |:--:|:--:|:--:|:--:|:--:|:--:| -| 依赖数量 | [10](http://npm.anvaka.com/#/view/2d/koishi-core/1.3.0) / [21](http://npm.anvaka.com/#/view/2d/koishi/1.3.0) | [62](http://npm.anvaka.com/#/view/2d/cqhttp/1.1.1) | [37](http://npm.anvaka.com/#/view/2d/cq-websocket/2.0.2) | [65](http://npm.anvaka.com/#/view/2d/lemon-bot/0.6.0) | [73](http://npm.anvaka.com/#/view/2d/%2540ionjs%252Fcore/0.6.5) | -| 安装体积 (MB) | [0.78](https://packagephobia.now.sh/result?p=koishi-core@1.3.0) / [2.14](https://packagephobia.now.sh/result?p=koishi@1.3.0) | [1.86](https://packagephobia.now.sh/result?p=cqhttp@1.1.1) | [2.82](https://packagephobia.now.sh/result?p=cq-websocket) | [2.56](https://packagephobia.now.sh/result?p=lemon-bot) | [2.32](https://packagephobia.now.sh/result?p=@ionjs/core) | +| 依赖数量 | [10](http://npm.anvaka.com/#/view/2d/koishi-core/1.10.0) / [21](http://npm.anvaka.com/#/view/2d/koishi/1.10.0) | [62](http://npm.anvaka.com/#/view/2d/cqhttp/1.1.1) | [37](http://npm.anvaka.com/#/view/2d/cq-websocket/2.0.2) | [65](http://npm.anvaka.com/#/view/2d/lemon-bot/0.6.0) | [73](http://npm.anvaka.com/#/view/2d/%2540ionjs%252Fcore/0.6.5) | +| 安装体积 (MB) | [0.78](https://packagephobia.now.sh/result?p=koishi-core@1.10.0) / [2.28](https://packagephobia.now.sh/result?p=koishi@1.10.0) | [1.86](https://packagephobia.now.sh/result?p=cqhttp@1.1.1) | [2.82](https://packagephobia.now.sh/result?p=cq-websocket) | [2.56](https://packagephobia.now.sh/result?p=lemon-bot) | [2.32](https://packagephobia.now.sh/result?p=@ionjs/core) | | HTTP | ✔️ | ✔️ | ❌ | ✔️ | ✔️ | | WebSocket | ✔️ | ❌ | ✔️ | ❌ | ❌ | | 反向 WebSocket | ❌ | ❌ | ❌ | ❌ | ❌ | diff --git a/package.json b/package.json index 99953191af..61fca4f584 100644 --- a/package.json +++ b/package.json @@ -23,21 +23,21 @@ "version": "1.0.0", "license": "MIT", "devDependencies": { - "@octokit/rest": "^17.0.0", + "@octokit/rest": "^17.0.1", "@types/cross-spawn": "^6.0.1", "@types/fs-extra": "^8.1.0", - "@types/jest": "^25.1.3", - "@types/node": "^13.7.7", + "@types/jest": "^25.1.4", + "@types/node": "^13.9.0", "@types/semver": "^7.1.0", - "@typescript-eslint/eslint-plugin": "^2.22.0", - "@typescript-eslint/parser": "^2.22.0", - "cac": "^6.5.6", + "@typescript-eslint/eslint-plugin": "^2.23.0", + "@typescript-eslint/parser": "^2.23.0", + "cac": "^6.5.7", "cross-spawn": "^7.0.1", "del": "^5.1.0", "eslint": "^6.8.0", "eslint-config-standard": "^14.1.0", "eslint-plugin-import": "^2.20.1", - "eslint-plugin-jest": "^23.8.1", + "eslint-plugin-jest": "^23.8.2", "eslint-plugin-node": "^11.0.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-standard": "^4.0.1", @@ -47,9 +47,9 @@ "jest": "^25.1.0", "kleur": "^3.0.3", "latest-version": "^5.1.0", - "open": "^7.0.2", + "open": "^7.0.3", "ora": "^4.0.3", - "p-map": "^3.0.0", + "p-map": "^4.0.0", "prompts": "^2.3.1", "semver": "^7.1.3", "ts-jest": "^25.2.1", diff --git a/packages/database-level/package.json b/packages/database-level/package.json index cc12bc5d88..fdf1a02a31 100644 --- a/packages/database-level/package.json +++ b/packages/database-level/package.json @@ -1,7 +1,7 @@ { "name": "koishi-database-level", "description": "Leveldb support for Koishi", - "version": "1.1.4", + "version": "1.1.5", "main": "dist/index.js", "files": [ "dist" @@ -33,10 +33,10 @@ "leveldb" ], "devDependencies": { - "koishi-test-utils": "^3.1.3" + "koishi-test-utils": "^3.1.4" }, "peerDependencies": { - "koishi-core": "^1.10.1" + "koishi-core": "^1.11.0" }, "dependencies": { "@types/leveldown": "^4.0.2", diff --git a/packages/database-memory/package.json b/packages/database-memory/package.json index f2ae5b3580..73fc0424e2 100644 --- a/packages/database-memory/package.json +++ b/packages/database-memory/package.json @@ -1,7 +1,7 @@ { "name": "koishi-database-memory", "description": "An in-memory database implementation for Koishi", - "version": "1.1.4", + "version": "1.1.5", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -22,7 +22,7 @@ }, "homepage": "https://github.com/koishijs/koishi/tree/master/packages/database-memory#readme", "peerDependencies": { - "koishi-core": "^1.10.1" + "koishi-core": "^1.11.0" }, "dependencies": { "koishi-utils": "^1.0.4" diff --git a/packages/database-mysql/package.json b/packages/database-mysql/package.json index 06fc22aed3..87bc779b9e 100644 --- a/packages/database-mysql/package.json +++ b/packages/database-mysql/package.json @@ -1,7 +1,7 @@ { "name": "koishi-database-mysql", "description": "MySQL support for Koishi", - "version": "1.1.4", + "version": "1.1.5", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -35,7 +35,7 @@ "@types/mysql": "^2.15.9" }, "peerDependencies": { - "koishi-core": "^1.10.1" + "koishi-core": "^1.11.0" }, "dependencies": { "koishi-utils": "^1.0.4", diff --git a/packages/database-sqlite/package.json b/packages/database-sqlite/package.json index ffb72a6f85..c10a0d4a5c 100644 --- a/packages/database-sqlite/package.json +++ b/packages/database-sqlite/package.json @@ -1,6 +1,6 @@ { "name": "koishi-database-sqlite", - "version": "1.0.0-alpha.10", + "version": "1.0.0-alpha.11", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -22,10 +22,10 @@ "homepage": "https://github.com/koishijs/koishi/tree/master/packages/database-sqlite#readme", "devDependencies": { "@types/sqlite3": "^3.1.6", - "koishi-test-utils": "^3.1.3" + "koishi-test-utils": "^3.1.4" }, "peerDependencies": { - "koishi-core": "^1.10.1" + "koishi-core": "^1.11.0" }, "dependencies": { "koishi-utils": "^1.0.4", diff --git a/packages/koishi-cli/README.md b/packages/koishi-cli/README.md index f9a3e51a68..eb49f94f1e 100644 --- a/packages/koishi-cli/README.md +++ b/packages/koishi-cli/README.md @@ -59,10 +59,10 @@ Koishi 在开发时借助了下面的工具: ### 对比 -| 特性 | [koishi
1.3.0](https://www.npmjs.com/package/koishi/v/1.3.0) | [cqhttp
1.2.0](https://www.npmjs.com/package/cqhttp/v/1.2.0) | [cq-websocket
2.0.2](https://www.npmjs.com/package/cq-websocket/v/2.0.2) | [lemon-bot
0.6.0](https://www.npmjs.com/package/lemon-bot/v/0.6.0) | [@ionjs/core
0.6.5](https://www.npmjs.com/package/@ionjs/core/v/0.6.5) | +| 特性 | [koishi
1.10.0](https://www.npmjs.com/package/koishi/v/1.10.0) | [cqhttp
1.2.0](https://www.npmjs.com/package/cqhttp/v/1.2.0) | [cq-websocket
2.0.2](https://www.npmjs.com/package/cq-websocket/v/2.0.2) | [lemon-bot
0.6.0](https://www.npmjs.com/package/lemon-bot/v/0.6.0) | [@ionjs/core
0.6.5](https://www.npmjs.com/package/@ionjs/core/v/0.6.5) | |:--:|:--:|:--:|:--:|:--:|:--:| -| 依赖数量 | [10](http://npm.anvaka.com/#/view/2d/koishi-core/1.3.0) / [21](http://npm.anvaka.com/#/view/2d/koishi/1.3.0) | [62](http://npm.anvaka.com/#/view/2d/cqhttp/1.1.1) | [37](http://npm.anvaka.com/#/view/2d/cq-websocket/2.0.2) | [65](http://npm.anvaka.com/#/view/2d/lemon-bot/0.6.0) | [73](http://npm.anvaka.com/#/view/2d/%2540ionjs%252Fcore/0.6.5) | -| 安装体积 (MB) | [0.78](https://packagephobia.now.sh/result?p=koishi-core@1.3.0) / [2.14](https://packagephobia.now.sh/result?p=koishi@1.3.0) | [1.86](https://packagephobia.now.sh/result?p=cqhttp@1.1.1) | [2.82](https://packagephobia.now.sh/result?p=cq-websocket) | [2.56](https://packagephobia.now.sh/result?p=lemon-bot) | [2.32](https://packagephobia.now.sh/result?p=@ionjs/core) | +| 依赖数量 | [10](http://npm.anvaka.com/#/view/2d/koishi-core/1.10.0) / [21](http://npm.anvaka.com/#/view/2d/koishi/1.10.0) | [62](http://npm.anvaka.com/#/view/2d/cqhttp/1.1.1) | [37](http://npm.anvaka.com/#/view/2d/cq-websocket/2.0.2) | [65](http://npm.anvaka.com/#/view/2d/lemon-bot/0.6.0) | [73](http://npm.anvaka.com/#/view/2d/%2540ionjs%252Fcore/0.6.5) | +| 安装体积 (MB) | [0.78](https://packagephobia.now.sh/result?p=koishi-core@1.10.0) / [2.28](https://packagephobia.now.sh/result?p=koishi@1.10.0) | [1.86](https://packagephobia.now.sh/result?p=cqhttp@1.1.1) | [2.82](https://packagephobia.now.sh/result?p=cq-websocket) | [2.56](https://packagephobia.now.sh/result?p=lemon-bot) | [2.32](https://packagephobia.now.sh/result?p=@ionjs/core) | | HTTP | ✔️ | ✔️ | ❌ | ✔️ | ✔️ | | WebSocket | ✔️ | ❌ | ✔️ | ❌ | ❌ | | 反向 WebSocket | ❌ | ❌ | ❌ | ❌ | ❌ | diff --git a/packages/koishi-cli/package.json b/packages/koishi-cli/package.json index b96ea98d47..3fb2c32fb5 100644 --- a/packages/koishi-cli/package.json +++ b/packages/koishi-cli/package.json @@ -1,7 +1,7 @@ { "name": "koishi", "description": "A QQ bot framework based on CQHTTP", - "version": "1.10.1", + "version": "1.11.0", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -32,15 +32,15 @@ ], "devDependencies": { "@types/js-yaml": "^3.12.2", - "@types/prompts": "^2.0.3" + "@types/prompts": "^2.0.5" }, "dependencies": { - "cac": "^6.5.6", + "cac": "^6.5.7", "js-yaml": "^3.13.1", "kleur": "^3.0.3", - "koishi-core": "^1.10.1", - "koishi-plugin-common": "^2.1.5", - "koishi-plugin-schedule": "^1.0.10", + "koishi-core": "^1.11.0", + "koishi-plugin-common": "^2.1.6", + "koishi-plugin-schedule": "^1.0.11", "koishi-utils": "^1.0.4", "prompts": "^2.3.1" } diff --git a/packages/koishi-cli/src/worker.ts b/packages/koishi-cli/src/worker.ts index 6347e45b25..af2c13d960 100644 --- a/packages/koishi-cli/src/worker.ts +++ b/packages/koishi-cli/src/worker.ts @@ -16,8 +16,7 @@ if (process.env.KOISHI_LOG_LEVEL !== undefined) { } function handleException (error: any) { - const message = types.isNativeError(error) ? error.stack : String(error) - logger.error(message, baseLogLevel) + logger.error(error, baseLogLevel) process.exit(1) } diff --git a/packages/koishi-core/package.json b/packages/koishi-core/package.json index 58fdb7d388..33510401ef 100644 --- a/packages/koishi-core/package.json +++ b/packages/koishi-core/package.json @@ -1,7 +1,7 @@ { "name": "koishi-core", "description": "Core features for Koishi", - "version": "1.10.1", + "version": "1.11.0", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -35,8 +35,8 @@ "@types/debug": "^4.1.5", "@types/ws": "^7.2.2", "get-port": "^5.1.1", - "koishi-database-memory": "^1.1.4", - "koishi-test-utils": "^3.1.3" + "koishi-database-memory": "^1.1.5", + "koishi-test-utils": "^3.1.4" }, "dependencies": { "axios": "^0.19.2", @@ -44,6 +44,7 @@ "escape-string-regexp": "^2.0.0", "koishi-utils": "^1.0.4", "leven": "^3.1.0", - "ws": "^7.2.1" + "ms": "^2.1.2", + "ws": "^7.2.3" } } diff --git a/packages/koishi-core/src/app.ts b/packages/koishi-core/src/app.ts index 703f2f70a6..f5c43799dc 100644 --- a/packages/koishi-core/src/app.ts +++ b/packages/koishi-core/src/app.ts @@ -20,8 +20,11 @@ export interface AppOptions { type?: ServerType database?: DatabaseConfig nickname?: string | string[] + retryTimes?: number + retryInterval?: number maxMiddlewares?: number commandPrefix?: string | string[] + defaultAuthority?: number | ((meta: Meta) => number) quickOperationTimeout?: number similarityCoefficient?: number } @@ -75,6 +78,7 @@ function createLeadingRE (patterns: string[], prefix = '', suffix = '') { const defaultOptions: AppOptions = { maxMiddlewares: 64, + retryInterval: 5000, } export enum Status { closed, opening, open, closing } @@ -375,7 +379,10 @@ export class App extends Context { // attach user data const userFields = new Set(['flag']) this.emitEvent(meta, 'before-user', userFields, meta.$argv) - const user = await this.database.observeUser(meta.userId, Array.from(userFields)) + const defaultAuthority = typeof this.options.defaultAuthority === 'function' + ? this.options.defaultAuthority(meta) + : this.options.defaultAuthority || 0 + const user = await this.database.observeUser(meta.userId, defaultAuthority, Array.from(userFields)) Object.defineProperty(meta, '$user', { value: user, writable: true }) // emit attach event diff --git a/packages/koishi-core/src/command.ts b/packages/koishi-core/src/command.ts index f4e06fe0bb..d1942c1da6 100644 --- a/packages/koishi-core/src/command.ts +++ b/packages/koishi-core/src/command.ts @@ -206,7 +206,7 @@ export class Command { option (rawName: string, description: string, config?: OptionConfig): this option (rawName: string, ...args: [OptionConfig?] | [string, OptionConfig?]) { const description = typeof args[0] === 'string' ? args.shift() as string : undefined - const config = args[0] as CommandConfig || {} + const config = args[0] as OptionConfig || {} const option = parseOption(rawName, description, config, this._optsDef) this._options.push(option) for (const name of option.names) { diff --git a/packages/koishi-core/src/sender.ts b/packages/koishi-core/src/sender.ts index b607da8b24..d8960f0c59 100644 --- a/packages/koishi-core/src/sender.ts +++ b/packages/koishi-core/src/sender.ts @@ -21,10 +21,11 @@ import { } from './meta' export class SenderError extends Error { - constructor (args: Record, url: string, retcode: number) { + constructor (args: Record, url: string, retcode: number, selfId: number) { super(`Error when trying to send to ${url}, args: ${JSON.stringify(args)}, retcode: ${retcode}`) Object.defineProperties(this, { name: { value: 'SenderError' }, + selfId: { value: selfId }, code: { value: retcode }, args: { value: args }, url: { value: url }, @@ -77,9 +78,9 @@ export class Sender { if (retcode === 0 && !silent) { return camelCase(data) } else if (retcode < 0 && !silent) { - throw new SenderError(params, action, retcode) + throw new SenderError(params, action, retcode, this.app.selfId) } else if (retcode > 1) { - throw new SenderError(params, action, retcode) + throw new SenderError(params, action, retcode, this.app.selfId) } } diff --git a/packages/koishi-core/src/server.ts b/packages/koishi-core/src/server.ts index 799664a673..00b7f311a1 100644 --- a/packages/koishi-core/src/server.ts +++ b/packages/koishi-core/src/server.ts @@ -1,3 +1,4 @@ +import ms from 'ms' import WebSocket from 'ws' import * as http from 'http' import { errors } from './messages' @@ -29,7 +30,7 @@ export abstract class Server { } protected debug (format: any, ...params: any[]) { - this.app?.logger('koishi:sender').debug(format, ...params) + this.app?.logger('koishi:server').debug(format, ...params) } protected prepareMeta (data: any) { @@ -277,6 +278,7 @@ let counter = 0 export class WsClient extends Server { public socket: WebSocket + private _retryCount = 0 private _listeners: Record void> = {} send (data: any): Promise { @@ -290,16 +292,33 @@ export class WsClient extends Server { } _listen (): Promise { - return new Promise((resolve, reject) => { + const connect = (resolve: () => void, reject: (reason: Error) => void) => { this.debug('websocket client opening') const headers: Record = {} - const { token, server } = this.app.options + const { token, server, retryInterval, retryTimes } = this.app.options if (token) headers.Authorization = `Bearer ${token}` this.socket = new WebSocket(server, { headers }) - this.socket.once('error', reject) + this.socket.on('error', error => this.debug(error)) + + this.socket.once('close', (code) => { + if (!this.isListening || code === 1005) return + + const message = `failed to connect to ${server}` + if (!retryInterval || this._retryCount >= retryTimes) { + return reject(new Error(message)) + } + + this._retryCount++ + this.debug(`${message}, will retry in ${ms(retryInterval)}...`) + setTimeout(() => { + if (this.isListening) connect(resolve, reject) + }, retryInterval) + }) this.socket.once('open', () => { + this._retryCount = 0 + this.socket.send(JSON.stringify({ action: 'get_version_info', echo: -1, @@ -317,11 +336,13 @@ export class WsClient extends Server { } catch (error) { return reject(new Error(data)) } + if (!resolved) { resolved = true this.debug('connect to ws server:', this.app.options.server) resolve() } + if ('post_type' in parsed) { const meta = this.prepareMeta(parsed) if (meta) this.dispatchMeta(meta) @@ -333,11 +354,13 @@ export class WsClient extends Server { } }) }) - }) + } + return new Promise(connect) } _close () { this.socket.close() + this._retryCount = 0 this.debug('websocket client closed') } } diff --git a/packages/koishi-core/tests/ws-client.spec.ts b/packages/koishi-core/tests/ws-client.spec.ts index de7303e4f9..1e254e968a 100644 --- a/packages/koishi-core/tests/ws-client.spec.ts +++ b/packages/koishi-core/tests/ws-client.spec.ts @@ -6,8 +6,13 @@ let app1: App, app2: App beforeAll(async () => { server = await createWsServer() - app1 = server.createBoundApp() - app2 = server.createBoundApp({ selfId: BASE_SELF_ID + 1 }) + app1 = server.createBoundApp({ + retryTimes: 1, + retryInterval: 100, + }) + app2 = server.createBoundApp({ + selfId: BASE_SELF_ID + 1, + }) }) afterAll(() => server.close()) @@ -28,8 +33,10 @@ describe('WebSocket Server', () => { await expect(app1.start()).rejects.toHaveProperty('message', 'authorization failed') app1.options.token = 'token' await expect(app1.start()).resolves.toBeUndefined() + await server.close() + await expect(app1.start()).rejects.toHaveProperty('message') server.token = null - await app1.stop() + server.open() await expect(app1.start()).resolves.toBeUndefined() }) diff --git a/packages/plugin-common/package.json b/packages/plugin-common/package.json index bb286e0ffc..4dc8413bed 100644 --- a/packages/plugin-common/package.json +++ b/packages/plugin-common/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-common", "description": "Common plugins for Koishi", - "version": "2.1.5", + "version": "2.1.6", "main": "dist/index.js", "typings": "dist/index.d.ts", "author": "Shigma <1700011071@pku.edu.cn>", @@ -28,11 +28,11 @@ "plugin" ], "devDependencies": { - "koishi-database-memory": "^1.1.4", - "koishi-test-utils": "^3.1.3" + "koishi-database-memory": "^1.1.5", + "koishi-test-utils": "^3.1.4" }, "dependencies": { - "koishi-core": "^1.10.1", + "koishi-core": "^1.11.0", "koishi-utils": "^1.0.4" } } diff --git a/packages/plugin-common/src/broadcast.ts b/packages/plugin-common/src/broadcast.ts index e57adb7c81..7db9d9b165 100644 --- a/packages/plugin-common/src/broadcast.ts +++ b/packages/plugin-common/src/broadcast.ts @@ -1,4 +1,4 @@ -import { Context, appMap } from 'koishi-core' +import { Context, appMap, GroupFlag } from 'koishi-core' import { sleep } from 'koishi-utils' export interface BroadcastOptions { @@ -12,27 +12,32 @@ const defaultOptions: BroadcastOptions = { export default function apply (ctx: Context, config: BroadcastOptions = {}) { config = { ...defaultOptions, ...config } - async function broadcast (selfId: string | number, groups: number[], message: string) { + async function broadcast (selfId: string | number, groupIds: number[], message: string) { const { sender } = appMap[selfId] - for (let index = 0; index < groups.length; index++) { + for (let index = 0; index < groupIds.length; index++) { if (index) await sleep(config.broadcastInterval) - sender.sendGroupMsgAsync(groups[index], message) + sender.sendGroupMsgAsync(groupIds[index], message) } } ctx.command('broadcast ', '全服广播', { authority: 4 }) + .option('-f, --forced', '无视 noEmit 标签进行广播') .option('-o, --only', '仅向当前 Bot 负责的群进行广播') .action(async ({ options, meta }, message) => { if (!message) return meta.$send('请输入要发送的文本。') if (options.only) { - const groups = await ctx.database.getAllGroups(['id'], [ctx.app.selfId]) + let groups = await ctx.database.getAllGroups(['id', 'flag'], [ctx.app.selfId]) + if (!options.forced) { + groups = groups.filter(g => !(g.flag & GroupFlag.noEmit)) + } return broadcast(ctx.app.selfId, groups.map(g => g.id), message) } - const groups = await ctx.database.getAllGroups(['id', 'assignee']) + const groups = await ctx.database.getAllGroups(['id', 'assignee', 'flag']) const assignMap: Record = {} - for (const { id, assignee } of groups) { + for (const { id, assignee, flag } of groups) { + if (!options.forced && (flag & GroupFlag.noEmit)) continue if (!assignMap[assignee]) { assignMap[assignee] = [id] } else { diff --git a/packages/plugin-common/src/welcome.ts b/packages/plugin-common/src/welcome.ts index e990f5bfe1..16696a46b5 100644 --- a/packages/plugin-common/src/welcome.ts +++ b/packages/plugin-common/src/welcome.ts @@ -6,6 +6,7 @@ const defaultMessage = (meta: Meta<'notice'>) => `欢迎新大佬 [CQ:at,qq=${me export default function apply (ctx: Context, message: WelcomeMessage = defaultMessage) { ctx.receiver.on('group-increase', async (meta) => { + if (meta.userId === ctx.app.selfId) return if (ctx.database) { const group = await ctx.database.getGroup(meta.groupId, 0, ['assignee']) if (group.assignee !== ctx.app.selfId) return diff --git a/packages/plugin-common/tests/broadcast.spec.ts b/packages/plugin-common/tests/broadcast.spec.ts index 566dfd0c20..b8bb5dc2fb 100644 --- a/packages/plugin-common/tests/broadcast.spec.ts +++ b/packages/plugin-common/tests/broadcast.spec.ts @@ -1,5 +1,5 @@ -import { MockedApp, BASE_SELF_ID } from 'koishi-test-utils' -import { startAll, stopAll } from 'koishi-core' +import { MockedApp, BASE_SELF_ID, utils } from 'koishi-test-utils' +import { startAll, stopAll, GroupFlag } from 'koishi-core' import { broadcast } from '../src' import 'koishi-database-memory' @@ -13,16 +13,30 @@ beforeAll(async () => { await app1.database.getUser(123, 4) await app1.database.getGroup(321, app1.selfId) await app1.database.getGroup(654, app1.selfId) + await app1.database.setGroup(654, { flag: GroupFlag.noEmit }) await app2.database.getGroup(987, app2.selfId) }) afterAll(() => stopAll()) +utils.sleep.mockResolvedValue() + +beforeEach(() => utils.sleep.mockClear()) + +test('check message', async () => { + await app1.receiveMessage('user', 'broadcast', 123) + expect(utils.sleep).toBeCalledTimes(0) + app1.shouldHaveLastRequests([ + ['send_private_msg', { message: '请输入要发送的文本。', userId: 123 }], + ]) + app2.shouldHaveNoRequests() +}) + test('basic support', async () => { await app1.receiveMessage('user', 'broadcast foo bar', 123) + expect(utils.sleep).toBeCalledTimes(0) app1.shouldHaveLastRequests([ ['send_group_msg', { message: 'foo bar', groupId: 321 }], - ['send_group_msg', { message: 'foo bar', groupId: 654 }], ]) app2.shouldHaveLastRequests([ ['send_group_msg', { message: 'foo bar', groupId: 987 }], @@ -31,6 +45,29 @@ test('basic support', async () => { test('self only', async () => { await app1.receiveMessage('user', 'broadcast -o foo bar', 123) + expect(utils.sleep).toBeCalledTimes(0) + app1.shouldHaveLastRequests([ + ['send_group_msg', { message: 'foo bar', groupId: 321 }], + ]) + app2.shouldHaveNoRequests() +}) + +test('force emit', async () => { + await app1.receiveMessage('user', 'broadcast -f foo bar', 123) + expect(utils.sleep).toBeCalledTimes(1) + app1.shouldHaveLastRequests([ + ['send_group_msg', { message: 'foo bar', groupId: 321 }], + ['send_group_msg', { message: 'foo bar', groupId: 654 }], + ]) + app2.shouldHaveLastRequests([ + ['send_group_msg', { message: 'foo bar', groupId: 987 }], + ]) + app2.shouldHaveNoRequests() +}) + +test('self only & force emit', async () => { + await app1.receiveMessage('user', 'broadcast -of foo bar', 123) + expect(utils.sleep).toBeCalledTimes(1) app1.shouldHaveLastRequests([ ['send_group_msg', { message: 'foo bar', groupId: 321 }], ['send_group_msg', { message: 'foo bar', groupId: 654 }], diff --git a/packages/plugin-nlp/package.json b/packages/plugin-nlp/package.json index d9076591ec..1ca26891ad 100644 --- a/packages/plugin-nlp/package.json +++ b/packages/plugin-nlp/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-nlp", "description": "Natural Language Processor for Koishi", - "version": "1.0.5", + "version": "1.0.6", "main": "dist/index.js", "typings": "dist/index.d.ts", "author": "Shigma <1700011071@pku.edu.cn>", @@ -30,11 +30,11 @@ "jieba" ], "devDependencies": { - "koishi-test-utils": "^3.1.3" + "koishi-test-utils": "^3.1.4" }, "dependencies": { - "koishi-core": "^1.10.1", + "koishi-core": "^1.11.0", "koishi-utils": "^1.0.4", - "nodejieba": "^2.4.0" + "nodejieba": "^2.4.1" } } diff --git a/packages/plugin-nlp/src/index.ts b/packages/plugin-nlp/src/index.ts index 562254127a..162b46ca01 100644 --- a/packages/plugin-nlp/src/index.ts +++ b/packages/plugin-nlp/src/index.ts @@ -1,5 +1,5 @@ import { Command, Meta, Context, ParsedLine, ParsedCommandLine } from 'koishi-core' -import { tag, load } from 'nodejieba' +import { tag, load, TagResult, LoadOptions } from 'nodejieba' import { resolve } from 'path' declare module 'koishi-core/dist/command' { @@ -21,25 +21,13 @@ export interface Intension extends Partial { export type IntenderCallback = (meta: Meta, keyword: string) => Intension -// TODO: pending nodejieba typings -interface TagResult { - word: string - tag: string -} - export interface Intender { command: Command keywords: string[] callback: IntenderCallback } -export interface NlpConfig { - // TODO: pending nodejieba typings - dict?: string - hmmDict?: string - userDict?: string - idfDict?: string - stopWordDict?: string +export interface NlpConfig extends LoadOptions { threshold?: number } diff --git a/packages/plugin-recorder/package.json b/packages/plugin-recorder/package.json index e1784e743d..6a9f0ee605 100644 --- a/packages/plugin-recorder/package.json +++ b/packages/plugin-recorder/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-recorder", "description": "Save Chat Records for Koishi", - "version": "1.0.0-alpha.8", + "version": "1.0.0-alpha.9", "main": "dist/index.js", "typings": "dist/index.d.ts", "author": "Shigma <1700011071@pku.edu.cn>", @@ -31,10 +31,10 @@ ], "devDependencies": { "del": "^5.1.0", - "koishi-test-utils": "^3.1.3" + "koishi-test-utils": "^3.1.4" }, "dependencies": { - "koishi-core": "^1.10.1", + "koishi-core": "^1.11.0", "koishi-utils": "^1.0.4" } } diff --git a/packages/plugin-schedule/package.json b/packages/plugin-schedule/package.json index dc0ab33d6a..c22d3860b4 100644 --- a/packages/plugin-schedule/package.json +++ b/packages/plugin-schedule/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-schedule", "description": "Schedule plugin for Koishi", - "version": "1.0.10", + "version": "1.0.11", "main": "dist/index.js", "typings": "dist/index.d.ts", "author": "Shigma <1700011071@pku.edu.cn>", @@ -31,12 +31,12 @@ ], "devDependencies": { "@types/ms": "^0.7.31", - "koishi-database-level": "^1.1.4", - "koishi-database-mysql": "^1.1.4", - "koishi-test-utils": "^3.1.3" + "koishi-database-level": "^1.1.5", + "koishi-database-mysql": "^1.1.5", + "koishi-test-utils": "^3.1.4" }, "dependencies": { - "koishi-core": "^1.10.1", + "koishi-core": "^1.11.0", "koishi-utils": "^1.0.4", "ms": "^2.1.2" } diff --git a/packages/plugin-teach/package.json b/packages/plugin-teach/package.json index e13a124132..319f001f06 100644 --- a/packages/plugin-teach/package.json +++ b/packages/plugin-teach/package.json @@ -1,7 +1,7 @@ { "name": "koishi-plugin-teach", "description": "Teach plugin for Koishi", - "version": "0.1.19", + "version": "0.1.20", "main": "dist/index.js", "typings": "dist/index.d.ts", "author": "Shigma <1700011071@pku.edu.cn>", @@ -31,12 +31,12 @@ "conversation" ], "devDependencies": { - "koishi-database-level": "^1.1.4", - "koishi-database-mysql": "^1.1.4", - "koishi-test-utils": "^3.1.3" + "koishi-database-level": "^1.1.5", + "koishi-database-mysql": "^1.1.5", + "koishi-test-utils": "^3.1.4" }, "dependencies": { - "koishi-core": "^1.10.1", + "koishi-core": "^1.11.0", "koishi-utils": "^1.0.4" } } diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 227ffa0e23..2c7714fc30 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "koishi-test-utils", "description": "Test utilities for Koishi", - "version": "3.1.3", + "version": "3.1.4", "main": "dist/index.js", "typings": "dist/index.d.ts", "files": [ @@ -37,13 +37,13 @@ }, "devDependencies": { "@types/debug": "^4.1.5", - "@types/jest": "^25.1.3" + "@types/jest": "^25.1.4" }, "dependencies": { "axios": "^0.19.2", "debug": "^4.1.1", "get-port": "^5.1.1", - "koishi-core": "^1.10.1", + "koishi-core": "^1.11.0", "koishi-utils": "^1.0.4" } } diff --git a/packages/test-utils/src/server.ts b/packages/test-utils/src/server.ts index 9ea24bfa32..a4034ef839 100644 --- a/packages/test-utils/src/server.ts +++ b/packages/test-utils/src/server.ts @@ -21,6 +21,10 @@ export class HttpServer extends MockedServer { constructor (public cqhttpPort: number, public koishiPort: number, public token?: string) { super() + this.open() + } + + open () { this.server = http.createServer((req, res) => { let body = '' req.on('data', chunk => body += chunk) @@ -49,7 +53,7 @@ export class HttpServer extends MockedServer { res.write(JSON.stringify(this.receive(path, params))) res.end() }) - }).listen(cqhttpPort) + }).listen(this.cqhttpPort) } post (meta: Meta, port = this.koishiPort, secret?: string) { @@ -91,7 +95,11 @@ export class WsServer extends MockedServer { constructor (public cqhttpPort: number, public token?: string) { super() - this.server = new ws.Server({ port: cqhttpPort }) + this.open() + } + + open () { + this.server = new ws.Server({ port: this.cqhttpPort }) this.server.on('connection', (socket, req) => { if (this.token) { const signature = req.headers.authorization