utils.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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 BASE36 = '0123456789abcdefghijklmnopqrstuvwxyz';
  7. const bs36 = baseX(BASE36);
  8. function toBase36(data) {
  9. return bs36.encode(Buffer.from(data));
  10. }
  11. function fromBase36(data) {
  12. return bs36.decode(data);
  13. }
  14. function bufferRemoveZeroes(buf) {
  15. const i = buf.indexOf(0);
  16. if (i >= 0) {
  17. return buf.slice(0, i);
  18. }
  19. return buf;
  20. }
  21. function getFileHash(filename, hashName, enc) {
  22. return new Promise((resolve, reject) => {
  23. const hash = crypto.createHash(hashName);
  24. const rs = fs.createReadStream(filename);
  25. rs.on('error', reject);
  26. rs.on('data', chunk => hash.update(chunk));
  27. rs.on('end', () => resolve(hash.digest(enc)));
  28. });
  29. }
  30. function sleep(ms) {
  31. return new Promise(resolve => setTimeout(resolve, ms));
  32. }
  33. function randomHexString(len) {
  34. return crypto.randomBytes(len).toString('hex')
  35. }
  36. async function touchFile(filename) {
  37. await fs.utimes(filename, Date.now()/1000, Date.now()/1000);
  38. }
  39. function spawnProcess(cmd, opts) {
  40. let {args, killAfter, onData, abort} = opts;
  41. killAfter = (killAfter ? killAfter : 120);//seconds
  42. onData = (onData ? onData : () => {});
  43. args = (args ? args : []);
  44. return new Promise((resolve, reject) => { (async() => {
  45. let resolved = false;
  46. const proc = spawn(cmd, args, {detached: true});
  47. let stdout = '';
  48. proc.stdout.on('data', (data) => {
  49. stdout += data;
  50. onData(data);
  51. });
  52. let stderr = '';
  53. proc.stderr.on('data', (data) => {
  54. stderr += data;
  55. onData(data);
  56. });
  57. proc.on('close', (code) => {
  58. resolved = true;
  59. resolve({status: 'close', code, stdout, stderr});
  60. });
  61. proc.on('error', (error) => {
  62. reject({status: 'error', error, stdout, stderr});
  63. });
  64. while (!resolved) {
  65. await sleep(1000);
  66. killAfter -= 1;
  67. if (killAfter <= 0 || (abort && abort())) {
  68. process.kill(proc.pid);
  69. if (killAfter <= 0) {
  70. reject({status: 'killed', stdout, stderr});
  71. } else {
  72. reject({status: 'abort', stdout, stderr});
  73. }
  74. break;
  75. }
  76. }
  77. })().catch(reject); });
  78. }
  79. async function findFiles(callback, dir) {
  80. if (!(callback && dir))
  81. return;
  82. let result = true;
  83. const files = await fs.readdir(dir, { withFileTypes: true });
  84. for (const file of files) {
  85. const found = path.resolve(dir, file.name);
  86. if (file.isDirectory())
  87. result = await findFiles(callback, found);
  88. else
  89. await callback(found);
  90. }
  91. return result;
  92. }
  93. module.exports = {
  94. toBase36,
  95. fromBase36,
  96. bufferRemoveZeroes,
  97. getFileHash,
  98. sleep,
  99. randomHexString,
  100. touchFile,
  101. spawnProcess,
  102. findFiles
  103. };