growi-bridge.js 3.1 KB

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