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