utils.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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 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 randomHexString(len) {
  35. return crypto.randomBytes(len).toString('hex')
  36. }
  37. async function touchFile(filename) {
  38. await fs.utimes(filename, Date.now()/1000, Date.now()/1000);
  39. }
  40. function spawnProcess(cmd, opts) {
  41. let {args, killAfter, onData, onUsage, onUsageInterval, abort} = opts;
  42. killAfter = (killAfter ? killAfter : 120);//seconds
  43. onData = (onData ? onData : () => {});
  44. args = (args ? args : []);
  45. onUsageInterval = (onUsageInterval ? onUsageInterval : 30);//seconds
  46. return new Promise((resolve, reject) => { (async() => {
  47. let resolved = false;
  48. const proc = spawn(cmd, args, {detached: true});
  49. let stdout = '';
  50. proc.stdout.on('data', (data) => {
  51. stdout += data;
  52. onData(data);
  53. });
  54. let stderr = '';
  55. proc.stderr.on('data', (data) => {
  56. stderr += data;
  57. onData(data);
  58. });
  59. proc.on('close', (code) => {
  60. resolved = true;
  61. resolve({status: 'close', code, stdout, stderr});
  62. });
  63. proc.on('error', (error) => {
  64. reject({status: 'error', error, stdout, stderr});
  65. });
  66. //ждем процесс, контролируем его работу раз в секунду
  67. let onUsageCounter = onUsageInterval;
  68. while (!resolved) {
  69. await sleep(1000);
  70. onUsageCounter--;
  71. if (onUsage && onUsageCounter <= 0) {
  72. const stats = await pidusage(proc.pid);
  73. onUsage(stats);
  74. onUsageCounter = onUsageInterval;
  75. }
  76. killAfter--;
  77. if (killAfter <= 0 || (abort && abort())) {
  78. process.kill(proc.pid);
  79. if (killAfter <= 0) {
  80. reject({status: 'killed', stdout, stderr});
  81. } else {
  82. reject({status: 'abort', stdout, stderr});
  83. }
  84. break;
  85. }
  86. }
  87. })().catch(reject); });
  88. }
  89. async function findFiles(callback, dir) {
  90. if (!(callback && dir))
  91. return;
  92. let result = true;
  93. const files = await fs.readdir(dir, { withFileTypes: true });
  94. for (const file of files) {
  95. const found = path.resolve(dir, file.name);
  96. if (file.isDirectory())
  97. result = await findFiles(callback, found);
  98. else
  99. await callback(found);
  100. }
  101. return result;
  102. }
  103. module.exports = {
  104. toBase36,
  105. fromBase36,
  106. bufferRemoveZeroes,
  107. getFileHash,
  108. sleep,
  109. randomHexString,
  110. touchFile,
  111. spawnProcess,
  112. findFiles
  113. };