onebots 0.0.14 → 0.0.16

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 CHANGED
@@ -18,35 +18,56 @@
18
18
  </div>
19
19
 
20
20
  # 使用示例
21
- 1. 新建一个node项目
21
+ ## 全局安装
22
+ ### 1 安装依赖
23
+ ```shell
24
+ npm install -g onebots
25
+ ```
26
+ ### 2 初始化配置文件
27
+ (1) 配置文件存到(用户目录/.onebots/config.yaml)
28
+ ```shell
29
+ onebots
30
+ ```
31
+ (2) 配置文件存到(当前目录/config.yaml)
32
+ ```shell
33
+ onebots -c config.yaml
34
+ ```
35
+ 二选一即可
36
+ ### 3 更改配置文件后,启动项目
37
+
38
+ (1) 使用全局配置文件(用户目录/.onebots/config.yaml)
39
+ ```shell
40
+ onebots
41
+ ```
42
+ (2) 使用指定配置文件(当前目录/config.yaml)
43
+ ```shell
44
+ onebots -c config.yaml
45
+ ```
46
+ # 2 在NodeJS项目中启动
47
+ ## 1 初始化node项目
22
48
  ```shell
23
49
  npm init -y
24
50
  ```
25
- 2. 安装onebots
51
+ ## 2. 安装onebots
26
52
  ```shell
27
53
  npm install onebots
28
54
  ```
29
- 3. 在项目跟目录添加配置文件config.yaml
55
+ ## 3. 在项目跟目录添加配置文件config.yaml
30
56
  ```yaml
31
57
  port: 6727 # 项目onebots监听的端口(默认:6727)
32
58
  1472258369: # 你的机器人账户
33
59
  version: V11 # oneBot版本(V11 或 V12)
34
60
  ```
35
- 4. 新建入口文件`index.js`并输入一下内容
61
+ ## 4. 新建入口文件`index.js`并输入一下内容
36
62
  ```javascript
37
63
  const {createApp}=require('onebots')
38
- createApp()
64
+ createApp('config.yaml')
39
65
  .start()
40
66
  ```
41
- 5. 启动项目
67
+ ## 5. 启动项目
42
68
  ```shell
43
69
  node ./index.js
44
70
  ```
45
- # 使用命令行启动
46
- ```shell
47
- npm install -g onebots
48
- onebots
49
- ```
50
71
  # 使用接口管理oneBot
51
72
 
52
73
  | url | method | params | desc |
package/lib/bin.js CHANGED
@@ -2,4 +2,10 @@
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const app_1 = require("./server/app");
5
- (0, app_1.createApp)().start();
5
+ const execArgv = process.argv.splice(2);
6
+ const obj = {};
7
+ for (let i = 0; i < execArgv.length; i += 2) {
8
+ obj[execArgv[i]] = execArgv[i + 1];
9
+ }
10
+ console.log(obj);
11
+ (0, app_1.createApp)(obj['-c']).start();
package/lib/onebot.js CHANGED
@@ -51,6 +51,53 @@ class OneBot extends events_1.EventEmitter {
51
51
  }
52
52
  async start() {
53
53
  this.startListen();
54
+ const disposeArr = [];
55
+ const clean = () => {
56
+ while (disposeArr.length) {
57
+ disposeArr.shift()();
58
+ }
59
+ };
60
+ this.client.on('system.login.qrcode', function qrcodeHelper() {
61
+ console.log('扫码后回车继续');
62
+ process.stdin.once('data', () => {
63
+ this.login();
64
+ });
65
+ disposeArr.push(() => {
66
+ this.off('system.login.qrcode', qrcodeHelper);
67
+ });
68
+ });
69
+ this.client.on('system.login.device', function deviceHelper() {
70
+ console.log('请输入密保手机接收的验证码');
71
+ this.sendSmsCode();
72
+ process.stdin.once('data', (e) => {
73
+ this.submitSmsCode(e.toString().trim());
74
+ });
75
+ disposeArr.push(() => {
76
+ this.off('system.login.device', deviceHelper);
77
+ });
78
+ });
79
+ this.client.on('system.login.error', function errorHandler(e) {
80
+ if (e.message.includes('密码错误')) {
81
+ process.stdin.once('data', (e) => {
82
+ this.login(e.toString().trim());
83
+ });
84
+ }
85
+ else {
86
+ process.exit();
87
+ }
88
+ this.off('system.login.error', errorHandler);
89
+ });
90
+ this.client.on('system.login.slider', function sliderHelper(e) {
91
+ console.log('滑块验证地址:' + e.url);
92
+ console.log('请输入滑块验证返回的ticket');
93
+ process.stdin.once('data', (e) => {
94
+ this.submitSlider(e.toString().trim());
95
+ });
96
+ disposeArr.push(() => {
97
+ this.off('system.login.slider', sliderHelper);
98
+ });
99
+ });
100
+ this.client.on('system.online', clean);
54
101
  await this.client.login(this.password);
55
102
  }
56
103
  startListen() {
package/lib/server/app.js CHANGED
@@ -32,7 +32,6 @@ const koa_1 = __importDefault(require("koa"));
32
32
  const os = __importStar(require("os"));
33
33
  const fs_1 = require("fs");
34
34
  const log4js_1 = require("log4js");
35
- const path_1 = require("path");
36
35
  const http_1 = require("http");
37
36
  const js_yaml_1 = __importDefault(require("js-yaml"));
38
37
  const koa_bodyparser_1 = __importDefault(require("koa-bodyparser"));
@@ -43,6 +42,7 @@ const router_1 = require("./router");
43
42
  const fs_2 = require("fs");
44
43
  const V11_1 = require("../service/V11");
45
44
  const V12_1 = require("../service/V12");
45
+ const path = __importStar(require("path"));
46
46
  class App extends koa_1.default {
47
47
  constructor(config = {}) {
48
48
  super(config);
@@ -135,11 +135,11 @@ class App extends koa_1.default {
135
135
  });
136
136
  this.router.get('/qrcode', (ctx) => {
137
137
  const { uin } = ctx.query;
138
- const uinUrl = (0, path_1.join)(App.configDir, 'data', uin);
138
+ const uinUrl = path.join(App.configDir, 'data', uin);
139
139
  if (!(0, fs_1.existsSync)(uinUrl)) {
140
140
  return ctx.res.writeHead(400).end('未登录');
141
141
  }
142
- const qrcodePath = (0, path_1.join)(App.configDir, 'data', uin, 'qrcode.png');
142
+ const qrcodePath = path.join(App.configDir, 'data', uin, 'qrcode.png');
143
143
  let file = null;
144
144
  try {
145
145
  file = (0, fs_2.readFileSync)(qrcodePath); //读取文件
@@ -161,7 +161,7 @@ class App extends koa_1.default {
161
161
  };
162
162
  });
163
163
  this.router.post('/add', (ctx, next) => {
164
- const { uin, ...config } = ctx.request.body;
164
+ const { uin, ...config } = (ctx.request.body || {});
165
165
  try {
166
166
  this.addAccount(uin, config);
167
167
  ctx.body = `添加成功`;
@@ -171,7 +171,7 @@ class App extends koa_1.default {
171
171
  }
172
172
  });
173
173
  this.router.post('/edit', (ctx, next) => {
174
- const { uin, ...config } = ctx.request.body;
174
+ const { uin, ...config } = (ctx.request.body || {});
175
175
  try {
176
176
  this.updateAccount(Number(uin), config);
177
177
  ctx.body = `修改成功`;
@@ -196,16 +196,19 @@ class App extends koa_1.default {
196
196
  }
197
197
  exports.App = App;
198
198
  _a = App;
199
- App.configDir = (0, path_1.join)(os.homedir(), '.onebots');
200
- App.configPath = (0, path_1.join)(_a.configDir, 'config.yaml');
199
+ App.configDir = path.join(os.homedir(), '.onebots');
200
+ App.configPath = path.join(_a.configDir, 'config.yaml');
201
201
  function createApp(config = 'config.yaml') {
202
202
  if (typeof config === 'string') {
203
+ config = path.resolve(process.cwd(), config);
204
+ App.configDir = path.dirname(config);
205
+ App.configPath = config;
203
206
  if (!(0, fs_1.existsSync)(App.configDir)) {
204
207
  (0, fs_1.mkdirSync)(App.configDir);
205
208
  }
206
- App.configPath = (0, path_1.join)(App.configDir, config);
209
+ App.configPath = path.resolve(App.configDir, config);
207
210
  if (!(0, fs_1.existsSync)(App.configPath)) {
208
- (0, fs_1.copyFileSync)((0, path_1.resolve)(__dirname, '../config.sample.yaml'), App.configPath);
211
+ (0, fs_1.copyFileSync)(path.resolve(__dirname, '../config.sample.yaml'), App.configPath);
209
212
  console.log('未找到对应配置文件,已自动生成默认配置文件,请修改配置文件后重新启动');
210
213
  console.log(`配置文件在: ${App.configPath}`);
211
214
  process.exit();
@@ -229,7 +229,7 @@ class V11 extends events_1.EventEmitter {
229
229
  }
230
230
  else if (ctx.method === "POST") {
231
231
  try {
232
- const params = { ...ctx.query, ...ctx.request.body };
232
+ const params = { ...(ctx.request.query || {}), ...(ctx.request.body || {}) };
233
233
  const ret = await this.apply({ action, params });
234
234
  ctx.res.writeHead(200).end(ret);
235
235
  }
@@ -11,10 +11,14 @@ export declare class CommonAction {
11
11
  getSelfInfo(this: V12): {
12
12
  user_id: number;
13
13
  nickname: string;
14
+ user_displayname: string;
14
15
  };
15
16
  getStatus(this: V12): {
16
- online: OnlineStatus;
17
17
  good: boolean;
18
+ bots: {
19
+ self: any;
20
+ online: OnlineStatus;
21
+ }[];
18
22
  };
19
23
  getLatestEvents(this: V12, limit?: number, timout?: number): Promise<V12.Payload<keyof Action>[]>;
20
24
  getVersion(this: V12): {
@@ -16,13 +16,19 @@ class CommonAction {
16
16
  getSelfInfo() {
17
17
  return {
18
18
  user_id: this.client.uin,
19
- nickname: this.client.nickname
19
+ nickname: this.client.nickname,
20
+ user_displayname: ''
20
21
  };
21
22
  }
22
23
  getStatus() {
23
24
  return {
24
- online: this.client.status = oicq_1.OnlineStatus.Online,
25
- good: this.oneBot.status === onebot_1.OneBotStatus.Good
25
+ good: this.oneBot.status === onebot_1.OneBotStatus.Good,
26
+ bots: [
27
+ {
28
+ self: this.action.getSelfInfo.apply(this),
29
+ online: this.client.status = oicq_1.OnlineStatus.Online,
30
+ }
31
+ ]
26
32
  };
27
33
  }
28
34
  getLatestEvents(limit = 0, timout = 0) {
@@ -37,7 +43,7 @@ class CommonAction {
37
43
  return {
38
44
  impl: 'onebots',
39
45
  platform: 'qq',
40
- version: '0.0.5',
46
+ version: '0.0.15',
41
47
  onebot_version: '12'
42
48
  };
43
49
  }
@@ -29,7 +29,7 @@ export declare class V12 extends EventEmitter implements OneBot.Base {
29
29
  private startWs;
30
30
  private startWsReverse;
31
31
  stop(force?: boolean): Promise<void>;
32
- dispatch<T extends Record<string, any>>(data?: T): void;
32
+ dispatch(data: Record<string, any>): void;
33
33
  apply(req: any): Promise<string>;
34
34
  private _httpRequestHandler;
35
35
  /**
@@ -68,7 +68,7 @@ export declare namespace V12 {
68
68
  url: string;
69
69
  }
70
70
  interface Result<T extends any> {
71
- status: 'success' | 'failed';
71
+ status: 'ok' | 'failed';
72
72
  retcode: 0 | 10001 | 10002 | 10003 | 10004 | 10005 | 10006 | 10007;
73
73
  data: T;
74
74
  message: string;
@@ -78,8 +78,12 @@ export declare namespace V12 {
78
78
  type Payload<T extends any> = {
79
79
  id: string;
80
80
  impl: 'oicq_onebot';
81
+ version: 12;
81
82
  platform: 'qq';
82
- self_id: `${number}`;
83
+ self: {
84
+ platform: 'qq';
85
+ user_id: `${number}`;
86
+ };
83
87
  time: number;
84
88
  type: 'meta' | 'message' | 'notice' | 'request';
85
89
  detail_type: string;
@@ -90,13 +94,28 @@ export declare namespace V12 {
90
94
  params: any;
91
95
  echo?: string;
92
96
  }
97
+ type MetaEventMap = {
98
+ connect: {
99
+ detail_type: 'connect';
100
+ version: ReturnType<Action['getVersion']>;
101
+ };
102
+ heartbeat: {
103
+ detail_type: 'heartbeat';
104
+ interval: number;
105
+ };
106
+ status_update: {
107
+ detail_type: 'status_update';
108
+ status: ReturnType<Action['getStatus']>;
109
+ };
110
+ };
93
111
  function success<T extends any>(data: T, retcode?: Result<T>['retcode'], echo?: string): Result<T>;
94
112
  function error(message: string, retcode?: Result<null>['retcode'], echo?: string): Result<null>;
95
- function genMetaEvent(uin: number, type: string): {
113
+ function genMetaEvent<K extends keyof MetaEventMap>(uin: number, type: K, data: Omit<MetaEventMap[K], K>): {
96
114
  self_id: number;
97
115
  time: number;
98
116
  type: string;
99
- detail_type: string;
117
+ status: string;
118
+ detail_type: K;
100
119
  sub_type: string;
101
- };
120
+ } & Omit<MetaEventMap[K], K>;
102
121
  }
@@ -88,14 +88,10 @@ class V12 extends events_1.EventEmitter {
88
88
  });
89
89
  if (this.config.heartbeat) {
90
90
  this.heartbeat = setInterval(() => {
91
- this.dispatch({
92
- self_id: this.client.uin,
93
- time: Math.floor(Date.now() / 1000),
94
- type: "meta",
91
+ this.dispatch(V12.genMetaEvent(this.client.uin, 'heartbeat', {
95
92
  detail_type: "heartbeat",
96
- interval: this.config.heartbeat * 1000,
97
- status: this.action.getStatus.apply(this)
98
- });
93
+ interval: new Date().getTime() + this.config.heartbeat * 1000
94
+ }));
99
95
  }, this.config.heartbeat * 1000);
100
96
  }
101
97
  }
@@ -207,41 +203,38 @@ class V12 extends events_1.EventEmitter {
207
203
  (0, fs_1.rmSync)(this.client.dir, { force: true, recursive: true });
208
204
  }
209
205
  }
210
- dispatch(data = {}) {
211
- if (!data)
212
- data = {};
213
- if (!data.post_type) {
214
- // @ts-ignore
215
- data.sub_type = 'online';
216
- if (data.image) {
217
- // @ts-ignore
218
- data.system_type = 'login';
219
- // @ts-ignore
220
- data.sub_type = 'qrcode';
206
+ dispatch(data) {
207
+ if (!data || typeof data !== "object")
208
+ data = { args: data || [] };
209
+ if (!data['post_type']) {
210
+ data['sub_type'] = 'online';
211
+ if (data['image']) {
212
+ data['system_type'] = 'login';
213
+ data['sub_type'] = 'qrcode';
221
214
  }
222
- else if (data.url) {
223
- // @ts-ignore
224
- data.system_type = 'login';
225
- // @ts-ignore
215
+ else if (data['url']) {
216
+ data['system_type'] = 'login';
226
217
  data.sub_type = 'slider';
227
218
  if (data.phone) {
228
- // @ts-ignore
229
219
  data.sub_type = 'device';
230
220
  }
231
221
  }
232
222
  else if (data.message) {
233
- // @ts-ignore
234
223
  data.system_type = 'login';
235
- // @ts-ignore
236
224
  data.sub_type = 'error';
237
225
  }
238
226
  }
239
227
  const payload = {
240
228
  id: (0, utils_1.uuid)(),
241
229
  impl: 'oicq_onebot',
230
+ version: 12,
242
231
  platform: 'qq',
243
- self_id: `${this.client.uin}`,
232
+ self: {
233
+ platform: 'qq',
234
+ user_id: `${this.client.uin}`
235
+ },
244
236
  type: data.post_type || 'meta',
237
+ alt_message: data.raw_message,
245
238
  detail_type: data.message_type || data.notice_type || data.request_type || data.system_type,
246
239
  ...data,
247
240
  };
@@ -368,7 +361,7 @@ class V12 extends events_1.EventEmitter {
368
361
  }
369
362
  else if (ctx.method === "POST") {
370
363
  try {
371
- const params = { ...ctx.query, ...ctx.request.body };
364
+ const params = { ...(ctx.request.query || {}), ...(ctx.request.body || {}) };
372
365
  const ret = await this.apply({ action, params });
373
366
  ctx.res.writeHead(200).end(ret);
374
367
  }
@@ -414,7 +407,8 @@ class V12 extends events_1.EventEmitter {
414
407
  const headers = {
415
408
  "X-Self-ID": String(this.client.uin),
416
409
  "X-Client-Role": "Universal",
417
- "User-Agent": "OneBot",
410
+ "User-Agent": "OneBot/12 (qq) node-Onebots/0.0.15",
411
+ "Sec-WebSocket-Protocol": "12.onebots.v0.0.15"
418
412
  };
419
413
  if (config.access_token)
420
414
  headers.Authorization = "Bearer " + config.access_token;
@@ -435,7 +429,7 @@ class V12 extends events_1.EventEmitter {
435
429
  setTimeout(() => {
436
430
  if (timestmap < this.timestamp)
437
431
  return;
438
- this._createWsr(url, config);
432
+ this.startWsReverse(config);
439
433
  }, this.config.reconnect_interval * 1000);
440
434
  });
441
435
  return ws;
@@ -455,7 +449,7 @@ class V12 extends events_1.EventEmitter {
455
449
  this._quickOperate(event, res);
456
450
  ret = JSON.stringify({
457
451
  retcode: 0,
458
- status: "success",
452
+ status: "ok",
459
453
  data: null,
460
454
  message: null,
461
455
  echo: data.echo
@@ -487,8 +481,8 @@ class V12 extends events_1.EventEmitter {
487
481
  }));
488
482
  }
489
483
  });
490
- this.dispatch(V12.genMetaEvent(this.client.uin, "connect"));
491
- this.dispatch(V12.genMetaEvent(this.client.uin, "enable"));
484
+ this.dispatch(V12.genMetaEvent(this.client.uin, "connect", this.action.getVersion.apply(this)));
485
+ this.dispatch(V12.genMetaEvent(this.client.uin, "status_update", this.action.getStatus.apply(this)));
492
486
  }
493
487
  }
494
488
  exports.V12 = V12;
@@ -507,7 +501,7 @@ exports.V12 = V12;
507
501
  function success(data, retcode = 0, echo) {
508
502
  return {
509
503
  retcode,
510
- status: retcode === 0 ? 'success' : 'failed',
504
+ status: retcode === 0 ? 'ok' : 'failed',
511
505
  data,
512
506
  message: '',
513
507
  echo
@@ -524,13 +518,15 @@ exports.V12 = V12;
524
518
  };
525
519
  }
526
520
  V12.error = error;
527
- function genMetaEvent(uin, type) {
521
+ function genMetaEvent(uin, type, data) {
528
522
  return {
529
523
  self_id: uin,
530
524
  time: Math.floor(Date.now() / 1000),
531
525
  type: "meta",
532
- detail_type: "lifecycle",
533
- sub_type: type,
526
+ status: 'ok',
527
+ detail_type: type,
528
+ sub_type: '',
529
+ ...data
534
530
  };
535
531
  }
536
532
  V12.genMetaEvent = genMetaEvent;
package/lib/utils.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export declare function deepMerge<T extends any>(base: T, ...from: T[]): T;
2
2
  export declare function deepClone<T extends any>(obj: T): T;
3
- export declare function pick<T, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean): Pick<T, K>;
3
+ export declare function pick<T extends object, K extends keyof T>(source: T, keys?: Iterable<K>, forced?: boolean): Pick<T, K>;
4
4
  export declare function omit<T, K extends keyof T>(source: T, keys?: Iterable<K>): Omit<T, K>;
5
5
  export interface Class {
6
6
  new (...args: any[]): any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "onebots",
3
- "version": "0.0.14",
3
+ "version": "0.0.16",
4
4
  "description": "基于oicq的多例oneBot实现",
5
5
  "main": "lib/index.js",
6
6
  "bin": {
@@ -9,7 +9,7 @@
9
9
  "scripts": {
10
10
  "start": "node .",
11
11
  "build": "tsc --project tsconfig.json && tsc-alias -p tsconfig.json",
12
- "dev": "ts-node-dev -r tsconfig-paths/register ./src/test.ts",
12
+ "dev": "ts-node-dev -r tsconfig-paths/register ./src/bin.ts -c config.yaml",
13
13
  "pub": "npm publish --access public",
14
14
  "test": "echo \"Error: no test specified\" && exit 1"
15
15
  },