ZipStreamer.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. const fs = require('fs-extra');
  2. const path = require('path');
  3. const zipStream = require('zip-stream');
  4. const unzipStream = require('./node_stream_zip');
  5. class ZipStreamer {
  6. constructor() {
  7. }
  8. //TODO: сделать рекурсивный обход директорий, пока только файлы
  9. //files = ['filename', 'dirname/']
  10. pack(zipFile, files, options, entryCallback) {
  11. return new Promise((resolve, reject) => { (async() => {
  12. entryCallback = (entryCallback ? entryCallback : () => {});
  13. const zip = new zipStream(options);
  14. const outputStream = fs.createWriteStream(zipFile);
  15. outputStream.on('error', reject);
  16. outputStream.on('finish', async() => {
  17. let file = {path: zipFile};
  18. try {
  19. file.size = (await fs.stat(zipFile)).size;
  20. } catch (e) {
  21. reject(e);
  22. }
  23. resolve(file);
  24. });
  25. zip.on('error', reject);
  26. zip.pipe(outputStream);
  27. const zipAddEntry = (filename) => {
  28. return new Promise((resolve, reject) => {
  29. const basename = path.basename(filename);
  30. const source = fs.createReadStream(filename);
  31. zip.entry(source, {name: basename}, (err, entry) => {
  32. if (err) reject(err);
  33. resolve(entry);
  34. });
  35. });
  36. };
  37. for (const filename of files) {
  38. const entry = await zipAddEntry(filename);
  39. entryCallback({path: entry.name, size: entry.size, compressedSize: entry.csize});
  40. }
  41. zip.finish();
  42. })().catch(reject); });
  43. }
  44. unpack(zipFile, outputDir, options, entryCallback) {
  45. return new Promise((resolve, reject) => {
  46. entryCallback = (entryCallback ? entryCallback : () => {});
  47. const {
  48. limitFileSize = 0,
  49. limitFileCount = 0,
  50. decodeEntryNameCallback = false,
  51. } = options;
  52. const unzip = new unzipStream({file: zipFile});
  53. unzip.on('error', reject);
  54. let files = [];
  55. unzip.on('extract', (en) => {
  56. const entry = {path: en.name, size: en.size, compressedSize: en.compressedSize};
  57. entryCallback(entry);
  58. files.push(entry);
  59. });
  60. unzip.on('ready', () => {
  61. if (limitFileCount || limitFileSize || decodeEntryNameCallback) {
  62. const entries = Object.values(unzip.entries());
  63. if (limitFileCount && entries.length > limitFileCount) {
  64. reject(new Error('Слишком много файлов'));
  65. return;
  66. }
  67. for (const entry of entries) {
  68. if (limitFileSize && !entry.isDirectory && entry.size > limitFileSize) {
  69. reject(new Error('Файл слишком большой'));
  70. return;
  71. }
  72. if (decodeEntryNameCallback) {
  73. entry.name = (decodeEntryNameCallback(entry.nameRaw)).toString();
  74. }
  75. }
  76. }
  77. unzip.extract(null, outputDir, (err) => {
  78. if (err) {
  79. reject(err);
  80. return;
  81. }
  82. try {
  83. unzip.close();
  84. resolve(files);
  85. } catch (e) {
  86. reject(e);
  87. }
  88. });
  89. });
  90. });
  91. }
  92. }
  93. module.exports = ZipStreamer;