growi-bridge.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. const logger = require('@alias/logger')('growi:services:GrowiBridgeService'); // eslint-disable-line no-unused-vars
  2. const fs = require('fs');
  3. const path = require('path');
  4. const streamToPromise = require('stream-to-promise');
  5. const unzipper = require('unzipper');
  6. /**
  7. * the service class for bridging GROWIs (export and import)
  8. * common properties and methods between export service and import service are defined in this service
  9. */
  10. class GrowiBridgeService {
  11. constructor(crowi) {
  12. this.crowi = crowi;
  13. this.encoding = 'utf-8';
  14. this.metaFileName = 'meta.json';
  15. }
  16. /**
  17. * getter for encoding
  18. *
  19. * @memberOf GrowiBridgeService
  20. * @return {string} encoding
  21. */
  22. getEncoding() {
  23. return this.encoding;
  24. }
  25. /**
  26. * getter for metaFileName
  27. *
  28. * @memberOf GrowiBridgeService
  29. * @return {string} base name of meta file
  30. */
  31. getMetaFileName() {
  32. return this.metaFileName;
  33. }
  34. /**
  35. * get a model from collection name
  36. *
  37. * @memberOf GrowiBridgeService
  38. * @param {string} collectionName collection name
  39. * @return {object} instance of mongoose model
  40. */
  41. getModelFromCollectionName(collectionName) {
  42. const Model = Object.values(this.crowi.models).find((m) => {
  43. return m.collection != null && m.collection.name === collectionName;
  44. });
  45. return Model;
  46. }
  47. /**
  48. * get the absolute path to a file
  49. * this method must must be bound to the caller (this.baseDir is undefined in this service)
  50. *
  51. * @memberOf GrowiBridgeService
  52. * @param {string} fileName base name of file
  53. * @return {string} absolute path to the file
  54. */
  55. getFile(fileName) {
  56. if (this.baseDir == null) {
  57. throw new Error('baseDir is not defined');
  58. }
  59. const jsonFile = path.join(this.baseDir, fileName);
  60. // throws err if the file does not exist
  61. fs.accessSync(jsonFile);
  62. return jsonFile;
  63. }
  64. /**
  65. * parse a zip file
  66. *
  67. * @memberOf GrowiBridgeService
  68. * @param {string} zipFile path to zip file
  69. * @return {object} meta{object} and files{Array.<object>}
  70. */
  71. async parseZipFile(zipFile) {
  72. const fileStat = fs.statSync(zipFile);
  73. const innerFileStats = [];
  74. let meta = {};
  75. const readStream = fs.createReadStream(zipFile);
  76. const unzipStream = readStream.pipe(unzipper.Parse());
  77. unzipStream.on('entry', async(entry) => {
  78. const fileName = entry.path;
  79. const size = entry.vars.uncompressedSize; // There is also compressedSize;
  80. if (fileName === this.getMetaFileName()) {
  81. meta = JSON.parse((await entry.buffer()).toString());
  82. }
  83. else {
  84. innerFileStats.push({
  85. fileName,
  86. collectionName: path.basename(fileName, '.json'),
  87. size,
  88. });
  89. }
  90. entry.autodrain();
  91. });
  92. try {
  93. await streamToPromise(unzipStream);
  94. }
  95. // if zip is broken
  96. catch (err) {
  97. logger.error(err);
  98. return null;
  99. }
  100. return {
  101. meta,
  102. fileName: path.basename(zipFile),
  103. fileStat,
  104. innerFileStats,
  105. };
  106. }
  107. }
  108. module.exports = GrowiBridgeService;