utils.js 3.8 KB

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