utils.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. const { spawn } = require('child_process');
  2. const fs = require('fs-extra');
  3. const path = require('path');
  4. const crypto = require('crypto');
  5. const baseX = require('base-x');
  6. const pidusage = require('pidusage');
  7. const BASE36 = '0123456789abcdefghijklmnopqrstuvwxyz';
  8. const bs36 = baseX(BASE36);
  9. function toBase36(data) {
  10. return bs36.encode(Buffer.from(data));
  11. }
  12. function fromBase36(data) {
  13. return Buffer.from(bs36.decode(data));
  14. }
  15. function bufferRemoveZeroes(buf) {
  16. const i = buf.indexOf(0);
  17. if (i >= 0) {
  18. return buf.slice(0, i);
  19. }
  20. return buf;
  21. }
  22. function getFileHash(filename, hashName, enc) {
  23. return new Promise((resolve, reject) => {
  24. const hash = crypto.createHash(hashName);
  25. const rs = fs.createReadStream(filename);
  26. rs.on('error', reject);
  27. rs.on('data', chunk => hash.update(chunk));
  28. rs.on('end', () => resolve(hash.digest(enc)));
  29. });
  30. }
  31. function sleep(ms) {
  32. return new Promise(resolve => setTimeout(resolve, ms));
  33. }
  34. function toUnixTime(time) {
  35. return parseInt(time/1000);
  36. }
  37. function randomHexString(len) {
  38. return crypto.randomBytes(len).toString('hex')
  39. }
  40. async function touchFile(filename) {
  41. await fs.utimes(filename, Date.now()/1000, Date.now()/1000);
  42. }
  43. function spawnProcess(cmd, opts) {
  44. let {args, killAfter, onData, onUsage, onUsageInterval, abort} = opts;
  45. killAfter = (killAfter ? killAfter : 120);//seconds
  46. onData = (onData ? onData : () => {});
  47. args = (args ? args : []);
  48. onUsageInterval = (onUsageInterval ? onUsageInterval : 30);//seconds
  49. return new Promise((resolve, reject) => { (async() => {
  50. let resolved = false;
  51. const proc = spawn(cmd, args, {detached: true});
  52. let stdout = '';
  53. proc.stdout.on('data', (data) => {
  54. stdout += data;
  55. onData(data);
  56. });
  57. let stderr = '';
  58. proc.stderr.on('data', (data) => {
  59. stderr += data;
  60. onData(data);
  61. });
  62. proc.on('close', (code) => {
  63. resolved = true;
  64. resolve({status: 'close', code, stdout, stderr});
  65. });
  66. proc.on('error', (error) => {
  67. reject({status: 'error', error, stdout, stderr});
  68. });
  69. //ждем процесс, контролируем его работу раз в секунду
  70. let onUsageCounter = onUsageInterval;
  71. while (!resolved) {
  72. await sleep(1000);
  73. onUsageCounter--;
  74. if (onUsage && onUsageCounter <= 0) {
  75. const stats = await pidusage(proc.pid);
  76. onUsage(stats);
  77. onUsageCounter = onUsageInterval;
  78. }
  79. killAfter--;
  80. if (killAfter <= 0 || (abort && abort())) {
  81. process.kill(proc.pid);
  82. if (killAfter <= 0) {
  83. reject({status: 'killed', stdout, stderr});
  84. } else {
  85. reject({status: 'abort', stdout, stderr});
  86. }
  87. break;
  88. }
  89. }
  90. })().catch(reject); });
  91. }
  92. async function findFiles(callback, dir) {
  93. if (!(callback && dir))
  94. return;
  95. let result = true;
  96. const files = await fs.readdir(dir, { withFileTypes: true });
  97. for (const file of files) {
  98. const found = path.resolve(dir, file.name);
  99. if (file.isDirectory())
  100. result = await findFiles(callback, found);
  101. else
  102. await callback(found);
  103. }
  104. return result;
  105. }
  106. module.exports = {
  107. toBase36,
  108. fromBase36,
  109. bufferRemoveZeroes,
  110. getFileHash,
  111. sleep,
  112. toUnixTime,
  113. randomHexString,
  114. touchFile,
  115. spawnProcess,
  116. findFiles
  117. };