onebots 0.4.19 → 0.4.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -6
- package/lib/config.sample.yaml +2 -0
- package/lib/onebot.d.ts +4 -1
- package/lib/onebot.js +17 -2
- package/lib/server/app.d.ts +1 -0
- package/lib/server/app.js +1 -0
- package/lib/service/V11/action/common.d.ts +2 -1
- package/lib/service/V11/action/common.js +10 -2
- package/lib/service/V11/action/friend.d.ts +1 -1
- package/lib/service/V11/action/friend.js +2 -1
- package/lib/service/V11/action/group.d.ts +1 -1
- package/lib/service/V11/action/group.js +2 -1
- package/lib/service/V11/db_entities.d.ts +13 -0
- package/lib/service/V11/db_entities.js +63 -0
- package/lib/service/V11/db_sqlite.d.ts +52 -0
- package/lib/service/V11/db_sqlite.js +117 -0
- package/lib/service/V11/index.d.ts +15 -8
- package/lib/service/V11/index.js +73 -18
- package/lib/service/V11/utils.js +5 -1
- package/lib/service/V12/index.d.ts +2 -1
- package/lib/service/V12/index.js +3 -1
- package/lib/service/shareMusicCustom.d.ts +19 -0
- package/lib/service/shareMusicCustom.js +52 -0
- package/lib/types.d.ts +9 -0
- package/lib/types.js +26 -0
- package/lib/utils.d.ts +6 -0
- package/lib/utils.js +6 -0
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -83,15 +83,17 @@ general: # 通用配置,在单个配置省略时的默认值
|
|
|
83
83
|
# ...其他配置项参考icqq的Config配置
|
|
84
84
|
# 每个账号的单独配置(用于覆盖通用配置)
|
|
85
85
|
123456789:
|
|
86
|
+
password: '' # 账号密码,未配置则扫码登陆
|
|
86
87
|
version: V11 # 使用的oneBot版本
|
|
87
88
|
# ...其他配置项参见上方对应oneBot版本的通用配置
|
|
88
89
|
protocol:
|
|
89
90
|
platform: 2
|
|
90
91
|
sign_api_addr: '' #你的签名地址
|
|
91
|
-
password: '' # 账号密码,未配置则扫码登陆
|
|
92
92
|
# ...其他配置项参考icqq的Config配置
|
|
93
93
|
```
|
|
94
|
+
|
|
94
95
|
# 配置解释
|
|
96
|
+
|
|
95
97
|
## Config
|
|
96
98
|
| 配置项 | 类型 | 默认值 | desc |
|
|
97
99
|
|:---------|:-----------------------------|:--------|:-------|
|
|
@@ -100,11 +102,12 @@ general: # 通用配置,在单个配置省略时的默认值
|
|
|
100
102
|
| general | OneBotConfig | general | 通用配置 |
|
|
101
103
|
| [number] | OneBotConfig\|OneBotConfig[] | - | 机器人配置 |
|
|
102
104
|
## OneBotConfig
|
|
103
|
-
| 配置项 | 类型 | 默认值 | desc
|
|
104
|
-
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
105
|
+
| 配置项 | 类型 | 默认值 | desc |
|
|
106
|
+
|:---------|:----------|:----------|:-------------------|
|
|
107
|
+
| password | string | - | 账号密码 未填写或填写为空则扫码登陆 |
|
|
108
|
+
| V11 | ConfigV11 | configV11 | V11配置 |
|
|
109
|
+
| V12 | ConfigV12 | configV12 | V12配置 |
|
|
110
|
+
| protocol | Config | {} | icqq配置 |
|
|
108
111
|
## ConfigV11
|
|
109
112
|
| 配置项 | 类型 | 默认值 | desc |
|
|
110
113
|
|:--------------------|:---------|:-------|:-----------|
|
package/lib/config.sample.yaml
CHANGED
|
@@ -31,6 +31,8 @@ general: # 通用配置,在单个配置省略时的默认值
|
|
|
31
31
|
# 每个账号的单独配置(用于覆盖通用配置)
|
|
32
32
|
123456789:
|
|
33
33
|
version: V11 # 使用的oneBot版本
|
|
34
|
+
password:'' # 账号密码,未配置则扫码登陆
|
|
35
|
+
group_whitelist: [] # 群消息派发白名单,只有数组中的群号才派发,为空则全部派发
|
|
34
36
|
protocol: # 将会覆盖通用配置中的protocol
|
|
35
37
|
platform: 1
|
|
36
38
|
# 。。。其他配置项参见上方对应oneBot版本的通用配置
|
package/lib/onebot.d.ts
CHANGED
|
@@ -22,7 +22,8 @@ export declare class OneBot<V extends OneBot.Version> extends EventEmitter {
|
|
|
22
22
|
start(): Promise<[boolean, any]>;
|
|
23
23
|
startListen(): void;
|
|
24
24
|
stop(force?: boolean): Promise<void>;
|
|
25
|
-
|
|
25
|
+
system_online(event: any, data: any): void;
|
|
26
|
+
dispatch(event: any, data: any): Promise<void>;
|
|
26
27
|
}
|
|
27
28
|
export declare enum OneBotStatus {
|
|
28
29
|
Good = 0,
|
|
@@ -34,11 +35,13 @@ export declare namespace OneBot {
|
|
|
34
35
|
type Config<V extends Version = 'V11'> = ({
|
|
35
36
|
version?: V;
|
|
36
37
|
password?: string;
|
|
38
|
+
group_whitelist?: number[];
|
|
37
39
|
protocol?: IcqqConfig;
|
|
38
40
|
} & (V extends 'V11' ? V11.Config : V12.Config));
|
|
39
41
|
interface Base {
|
|
40
42
|
start(path?: string): any;
|
|
41
43
|
stop(): any;
|
|
44
|
+
system_online(...args: any[]): any;
|
|
42
45
|
dispatch(...args: any[]): any;
|
|
43
46
|
apply(...args: any[]): any;
|
|
44
47
|
}
|
package/lib/onebot.js
CHANGED
|
@@ -162,6 +162,7 @@ class OneBot extends events_1.EventEmitter {
|
|
|
162
162
|
});
|
|
163
163
|
}
|
|
164
164
|
startListen() {
|
|
165
|
+
this.client.on('system.online', this.system_online.bind(this, "system.online"));
|
|
165
166
|
this.client.trap('system', this.dispatch.bind(this, 'system'));
|
|
166
167
|
this.client.trap('notice', this.dispatch.bind(this, 'notice'));
|
|
167
168
|
this.client.trap('request', this.dispatch.bind(this, 'request'));
|
|
@@ -176,20 +177,34 @@ class OneBot extends events_1.EventEmitter {
|
|
|
176
177
|
}
|
|
177
178
|
this.client.logout(force);
|
|
178
179
|
}
|
|
179
|
-
|
|
180
|
+
system_online(event, data) {
|
|
180
181
|
for (const instance of this.instances) {
|
|
182
|
+
instance.system_online(data);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async dispatch(event, data) {
|
|
186
|
+
let group_id = data["group_id"];
|
|
187
|
+
for (const instance of this.instances) {
|
|
188
|
+
if (group_id) {
|
|
189
|
+
// 群消息派发白名单
|
|
190
|
+
let lst = instance.config.group_whitelist;
|
|
191
|
+
if (lst && lst.length > 0 && !lst.includes(group_id))
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
181
194
|
const result = instance.format(event, data);
|
|
182
|
-
if (data.source) {
|
|
195
|
+
if (data.source) { // 有 data.source 字段代表这是个回复
|
|
183
196
|
switch (data.message_type) {
|
|
184
197
|
case 'group':
|
|
185
198
|
data.message.unshift({
|
|
186
199
|
type: 'reply',
|
|
200
|
+
seq: data.source.seq,
|
|
187
201
|
id: (0, icqq_2.genGroupMessageId)(data.group_id, data.source.user_id, data.source.seq, data.source.rand, data.source.time)
|
|
188
202
|
});
|
|
189
203
|
break;
|
|
190
204
|
case 'private':
|
|
191
205
|
data.message.unshift({
|
|
192
206
|
type: 'reply',
|
|
207
|
+
seq: data.source.seq,
|
|
193
208
|
id: (0, icqq_2.genDmMessageId)(data.source.user_id, data.source.seq, data.source.rand, data.source.time)
|
|
194
209
|
});
|
|
195
210
|
break;
|
package/lib/server/app.d.ts
CHANGED
package/lib/server/app.js
CHANGED
|
@@ -30,6 +30,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
30
30
|
exports.defineConfig = exports.createApp = exports.App = void 0;
|
|
31
31
|
const koa_1 = __importDefault(require("koa"));
|
|
32
32
|
const os = __importStar(require("os"));
|
|
33
|
+
require("reflect-metadata");
|
|
33
34
|
const fs_1 = require("fs");
|
|
34
35
|
const log4js_1 = require("log4js");
|
|
35
36
|
const http_1 = require("http");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Message } from "icqq";
|
|
1
2
|
import { V11 } from "../../../service/V11";
|
|
2
3
|
export declare class CommonAction {
|
|
3
4
|
/**
|
|
@@ -16,7 +17,7 @@ export declare class CommonAction {
|
|
|
16
17
|
* 获取消息
|
|
17
18
|
* @param message_id {string} 消息id
|
|
18
19
|
*/
|
|
19
|
-
getMsg(this: V11, message_id:
|
|
20
|
+
getMsg(this: V11, message_id: number): Promise<Message>;
|
|
20
21
|
/**
|
|
21
22
|
* 获取合并消息
|
|
22
23
|
* @param id {string} 合并id
|
|
@@ -24,8 +24,16 @@ class CommonAction {
|
|
|
24
24
|
* 获取消息
|
|
25
25
|
* @param message_id {string} 消息id
|
|
26
26
|
*/
|
|
27
|
-
getMsg(message_id) {
|
|
28
|
-
|
|
27
|
+
async getMsg(message_id) {
|
|
28
|
+
if (message_id == 0)
|
|
29
|
+
throw new Error('getMsg: message_id[0] is invalid');
|
|
30
|
+
let msg_entry = await this.db.getMsgById(message_id);
|
|
31
|
+
if (!msg_entry)
|
|
32
|
+
throw new Error(`getMsg: can not find msg[${message_id}] in db`);
|
|
33
|
+
let msg = await this.client.getMsg(msg_entry.base64_id);
|
|
34
|
+
msg.message_id = String(message_id); // nonebot v11 要求 message_id 是 number 类型
|
|
35
|
+
msg["real_id"] = msg.message_id; // nonebot 的reply类型会检测real_id是否存在,虽然它从未使用
|
|
36
|
+
return msg;
|
|
29
37
|
}
|
|
30
38
|
/**
|
|
31
39
|
* 获取合并消息
|
|
@@ -8,7 +8,7 @@ export declare class FriendAction {
|
|
|
8
8
|
* @param message {import('icqq').Sendable} 发送的消息
|
|
9
9
|
* @param message_id {string} 引用的消息ID
|
|
10
10
|
*/
|
|
11
|
-
sendPrivateMsg(this: V11, user_id: number, message: string | SegmentElem | SegmentElem[], message_id?: string): Promise<
|
|
11
|
+
sendPrivateMsg(this: V11, user_id: number, message: string | SegmentElem | SegmentElem[], message_id?: string): Promise<any>;
|
|
12
12
|
/**
|
|
13
13
|
* 获取好友列表
|
|
14
14
|
*/
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.FriendAction = void 0;
|
|
4
4
|
const utils_1 = require("../../../service/V11/utils");
|
|
5
|
+
const shareMusicCustom_1 = require("../../../service/shareMusicCustom");
|
|
5
6
|
class FriendAction {
|
|
6
7
|
/**
|
|
7
8
|
* 发送私聊消息
|
|
@@ -13,7 +14,7 @@ class FriendAction {
|
|
|
13
14
|
const msg = message_id ? await this.client.getMsg(message_id) : undefined;
|
|
14
15
|
const { element, quote, music, share } = await utils_1.processMessage.apply(this.client, [message, msg]);
|
|
15
16
|
if (music)
|
|
16
|
-
return await this.client.pickFriend(user_id)
|
|
17
|
+
return await shareMusicCustom_1.shareMusic.call(this.client.pickFriend(user_id), music);
|
|
17
18
|
if (share)
|
|
18
19
|
return await this.client.pickFriend(user_id).shareUrl(music.data);
|
|
19
20
|
if (element.length) {
|
|
@@ -7,7 +7,7 @@ export declare class GroupAction {
|
|
|
7
7
|
* @param message {import('icqq').Sendable} 消息
|
|
8
8
|
* @param message_id {string} 引用的消息ID
|
|
9
9
|
*/
|
|
10
|
-
sendGroupMsg(this: V11, group_id: number, message: string | SegmentElem | SegmentElem[], message_id?: string): Promise<
|
|
10
|
+
sendGroupMsg(this: V11, group_id: number, message: string | SegmentElem | SegmentElem[], message_id?: string): Promise<any>;
|
|
11
11
|
/**
|
|
12
12
|
* 群组踢人
|
|
13
13
|
* @param group_id {number} 群id
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.GroupAction = void 0;
|
|
4
4
|
const utils_1 = require("../../../service/V11/utils");
|
|
5
|
+
const shareMusicCustom_1 = require("../../../service/shareMusicCustom");
|
|
5
6
|
class GroupAction {
|
|
6
7
|
/**
|
|
7
8
|
* 发送群聊消息
|
|
@@ -13,7 +14,7 @@ class GroupAction {
|
|
|
13
14
|
const msg = message_id ? await this.client.getMsg(message_id) : undefined;
|
|
14
15
|
const { element, quote, music, share } = await utils_1.processMessage.apply(this.client, [message, msg]);
|
|
15
16
|
if (music)
|
|
16
|
-
return await this.client.pickGroup(group_id)
|
|
17
|
+
return await shareMusicCustom_1.shareMusic.call(this.client.pickGroup(group_id), music);
|
|
17
18
|
if (share)
|
|
18
19
|
return await this.client.pickGroup(group_id).shareUrl(music.data);
|
|
19
20
|
if (element.length) {
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.MsgEntry = void 0;
|
|
13
|
+
const typeorm_1 = require("typeorm");
|
|
14
|
+
let MsgEntry = class MsgEntry {
|
|
15
|
+
};
|
|
16
|
+
exports.MsgEntry = MsgEntry;
|
|
17
|
+
__decorate([
|
|
18
|
+
(0, typeorm_1.PrimaryGeneratedColumn)(),
|
|
19
|
+
__metadata("design:type", Number)
|
|
20
|
+
], MsgEntry.prototype, "id", void 0);
|
|
21
|
+
__decorate([
|
|
22
|
+
(0, typeorm_1.Column)(),
|
|
23
|
+
__metadata("design:type", String)
|
|
24
|
+
], MsgEntry.prototype, "base64_id", void 0);
|
|
25
|
+
__decorate([
|
|
26
|
+
(0, typeorm_1.Column)(),
|
|
27
|
+
__metadata("design:type", Number)
|
|
28
|
+
], MsgEntry.prototype, "seq", void 0);
|
|
29
|
+
__decorate([
|
|
30
|
+
(0, typeorm_1.Column)(),
|
|
31
|
+
__metadata("design:type", Number)
|
|
32
|
+
], MsgEntry.prototype, "user_id", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, typeorm_1.Column)(),
|
|
35
|
+
__metadata("design:type", String)
|
|
36
|
+
], MsgEntry.prototype, "nickname", void 0);
|
|
37
|
+
__decorate([
|
|
38
|
+
(0, typeorm_1.Column)(),
|
|
39
|
+
__metadata("design:type", Number)
|
|
40
|
+
], MsgEntry.prototype, "group_id", void 0);
|
|
41
|
+
__decorate([
|
|
42
|
+
(0, typeorm_1.Column)(),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], MsgEntry.prototype, "group_name", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
(0, typeorm_1.Column)({ length: 1024 }),
|
|
47
|
+
__metadata("design:type", String)
|
|
48
|
+
], MsgEntry.prototype, "content", void 0);
|
|
49
|
+
__decorate([
|
|
50
|
+
(0, typeorm_1.Column)({ default: false }),
|
|
51
|
+
__metadata("design:type", Boolean)
|
|
52
|
+
], MsgEntry.prototype, "recalled", void 0);
|
|
53
|
+
__decorate([
|
|
54
|
+
(0, typeorm_1.CreateDateColumn)(),
|
|
55
|
+
__metadata("design:type", Date)
|
|
56
|
+
], MsgEntry.prototype, "create_time", void 0);
|
|
57
|
+
__decorate([
|
|
58
|
+
(0, typeorm_1.Column)({ nullable: true }),
|
|
59
|
+
__metadata("design:type", Date)
|
|
60
|
+
], MsgEntry.prototype, "recall_time", void 0);
|
|
61
|
+
exports.MsgEntry = MsgEntry = __decorate([
|
|
62
|
+
(0, typeorm_1.Entity)()
|
|
63
|
+
], MsgEntry);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { MsgEntry } from "./db_entities";
|
|
2
|
+
import { DataSource, Repository } from "typeorm";
|
|
3
|
+
import { Logger } from "log4js";
|
|
4
|
+
import { AsyncLock } from "../../types";
|
|
5
|
+
export declare class Database {
|
|
6
|
+
logger: Logger;
|
|
7
|
+
dbPath: string;
|
|
8
|
+
dataSource: DataSource;
|
|
9
|
+
/**
|
|
10
|
+
* 消息在数据库中的保留时间
|
|
11
|
+
*/
|
|
12
|
+
msgHistoryPreserveDays: number;
|
|
13
|
+
msgHistoryCheckInterval: number;
|
|
14
|
+
msgRepo: Repository<MsgEntry>;
|
|
15
|
+
dbLock: AsyncLock;
|
|
16
|
+
constructor(dbPath: string, logger: Logger);
|
|
17
|
+
initDB(): Promise<void>;
|
|
18
|
+
/**
|
|
19
|
+
* 增加或更新一条消息到数据库
|
|
20
|
+
* @param msgData
|
|
21
|
+
*/
|
|
22
|
+
addOrUpdateMsg(msgData: MsgEntry): Promise<number>;
|
|
23
|
+
/**
|
|
24
|
+
* 通过 icqq 的 base64 格式的 message_id 获取一个 MsgData 对象
|
|
25
|
+
* @param base64_id
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
getMsgByBase64Id(base64_id: string): Promise<MsgEntry | null>;
|
|
29
|
+
/**
|
|
30
|
+
* 通过 number 类型的 id 自增主键获取一个 MsgData 对象
|
|
31
|
+
* @param id
|
|
32
|
+
* @returns
|
|
33
|
+
*/
|
|
34
|
+
getMsgById(id: number): Promise<MsgEntry | null>;
|
|
35
|
+
/**
|
|
36
|
+
* 通过参数从数据库中查找消息
|
|
37
|
+
* @param user_id
|
|
38
|
+
* @param group_id
|
|
39
|
+
* @param seq
|
|
40
|
+
*/
|
|
41
|
+
getMsgByParams(user_id: number, group_id: number, seq: number): Promise<MsgEntry | null>;
|
|
42
|
+
/**
|
|
43
|
+
* 将一条消息标记为 recalled
|
|
44
|
+
* @param base64_id
|
|
45
|
+
* @param id
|
|
46
|
+
*/
|
|
47
|
+
markMsgAsRecalled(base64_id?: string, id?: number): Promise<void>;
|
|
48
|
+
/**
|
|
49
|
+
* 根据 `msgPreserveDays` 变量定义的保留期限收缩数据库
|
|
50
|
+
*/
|
|
51
|
+
shrinkDB(): Promise<void>;
|
|
52
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Database = void 0;
|
|
4
|
+
const db_entities_1 = require("./db_entities");
|
|
5
|
+
const typeorm_1 = require("typeorm");
|
|
6
|
+
const types_1 = require("../../types");
|
|
7
|
+
class Database {
|
|
8
|
+
constructor(dbPath, logger) {
|
|
9
|
+
/**
|
|
10
|
+
* 消息在数据库中的保留时间
|
|
11
|
+
*/
|
|
12
|
+
this.msgHistoryPreserveDays = 14; // 历史消息默认存储2周
|
|
13
|
+
this.msgHistoryCheckInterval = 1 * 24 * 3600 * 1000; // 历史记录检查间隔
|
|
14
|
+
this.dbPath = dbPath;
|
|
15
|
+
this.logger = logger;
|
|
16
|
+
this.dbLock = new types_1.AsyncLock();
|
|
17
|
+
this.dataSource = new typeorm_1.DataSource({
|
|
18
|
+
type: "better-sqlite3",
|
|
19
|
+
database: dbPath,
|
|
20
|
+
entities: [db_entities_1.MsgEntry],
|
|
21
|
+
});
|
|
22
|
+
this.initDB();
|
|
23
|
+
}
|
|
24
|
+
async initDB() {
|
|
25
|
+
try {
|
|
26
|
+
await this.dataSource.initialize();
|
|
27
|
+
await this.dataSource.synchronize(false);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
this.logger.error(`sqlite [${this.dbPath}] open fail!`, err);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
this.msgRepo = this.dataSource.getRepository(db_entities_1.MsgEntry);
|
|
34
|
+
this.logger.debug(`sqlite [${this.dbPath}] open success`);
|
|
35
|
+
setInterval(() => {
|
|
36
|
+
this.shrinkDB();
|
|
37
|
+
}, this.msgHistoryCheckInterval);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 增加或更新一条消息到数据库
|
|
41
|
+
* @param msgData
|
|
42
|
+
*/
|
|
43
|
+
async addOrUpdateMsg(msgData) {
|
|
44
|
+
await this.dbLock.lock();
|
|
45
|
+
try {
|
|
46
|
+
let msgDataExists = await this.getMsgByParams(msgData.user_id, msgData.group_id, msgData.seq);
|
|
47
|
+
if (msgDataExists) {
|
|
48
|
+
// send_msg() 返回值和同步的 message 消息哪个先来不确定,send_msg 返回值后来时不允许更新数据库
|
|
49
|
+
if (msgData.content.length == 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
msgData.id = msgDataExists.id;
|
|
53
|
+
await this.msgRepo.update({ id: msgData.id }, msgData);
|
|
54
|
+
return msgDataExists.id;
|
|
55
|
+
}
|
|
56
|
+
msgData = await this.msgRepo.save(msgData);
|
|
57
|
+
this.logger.debug(`addMsg with id:${msgData.id}`);
|
|
58
|
+
return msgData.id;
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
this.dbLock.unlock();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 通过 icqq 的 base64 格式的 message_id 获取一个 MsgData 对象
|
|
66
|
+
* @param base64_id
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
async getMsgByBase64Id(base64_id) {
|
|
70
|
+
let ret = await this.msgRepo.findOneBy({ base64_id: base64_id });
|
|
71
|
+
return ret;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* 通过 number 类型的 id 自增主键获取一个 MsgData 对象
|
|
75
|
+
* @param id
|
|
76
|
+
* @returns
|
|
77
|
+
*/
|
|
78
|
+
async getMsgById(id) {
|
|
79
|
+
let ret = await this.msgRepo.findOneBy({ id: id });
|
|
80
|
+
return ret;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 通过参数从数据库中查找消息
|
|
84
|
+
* @param user_id
|
|
85
|
+
* @param group_id
|
|
86
|
+
* @param seq
|
|
87
|
+
*/
|
|
88
|
+
async getMsgByParams(user_id, group_id, seq) {
|
|
89
|
+
let ret = await this.msgRepo.findOneBy({ user_id: user_id, group_id: group_id, seq: seq });
|
|
90
|
+
return ret;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* 将一条消息标记为 recalled
|
|
94
|
+
* @param base64_id
|
|
95
|
+
* @param id
|
|
96
|
+
*/
|
|
97
|
+
async markMsgAsRecalled(base64_id, id) {
|
|
98
|
+
if (base64_id || id)
|
|
99
|
+
await this.msgRepo.update(base64_id ? { base64_id: base64_id } : { id: id }, { recalled: true, recall_time: new Date() });
|
|
100
|
+
else
|
|
101
|
+
throw new Error("base64_id 或 id 参数至少一个应该被赋值");
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 根据 `msgPreserveDays` 变量定义的保留期限收缩数据库
|
|
105
|
+
*/
|
|
106
|
+
async shrinkDB() {
|
|
107
|
+
let dt = new Date();
|
|
108
|
+
dt.setDate(dt.getDate() - this.msgHistoryPreserveDays);
|
|
109
|
+
await this.msgRepo
|
|
110
|
+
.createQueryBuilder()
|
|
111
|
+
.delete()
|
|
112
|
+
.from(db_entities_1.MsgEntry)
|
|
113
|
+
.where("create_time < :dt", { dt: dt })
|
|
114
|
+
.execute();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
exports.Database = Database;
|
|
@@ -8,8 +8,7 @@ import { Logger } from "log4js";
|
|
|
8
8
|
import { WebSocket, WebSocketServer } from "ws";
|
|
9
9
|
import { Dispose } from "../../types";
|
|
10
10
|
import { EventEmitter } from "events";
|
|
11
|
-
import { Database } from "
|
|
12
|
-
import { V12 } from "../../service/V12";
|
|
11
|
+
import { Database } from "./db_sqlite";
|
|
13
12
|
export declare class V11 extends EventEmitter implements OneBot.Base {
|
|
14
13
|
oneBot: OneBot<'V11'>;
|
|
15
14
|
client: Client;
|
|
@@ -19,11 +18,7 @@ export declare class V11 extends EventEmitter implements OneBot.Base {
|
|
|
19
18
|
protected timestamp: number;
|
|
20
19
|
protected heartbeat?: NodeJS.Timeout;
|
|
21
20
|
private path;
|
|
22
|
-
db: Database
|
|
23
|
-
eventBuffer: V12.Payload<keyof Action>[];
|
|
24
|
-
KVMap: Record<number, string>;
|
|
25
|
-
files: Record<string, V12.FileInfo>;
|
|
26
|
-
}>;
|
|
21
|
+
db: Database;
|
|
27
22
|
disposes: Dispose[];
|
|
28
23
|
protected _queue: Array<{
|
|
29
24
|
method: keyof Action;
|
|
@@ -41,8 +36,20 @@ export declare class V11 extends EventEmitter implements OneBot.Base {
|
|
|
41
36
|
private startWsReverse;
|
|
42
37
|
stop(force?: boolean): Promise<void>;
|
|
43
38
|
format(_: any, data: any): any;
|
|
44
|
-
|
|
39
|
+
system_online(data: any): void;
|
|
40
|
+
dispatch(data: any): Promise<void>;
|
|
45
41
|
private _formatEvent;
|
|
42
|
+
private addMsgToDB;
|
|
43
|
+
/**
|
|
44
|
+
* 从 send_msg_xxx() 调用的返回值中提取消息存入数据库(可以让前端在没有收到同步的message数据前就有能力拿到消息对应的base64_id)
|
|
45
|
+
* (也有可能来的比message慢,后来的话会被数据库忽略)
|
|
46
|
+
* @param user_id 发送者
|
|
47
|
+
* @param group_id 群号,私聊为0
|
|
48
|
+
* @param seq 消息序号
|
|
49
|
+
* @param base64_id icqq返回的base64格式的消息id
|
|
50
|
+
*/
|
|
51
|
+
private addMsgToDBFromSendMsgResult;
|
|
52
|
+
private getReplyMsgIdFromDB;
|
|
46
53
|
private _httpRequestHandler;
|
|
47
54
|
/**
|
|
48
55
|
* 处理ws消息
|
package/lib/service/V11/index.js
CHANGED
|
@@ -16,9 +16,10 @@ const http_1 = __importDefault(require("http"));
|
|
|
16
16
|
const https_1 = __importDefault(require("https"));
|
|
17
17
|
const events_1 = require("events");
|
|
18
18
|
const fs_1 = require("fs");
|
|
19
|
-
const
|
|
19
|
+
const db_sqlite_1 = require("./db_sqlite");
|
|
20
20
|
const path_1 = require("path");
|
|
21
21
|
const app_1 = require("../../server/app");
|
|
22
|
+
const db_entities_1 = require("./db_entities");
|
|
22
23
|
class V11 extends events_1.EventEmitter {
|
|
23
24
|
constructor(oneBot, client, config) {
|
|
24
25
|
super();
|
|
@@ -31,9 +32,8 @@ class V11 extends events_1.EventEmitter {
|
|
|
31
32
|
this.queue_running = false;
|
|
32
33
|
this.wsr = new Set();
|
|
33
34
|
this.action = new action_1.Action();
|
|
34
|
-
this.db = new db_1.Database((0, path_1.join)(app_1.App.configDir, 'data', this.oneBot.uin + '.json'));
|
|
35
|
-
this.db.sync({ eventBuffer: [], KVMap: {}, files: {} });
|
|
36
35
|
this.logger = this.oneBot.app.getLogger(this.oneBot.uin, this.version);
|
|
36
|
+
this.db = new db_sqlite_1.Database((0, path_1.join)(app_1.App.configDir, 'data', this.oneBot.uin + '.db'), this.logger);
|
|
37
37
|
}
|
|
38
38
|
start(path) {
|
|
39
39
|
this.path = `/${this.oneBot.uin}`;
|
|
@@ -190,19 +190,27 @@ class V11 extends events_1.EventEmitter {
|
|
|
190
190
|
format(_, data) {
|
|
191
191
|
return data;
|
|
192
192
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
}
|
|
193
|
+
system_online(data) {
|
|
194
|
+
this.logger.info("【好友列表】");
|
|
195
|
+
this.client.fl.forEach(item => this.logger.info(`\t${item.nickname}(${item.user_id})`));
|
|
196
|
+
this.logger.info("【群列表】");
|
|
197
|
+
this.client.gl.forEach(item => this.logger.info(`\t${item.group_name}(${item.group_id})`));
|
|
198
|
+
this.logger.info('');
|
|
199
|
+
}
|
|
200
|
+
async dispatch(data) {
|
|
201
|
+
data.post_type = data.post_type || 'system';
|
|
198
202
|
if (data.message && data.post_type === 'message') {
|
|
199
203
|
if (this.config.post_message_format === 'array') {
|
|
200
204
|
data.message = (0, icqq_cq_enable_1.toSegment)(data.message);
|
|
205
|
+
if (data.source) { // reply
|
|
206
|
+
let msg0 = data.message[0];
|
|
207
|
+
msg0.data['id'] = await this.getReplyMsgIdFromDB(data);
|
|
208
|
+
}
|
|
201
209
|
}
|
|
202
210
|
else {
|
|
203
211
|
if (data.source) {
|
|
204
|
-
this.db.set(`KVMap.${data.source.seq}`, data.message[0].id);
|
|
205
212
|
data.message.shift();
|
|
213
|
+
// segment 更好用, cq 一般只用来显示,就不存储真实id了, 有需求的自己去改
|
|
206
214
|
data.message = (0, icqq_cq_enable_1.toCqcode)(data).replace(/^(\[CQ:reply,id=)(.+?)\]/, `$1${data.source.seq}]`);
|
|
207
215
|
}
|
|
208
216
|
else {
|
|
@@ -211,12 +219,14 @@ class V11 extends events_1.EventEmitter {
|
|
|
211
219
|
}
|
|
212
220
|
}
|
|
213
221
|
if (data.message_id) {
|
|
214
|
-
this.
|
|
215
|
-
|
|
222
|
+
data.message_id = await this.addMsgToDB(data);
|
|
223
|
+
}
|
|
224
|
+
if (data.post_type == 'notice' && String(data.notice_type).endsWith('_recall')) {
|
|
225
|
+
this.db.markMsgAsRecalled(data.base64_id);
|
|
216
226
|
}
|
|
217
227
|
if (data.font) {
|
|
218
228
|
const fontNo = Buffer.from(data.font).readUInt32BE();
|
|
219
|
-
this.db.set(`KVMap.${data.fontNo}`,
|
|
229
|
+
// this.db.set(`KVMap.${data.fontNo}`,data.font)
|
|
220
230
|
data.font = fontNo;
|
|
221
231
|
}
|
|
222
232
|
data.time = Math.floor(Date.now() / 1000);
|
|
@@ -282,6 +292,49 @@ class V11 extends events_1.EventEmitter {
|
|
|
282
292
|
return JSON.stringify(data);
|
|
283
293
|
}
|
|
284
294
|
}
|
|
295
|
+
async addMsgToDB(data) {
|
|
296
|
+
if (!data.sender || !('user_id' in data.sender)) { // eg. notice
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
let msg = new db_entities_1.MsgEntry();
|
|
300
|
+
msg.base64_id = data.message_id;
|
|
301
|
+
msg.seq = data.seq;
|
|
302
|
+
msg.user_id = data.sender.user_id;
|
|
303
|
+
msg.nickname = data.sender.nickname;
|
|
304
|
+
if (data.message_type === 'group') {
|
|
305
|
+
msg.group_id = data.group_id;
|
|
306
|
+
msg.group_name = data["group_name"] || ''; // 可能不存在(gocq默认不发)
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
msg.group_id = 0;
|
|
310
|
+
msg.group_name = '';
|
|
311
|
+
}
|
|
312
|
+
msg.content = data.cqCode;
|
|
313
|
+
return await this.db.addOrUpdateMsg(msg);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* 从 send_msg_xxx() 调用的返回值中提取消息存入数据库(可以让前端在没有收到同步的message数据前就有能力拿到消息对应的base64_id)
|
|
317
|
+
* (也有可能来的比message慢,后来的话会被数据库忽略)
|
|
318
|
+
* @param user_id 发送者
|
|
319
|
+
* @param group_id 群号,私聊为0
|
|
320
|
+
* @param seq 消息序号
|
|
321
|
+
* @param base64_id icqq返回的base64格式的消息id
|
|
322
|
+
*/
|
|
323
|
+
async addMsgToDBFromSendMsgResult(user_id, group_id, seq, base64_id) {
|
|
324
|
+
let msg = new db_entities_1.MsgEntry();
|
|
325
|
+
msg.base64_id = base64_id;
|
|
326
|
+
msg.seq = seq;
|
|
327
|
+
msg.user_id = user_id;
|
|
328
|
+
msg.nickname = '';
|
|
329
|
+
msg.group_id = group_id;
|
|
330
|
+
msg.content = '';
|
|
331
|
+
return await this.db.addOrUpdateMsg(msg);
|
|
332
|
+
}
|
|
333
|
+
async getReplyMsgIdFromDB(data) {
|
|
334
|
+
let group_id = (data.message_type === 'group') ? data.group_id : 0;
|
|
335
|
+
let msg = await this.db.getMsgByParams(data.source.user_id, group_id, data.source.seq);
|
|
336
|
+
return msg ? msg.id : 0;
|
|
337
|
+
}
|
|
285
338
|
async _httpRequestHandler(ctx) {
|
|
286
339
|
if (ctx.method === 'OPTIONS') {
|
|
287
340
|
return ctx.writeHead(200, {
|
|
@@ -375,7 +428,9 @@ class V11 extends events_1.EventEmitter {
|
|
|
375
428
|
error: {
|
|
376
429
|
code, message
|
|
377
430
|
},
|
|
378
|
-
echo: data?.echo
|
|
431
|
+
echo: data?.echo,
|
|
432
|
+
msg: e.message,
|
|
433
|
+
action: data.action
|
|
379
434
|
}));
|
|
380
435
|
}
|
|
381
436
|
});
|
|
@@ -447,7 +502,7 @@ class V11 extends events_1.EventEmitter {
|
|
|
447
502
|
async apply(req) {
|
|
448
503
|
let { action, params, echo } = req;
|
|
449
504
|
if (typeof params.message_id == 'number' || /^\d+$/.test(params.message_id)) {
|
|
450
|
-
params.message_id = this.db.
|
|
505
|
+
params.message_id = (await this.db.getMsgById(params.message_id)).id; // 调用api时把本地的数字id转为base64发给icqq
|
|
451
506
|
}
|
|
452
507
|
action = (0, utils_1.toLine)(action);
|
|
453
508
|
let is_async = action.includes("_async");
|
|
@@ -510,7 +565,7 @@ class V11 extends events_1.EventEmitter {
|
|
|
510
565
|
}
|
|
511
566
|
else {
|
|
512
567
|
try {
|
|
513
|
-
ret = this.action[method].apply(this, args);
|
|
568
|
+
ret = await this.action[method].apply(this, args);
|
|
514
569
|
}
|
|
515
570
|
catch (e) {
|
|
516
571
|
return JSON.stringify(V11.error(e.message));
|
|
@@ -531,9 +586,9 @@ class V11 extends events_1.EventEmitter {
|
|
|
531
586
|
result.data = [...result.data.values()];
|
|
532
587
|
if (result.data?.message)
|
|
533
588
|
result.data.message = (0, icqq_cq_enable_1.toSegment)(result.data.message);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
result.data.message_id = result.data.seq;
|
|
589
|
+
// send_msg_xxx 时提前把数据写入数据库(也有可能来的比message慢,后来的话会被数据库忽略)
|
|
590
|
+
if (result.status === 'ok' && params.user_id && result.data?.message_id && result.data?.seq) {
|
|
591
|
+
result.data.message_id = await this.addMsgToDBFromSendMsgResult(params.user_id, params.group_id || 0, result.data.seq, result.data.message_id);
|
|
537
592
|
}
|
|
538
593
|
if (echo) {
|
|
539
594
|
result.echo = echo;
|
package/lib/service/V11/utils.js
CHANGED
|
@@ -9,8 +9,12 @@ async function processMessage(message, source) {
|
|
|
9
9
|
if (quote)
|
|
10
10
|
(0, utils_1.remove)(elements, quote);
|
|
11
11
|
let music = elements.find(e => e.type === 'music');
|
|
12
|
-
if (music)
|
|
12
|
+
if (music) {
|
|
13
13
|
(0, utils_1.remove)(elements, music);
|
|
14
|
+
if (String(music.platform) === 'custom') {
|
|
15
|
+
music.platform = music['subtype']; // gocq 的平台数据存储在 subtype 内,兼容 icqq 时要求前端必须发送 id 字段
|
|
16
|
+
}
|
|
17
|
+
}
|
|
14
18
|
let share = elements.find(e => e.type === 'share');
|
|
15
19
|
if (share)
|
|
16
20
|
(0, utils_1.remove)(elements, share);
|
|
@@ -47,7 +47,8 @@ export declare class V12 extends EventEmitter implements OneBot.Base {
|
|
|
47
47
|
friend: any;
|
|
48
48
|
member: any;
|
|
49
49
|
};
|
|
50
|
-
|
|
50
|
+
system_online(data: any): void;
|
|
51
|
+
dispatch(data: Record<string, any>): Promise<void>;
|
|
51
52
|
apply(req: V12.RequestAction): Promise<string>;
|
|
52
53
|
private httpAuth;
|
|
53
54
|
private httpRequestHandler;
|
package/lib/service/V12/index.js
CHANGED
|
@@ -351,7 +351,9 @@ class V12 extends events_1.EventEmitter {
|
|
|
351
351
|
};
|
|
352
352
|
return V12.formatPayload(this.oneBot.uin, event, data);
|
|
353
353
|
}
|
|
354
|
-
|
|
354
|
+
system_online(data) {
|
|
355
|
+
}
|
|
356
|
+
async dispatch(data) {
|
|
355
357
|
const payload = {
|
|
356
358
|
id: (0, utils_2.uuid)(),
|
|
357
359
|
impl: 'onebots',
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Contactable } from "icqq/lib/internal";
|
|
2
|
+
import { MusicElem } from "icqq/lib/message";
|
|
3
|
+
import { Encodable } from "icqq/lib/core/protobuf";
|
|
4
|
+
/** 发送音乐分享(允许自定义参数) */
|
|
5
|
+
export declare function shareMusic(this: Contactable, music: MusicElem): Promise<void>;
|
|
6
|
+
/**
|
|
7
|
+
* 构造频道b77音乐分享
|
|
8
|
+
* @param channel_id {string} 子频道id
|
|
9
|
+
* @param guild_id {string} 频道id
|
|
10
|
+
* @param music 音乐分享数据
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildMusic(channel_id: string, guild_id: string, music: MusicElem): Promise<Encodable>;
|
|
13
|
+
/**
|
|
14
|
+
* 构造b77音乐分享
|
|
15
|
+
* @param target {number} 群id或者好友qq
|
|
16
|
+
* @param bu {0|1} 类型表示:0 为好友 1 为群
|
|
17
|
+
* @param music 音乐分享数据
|
|
18
|
+
*/
|
|
19
|
+
export declare function buildMusic(target: number, bu: 0 | 1, music: MusicElem): Promise<Encodable>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildMusic = exports.shareMusic = void 0;
|
|
4
|
+
const message_1 = require("icqq/lib/message");
|
|
5
|
+
const core_1 = require("icqq/lib/core");
|
|
6
|
+
const process_1 = require("process");
|
|
7
|
+
/** 发送音乐分享(允许自定义参数) */
|
|
8
|
+
async function shareMusic(music) {
|
|
9
|
+
const body = await buildMusic((this.gid || this.uid), this.dm ? 0 : 1, music);
|
|
10
|
+
await this.c.sendOidb("OidbSvc.0xb77_9", core_1.pb.encode(body));
|
|
11
|
+
}
|
|
12
|
+
exports.shareMusic = shareMusic;
|
|
13
|
+
async function buildMusic(target, bu, music) {
|
|
14
|
+
const { appid, package_name, sign, getMusicInfo } = message_1.musicFactory[music.platform];
|
|
15
|
+
let style = 4;
|
|
16
|
+
try {
|
|
17
|
+
let { singer = null, title = null, jumpUrl = null, musicUrl = null, preview = null } = music.id ? await getMusicInfo(music.id) : {};
|
|
18
|
+
singer = music['content'] || music.singer || singer; // 自定义参数优先级高于默认值(gocq的参数名与icqq有区别,做下兼容)
|
|
19
|
+
title = music.title || title;
|
|
20
|
+
jumpUrl = music.jumpUrl || jumpUrl;
|
|
21
|
+
musicUrl = music['url'] || music['voice'] || music.musicUrl || musicUrl;
|
|
22
|
+
preview = music['image'] || music.preview || preview;
|
|
23
|
+
if (!musicUrl)
|
|
24
|
+
style = 0;
|
|
25
|
+
return {
|
|
26
|
+
1: appid,
|
|
27
|
+
2: 1,
|
|
28
|
+
3: style,
|
|
29
|
+
5: {
|
|
30
|
+
1: 1,
|
|
31
|
+
2: "0.0.0",
|
|
32
|
+
3: package_name,
|
|
33
|
+
4: sign
|
|
34
|
+
},
|
|
35
|
+
10: typeof bu === 'string' ? 3 : bu,
|
|
36
|
+
11: target,
|
|
37
|
+
12: {
|
|
38
|
+
10: title,
|
|
39
|
+
11: singer,
|
|
40
|
+
12: "[分享]" + title,
|
|
41
|
+
13: jumpUrl,
|
|
42
|
+
14: preview,
|
|
43
|
+
16: musicUrl,
|
|
44
|
+
},
|
|
45
|
+
19: typeof bu === 'string' ? Number(bu) : undefined
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
throw new Error("unknown music id: " + music.id + ", in platform: " + music.platform + ", with title: " + process_1.title);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.buildMusic = buildMusic;
|
package/lib/types.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
export type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal" | "mark" | "off";
|
|
2
2
|
export type Dispose = () => any;
|
|
3
3
|
export type MayBeArray<T extends any> = T | T[];
|
|
4
|
+
/**
|
|
5
|
+
* 异步锁---
|
|
6
|
+
*/
|
|
7
|
+
export declare class AsyncLock {
|
|
8
|
+
private _lock;
|
|
9
|
+
private _waitList;
|
|
10
|
+
lock(): Promise<void>;
|
|
11
|
+
unlock(): void;
|
|
12
|
+
}
|
package/lib/types.js
CHANGED
|
@@ -1,2 +1,28 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AsyncLock = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* 异步锁---
|
|
6
|
+
*/
|
|
7
|
+
class AsyncLock {
|
|
8
|
+
constructor() {
|
|
9
|
+
this._lock = false;
|
|
10
|
+
this._waitList = [];
|
|
11
|
+
}
|
|
12
|
+
async lock() {
|
|
13
|
+
if (this._lock) {
|
|
14
|
+
await new Promise((resolve) => {
|
|
15
|
+
this._waitList.push(resolve);
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
this._lock = true;
|
|
19
|
+
}
|
|
20
|
+
unlock() {
|
|
21
|
+
this._lock = false;
|
|
22
|
+
if (this._waitList.length > 0) {
|
|
23
|
+
let resolve = this._waitList.shift();
|
|
24
|
+
resolve && resolve();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.AsyncLock = AsyncLock;
|
package/lib/utils.d.ts
CHANGED
|
@@ -4,6 +4,12 @@ export declare function transformObj(obj: any, callback: any): any;
|
|
|
4
4
|
export declare function deepClone<T extends any>(obj: T): T;
|
|
5
5
|
export declare function pick<T extends object, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean): Pick<T, K>;
|
|
6
6
|
export declare function omit<T, K extends keyof T>(source: T, keys?: Iterable<K>): Omit<T, K>;
|
|
7
|
+
/**
|
|
8
|
+
* 将驼峰命名替换为下划线分割命名
|
|
9
|
+
* @param name
|
|
10
|
+
* @returns
|
|
11
|
+
* @todo 是否应该改名 ToUnderLine()?
|
|
12
|
+
*/
|
|
7
13
|
export declare function toLine<T extends string>(name: T): string;
|
|
8
14
|
export interface Class {
|
|
9
15
|
new (...args: any[]): any;
|
package/lib/utils.js
CHANGED
|
@@ -114,6 +114,12 @@ function omit(source, keys) {
|
|
|
114
114
|
return result;
|
|
115
115
|
}
|
|
116
116
|
exports.omit = omit;
|
|
117
|
+
/**
|
|
118
|
+
* 将驼峰命名替换为下划线分割命名
|
|
119
|
+
* @param name
|
|
120
|
+
* @returns
|
|
121
|
+
* @todo 是否应该改名 ToUnderLine()?
|
|
122
|
+
*/
|
|
117
123
|
function toLine(name) {
|
|
118
124
|
return name.replace(/([A-Z])/g, "_$1").toLowerCase();
|
|
119
125
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "onebots",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.21",
|
|
4
4
|
"description": "基于icqq的多例oneBot实现",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=16"
|
|
@@ -64,6 +64,9 @@
|
|
|
64
64
|
"koa-bodyparser": "^4.3.0",
|
|
65
65
|
"log4js": "^6.5.2",
|
|
66
66
|
"mime-types": "^2.1.35",
|
|
67
|
-
"ws": "^8.8.0"
|
|
67
|
+
"ws": "^8.8.0",
|
|
68
|
+
"better-sqlite3": "^8.6.0",
|
|
69
|
+
"reflect-metadata": "^0.1.13",
|
|
70
|
+
"typeorm": "^0.3.17"
|
|
68
71
|
}
|
|
69
72
|
}
|