onebots 0.4.30 → 0.4.32

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.
@@ -96,7 +96,10 @@ class IcqqAdapter extends adapter_1.Adapter {
96
96
  createOneBot(uin, protocol, versions) {
97
97
  const oneBot = super.createOneBot(uin, protocol, versions);
98
98
  __classPrivateFieldSet(this, _IcqqAdapter_password, this.app.config[`icqq.${uin}`].password, "f");
99
- oneBot.internal = new icqq_1.Client((0, utils_1.deepMerge)(protocol, (0, utils_1.deepClone)(exports.defaultIcqqConfig)));
99
+ oneBot.internal = new icqq_1.Client((0, utils_1.deepMerge)(protocol, (0, utils_1.deepClone)({
100
+ ...exports.defaultIcqqConfig,
101
+ log_level: this.app.config.log_level
102
+ })));
100
103
  return oneBot;
101
104
  }
102
105
  formatEventPayload(version, event, data) {
@@ -207,8 +210,8 @@ class IcqqAdapter extends adapter_1.Adapter {
207
210
  toCqcode(version, messageArr) {
208
211
  return [].concat(messageArr).map(item => {
209
212
  if (item.type === 'text')
210
- return item.data.text;
211
- const dataStr = Object.entries(item.data).map(([key, value]) => {
213
+ return item.data?.text || item.text;
214
+ const dataStr = Object.entries(item.data || item).map(([key, value]) => {
212
215
  // is Buffer
213
216
  if (value instanceof Buffer)
214
217
  return `${key}=${value.toString('base64')}`;
@@ -219,7 +222,7 @@ class IcqqAdapter extends adapter_1.Adapter {
219
222
  if (value instanceof Array)
220
223
  return `${key}=${value.map(v => JSON.stringify(v)).join(',')}`;
221
224
  // is String
222
- return `${key}=${item.data[key]}`;
225
+ return `${key}=${item.data?.[key] || item[key]}`;
223
226
  });
224
227
  return `[CQ:${item.type},${dataStr.join(',')}]`;
225
228
  }).join('');
@@ -26,7 +26,6 @@ class QQAdapter extends adapter_1.Adapter {
26
26
  }
27
27
  qqBot.stop();
28
28
  };
29
- const _this = this;
30
29
  const messageHandler = (event) => {
31
30
  this.emit('message.receive', oneBot.uin, event);
32
31
  };
@@ -73,10 +72,13 @@ class QQAdapter extends adapter_1.Adapter {
73
72
  text: item
74
73
  }
75
74
  };
76
- const { type, ...data } = item;
75
+ const { type, data, ...other } = item;
77
76
  return {
78
77
  type,
79
- data
78
+ data: {
79
+ ...data,
80
+ ...other
81
+ }
80
82
  };
81
83
  });
82
84
  }
@@ -125,7 +127,7 @@ class QQAdapter extends adapter_1.Adapter {
125
127
  formatEventPayload(version, event, data) {
126
128
  const result = {
127
129
  id: data.id,
128
- type: event,
130
+ [version === 'V12' ? 'type' : 'post_type']: event,
129
131
  version: version,
130
132
  self: {
131
133
  platform: 'qq',
@@ -133,9 +135,10 @@ class QQAdapter extends adapter_1.Adapter {
133
135
  },
134
136
  detail_type: data.message_type || data.notice_type || data.request_type,
135
137
  platform: 'qq',
138
+ time: data.timestamp,
136
139
  ...data,
137
140
  };
138
- delete data.bot;
141
+ delete result.bot;
139
142
  return result;
140
143
  }
141
144
  async start(uin) {
@@ -25,8 +25,6 @@ general: # 通用配置,在单个配置省略时的默认值
25
25
  use_ws: true # 是否启用 websocket
26
26
  webhook: [ ] # http 上报地址
27
27
  ws_reverse: [ ] # 反向ws连接地址
28
- protocol:
29
- platform: 2
30
28
  # 每个账号的单独配置(用于覆盖通用配置)
31
29
  icqq.123456789: # `${适配器名称}:${账号}`
32
30
  versions:
package/lib/db.d.ts CHANGED
@@ -1,16 +1,21 @@
1
- import { Keys, Value } from "@zhinjs/shared";
2
- export declare class Database<T extends object = object> {
3
- private readonly path;
1
+ export declare class JsonDB {
2
+ private readonly filePath;
4
3
  private data;
5
- constructor(path: string);
6
- sync(defaultValue: T): void;
7
- get<K extends Keys<T>>(key: K): Value<T, K>;
8
- delete<K extends Keys<T>>(key: K): boolean;
9
- set<K extends Keys<T>>(key: K, value: Value<T, K>): void;
10
- }
11
- export declare namespace Database {
12
- interface Config {
13
- path: string;
14
- force?: boolean;
15
- }
4
+ constructor(filePath: string);
5
+ private init;
6
+ private write;
7
+ private read;
8
+ findIndex<T>(route: string, predicate: (value: T, index: number, obj: T[]) => unknown): number;
9
+ indexOf<T>(route: string, item: T): number;
10
+ get<T>(route: string, initialValue?: T): T | undefined;
11
+ set<T>(route: string, data: T): T;
12
+ delete(route: string): boolean;
13
+ private getArray;
14
+ unshift<T>(route: string, ...data: T[]): number;
15
+ shift<T>(route: string): T;
16
+ push<T>(route: string, ...data: T[]): number;
17
+ pop<T>(route: string): T;
18
+ splice<T>(route: string, index?: number, deleteCount?: number, ...data: T[]): T[];
19
+ find<T>(route: string, callback: (item: T) => boolean): T | undefined;
20
+ filter<T>(route: string, callback: (item: T) => boolean): T[];
16
21
  }
package/lib/db.js CHANGED
@@ -1,58 +1,149 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Database = void 0;
4
- const fs_1 = require("fs");
5
- const shared_1 = require("@zhinjs/shared");
6
- class Database {
7
- constructor(path) {
8
- this.path = path;
26
+ exports.JsonDB = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ const utils_1 = require("./utils");
30
+ class JsonDB {
31
+ constructor(filePath) {
32
+ this.filePath = filePath;
9
33
  this.data = {};
10
- if (!this.path.toLowerCase().endsWith(".json"))
11
- this.path = this.path + ".json";
12
- if (!(0, fs_1.existsSync)(this.path)) {
13
- (0, fs_1.writeFileSync)(this.path, "", "utf-8");
14
- }
34
+ const dir = path.dirname(this.filePath);
35
+ if (fs.existsSync(dir))
36
+ fs.mkdirSync(dir, { recursive: true });
37
+ if (!this.filePath.endsWith('.jsondb'))
38
+ this.filePath = this.filePath + '.jsondb';
39
+ if (!fs.existsSync(this.filePath))
40
+ this.write();
41
+ this.init();
15
42
  }
16
- sync(defaultValue) {
17
- try {
18
- this.data = JSON.parse((0, fs_1.readFileSync)(this.path, "utf-8"));
19
- }
20
- catch {
21
- this.data = defaultValue;
22
- (0, fs_1.writeFileSync)(this.path, JSON.stringify(defaultValue, null, 2), "utf-8");
43
+ init() {
44
+ this.read();
45
+ }
46
+ write() {
47
+ fs.writeFileSync(this.filePath, (0, utils_1.stringifyObj)(this.data), 'utf8');
48
+ }
49
+ read() {
50
+ this.data = (0, utils_1.parseObjFromStr)(fs.readFileSync(this.filePath, 'utf8'));
51
+ }
52
+ findIndex(route, predicate) {
53
+ const arr = this.getArray(route);
54
+ return arr.findIndex(predicate);
55
+ }
56
+ indexOf(route, item) {
57
+ return this.findIndex(route, (value) => value === item);
58
+ }
59
+ get(route, initialValue) {
60
+ this.read();
61
+ const parentPath = route.split('.');
62
+ const key = parentPath.pop();
63
+ if (!key)
64
+ return this.data;
65
+ let temp = this.data;
66
+ while (parentPath.length) {
67
+ const currentKey = parentPath.shift();
68
+ if (!Reflect.has(temp, currentKey))
69
+ Reflect.set(temp, key, {});
70
+ temp = Reflect.get(temp, currentKey);
23
71
  }
72
+ if (temp[key] !== undefined)
73
+ return temp[key];
74
+ temp[key] = initialValue;
75
+ this.write();
76
+ return initialValue;
77
+ }
78
+ set(route, data) {
79
+ const parentPath = route.split('.');
80
+ const key = parentPath.pop();
81
+ if (!key)
82
+ throw new SyntaxError(`route can't empty`);
83
+ const parentObj = this.get(parentPath.join('.'), {});
84
+ if (!parentObj)
85
+ throw new SyntaxError(`can't set property ${key} of undefined`);
86
+ parentObj[key] = data;
87
+ this.write();
88
+ return data;
89
+ }
90
+ delete(route) {
91
+ const parentPath = route.split('.');
92
+ const key = parentPath.pop();
93
+ if (!key)
94
+ throw new SyntaxError(`route can't empty`);
95
+ const parentObj = this.get(parentPath.join('.'), {});
96
+ if (!parentObj)
97
+ throw new SyntaxError(`property ${key} is not exist of undefined`);
98
+ const result = delete parentObj[key];
99
+ this.write();
100
+ return result;
101
+ }
102
+ getArray(route) {
103
+ if (!route)
104
+ throw new Error(`route can't empty`);
105
+ const arr = this.get(route, []);
106
+ if (!arr)
107
+ throw new SyntaxError(`route ${route} is not define`);
108
+ if (!Array.isArray(arr))
109
+ throw new TypeError(`data ${route} is not an Array`);
110
+ return arr;
111
+ }
112
+ unshift(route, ...data) {
113
+ const arr = this.getArray(route);
114
+ const result = arr.unshift(...data);
115
+ this.write();
116
+ return result;
117
+ }
118
+ shift(route) {
119
+ const arr = this.getArray(route);
120
+ const result = arr.shift();
121
+ this.write();
122
+ return result;
123
+ }
124
+ push(route, ...data) {
125
+ const arr = this.getArray(route);
126
+ const result = arr.push(...data);
127
+ this.write();
128
+ return result;
129
+ }
130
+ pop(route) {
131
+ const arr = this.getArray(route);
132
+ const result = arr.pop();
133
+ this.write();
134
+ return result;
135
+ }
136
+ splice(route, index = 0, deleteCount = 0, ...data) {
137
+ const arr = this.getArray(route);
138
+ const result = arr.splice(index, deleteCount, ...data);
139
+ this.write();
140
+ return result;
141
+ }
142
+ find(route, callback) {
143
+ return this.getArray(route).find(callback);
24
144
  }
25
- get(key) {
26
- const value = (0, shared_1.getValue)(this.data, key);
27
- if (typeof value !== "object")
28
- return value;
29
- const saveValue = () => {
30
- this.set(key, value);
31
- };
32
- return new Proxy(value, {
33
- set(target, k, v) {
34
- const res = Reflect.set(target, k, v);
35
- saveValue();
36
- return res;
37
- },
38
- deleteProperty(target, p) {
39
- const res = Reflect.deleteProperty(target, p);
40
- saveValue();
41
- return res;
42
- },
43
- defineProperty(target, p, r) {
44
- const res = Reflect.defineProperty(target, p, r);
45
- saveValue();
46
- return res;
47
- },
48
- });
49
- }
50
- delete(key) {
51
- return (0, shared_1.deleteValue)(this.data, key);
52
- }
53
- set(key, value) {
54
- (0, shared_1.setValue)(this.data, key, value);
55
- return (0, fs_1.writeFileSync)(this.path, JSON.stringify(this.data, null, 2), "utf-8");
145
+ filter(route, callback) {
146
+ return this.getArray(route).filter(callback);
56
147
  }
57
148
  }
58
- exports.Database = Database;
149
+ exports.JsonDB = JsonDB;
@@ -19,7 +19,9 @@ class CommonAction {
19
19
  async deleteMsg(message_id) {
20
20
  if (message_id == 0)
21
21
  throw new Error('getMsg: message_id[0] is invalid');
22
- let msg_entry = await this.db.getMsgById(message_id);
22
+ let msg_entry = this.db.find('messages', (message) => {
23
+ return message.id === message_id;
24
+ });
23
25
  if (!msg_entry)
24
26
  throw new Error(`getMsg: can not find msg[${message_id}] in db`);
25
27
  return this.adapter.call(this.oneBot.uin, 'V11', 'deleteMsg', [msg_entry.base64_id]);
@@ -32,7 +34,9 @@ class CommonAction {
32
34
  async getMsg(message_id) {
33
35
  if (message_id == 0)
34
36
  throw new Error('getMsg: message_id[0] is invalid');
35
- let msg_entry = await this.db.getMsgById(message_id);
37
+ let msg_entry = this.db.find('messages', (message) => {
38
+ return message.id === message_id;
39
+ });
36
40
  if (!msg_entry)
37
41
  throw new Error(`getMsg: can not find msg[${message_id}] in db`);
38
42
  let msg = await this.adapter.call(this.oneBot.uin, 'V11', 'getMsg', [msg_entry.base64_id]);
@@ -28,5 +28,5 @@ export declare class FriendAction {
28
28
  * @param user_id {number} 用户id
29
29
  * @param times 点赞次数
30
30
  */
31
- sendUserLike(this: V11, user_id: number, times?: number): Promise<any>;
31
+ sendLike(this: V11, user_id: number, times?: number): Promise<any>;
32
32
  }
@@ -38,8 +38,8 @@ class FriendAction {
38
38
  * @param user_id {number} 用户id
39
39
  * @param times 点赞次数
40
40
  */
41
- async sendUserLike(user_id, times) {
42
- return this.adapter.call(this.oneBot.uin, 'V11', 'sendUserLike', [user_id, times]);
41
+ async sendLike(user_id, times) {
42
+ return this.adapter.call(this.oneBot.uin, 'V11', 'sendLike', [user_id, times]);
43
43
  }
44
44
  }
45
45
  exports.FriendAction = FriendAction;
@@ -1,5 +1,5 @@
1
- export declare class MsgEntry {
2
- id?: number;
1
+ export interface MsgEntry {
2
+ id: number;
3
3
  base64_id: string;
4
4
  seq: number;
5
5
  user_id: string;
@@ -7,7 +7,7 @@ export declare class MsgEntry {
7
7
  group_id: number;
8
8
  group_name: string;
9
9
  content: string;
10
- recalled: boolean;
11
- create_time: Date;
12
- recall_time?: Date;
10
+ recalled?: boolean;
11
+ create_time?: number;
12
+ recall_time?: number;
13
13
  }
@@ -1,63 +1,2 @@
1
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
2
  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", String)
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);
@@ -5,9 +5,9 @@ import { OneBot, OneBotStatus } from "../../onebot";
5
5
  import { Logger } from "log4js";
6
6
  import { WebSocket, WebSocketServer } from "ws";
7
7
  import { Dispose } from "../../types";
8
- import { Database } from "./db_sqlite";
9
8
  import { Service } from "../../service";
10
9
  import { Dict } from "@zhinjs/shared";
10
+ import { JsonDB } from "../../db";
11
11
  export declare class V11 extends Service<"V11"> implements OneBot.Base {
12
12
  oneBot: OneBot<"V11">;
13
13
  config: OneBot.Config<"V11">;
@@ -15,7 +15,7 @@ export declare class V11 extends Service<"V11"> implements OneBot.Base {
15
15
  version: OneBot.Version;
16
16
  protected timestamp: number;
17
17
  protected heartbeat?: NodeJS.Timeout;
18
- db: Database;
18
+ db: JsonDB;
19
19
  disposes: Dispose[];
20
20
  protected _queue: Array<{
21
21
  method: keyof Action;
@@ -13,11 +13,10 @@ const utils_1 = require("../../utils");
13
13
  const onebot_2 = require("../../onebot");
14
14
  const http_1 = __importDefault(require("http"));
15
15
  const https_1 = __importDefault(require("https"));
16
- const db_sqlite_1 = require("./db_sqlite");
17
16
  const path_1 = require("path");
18
17
  const app_1 = require("../../server/app");
19
- const db_entities_1 = require("./db_entities");
20
18
  const service_1 = require("../../service");
19
+ const db_1 = require("../../db");
21
20
  const sendMsgTypes = ["private", "group", "discuss"];
22
21
  const sendMsgMethodRegex = new RegExp(`send_(${sendMsgTypes.join("|")})_msg`);
23
22
  class V11 extends service_1.Service {
@@ -32,7 +31,7 @@ class V11 extends service_1.Service {
32
31
  this.wsr = new Set();
33
32
  this.action = new action_1.Action();
34
33
  this.logger = this.oneBot.adapter.getLogger(this.oneBot.uin, this.version);
35
- this.db = new db_sqlite_1.Database((0, path_1.join)(app_1.App.configDir, "data", this.oneBot.uin + ".db"), this.logger);
34
+ this.db = new db_1.JsonDB((0, path_1.join)(app_1.App.configDir, 'data', `${this.oneBot.uin}_v11.jsondb`));
36
35
  this.oneBot.on("online", async () => {
37
36
  this.logger.info("【好友列表】");
38
37
  const friendList = await this.oneBot.getFriendList("V11");
@@ -228,7 +227,13 @@ class V11 extends service_1.Service {
228
227
  data.message_id = await this.addMsgToDB(data);
229
228
  }
230
229
  if (data.post_type == "notice" && String(data.notice_type).endsWith("_recall")) {
231
- this.db.markMsgAsRecalled(data.base64_id);
230
+ const msgIdx = this.db.findIndex('messages', (message) => {
231
+ return message.base64_id === data.base64_id;
232
+ });
233
+ if (msgIdx >= 0) {
234
+ this.db.set(`messages.${msgIdx}.recalled`, true);
235
+ this.db.set(`messages.${msgIdx}.recall_time`, parseInt((Date.now() / 1000) + ''));
236
+ }
232
237
  }
233
238
  if (data.font) {
234
239
  const fontNo = Buffer.from(data.font).readUInt32BE();
@@ -304,21 +309,21 @@ class V11 extends service_1.Service {
304
309
  // eg. notice
305
310
  return;
306
311
  }
307
- let msg = new db_entities_1.MsgEntry();
308
- msg.base64_id = data.message_id;
309
- msg.seq = data.seq;
310
- msg.user_id = data.sender.user_id;
311
- msg.nickname = data.sender.nickname;
312
- if (data.message_type === "group") {
313
- msg.group_id = data.group_id;
314
- msg.group_name = data["group_name"] || ""; // 可能不存在(gocq默认不发)
315
- }
316
- else {
317
- msg.group_id = 0;
318
- msg.group_name = "";
319
- }
320
- msg.content = data.cqCode || data.message;
321
- return await this.db.addOrUpdateMsg(msg);
312
+ const id = (0, utils_1.randomInt)(1, Number.MAX_SAFE_INTEGER);
313
+ this.db.push('messages', {
314
+ id,
315
+ base64_id: data.base64_id,
316
+ seq: data.seq,
317
+ user_id: data.sender.user_id,
318
+ nickname: data.sender.nickname,
319
+ group_id: data.group_id || 0,
320
+ group_name: data.group_name || '',
321
+ content: data.cqCode || data.message,
322
+ create_time: data.time,
323
+ });
324
+ if (this.db.get('messages').length > 1000)
325
+ this.db.shift('messages');
326
+ return id;
322
327
  }
323
328
  /**
324
329
  * 从 send_msg_xxx() 调用的返回值中提取消息存入数据库(可以让前端在没有收到同步的message数据前就有能力拿到消息对应的base64_id)
@@ -329,20 +334,27 @@ class V11 extends service_1.Service {
329
334
  * @param base64_id icqq返回的base64格式的消息id
330
335
  */
331
336
  async addMsgToDBFromSendMsgResult(user_id, group_id, seq, base64_id) {
332
- let msg = new db_entities_1.MsgEntry();
333
- msg.base64_id = base64_id;
334
- msg.seq = seq;
335
- msg.user_id = user_id;
336
- msg.nickname = "";
337
- msg.group_id = group_id;
338
- msg.group_name = "";
339
- msg.content = "";
340
- return await this.db.addOrUpdateMsg(msg);
337
+ const id = (0, utils_1.randomInt)(1, Number.MAX_SAFE_INTEGER);
338
+ this.db.push('messages', {
339
+ id,
340
+ base64_id,
341
+ seq,
342
+ user_id,
343
+ nickname: '',
344
+ group_id,
345
+ group_name: '',
346
+ content: '',
347
+ });
348
+ if (this.db.get('messages').length > 1000)
349
+ this.db.shift('messages');
350
+ return id;
341
351
  }
342
352
  async getReplyMsgIdFromDB(data) {
343
353
  let group_id = data.message_type === "group" ? data.group_id : 0;
344
- let msg = await this.db.getMsgByParams(data.source.user_id, group_id, data.source.seq);
345
- return msg ? msg.id : 0;
354
+ let msg = await this.db.find('messages', (message) => {
355
+ return message.user_id === data.user_id && message.group_id === group_id && message.seq === data.source.seq;
356
+ });
357
+ return msg?.id || 0;
346
358
  }
347
359
  async _httpRequestHandler(ctx) {
348
360
  if (ctx.method === "OPTIONS") {
@@ -517,7 +529,9 @@ class V11 extends service_1.Service {
517
529
  async apply(req) {
518
530
  let { action, params, echo } = req;
519
531
  if (typeof params.message_id == "number" || /^\d+$/.test(params.message_id)) {
520
- params.message_id = (await this.db.getMsgById(params.message_id)).id; // 调用api时把本地的数字id转为base64发给icqq
532
+ params.message_id = (await this.db.find('messages', (message) => {
533
+ return params.message_id === message.id;
534
+ }))?.base64_id; // 调用api时把本地的数字id转为base64发给icqq
521
535
  }
522
536
  action = (0, utils_1.toLine)(action);
523
537
  let is_async = action.includes("_async");
@@ -540,9 +554,6 @@ class V11 extends service_1.Service {
540
554
  else
541
555
  throw new Error("required message_type or input (user_id/group_id)");
542
556
  }
543
- else if (action === "send_like") {
544
- action = "send_user_like";
545
- }
546
557
  const method = (0, utils_1.toHump)(action);
547
558
  if (Reflect.has(this.action, method)) {
548
559
  const ARGS = String(Reflect.get(this.action, method)).match(/\(.*\)/)?.[0]
@@ -19,6 +19,8 @@ export declare class V12 extends Service<'V12'> implements OneBot.Base {
19
19
  wsr: Set<WebSocket>;
20
20
  private db;
21
21
  constructor(oneBot: OneBot<'V12'>, config: OneBot.Config<'V12'>);
22
+ addHistory(payload: V12.Payload<keyof Action>): number;
23
+ shiftHistory(): unknown;
22
24
  get history(): V12.Payload<keyof Action>[];
23
25
  getFile(file_id: string): V12.FileInfo;
24
26
  delFile(file_id: string): boolean;
@@ -25,20 +25,24 @@ class V12 extends service_1.Service {
25
25
  this.version = 'V12';
26
26
  this.timestamp = Date.now();
27
27
  this.wsr = new Set();
28
- this.db = new db_1.Database((0, path_1.join)(app_1.App.configDir, 'data', this.oneBot.uin + '.json'));
29
- this.db.sync({ eventBuffer: [], msgIdMap: {}, files: {} });
28
+ this.db = new db_1.JsonDB((0, path_1.join)(app_1.App.configDir, 'data', `${this.oneBot.uin}_v12.jsondb`));
30
29
  this.action = new action_1.Action();
31
30
  this.logger = this.oneBot.adapter.getLogger(this.oneBot.uin, this.version);
32
31
  }
32
+ addHistory(payload) {
33
+ return this.db.push('eventBuffer', payload);
34
+ }
35
+ shiftHistory() {
36
+ return this.db.shift('eventBuffer');
37
+ }
33
38
  get history() {
34
- return this.db.get('eventBuffer');
39
+ return this.db.get('eventBuffer', []);
35
40
  }
36
41
  getFile(file_id) {
37
42
  return this.db.get(`files.${file_id}`);
38
43
  }
39
44
  delFile(file_id) {
40
- const files = this.db.get(`files`);
41
- return delete files[file_id];
45
+ return this.db.delete(`files.${file_id}`);
42
46
  }
43
47
  saveFile(fileInfo) {
44
48
  const file_id = (0, utils_2.uuid)();
@@ -46,7 +50,7 @@ class V12 extends service_1.Service {
46
50
  return file_id;
47
51
  }
48
52
  get files() {
49
- const files = this.db.get('files');
53
+ const files = this.db.get('files', {});
50
54
  return Object.keys(files).map((file_id) => {
51
55
  return {
52
56
  file_id,
@@ -153,9 +157,9 @@ class V12 extends service_1.Service {
153
157
  if (!['message', 'notice', 'request', 'meta'].includes(payload.type))
154
158
  return;
155
159
  if (config.event_enabled) {
156
- this.history.push(payload);
160
+ this.addHistory(payload);
157
161
  if (config.event_buffer_size !== 0 && this.history.length > config.event_buffer_size)
158
- this.history.shift();
162
+ this.shiftHistory();
159
163
  }
160
164
  });
161
165
  }
@@ -360,12 +364,18 @@ class V12 extends service_1.Service {
360
364
  platform: 'qq',
361
365
  user_id: `${this.oneBot.uin}`
362
366
  },
363
- ...(0, utils_2.transformObj)(data, (key, value) => {
364
- if (!['user_id', 'group_id', 'discuss_id', 'member_id', 'channel_id', 'guild_id'].includes(key))
365
- return value;
366
- return value + '';
367
- }),
368
367
  };
368
+ Object.assign(payload, (0, utils_2.transformObj)(data, (key, value) => {
369
+ if (!['user_id', 'group_id', 'discuss_id', 'member_id', 'channel_id', 'guild_id'].includes(key))
370
+ return value;
371
+ return value + '';
372
+ }), {
373
+ self_id: `${this.oneBot.uin}`,
374
+ self: {
375
+ platform: 'qq',
376
+ user_id: `${this.oneBot.uin}`
377
+ },
378
+ });
369
379
  if (!this.filterFn(payload))
370
380
  return;
371
381
  this.emit('dispatch', payload);
@@ -563,6 +573,9 @@ class V12 extends service_1.Service {
563
573
  */
564
574
  _createWsr(url, config) {
565
575
  const timestmap = Date.now();
576
+ let remoteUrl = url;
577
+ if (config.access_token)
578
+ remoteUrl += `?access_token=${config.access_token}`;
566
579
  const headers = {
567
580
  "X-Self-ID": String(this.oneBot.uin),
568
581
  "X-Client-Role": "Universal",
@@ -571,7 +584,7 @@ class V12 extends service_1.Service {
571
584
  };
572
585
  if (config.access_token)
573
586
  headers.Authorization = "Bearer " + config.access_token;
574
- const ws = new ws_1.WebSocket(url, '12.onebots.v' + utils_1.version, { headers });
587
+ const ws = new ws_1.WebSocket(remoteUrl, { headers });
575
588
  ws.on("error", (err) => {
576
589
  this.logger.error(err.message);
577
590
  });
package/lib/utils.d.ts CHANGED
@@ -1,12 +1,10 @@
1
+ import { Dict } from "@zhinjs/shared";
1
2
  export declare const version: any;
2
3
  export declare function deepMerge(base: any, ...from: any[]): any;
3
4
  export declare function transformObj(obj: any, callback: any): any;
4
5
  export declare function deepClone<T extends any>(obj: T): T;
5
6
  export declare function pick<T extends object, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean): Pick<T, K>;
6
7
  export declare function omit<T, K extends keyof T>(source: T, keys?: Iterable<K>): Omit<T, K>;
7
- export declare function randomId(seed: string): number;
8
- export declare function randomId(seed: string, length: number): number;
9
- export declare function randomId(seed: string, min: number, max: number): number;
10
8
  /**
11
9
  * 将驼峰命名替换为下划线分割命名
12
10
  * @param name
@@ -22,5 +20,14 @@ export declare function toHump(action: string): string;
22
20
  export declare function remove<T>(list: T[], item: T): void;
23
21
  export declare function toBool(v: any): boolean;
24
22
  export declare function uuid(): string;
23
+ export declare function randomInt(max: number): number;
24
+ export declare function randomInt(min: number, max: number): number;
25
25
  export declare function protectedFields<T>(source: T, ...keys: ((keyof T) | string)[]): T;
26
26
  export declare function getProperties(obj: any): any;
27
+ export declare function setValueToObj(obj: Dict, keys: string[], value: any): boolean;
28
+ export declare function setValueToObj(obj: Dict, key: string, value: any): boolean;
29
+ export declare function getValueOfObj<T = any>(obj: Dict, key: string[]): T;
30
+ export declare function getValueOfObj<T = any>(obj: Dict, key: string): T;
31
+ export declare function getDataKeyOfObj(data: any, obj: Dict): string;
32
+ export declare function parseObjFromStr(str: string): any;
33
+ export declare function stringifyObj(value: any): string;
package/lib/utils.js CHANGED
@@ -22,13 +22,9 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
25
  Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.getProperties = exports.protectedFields = exports.uuid = exports.toBool = exports.remove = exports.toHump = exports.Mixin = exports.toLine = exports.randomId = exports.omit = exports.pick = exports.deepClone = exports.transformObj = exports.deepMerge = exports.version = void 0;
26
+ exports.stringifyObj = exports.parseObjFromStr = exports.getDataKeyOfObj = exports.getValueOfObj = exports.setValueToObj = exports.getProperties = exports.protectedFields = exports.randomInt = exports.uuid = exports.toBool = exports.remove = exports.toHump = exports.Mixin = exports.toLine = exports.omit = exports.pick = exports.deepClone = exports.transformObj = exports.deepMerge = exports.version = void 0;
30
27
  const crypto = __importStar(require("crypto"));
31
- const seed_random_1 = __importDefault(require("seed-random"));
32
28
  const packageJson = require('../package.json');
33
29
  exports.version = packageJson.version;
34
30
  // 合并对象/数组
@@ -118,19 +114,6 @@ function omit(source, keys) {
118
114
  return result;
119
115
  }
120
116
  exports.omit = omit;
121
- function randomId(seed, ...args) {
122
- let [min = 0, max = 1] = args;
123
- let formatter = (n) => n;
124
- if (args.length === 1) {
125
- const len = Math.min(Number.MAX_SAFE_INTEGER.toString().length, args[0]);
126
- min = 10 ** (len - 1);
127
- max = Math.min(Number.MAX_SAFE_INTEGER, 10 ** len - 1);
128
- formatter = (n) => Math.floor(n);
129
- }
130
- const rand = (0, seed_random_1.default)(seed);
131
- return formatter(rand() * (max - min) + min);
132
- }
133
- exports.randomId = randomId;
134
117
  /**
135
118
  * 将驼峰命名替换为下划线分割命名
136
119
  * @param name
@@ -175,6 +158,13 @@ function uuid() {
175
158
  return hex.substr(0, 8) + "-" + hex.substr(8, 4) + "-" + hex.substr(12, 4) + "-" + hex.substr(16, 4) + "-" + hex.substr(20);
176
159
  }
177
160
  exports.uuid = uuid;
161
+ function randomInt(...args) {
162
+ let min = args[0] || 0, max = args[1];
163
+ if (args.length === 1)
164
+ max = min, min = 0;
165
+ return Math.floor(Math.random() * (max - min) + min);
166
+ }
167
+ exports.randomInt = randomInt;
178
168
  function protectedFields(source, ...keys) {
179
169
  const protocolValue = (value) => {
180
170
  if (value && typeof value === 'object')
@@ -197,3 +187,95 @@ function getProperties(obj) {
197
187
  return Object.getOwnPropertyNames(obj).concat(getProperties(obj.__proto__));
198
188
  }
199
189
  exports.getProperties = getProperties;
190
+ function setValueToObj(obj, key, value) {
191
+ const keys = Array.isArray(key) ? key : key.split('.').filter(Boolean);
192
+ const lastKey = keys.pop();
193
+ if (!lastKey)
194
+ throw new SyntaxError(`key is empty`);
195
+ while (keys.length) {
196
+ const k = keys.shift();
197
+ obj = Reflect.get(obj, k);
198
+ if (!obj)
199
+ throw new SyntaxError(`can't set ${lastKey} to undefined`);
200
+ }
201
+ return Reflect.set(obj, lastKey, value);
202
+ }
203
+ exports.setValueToObj = setValueToObj;
204
+ function getValueOfObj(obj, key) {
205
+ const keys = Array.isArray(key) ? key : key.split('.').filter(Boolean);
206
+ const lastKey = keys.pop();
207
+ if (!lastKey)
208
+ throw new SyntaxError(`key is empty`);
209
+ while (keys.length) {
210
+ const k = keys.shift();
211
+ obj = Reflect.get(obj, k);
212
+ if (!obj)
213
+ throw new SyntaxError(`can't set ${lastKey} to undefined`);
214
+ }
215
+ return Reflect.get(obj, lastKey);
216
+ }
217
+ exports.getValueOfObj = getValueOfObj;
218
+ function getDataKeyOfObj(data, obj) {
219
+ const _get = (data, obj, prefix) => {
220
+ for (const [key, value] of Object.entries(obj)) {
221
+ if (value === data)
222
+ return [...prefix, key].join('.');
223
+ if (!value || typeof value !== 'object')
224
+ continue;
225
+ const result = _get(data, value, prefix);
226
+ if (result)
227
+ return result;
228
+ }
229
+ };
230
+ return _get(data, obj, []);
231
+ }
232
+ exports.getDataKeyOfObj = getDataKeyOfObj;
233
+ function parseObjFromStr(str) {
234
+ const result = JSON.parse(str);
235
+ const format = (data, keys) => {
236
+ if (!data)
237
+ return;
238
+ if (typeof data !== 'object' && typeof data !== 'string')
239
+ return;
240
+ if (typeof data === 'object')
241
+ return Object.entries(data).map(([k, v]) => format(v, [...keys, k]));
242
+ if (/\[Function:.+]/.test(data))
243
+ return setValueToObj(result, [...keys], new Function(`return (${data.slice(10, -1)})`)());
244
+ if (/\[Circular:.+]/.test(data))
245
+ setValueToObj(result, [...keys], getValueOfObj(result, data.slice(10, -1)));
246
+ };
247
+ format(result, []);
248
+ return result;
249
+ }
250
+ exports.parseObjFromStr = parseObjFromStr;
251
+ function stringifyObj(value) {
252
+ if (!value || typeof value !== 'object')
253
+ return value;
254
+ if (Array.isArray(value))
255
+ return `[${value.map(stringifyObj).join()}]`;
256
+ let result = { ...value }, cache = new WeakMap();
257
+ const _stringify = (obj, prefix) => {
258
+ for (const key of Reflect.ownKeys(obj)) {
259
+ if (typeof key === 'symbol')
260
+ continue;
261
+ const val = Reflect.get(obj, key);
262
+ if (!val || typeof val !== 'object') {
263
+ if (typeof val === 'function') {
264
+ setValueToObj(result, [...prefix, String(key)], `[Function:${(val + '').replace(/\n/g, '')}]`);
265
+ continue;
266
+ }
267
+ setValueToObj(result, [...prefix, String(key)], val);
268
+ continue;
269
+ }
270
+ if (cache.has(val)) {
271
+ setValueToObj(result, [...prefix, String(key)], `[Circular:${getDataKeyOfObj(val, value)}]`);
272
+ continue;
273
+ }
274
+ cache.set(val, getValueOfObj(value, [...prefix, String(key)]));
275
+ _stringify(val, [...prefix, String(key)]);
276
+ }
277
+ };
278
+ _stringify(value, []);
279
+ return JSON.stringify(result, null, 2);
280
+ }
281
+ exports.stringifyObj = stringifyObj;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onebots",
3
- "version": "0.4.30",
3
+ "version": "0.4.32",
4
4
  "description": "基于icqq的多例oneBot实现",
5
5
  "engines": {
6
6
  "node": ">=16"
@@ -56,8 +56,7 @@
56
56
  "/**/LICENSE"
57
57
  ],
58
58
  "peerDependencies": {
59
- "icqq": "latest",
60
- "sqlite3": "^5.1.6"
59
+ "icqq": "latest"
61
60
  },
62
61
  "dependencies": {
63
62
  "@koa/router": "^10.1.1",
@@ -69,8 +68,6 @@
69
68
  "log4js": "^6.5.2",
70
69
  "mime-types": "^2.1.35",
71
70
  "reflect-metadata": "^0.1.13",
72
- "seed-random": "^2.2.0",
73
- "typeorm": "^0.3.17",
74
71
  "ws": "^8.8.0"
75
72
  }
76
73
  }
@@ -1,52 +0,0 @@
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: string, 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
- }
@@ -1,115 +0,0 @@
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: "sqlite",
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 msgDataExists.id;
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 }, {
100
- recalled: true,
101
- recall_time: new Date(),
102
- });
103
- else
104
- throw new Error("base64_id 或 id 参数至少一个应该被赋值");
105
- }
106
- /**
107
- * 根据 `msgPreserveDays` 变量定义的保留期限收缩数据库
108
- */
109
- async shrinkDB() {
110
- let dt = new Date();
111
- dt.setDate(dt.getDate() - this.msgHistoryPreserveDays);
112
- await this.msgRepo.createQueryBuilder().delete().from(db_entities_1.MsgEntry).where("create_time < :dt", { dt: dt }).execute();
113
- }
114
- }
115
- exports.Database = Database;