node-automator 1.0.0

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.
Files changed (143) hide show
  1. package/LICENSE +15 -0
  2. package/assets/alert.png +0 -0
  3. package/assets/error.png +0 -0
  4. package/assets/success.png +0 -0
  5. package/commands/abort.js +11 -0
  6. package/commands/alert.js +19 -0
  7. package/commands/assemble.js +56 -0
  8. package/commands/assert.js +18 -0
  9. package/commands/base.js +363 -0
  10. package/commands/break.js +11 -0
  11. package/commands/change_filter.js +34 -0
  12. package/commands/cheerio.js +15 -0
  13. package/commands/clear_screen.js +14 -0
  14. package/commands/commit.js +31 -0
  15. package/commands/compare.js +23 -0
  16. package/commands/confirm.js +16 -0
  17. package/commands/continue.js +11 -0
  18. package/commands/copy.js +14 -0
  19. package/commands/cursor_up.js +12 -0
  20. package/commands/date.js +25 -0
  21. package/commands/debugger.js +11 -0
  22. package/commands/dingtalk.js +110 -0
  23. package/commands/disassemble.js +36 -0
  24. package/commands/divination.js +15 -0
  25. package/commands/download.js +12 -0
  26. package/commands/edit.js +83 -0
  27. package/commands/edit_excel.js +57 -0
  28. package/commands/env_optional.js +57 -0
  29. package/commands/eval.js +27 -0
  30. package/commands/exec_from_file.js +31 -0
  31. package/commands/export_diff_head.js +31 -0
  32. package/commands/file_info.js +41 -0
  33. package/commands/file_size.js +12 -0
  34. package/commands/files.js +14 -0
  35. package/commands/first_exist.js +18 -0
  36. package/commands/flatten.js +18 -0
  37. package/commands/ftp.js +161 -0
  38. package/commands/git_commit.js +31 -0
  39. package/commands/git_export_diff_head.js +13 -0
  40. package/commands/git_is_dirty.js +13 -0
  41. package/commands/hash.js +21 -0
  42. package/commands/http_request.js +12 -0
  43. package/commands/image_crop.js +19 -0
  44. package/commands/input.js +37 -0
  45. package/commands/interval.js +60 -0
  46. package/commands/is_dirty.js +31 -0
  47. package/commands/jwt_decode.js +22 -0
  48. package/commands/list2dict.js +32 -0
  49. package/commands/log.js +72 -0
  50. package/commands/loop.js +115 -0
  51. package/commands/loop_forever.js +66 -0
  52. package/commands/merge_files.js +39 -0
  53. package/commands/mgr.js +476 -0
  54. package/commands/modify.js +44 -0
  55. package/commands/move.js +14 -0
  56. package/commands/move_local.js +14 -0
  57. package/commands/multi_select.js +16 -0
  58. package/commands/mysql_connect.js +29 -0
  59. package/commands/mysql_end.js +13 -0
  60. package/commands/mysql_query.js +19 -0
  61. package/commands/notify.js +13 -0
  62. package/commands/open.js +30 -0
  63. package/commands/parse.js +18 -0
  64. package/commands/pause.js +15 -0
  65. package/commands/print.js +47 -0
  66. package/commands/read_cache.js +12 -0
  67. package/commands/read_cfg.js +13 -0
  68. package/commands/read_clipboard.js +19 -0
  69. package/commands/read_excel.js +17 -0
  70. package/commands/read_only_excel.js +40 -0
  71. package/commands/read_plain.js +14 -0
  72. package/commands/remove.js +14 -0
  73. package/commands/retrieve.js +17 -0
  74. package/commands/reveal.js +33 -0
  75. package/commands/revision_info.js +31 -0
  76. package/commands/schedule.js +80 -0
  77. package/commands/select.js +17 -0
  78. package/commands/send_email.js +25 -0
  79. package/commands/share_data.js +745 -0
  80. package/commands/shell.js +13 -0
  81. package/commands/sleep.js +17 -0
  82. package/commands/store.js +13 -0
  83. package/commands/store_optional.js +33 -0
  84. package/commands/stream.js +16 -0
  85. package/commands/stringify.js +24 -0
  86. package/commands/svn_add.js +26 -0
  87. package/commands/svn_commit.js +49 -0
  88. package/commands/svn_export_diff_head.js +13 -0
  89. package/commands/svn_is_dirty.js +13 -0
  90. package/commands/svn_update.js +27 -0
  91. package/commands/switch.js +18 -0
  92. package/commands/temp.js +12 -0
  93. package/commands/tencent_cos.js +323 -0
  94. package/commands/test.js +14 -0
  95. package/commands/title.js +18 -0
  96. package/commands/tmpdir.js +21 -0
  97. package/commands/translate.js +58 -0
  98. package/commands/traversal.js +38 -0
  99. package/commands/truncate.js +31 -0
  100. package/commands/truncate_all.js +62 -0
  101. package/commands/ts_sort.js +18 -0
  102. package/commands/unzip.js +50 -0
  103. package/commands/updating_revision.js +28 -0
  104. package/commands/valid_required.js +31 -0
  105. package/commands/void.js +10 -0
  106. package/commands/watch_mail.js +94 -0
  107. package/commands/web_socket.js +233 -0
  108. package/commands/which.js +60 -0
  109. package/commands/write_cache.js +16 -0
  110. package/commands/write_cfg.js +18 -0
  111. package/commands/write_clipboard.js +23 -0
  112. package/commands/write_excel.js +17 -0
  113. package/commands/write_plain.js +18 -0
  114. package/commands/zip.js +78 -0
  115. package/commands/zip_data.js +64 -0
  116. package/examples/print_env.yml +3 -0
  117. package/index.js +109 -0
  118. package/package.json +63 -0
  119. package/scratch/.gitkeep +0 -0
  120. package/utils/alert_tool.js +133 -0
  121. package/utils/base64_tool.js +13 -0
  122. package/utils/cache/local_cache.js +79 -0
  123. package/utils/cache/raw_cache.js +47 -0
  124. package/utils/cache/simple_local_cache.js +33 -0
  125. package/utils/cache/simple_sqlite_cache.js +43 -0
  126. package/utils/cache/simple_svn_cache.js +49 -0
  127. package/utils/cache/svn_cache.js +40 -0
  128. package/utils/cache_tool.js +53 -0
  129. package/utils/display_tool.js +85 -0
  130. package/utils/divination_util.js +555 -0
  131. package/utils/file_tool.js +529 -0
  132. package/utils/hash_tool.js +8 -0
  133. package/utils/interaction_tool.js +228 -0
  134. package/utils/log_tool.js +190 -0
  135. package/utils/parse_directive.js +194 -0
  136. package/utils/parse_tool.js +236 -0
  137. package/utils/request_tool.js +156 -0
  138. package/utils/scm_tool.js +108 -0
  139. package/utils/selection_tool.js +593 -0
  140. package/utils/shell_tool.js +162 -0
  141. package/utils/svn_diff/diff_file.js +44 -0
  142. package/utils/svn_diff/diff_parser.js +55 -0
  143. package/utils/transform_tool.js +520 -0
@@ -0,0 +1,58 @@
1
+ const { doRequest } = require("../utils/request_tool");
2
+ const { BaseCommand } = require("./base");
3
+ const crypto = require("crypto");
4
+ const { getCache, setCache } = require("../utils/cache_tool");
5
+
6
+ class TranslateCommand extends BaseCommand {
7
+ async execute() {
8
+ let data = this.selfData;
9
+ let q = this.content;
10
+ let from = data.from || "auto";
11
+ let to = data.to || "zh";
12
+ let appid = "20181030000227685";
13
+ let secret = "Clf6hhkAfZuXsNewanRf";
14
+ let salt = "tsubasa";
15
+ let sign = crypto.createHash("md5").update(`${appid}${q}${salt}${secret}`).digest("hex");
16
+ let cache = await getCache("translate") || {};
17
+ let ret = cache[from]?.[to]?.[q];
18
+ if (ret) {
19
+ return ret;
20
+ }
21
+ let translatedRaw = await doRequest({
22
+ src: "https://fanyi-api.baidu.com/api/trans/vip/translate",
23
+ quiet: true,
24
+ options: {
25
+ method: "POST",
26
+ formData: {
27
+ q,
28
+ from,
29
+ to,
30
+ appid,
31
+ salt,
32
+ sign,
33
+ }
34
+ }
35
+ });
36
+ try {
37
+ let translatedData = JSON.parse(translatedRaw);
38
+ let ret = translatedData?.trans_result?.[0]?.dst;
39
+ if (ret) {
40
+ cache[from] || (cache[from] = {});
41
+ cache[from][to] || (cache[from][to] = {});
42
+ cache[from][to][q] = ret;
43
+ setCache("translate", cache);
44
+ }
45
+ return ret || "";
46
+ } catch (error) {
47
+ return "";
48
+ }
49
+ }
50
+
51
+ getRequireContent() {
52
+ return true;
53
+ }
54
+ }
55
+
56
+ module.exports = {
57
+ TranslateCommand,
58
+ };
@@ -0,0 +1,38 @@
1
+ const { eval_code } = require("./share_data");
2
+ const { BaseCommand } = require("./base");
3
+
4
+ class TraversalCommand extends BaseCommand {
5
+ async execute() {
6
+ let data = this.selfData;
7
+ return traversal(this.content, eval_code(data.handler), eval_code(data.sizeOf), eval_code(data.childAt), data.output, eval_code(data.filter));
8
+ }
9
+
10
+ getRequireContent() {
11
+ return true;
12
+ }
13
+
14
+ getRequiredParams() {
15
+ return [
16
+ "sizeOf",
17
+ "childAt",
18
+ "handler",
19
+ ];
20
+ }
21
+ }
22
+
23
+ module.exports = {
24
+ TraversalCommand,
25
+ };
26
+
27
+
28
+
29
+ function traversal(root, handler, sizeOf, childAt, output, filter) {
30
+ if (!filter || filter(root)) {
31
+ handler(root, output);
32
+ }
33
+ for (let i = 0, size = sizeOf(root) || 0; i < size; ++i) {
34
+ let child = childAt(root, i);
35
+ traversal(child, handler, sizeOf, childAt, output, filter);
36
+ }
37
+ return output;
38
+ }
@@ -0,0 +1,31 @@
1
+ const { BaseCommand } = require("./base");
2
+
3
+ class TruncateCommand extends BaseCommand {
4
+ async execute() {
5
+ let data = this.selfData;
6
+ let content = this.content;
7
+ let flags = data.flags || "";
8
+ if (flags.indexOf("g") == -1) {
9
+ flags += "g";
10
+ }
11
+ let struct = data.struct;
12
+ let reg = new RegExp(data.pattern, flags);
13
+ let match = reg.exec(content);
14
+ match = match && match[1];
15
+ return match;
16
+ }
17
+
18
+ getRequireContent() {
19
+ return true;
20
+ }
21
+
22
+ getRequiredParams() {
23
+ return [
24
+ "pattern"
25
+ ];
26
+ }
27
+ }
28
+
29
+ module.exports = {
30
+ TruncateCommand,
31
+ };
@@ -0,0 +1,62 @@
1
+ const { convert } = require("../utils/transform_tool");
2
+ const { BaseCommand } = require("./base");
3
+
4
+ class TruncateAllCommand extends BaseCommand {
5
+ async execute() {
6
+ let data = this.selfData;
7
+ let content = this.content;
8
+ let flags = data.flags || "";
9
+ if (flags.indexOf("g") == -1) {
10
+ flags += "g";
11
+ }
12
+ let struct = data.struct;
13
+ let reg = new RegExp(data.pattern, flags);
14
+ let matches = [];
15
+ let match;
16
+ let full_match = data.full_match;
17
+ while(match = reg.exec(content)) {
18
+ let obj;
19
+ if (struct instanceof Array) {
20
+ obj = {};
21
+ // 匹配的完整字符串由 $ 表示
22
+ if (struct[0] != "$") {
23
+ struct.unshift("$");
24
+ }
25
+ match.forEach((v, i) => {
26
+ if (!full_match && i == 0) {
27
+ return;
28
+ }
29
+ let prop = struct[i];
30
+ let name;
31
+ let value = data.trim ? v.trim() : v;
32
+ if (typeof prop === "object") {
33
+ name = prop.name;
34
+ value = convert(value, prop.type);
35
+ } else {
36
+ name = prop;
37
+ }
38
+
39
+ obj[name] = value;
40
+ });
41
+ } else {
42
+ obj = full_match ? match : match.slice(1);
43
+ }
44
+ matches.push(obj);
45
+ }
46
+ return matches;
47
+ }
48
+
49
+ getRequireContent() {
50
+ return true;
51
+ }
52
+
53
+ getRequiredParams() {
54
+ return [
55
+ "pattern"
56
+ ];
57
+ }
58
+ }
59
+
60
+ module.exports = {
61
+ TruncateAllCommand,
62
+ };
@@ -0,0 +1,18 @@
1
+ const { get_file_list } = require("../utils/file_tool");
2
+ const { BaseCommand } = require("./base");
3
+
4
+ class TsSortCommand extends BaseCommand {
5
+ async execute() {
6
+ const ts_plus = require("typescript-plus");
7
+ let files = get_file_list(this.selfData.src);
8
+ let program = ts_plus.createProgram(files, {
9
+ reorderFiles: true,
10
+ });
11
+ let ret = ts_plus.reorderSourceFiles(program);
12
+ return ret.sortedFileNames;
13
+ }
14
+ }
15
+
16
+ module.exports = {
17
+ TsSortCommand,
18
+ };
@@ -0,0 +1,50 @@
1
+ const { read_plain, get_fst_file, get_full_path, format_bytes } = require("../utils/file_tool");
2
+ const { BaseCommand } = require("./base");
3
+ const fs = require("fs");
4
+ const il = require('iconv-lite');
5
+ const path = require("path");
6
+ const display_tool = require("../utils/display_tool");
7
+
8
+ class UnzipCommand extends BaseCommand {
9
+ async execute() {
10
+ let src = get_fst_file(this.selfData.src);
11
+ let dst = get_full_path(this.selfData.dst, "FOLDER");
12
+ let encoding = this.selfData?.options?.encoding;
13
+ let totalSize = fs.statSync(src).size;
14
+ let unzippedSize = 0;
15
+ let uncompressedSize = 0;
16
+ // await require('extract-zip')(src, { dir: dst });
17
+ const AdmZip = require("adm-zip");
18
+ // reading archives
19
+ var zip = new AdmZip(src);
20
+ var zipEntries = zip.getEntries(); // an array of ZipEntry records
21
+
22
+ zipEntries.forEach(function (entry, index, entries) {
23
+ console.log(entry.toString()); // outputs zip entries information
24
+ const fileName = il.decode(entry.rawEntryName, encoding || "cp936"); // cp866
25
+ const compressedData = entry.getCompressedData();
26
+ const uncompressedData = entry.getData();
27
+ display_tool.progress(index, entries.length, {
28
+ desc: `Unzipping ${fileName} ${format_bytes(compressedData.length)} >>> ${format_bytes(uncompressedData.length)}`,
29
+ depth: 0,
30
+ color: "cyan",
31
+ align: true,
32
+ });
33
+ if (entry.isDirectory) {
34
+ fs.mkdirSync(path.join(dst, fileName));
35
+ } else {
36
+ fs.writeFileSync(path.join(dst, fileName), entry.getData());
37
+ }
38
+ display_tool.progress(index + 1, entries.length, {
39
+ desc: `Unzipping ${fileName} ${format_bytes(compressedData.length)} >>> ${format_bytes(uncompressedData.length)}`,
40
+ depth: 0,
41
+ color: "cyan",
42
+ align: true,
43
+ });
44
+ });
45
+ }
46
+ }
47
+
48
+ module.exports = {
49
+ UnzipCommand,
50
+ };
@@ -0,0 +1,28 @@
1
+ const { parse } = require("../utils/file_tool");
2
+ const { exec_shell } = require("../utils/shell_tool");
3
+ const { BaseCommand } = require("./base");
4
+
5
+ class UpdatingRevisionCommand extends BaseCommand {
6
+ async execute() {
7
+ let currentInfo = await parse(await exec_shell({
8
+ cmd: "svn info",
9
+ cwd: this.selfData.cwd,
10
+ capture_stdout: true,
11
+ }), 'yaml');
12
+ let comingUpdates = await exec_shell({
13
+ cmd: `svn mergeinfo --show-revs eligible ${currentInfo.URL}`,
14
+ cwd: this.selfData.cwd,
15
+ capture_stdout: true,
16
+ });
17
+ comingUpdates = comingUpdates
18
+ .split(/[\r\n]{1,2}/)
19
+ .map(v => v.substr(1))
20
+ .filter(v => v && v != currentInfo.Revision)
21
+ ;
22
+ return comingUpdates;
23
+ }
24
+ }
25
+
26
+ module.exports = {
27
+ UpdatingRevisionCommand,
28
+ };
@@ -0,0 +1,31 @@
1
+ const { vital, success, error, info, getPrint, warn, log } = require("../utils/log_tool");
2
+ const { toArray } = require("../utils/transform_tool");
3
+ const { BaseCommand } = require("./base");
4
+
5
+ class ValidRequiredCommand extends BaseCommand {
6
+ async execute() {
7
+ let data = this.selfData;
8
+ const keys = toArray(data.key);
9
+ let failed = false;
10
+ log("");
11
+ for (let index = 0; index < keys.length; index++) {
12
+ const key = keys[index];
13
+ let ret = this.getDataByKey(key);
14
+ if (ret == null) {
15
+ failed = true;
16
+ warn(`${key} => ${getPrint(ret)}`);
17
+ } else {
18
+ info(`${key} => ${getPrint(ret)}`);
19
+ }
20
+ }
21
+ if (failed) {
22
+ throw (`参数校验失败,请检查环境变量或者启动参数`);
23
+ } else {
24
+ success(`参数校验成功`);
25
+ }
26
+ }
27
+ }
28
+
29
+ module.exports = {
30
+ ValidRequiredCommand,
31
+ };
@@ -0,0 +1,10 @@
1
+ const { BaseCommand } = require("./base");
2
+
3
+ class VoidCommand extends BaseCommand {
4
+ async execute() {
5
+ }
6
+ }
7
+
8
+ module.exports = {
9
+ VoidCommand,
10
+ };
@@ -0,0 +1,94 @@
1
+ const { setLastError, success, warn, getPrint } = require("../utils/log_tool");
2
+ const {
3
+ BaseCommand
4
+ } = require("./base");
5
+ const {
6
+ formatData
7
+ } = require("./share_data");
8
+
9
+ class WatchMailCommand extends BaseCommand {
10
+ async execute() {
11
+ const data = this.selfData;
12
+ await new Promise((resolve, reject) => {
13
+ const MailWatcher = require('mail-watcher');
14
+ // IMAP: 默认端口:143 (ssl安全链接端口:993)
15
+ // SMTP: 默认端口:25 (ssl安全链接端口:994)
16
+ // POP3: 默认端口:110 (ssl安全链接端口:995)
17
+ const imap = {
18
+ user: data.user,
19
+ password: data.password,
20
+ host: data.host,
21
+ port: data.port || (data.tls ? 993 : 143), // imap port
22
+ tls: data.tls, // use secure connection
23
+ // search: ['ALL'],
24
+ // search: ['UNSEEN'],
25
+ search: data.search || ["UNSEEN"],
26
+ tlsOptions: {
27
+ rejectUnauthorized: false
28
+ }
29
+ };
30
+ const mailWatcher = MailWatcher(imap);
31
+ const cache_mail_ids = [];
32
+ // const fs = require("fs");
33
+ mailWatcher.on('end', () => {
34
+ warn(`restart ...`);
35
+ mailWatcher.start();
36
+ })
37
+ .on('connected', () => {
38
+ resolve();
39
+ })
40
+ .on('error', (err) => {
41
+ setLastError(err);
42
+ resolve();
43
+ })
44
+ .on('mail',
45
+ /**
46
+ *
47
+ * @param {import('../lib').ParsedMail} mail
48
+ */
49
+ async (mail) => {
50
+ const subject = mail.subject;
51
+ const text = mail.text || require('html-to-text').convert(mail.html);
52
+ const id = mail.messageId;
53
+ // 值映射
54
+ let value_mapping = data.value_mapping;
55
+ let index = cache_mail_ids.indexOf(id);
56
+ if (index == -1) {
57
+ index = cache_mail_ids.length;
58
+ cache_mail_ids.push(id);
59
+ }
60
+ let mailData = {
61
+ index: index,
62
+ id,
63
+ subject,
64
+ text,
65
+ };
66
+ if (value_mapping) {
67
+ if (typeof value_mapping === "string") {
68
+ this.shareData[value_mapping] = mailData;
69
+ }
70
+ } else {
71
+ this.shareData['mail_data'] = mailData;
72
+ }
73
+ if (!data.quiet) {
74
+ success("");
75
+ success(getPrint(mailData));
76
+ }
77
+ let commandCfgs = data.commands;
78
+ if (commandCfgs) {
79
+ // 特殊处理字符的情况
80
+ if (typeof commandCfgs === "string") {
81
+ commandCfgs = formatData(commandCfgs);
82
+ }
83
+ // 默认从循环开始执行,增加深度
84
+ await this.exec(commandCfgs, this.depth + 1);
85
+ }
86
+ })
87
+ .start();
88
+ });
89
+ }
90
+ }
91
+
92
+ module.exports = {
93
+ WatchMailCommand,
94
+ };
@@ -0,0 +1,233 @@
1
+ const {
2
+ warn,
3
+ info,
4
+ success,
5
+ whisper,
6
+ getPrint,
7
+ setLastError,
8
+ getLastError
9
+ } = require("../utils/log_tool");
10
+ const {
11
+ format, formatTimeInMillisec
12
+ } = require("../utils/transform_tool");
13
+ const {
14
+ BaseCommand
15
+ } = require("./base");
16
+
17
+ const CODE2DESC = {
18
+ 0: "🟢 已连接",
19
+ ETIMEDOUT: "⏰ 已超时",
20
+ ECONNREFUSED: "⛔️ 被拒绝",
21
+ ENOTFOUND: "🛑 未找到",
22
+ };
23
+
24
+ class WebSocketCommand extends BaseCommand {
25
+ async execute() {
26
+ const WebSocketClient = require('websocket').client;
27
+ let url = this.selfData.url;
28
+ let name = this.selfData.name || "";
29
+ let name_postfix = name ? `(${name})` : '';
30
+ let protocols = this.selfData.protocols; // || 'echo-protocol';
31
+ // 字节顺序为 bigEndian(最高有效字节位于最前)或 littleEndian(最低有效字节位于最前)
32
+ let little_endian = this.selfData.little_endian;
33
+ /** @type {{type: string, name: string, bits: number}[]} */
34
+ let headers = this.selfData.headers;
35
+ /** @type {string[]} */
36
+ let body_retrieval = this.selfData.body_retrieval;
37
+ /** 生命周期,如果有设置,会在达到生命周期时,自动断开连接 */
38
+ let lifetime = this.selfData.lifetime;
39
+ let bodies = this.selfData.bodies;
40
+ let receivedBytesTotal = 0;
41
+ let receivedUTF8Total = 0;
42
+ let receivedIndex = 0;
43
+ let timeout = this.selfData.timeout || 0;
44
+ let quiet = this.selfData.quiet || false;
45
+ let endianSuffix = little_endian ? "LE" : "BE";
46
+
47
+ let rl;
48
+ let ok = true;
49
+ let msg = "";
50
+ await new Promise((resolve, reject) => {
51
+ let startTime = Date.now();
52
+ function resolveCode(code) {
53
+ let elapsedTime = Date.now() - startTime;
54
+ if (code) {
55
+ msg = `${CODE2DESC[code] || code} ${url} ${name_postfix} ${elapsedTime / 1000}s`;
56
+ setLastError(msg);
57
+ } else {
58
+ msg = `${CODE2DESC[code]} ${url} ${name_postfix} ${elapsedTime / 1000}s`;
59
+ success(msg);
60
+ }
61
+ }
62
+ var client = new WebSocketClient();
63
+ let timer = timeout ? setTimeout(() => {
64
+ client.removeAllListeners('connect');
65
+ client.removeAllListeners('connectFailed');
66
+ client.abort();
67
+ resolveCode('ETIMEDOUT');
68
+ reject();
69
+ }, timeout) : 0;
70
+
71
+ client.on('connectFailed', (err) => {
72
+ if (timer) clearTimeout(timer);
73
+ resolveCode(err.code);
74
+ reject();
75
+ });
76
+ client.on('connect', (connection) => {
77
+ if (timer) clearTimeout(timer);
78
+ resolveCode(0);
79
+ if (lifetime) {
80
+ setTimeout(() => {
81
+ !quiet && warn(`End of life cycle (${lifetime} ms)`);
82
+ connection.close(1000);
83
+ }, lifetime);
84
+ }
85
+ connection.on('error', (err) => {
86
+ msg = err;
87
+ setLastError(err);
88
+ reject();
89
+ });
90
+ connection.on('close', () => {
91
+ !quiet && warn('echo-protocol Connection Closed');
92
+ resolve();
93
+ });
94
+ connection.on('message', (message) => {
95
+ if (message.type === 'utf8') {
96
+ receivedUTF8Total += message.utf8Data.length;
97
+ !quiet && whisper(`[${receivedIndex++}] size=${message.utf8Data.length} total=${receivedUTF8Total}`, " ", true);
98
+ !quiet && info(message.utf8Data);
99
+ } else {
100
+ receivedBytesTotal += message.binaryData.length;
101
+ !quiet && whisper(`[${receivedIndex++}] size=${message.binaryData.length}B total=${+(receivedBytesTotal / 1024).toFixed(2)}kB`, " ", true);
102
+ // info("[hex]" + message.binaryData.toString("hex"));
103
+ let unpacked = {};
104
+ let offset = 0;
105
+ offset = this.readStruct(unpacked, headers, message.binaryData, little_endian, offset);
106
+ let body = bodies;
107
+ if (body_retrieval) {
108
+ for (const v of body_retrieval) {
109
+ if (!body) {
110
+ break;
111
+ }
112
+ body = body[unpacked[v]];
113
+ }
114
+ }
115
+ if (body) {
116
+ body.title && info(body.title);
117
+ offset = this.readStruct(unpacked, body.struct, message.binaryData, little_endian, offset);
118
+ }
119
+ !quiet && info(getPrint(unpacked, true));
120
+ }
121
+ });
122
+ /** @type {any[]} */
123
+ let sends = this.selfData.sends;
124
+ sends && sends.forEach(v => {
125
+ this.send(connection, v);
126
+ });
127
+
128
+ this.readInput(v => {
129
+ this.send(connection, v);
130
+ }, (v) => {
131
+ rl = v;
132
+ });
133
+ });
134
+ !quiet && warn(`Connecting websocket url=${url} protocols=${protocols}`);
135
+ let options = Object.assign({
136
+ rejectUnauthorized: false,
137
+ }, this.selfData.options);
138
+ client.connect(url, protocols, undefined, undefined, Object.assign(options));
139
+ })
140
+ .catch(reason => {
141
+ ok = false;
142
+ });
143
+ if (rl) {
144
+ rl.close();
145
+ }
146
+ return [msg, ok];
147
+ }
148
+
149
+ /**
150
+ *
151
+ * @param {connection} connection
152
+ * @param {string} v
153
+ */
154
+ send(connection, v) {
155
+ let encodingIdx = v.indexOf(":");
156
+ let encoding = v.substring(0, encodingIdx) || "utf8";
157
+ let content = v.substring(encodingIdx + 1);
158
+ info(`[send] ${content} encoding=${encoding}`);
159
+ connection.sendBytes(Buffer.from(content, encoding));
160
+ }
161
+
162
+ /**
163
+ *
164
+ * @param {(v: string)=>any} resolve
165
+ */
166
+ readInput(resolve, retrieve) {
167
+ const readline = require("readline");
168
+ const rl = readline.createInterface({
169
+ input: process.stdin,
170
+ output: null,
171
+ });
172
+ rl.question("", (input) => {
173
+ resolve(input);
174
+ rl.close();
175
+ this.readInput(resolve, retrieve);
176
+ });
177
+
178
+ rl.on("close", () => {
179
+
180
+ });
181
+ retrieve && retrieve(rl);
182
+ }
183
+
184
+ /**
185
+ *
186
+ * @param {object} unpacked
187
+ * @param {{type: string, name: string, bits: number, loop?: { name: string, struct: {type: string, name: string, bits: number}[] }}[]} structs
188
+ * @param {Buffer} buffer
189
+ * @param {boolean} little_endian
190
+ * @param {number} offset
191
+ * @returns
192
+ */
193
+ readStruct(unpacked, structs, buffer, little_endian, offset = 0) {
194
+ let endianSuffix = little_endian ? "LE" : "BE";
195
+ // let dataView = new DataView(new Uint8Array(buffer).buffer);
196
+ structs && structs.forEach(struct => {
197
+ // let v = dataView[`get${struct.type}${struct.bits}`](offset, little_endian);
198
+ let v;
199
+ let bytes = struct.bits >> 3;
200
+ if (struct.type == "String") {
201
+ let end = offset + bytes;
202
+ if (struct.trim) {
203
+ let idx = buffer.indexOf(0, offset);
204
+ if (idx > offset) {
205
+ end = idx;
206
+ }
207
+ }
208
+ v = buffer.toString(struct.encoding, offset, end);
209
+ } else {
210
+ v = buffer[`read${struct.type}${struct.bits}${struct.bits > 8 ? endianSuffix : ""}`](offset);
211
+ }
212
+ offset += bytes;
213
+ if (struct.name) {
214
+ unpacked[struct.name] = v;
215
+ }
216
+ if (struct.loop) {
217
+ let loopv = [];
218
+ for (let i = 0; i < v; ++i) {
219
+ let t = {};
220
+ offset = this.readStruct(t, struct.loop.struct, buffer, little_endian, offset);
221
+ loopv.push(t);
222
+ }
223
+ unpacked[struct.loop.name] = loopv;
224
+ }
225
+ });
226
+ return offset;
227
+ }
228
+
229
+ }
230
+
231
+ module.exports = {
232
+ WebSocketCommand,
233
+ };