Просмотр исходного кода

typescriptize export service related files

Futa Arai 2 лет назад
Родитель
Сommit
c4f9410193

+ 0 - 13
apps/app/src/server/models/vo/collection-progress.js

@@ -1,13 +0,0 @@
-class CollectionProgress {
-
-  constructor(collectionName, totalCount) {
-    this.collectionName = collectionName;
-    this.currentCount = 0;
-    this.insertedCount = 0;
-    this.modifiedCount = 0;
-    this.totalCount = totalCount;
-  }
-
-}
-
-module.exports = CollectionProgress;

+ 19 - 0
apps/app/src/server/models/vo/collection-progress.ts

@@ -0,0 +1,19 @@
+class CollectionProgress {
+
+  collectionName: string;
+
+  currentCount = 0;
+
+  insertedCount = 0;
+
+  modifiedCount = 0;
+
+  totalCount = 0;
+
+  constructor(collectionName: string) {
+    this.collectionName = collectionName;
+  }
+
+}
+
+export default CollectionProgress;

+ 12 - 7
apps/app/src/server/models/vo/collection-progressing-status.js → apps/app/src/server/models/vo/collection-progressing-status.ts

@@ -1,13 +1,18 @@
-const CollectionProgress = require('./collection-progress');
+import CollectionProgress from './collection-progress';
 
 class CollectionProgressingStatus {
 
-  constructor(collections) {
-    this.totalCount = 0;
+  totalCount = 0;
+
+  progressList: CollectionProgress[];
+
+  progressMap: Record<string, CollectionProgress>;
+
+  constructor(collections: string[]) {
     this.progressMap = {};
 
     this.progressList = collections.map((collectionName) => {
-      return new CollectionProgress(collectionName, 0);
+      return new CollectionProgress(collectionName);
     });
 
     // collection name to instance mapping
@@ -16,14 +21,14 @@ class CollectionProgressingStatus {
     });
   }
 
-  recalculateTotalCount() {
+  recalculateTotalCount(): void {
     this.progressList.forEach((p) => {
       this.progressMap[p.collectionName] = p;
       this.totalCount += p.totalCount;
     });
   }
 
-  get currentCount() {
+  get currentCount(): number {
     return this.progressList.reduce(
       (acc, crr) => acc + crr.currentCount,
       0,
@@ -32,4 +37,4 @@ class CollectionProgressingStatus {
 
 }
 
-module.exports = CollectionProgressingStatus;
+export default CollectionProgressingStatus;

+ 54 - 34
apps/app/src/server/service/export.js → apps/app/src/server/service/export.ts

@@ -1,20 +1,24 @@
+import fs from 'fs';
+import path from 'path';
+import { Readable, Transform } from 'stream';
+
 import { toArrayIfNot } from '~/utils/array-utils';
 import loggerFactory from '~/utils/logger';
 
+import CollectionProgress from '../models/vo/collection-progress';
+import CollectionProgressingStatus from '../models/vo/collection-progressing-status';
+
+import AppService from './app';
 import ConfigLoader from './config-loader';
+import GrowiBridgeService, { ZipFileStat } from './growi-bridge';
 
-const logger = loggerFactory('growi:services:ExportService'); // eslint-disable-line no-unused-vars
 
-const fs = require('fs');
-const path = require('path');
-const { Transform } = require('stream');
+const logger = loggerFactory('growi:services:ExportService'); // eslint-disable-line no-unused-vars
 
 const archiver = require('archiver');
 const mongoose = require('mongoose');
 const streamToPromise = require('stream-to-promise');
 
-const CollectionProgressingStatus = require('../models/vo/collection-progressing-status');
-
 class ExportProgressingStatus extends CollectionProgressingStatus {
 
   async init() {
@@ -32,14 +36,30 @@ class ExportProgressingStatus extends CollectionProgressingStatus {
 
 class ExportService {
 
+  crowi: any;
+
+  appService: AppService;
+
+  growiBridgeService: GrowiBridgeService;
+
+  getFile: (filename: string) => string;
+
+  per = 100;
+
+  zlibLevel = 9; // 0(min) - 9(max)
+
+  currentProgressingStatus: ExportProgressingStatus | null;
+
+  baseDir: string;
+
+  adminEvent: any;
+
   constructor(crowi) {
     this.crowi = crowi;
     this.appService = crowi.appService;
     this.growiBridgeService = crowi.growiBridgeService;
     this.getFile = this.growiBridgeService.getFile.bind(this);
     this.baseDir = path.join(crowi.tmpDir, 'downloads');
-    this.per = 100;
-    this.zlibLevel = 9; // 0(min) - 9(max)
 
     this.adminEvent = crowi.event('admin');
 
@@ -56,7 +76,7 @@ class ExportService {
     const zipFiles = fs.readdirSync(this.baseDir).filter(file => path.extname(file) === '.zip');
 
     // process serially so as not to waste memory
-    const zipFileStats = [];
+    const zipFileStats: ZipFileStat[] = [];
     const parseZipFilePromises = zipFiles.map((file) => {
       const zipFile = this.getFile(file);
       return this.growiBridgeService.parseZipFile(zipFile);
@@ -73,7 +93,7 @@ class ExportService {
     return {
       zipFileStats: filtered,
       isExporting,
-      progressList: isExporting ? this.currentProgressingStatus.progressList : null,
+      progressList: isExporting ? this.currentProgressingStatus?.progressList : null,
     };
   }
 
@@ -83,7 +103,7 @@ class ExportService {
    * @memberOf ExportService
    * @return {string} path to meta.json
    */
-  async createMetaJson() {
+  async createMetaJson(): Promise<string> {
     const metaJson = path.join(this.baseDir, this.growiBridgeService.getMetaFileName());
     const writeStream = fs.createWriteStream(metaJson, { encoding: this.growiBridgeService.getEncoding() });
     const passwordSeed = this.crowi.env.PASSWORD_SEED || null;
@@ -109,7 +129,7 @@ class ExportService {
    * @param {ExportProgress} exportProgress
    * @return {Transform}
    */
-  generateLogStream(exportProgress) {
+  generateLogStream(exportProgress: CollectionProgress | undefined): Transform {
     const logProgress = this.logProgress.bind(this);
 
     let count = 0;
@@ -130,9 +150,9 @@ class ExportService {
    * insert beginning/ending brackets and comma separator for Json Array
    *
    * @memberOf ExportService
-   * @return {TransformStream}
+   * @return {Transform}
    */
-  generateTransformStream() {
+  generateTransformStream(): Transform {
     let isFirst = true;
 
     const transformStream = new Transform({
@@ -171,7 +191,7 @@ class ExportService {
    * @param {string} collectionName collection name
    * @return {string} path to zip file
    */
-  async exportCollectionToJson(collectionName) {
+  async exportCollectionToJson(collectionName: string): Promise<string> {
     const collection = mongoose.connection.collection(collectionName);
 
     const nativeCursor = collection.find();
@@ -181,7 +201,7 @@ class ExportService {
     const transformStream = this.generateTransformStream();
 
     // log configuration
-    const exportProgress = this.currentProgressingStatus.progressMap[collectionName];
+    const exportProgress = this.currentProgressingStatus?.progressMap[collectionName];
     const logStream = this.generateLogStream(exportProgress);
 
     // create WritableStream
@@ -195,7 +215,7 @@ class ExportService {
 
     await streamToPromise(writeStream);
 
-    return writeStream.path;
+    return writeStream.path.toString();
   }
 
   /**
@@ -203,13 +223,13 @@ class ExportService {
    *
    * @memberOf ExportService
    * @param {Array.<string>} collections array of collection name
-   * @return {Array.<string>} paths to json files created
+   * @return {Array.<ZipFileStat>} info of zip file created
    */
-  async exportCollectionsToZippedJson(collections) {
+  async exportCollectionsToZippedJson(collections: string[]): Promise<ZipFileStat> {
     const metaJson = await this.createMetaJson();
 
     // process serially so as not to waste memory
-    const jsonFiles = [];
+    const jsonFiles: string[] = [];
     const jsonFilesPromises = collections.map(collectionName => this.exportCollectionToJson(collectionName));
     for await (const jsonFile of jsonFilesPromises) {
       jsonFiles.push(jsonFile);
@@ -236,7 +256,7 @@ class ExportService {
     // TODO: remove broken zip file
   }
 
-  async export(collections) {
+  async export(collections: string[]): Promise<ZipFileStat> {
     if (this.currentProgressingStatus != null) {
       throw new Error('There is an exporting process running.');
     }
@@ -244,7 +264,7 @@ class ExportService {
     this.currentProgressingStatus = new ExportProgressingStatus(collections);
     await this.currentProgressingStatus.init();
 
-    let zipFileStat;
+    let zipFileStat: ZipFileStat;
     try {
       zipFileStat = await this.exportCollectionsToZippedJson(collections);
     }
@@ -263,7 +283,9 @@ class ExportService {
    * @param {CollectionProgress} collectionProgress
    * @param {number} currentCount number of items exported
    */
-  logProgress(collectionProgress, currentCount) {
+  logProgress(collectionProgress: CollectionProgress | undefined, currentCount: number): void {
+    if (collectionProgress == null) return;
+
     const output = `${collectionProgress.collectionName}: ${currentCount}/${collectionProgress.totalCount} written`;
 
     // update exportProgress.currentCount
@@ -284,12 +306,11 @@ class ExportService {
   /**
    * emit progress event
    */
-  emitProgressEvent() {
-    const { currentCount, totalCount, progressList } = this.currentProgressingStatus;
+  emitProgressEvent(): void {
     const data = {
-      currentCount,
-      totalCount,
-      progressList,
+      currentCount: this.currentProgressingStatus?.currentCount,
+      totalCount: this.currentProgressingStatus?.totalCount,
+      progressList: this.currentProgressingStatus?.progressList,
     };
 
     // send event (in progress in global)
@@ -299,7 +320,7 @@ class ExportService {
   /**
    * emit start zipping event
    */
-  emitStartZippingEvent() {
+  emitStartZippingEvent(): void {
     this.adminEvent.emit('onStartZippingForExport', {});
   }
 
@@ -307,7 +328,7 @@ class ExportService {
    * emit terminate event
    * @param {object} zipFileStat added zip file status data
    */
-  emitTerminateEvent(zipFileStat) {
+  emitTerminateEvent(zipFileStat: ZipFileStat): void {
     this.adminEvent.emit('onTerminateForExport', { addedZipFileStat: zipFileStat });
   }
 
@@ -319,7 +340,7 @@ class ExportService {
    * @return {string} absolute path to the zip file
    * @see https://www.archiverjs.com/#quick-start
    */
-  async zipFiles(_configs) {
+  async zipFiles(_configs: {from: string, as: string}[]): Promise<string> {
     const configs = toArrayIfNot(_configs);
     const appTitle = this.appService.getAppTitle();
     const timeStamp = (new Date()).getTime();
@@ -365,10 +386,9 @@ class ExportService {
     return zipFile;
   }
 
-  getReadStreamFromRevision(revision, format) {
+  getReadStreamFromRevision(revision, format): Readable {
     const data = revision.body;
 
-    const Readable = require('stream').Readable;
     const readable = new Readable();
     readable._read = () => {};
     readable.push(data);
@@ -379,4 +399,4 @@ class ExportService {
 
 }
 
-module.exports = ExportService;
+export default ExportService;

+ 34 - 14
apps/app/src/server/service/growi-bridge.js → apps/app/src/server/service/growi-bridge.ts

@@ -1,31 +1,51 @@
+import fs from 'fs';
+import path from 'path';
+
+import unzipper from 'unzipper';
+
 import loggerFactory from '~/utils/logger';
 
-const fs = require('fs');
-const path = require('path');
 const streamToPromise = require('stream-to-promise');
-const unzipper = require('unzipper');
 
 const logger = loggerFactory('growi:services:GrowiBridgeService'); // eslint-disable-line no-unused-vars
 
+export type ZipFileStat = {
+  meta: object;
+  fileName: string;
+  zipFilePath: string;
+  fileStat: fs.Stats;
+  innerFileStats: {
+      fileName: string;
+      collectionName: string;
+      size: number;
+  }[];
+} | null
+
 /**
  * the service class for bridging GROWIs (export and import)
  * common properties and methods between export service and import service are defined in this service
  */
 class GrowiBridgeService {
 
+  crowi: any;
+
+  encoding: BufferEncoding = 'utf-8';
+
+  metaFileName = 'meta.json';
+
+  baseDir: string | undefined;
+
   constructor(crowi) {
     this.crowi = crowi;
-    this.encoding = 'utf-8';
-    this.metaFileName = 'meta.json';
   }
 
   /**
    * getter for encoding
    *
    * @memberOf GrowiBridgeService
-   * @return {string} encoding
+   * @return {BufferEncoding} encoding
    */
-  getEncoding() {
+  getEncoding(): BufferEncoding {
     return this.encoding;
   }
 
@@ -35,7 +55,7 @@ class GrowiBridgeService {
    * @memberOf GrowiBridgeService
    * @return {string} base name of meta file
    */
-  getMetaFileName() {
+  getMetaFileName(): string {
     return this.metaFileName;
   }
 
@@ -46,8 +66,8 @@ class GrowiBridgeService {
    * @param {string} collectionName collection name
    * @return {object} instance of mongoose model
    */
-  getModelFromCollectionName(collectionName) {
-    const Model = Object.values(this.crowi.models).find((m) => {
+  getModelFromCollectionName(collectionName: string) {
+    const Model = Object.values(this.crowi.models).find((m: any) => {
       return m.collection != null && m.collection.name === collectionName;
     });
 
@@ -62,7 +82,7 @@ class GrowiBridgeService {
    * @param {string} fileName base name of file
    * @return {string} absolute path to the file
    */
-  getFile(fileName) {
+  getFile(fileName: string): string {
     if (this.baseDir == null) {
       throw new Error('baseDir is not defined');
     }
@@ -82,9 +102,9 @@ class GrowiBridgeService {
    * @param {string} zipFile path to zip file
    * @return {object} meta{object} and files{Array.<object>}
    */
-  async parseZipFile(zipFile) {
+  async parseZipFile(zipFile: string): Promise<ZipFileStat> {
     const fileStat = fs.statSync(zipFile);
-    const innerFileStats = [];
+    const innerFileStats: {fileName: string, collectionName: string, size: number}[] = [];
     let meta = {};
 
     const readStream = fs.createReadStream(zipFile);
@@ -128,4 +148,4 @@ class GrowiBridgeService {
 
 }
 
-module.exports = GrowiBridgeService;
+export default GrowiBridgeService;

+ 2 - 1
apps/app/src/server/service/import.js

@@ -2,6 +2,8 @@ import gc from 'expose-gc/function';
 
 import loggerFactory from '~/utils/logger';
 
+import CollectionProgressingStatus from '../models/vo/collection-progressing-status';
+
 const fs = require('fs');
 const path = require('path');
 const { Writable, Transform } = require('stream');
@@ -13,7 +15,6 @@ const mongoose = require('mongoose');
 const streamToPromise = require('stream-to-promise');
 const unzipper = require('unzipper');
 
-const CollectionProgressingStatus = require('../models/vo/collection-progressing-status');
 const { createBatchStream } = require('../util/batch-stream');
 
 const { ObjectId } = mongoose.Types;