Taichi Masuyama 3 лет назад
Родитель
Сommit
05e6301de9

+ 40 - 48
packages/app/src/server/routes/apiv3/g2g-transfer.ts

@@ -4,6 +4,7 @@ import { body } from 'express-validator';
 import TransferKeyModel from '~/server/models/transfer-key';
 import { isG2GTransferError } from '~/server/models/vo/g2g-transfer-error';
 import { IDataGROWIInfo, X_GROWI_TRANSFER_KEY_HEADER_NAME } from '~/server/service/g2g-transfer';
+import customAxios from '~/utils/axios';
 import loggerFactory from '~/utils/logger';
 import { TransferKey } from '~/utils/vo/transfer-key';
 
@@ -18,6 +19,7 @@ const logger = loggerFactory('growi:routes:apiv3:transfer');
 const validator = {
   transfer: [
     body('transferKey').isString().withMessage('transferKey is required'),
+    body('collections').isArray().withMessage('collections is required'),
   ],
 };
 
@@ -98,13 +100,19 @@ module.exports = (crowi: Crowi): Router => {
 
   // Auto import
   router.post('/', verifyAndExtractTransferKey, async(req: Request & { transferKey: TransferKey }, res: ApiV3Response) => {
-    const { transferKey } = req;
-
+    const zipFile = req.body;
+    try {
+      await g2gTransferReceiverService.receive(zipFile);
+    }
+    catch (err) {
+      logger.error(err);
+      return res.apiv3Err(new ErrorV3('Error occurred while importing transfer data.', 'failed_to_receive'));
+    }
 
-    return;
+    return res.apiv3({ message: 'Successfully started to receive transfer data.' });
   });
 
-  router.get('/growi-info', /* verifyAndExtractTransferKey, */ async(req: Request & { transferKey: TransferKey }, res: ApiV3Response) => {
+  router.get('/growi-info', verifyAndExtractTransferKey, async(req: Request & { transferKey: TransferKey }, res: ApiV3Response) => {
     let growiInfo: IDataGROWIInfo;
     try {
       growiInfo = await g2gTransferReceiverService.answerGROWIInfo();
@@ -138,7 +146,7 @@ module.exports = (crowi: Crowi): Router => {
     // Save TransferKey document
     let transferKeyString: string;
     try {
-      transferKeyString = await g2gTransferService.createTransferKey(appSiteUrl);
+      transferKeyString = await g2gTransferReceiverService.createTransferKey(appSiteUrl);
     }
     catch (err) {
       logger.error(err);
@@ -152,11 +160,9 @@ module.exports = (crowi: Crowi): Router => {
   // TODO: Use socket to send progress info to the client
   // eslint-disable-next-line max-len
   router.post('/transfer', accessTokenParser, loginRequiredStrictly, adminRequired, validator.transfer, apiV3FormValidator, async(req: Request, res: ApiV3Response) => {
-    // 1. Ask
-    // 2. Start
-
-    const { transferKey: transferKeyString } = req.body;
+    const { transferKey: transferKeyString, collections } = req.body;
 
+    // Parse transfer key
     let tk: TransferKey;
     try {
       tk = TransferKey.parse(transferKeyString);
@@ -166,51 +172,37 @@ module.exports = (crowi: Crowi): Router => {
       return res.apiv3Err(new ErrorV3('Transfer key is invalid', 'transfer_key_invalid'), 400);
     }
 
-    const canTransfer = await g2gTransferPusherService.canTransfer();
+    // Ask growi info
+    // TODO: Ask progress as well
+    let fromGROWIInfo: IDataGROWIInfo;
+    try {
+      fromGROWIInfo = await g2gTransferPusherService.askGROWIInfo(tk);
+    }
+    catch (err) {
+      logger.error(err);
+      return res.apiv3Err(new ErrorV3('GROWI is incompatible to transfer data.', 'growi_incompatible_to_transfer'));
+    }
 
-    const { appUrl, key } = tk;
+    // Check if can transfer
+    const canTransfer = await g2gTransferPusherService.canTransfer(fromGROWIInfo);
+    if (!canTransfer) {
+      logger.debug('Could not transfer.');
+      return res.apiv3Err(new ErrorV3('GROWI is incompatible to transfer data.', 'growi_incompatible_to_transfer'));
+    }
 
-    // Generate export zip
-    let zipFileStream;
+    // Start transfer
     try {
-      zipFileStream = await g2gTransferPusherService.startTransfer(tk);
+      await g2gTransferPusherService.startTransfer(tk, collections);
     }
     catch (err) {
       logger.error(err);
-      return res.apiv3Err(new ErrorV3('Error occurred while'));
-    }
-
-    // Send a zip file to other growi via axios
-    // (async() => {
-    //   try {
-    //     // TODO: Make zipFileStream work
-    //     await axios.post('/_api/v3/g2g-transfer/', zipFileStream, {
-    //       baseURL: appUrl.origin,
-    //       headers: {
-    //         [X_GROWI_TRANSFER_KEY_HEADER_NAME]: key,
-    //       },
-    //     });
-    //   }
-    //   catch (errs) {
-    //     if (!Array.isArray(errs)) {
-    //       // TODO: socker.emit(failed_to_transfer);
-    //       return;
-    //     }
-
-    //     const err = errs[0];
-
-    //     if (!isG2GTransferError(err)) {
-    //       // TODO: socker.emit(failed_to_transfer);
-    //       return;
-    //     }
-
-    //     const g2gTransferError = err;
-
-    //     logger.error(g2gTransferError);
-    //     // TODO: socker.emit(failed_to_transfer);
-    //     return;
-    //   }
-    // })();
+
+      if (!isG2GTransferError(err)) {
+        return res.apiv3Err(new ErrorV3('Failed to transfer', 'failed_to_transfer'), 500);
+      }
+
+      return res.apiv3Err(new ErrorV3(err.message, err.code), 500);
+    }
 
     return res.apiv3({ message: 'Successfully requested auto transfer.' });
   });

+ 43 - 8
packages/app/src/server/service/g2g-transfer.ts

@@ -1,3 +1,4 @@
+import { createReadStream, ReadStream } from 'fs';
 import { Readable } from 'stream';
 
 import { Types as MongooseTypes } from 'mongoose';
@@ -40,8 +41,9 @@ interface Pusher {
   /**
    * Start transfer data between GROWIs
    * @param {TransferKey} tk TransferKey object
+   * @param {string[]} collections Collection name string array
    */
-  startTransfer(tk: TransferKey): Promise<Readable>
+  startTransfer(tk: TransferKey, collections: string[]): Promise<void>
 }
 
 interface Receiver {
@@ -109,8 +111,45 @@ export class G2GTransferPusherService implements Pusher {
 
   public async transferAttachments(): Promise<void> { return }
 
-  public async startTransfer(tk: TransferKey): Promise<any> {
-    await customAxiosXTar.post('/_api/v3/g2g-transfer/', { whatItShouldBe: 'a zip file' }, this.generateAxiosRequestConfig(tk));
+  public async startTransfer(tk: TransferKey, collections: string[]): Promise<void> {
+    const { appUrl, key } = tk;
+
+    let zipFileStream: ReadStream;
+    try {
+      const shouldEmit = false;
+      const zipFileStat = await this.crowi.exportService.export(collections, shouldEmit);
+      const zipFilePath = zipFileStat.zipFilePath;
+
+      zipFileStream = createReadStream(zipFilePath);
+    }
+    catch (err) {
+      logger.error(err);
+      throw err;
+    }
+
+    // Send a zip file to other growi via axios
+    try {
+      // TODO: Make zipFileStream work
+      await customAxiosXTar.post('/_api/v3/g2g-transfer/', zipFileStream, {
+        baseURL: appUrl.origin,
+        headers: {
+          [X_GROWI_TRANSFER_KEY_HEADER_NAME]: key,
+        },
+      });
+    }
+    catch (errs) {
+      if (!Array.isArray(errs)) {
+        // TODO: socker.emit(failed_to_transfer);
+        return;
+      }
+
+      const err = errs[0];
+      logger.error(err);
+
+
+      // TODO: socker.emit(failed_to_transfer);
+      return;
+    }
   }
 
   private generateAxiosRequestConfig(tk: TransferKey) {
@@ -175,11 +214,7 @@ export class G2GTransferReceiverService implements Receiver {
     return tkd.value;
   }
 
-  public async receive(zippedGROWIDataStream: Readable): Promise<void> {
-    // FIRST, Save from growi data into config
-    // Maybe save status there as well (completed)
-    // Receive a zip file via stream
-    // Unzip
+  public async receive(zipfile: Readable): Promise<void> {
     // Import data
     // Call onCompleteTransfer when finished