index.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import fs from 'fs';
  2. import path from 'path';
  3. import streamToPromise from 'stream-to-promise';
  4. import unzipStream, { type Entry } from 'unzip-stream';
  5. import loggerFactory from '~/utils/logger';
  6. import type { ZipFileStat } from '../interfaces/export';
  7. import { tapStreamDataByPromise } from './unzip-stream-utils';
  8. const logger = loggerFactory('growi:services:GrowiBridgeService'); // eslint-disable-line no-unused-vars
  9. /**
  10. * the service class for bridging GROWIs (export and import)
  11. * common properties and methods between export service and import service are defined in this service
  12. */
  13. class GrowiBridgeService {
  14. crowi: any;
  15. encoding: BufferEncoding = 'utf-8';
  16. metaFileName = 'meta.json';
  17. baseDir: string | undefined;
  18. constructor(crowi) {
  19. this.crowi = crowi;
  20. }
  21. /**
  22. * getter for encoding
  23. *
  24. * @memberOf GrowiBridgeService
  25. * @return {BufferEncoding} encoding
  26. */
  27. getEncoding(): BufferEncoding {
  28. return this.encoding;
  29. }
  30. /**
  31. * getter for metaFileName
  32. *
  33. * @memberOf GrowiBridgeService
  34. * @return {string} base name of meta file
  35. */
  36. getMetaFileName(): string {
  37. return this.metaFileName;
  38. }
  39. /**
  40. * get the absolute path to a file
  41. *
  42. * @memberOf GrowiBridgeService
  43. */
  44. getFile(fileName: string, baseDir: string): string {
  45. const jsonFile = path.join(baseDir, fileName);
  46. // throws err if the file does not exist
  47. fs.accessSync(jsonFile);
  48. return jsonFile;
  49. }
  50. /**
  51. * parse a zip file
  52. *
  53. * @memberOf GrowiBridgeService
  54. * @param {string} zipFile path to zip file
  55. * @return {object} meta{object} and files{Array.<object>}
  56. */
  57. async parseZipFile(zipFile: string): Promise<ZipFileStat | null> {
  58. const fileStat = fs.statSync(zipFile);
  59. const innerFileStats: Array<{ fileName: string, collectionName: string, size: number }> = [];
  60. let meta = {};
  61. const readStream = fs.createReadStream(zipFile);
  62. const unzipStreamPipe = readStream.pipe(unzipStream.Parse());
  63. let tapPromise;
  64. const unzipEntryStream = unzipStreamPipe.on('entry', (entry: Entry) => {
  65. const fileName = entry.path;
  66. const size = entry.size; // might be undefined in some archives
  67. if (fileName === this.getMetaFileName()) {
  68. tapPromise = tapStreamDataByPromise(entry).then((metaBuffer) => {
  69. meta = JSON.parse(metaBuffer.toString());
  70. });
  71. }
  72. else {
  73. innerFileStats.push({
  74. fileName,
  75. collectionName: path.basename(fileName, '.json'),
  76. size,
  77. });
  78. }
  79. entry.autodrain();
  80. });
  81. try {
  82. await streamToPromise(unzipEntryStream);
  83. await tapPromise;
  84. }
  85. // if zip is broken
  86. catch (err) {
  87. logger.error(err);
  88. return null;
  89. }
  90. return {
  91. meta,
  92. fileName: path.basename(zipFile),
  93. zipFilePath: zipFile,
  94. fileStat,
  95. innerFileStats,
  96. };
  97. }
  98. }
  99. export default GrowiBridgeService;