Bladeren bron

storage-node: cli: Introduce BaseCommand class.

Shamil Gadelshin 4 jaren geleden
bovenliggende
commit
809c194245

+ 21 - 0
storage-node/packages/cli/src/commands/base.ts

@@ -0,0 +1,21 @@
+// Composes an asset URL and logs it to console.
+import chalk from "chalk";
+import removeEndingForwardSlash from "@joystream/storage-utils/stripEndingSlash";
+
+// Commands base abstract class. Contains reusable methods.
+export abstract class BaseCommand {
+    // Creates the Colossus asset URL and logs it.
+    protected createAndLogAssetUrl(url: string, contentId: string): string {
+        const normalizedUrl = removeEndingForwardSlash(url);
+        const assetUrl = `${normalizedUrl}/asset/v0/${contentId}`;
+        console.log(chalk.yellow('Generated asset URL:', assetUrl));
+
+        return assetUrl;
+    }
+
+    // Shows the error message and ends the process with error code.
+    protected fail(message: string) {
+        console.log(chalk.red(message));
+        process.exit(1);
+    }
+}

+ 0 - 18
storage-node/packages/cli/src/commands/common.ts

@@ -1,18 +0,0 @@
-// Composes an asset URL and logs it to console.
-import chalk from "chalk";
-import removeEndingForwardSlash from "@joystream/storage-utils/stripEndingSlash";
-
-// Creates the Colossus asset URL and logs it.
-export function createAndLogAssetUrl(url: string, contentId: string) : string {
-    const normalizedUrl = removeEndingForwardSlash(url);
-    const assetUrl = `${normalizedUrl}/asset/v0/${contentId}`;
-    console.log(chalk.yellow('Generated asset URL:', assetUrl));
-
-    return assetUrl;
-}
-
-// Shows the error message and ends the process with error code.
-export function fail(message: string) {
-    console.log(chalk.red(message));
-    process.exit(1);
-}

+ 8 - 5
storage-node/packages/cli/src/commands/download.ts

@@ -1,15 +1,18 @@
 import axios from "axios";
 import chalk from "chalk"
 import fs from "fs";
-import {fail, createAndLogAssetUrl} from "./common";
+import {BaseCommand} from "./base";
 
-export class DownloadCommand {
+// Download command class. Validates input parameters and execute the logic for asset downloading.
+export class DownloadCommand extends BaseCommand{
     private readonly api: any;
     private readonly storageNodeUrl: string;
     private readonly contentId: string;
     private readonly filePath: string;
 
     constructor(api: any, storageNodeUrl: string, contentId: string, filePath: string) {
+        super();
+
         this.api = api;
         this.storageNodeUrl = storageNodeUrl;
         this.contentId = contentId;
@@ -33,13 +36,13 @@ export class DownloadCommand {
         if (!this.validateDownloadParameters(this.storageNodeUrl, this.contentId, this.filePath)) {
             return this.showDownloadUsage();
         }
-        const assetUrl = createAndLogAssetUrl(this.storageNodeUrl, this.contentId);
+        const assetUrl = this.createAndLogAssetUrl(this.storageNodeUrl, this.contentId);
         console.log(chalk.yellow('File path:', this.filePath));
 
         // Create file write stream and set error handler.
         const writer = fs.createWriteStream(this.filePath)
             .on('error', (err) => {
-                fail(`File write failed: ${err}`);
+                this.fail(`File write failed: ${err}`);
             });
 
         // Request file download.
@@ -59,7 +62,7 @@ export class DownloadCommand {
                 });
             });
         } catch (err) {
-            fail(`Colossus request failed: ${err.message}`);
+            this.fail(`Colossus request failed: ${err.message}`);
         }
     }
 }

+ 7 - 4
storage-node/packages/cli/src/commands/head.ts

@@ -1,13 +1,16 @@
 import axios from "axios";
 import chalk from "chalk"
-import {fail, createAndLogAssetUrl} from "./common";
+import {BaseCommand} from "./base";
 
-export class HeadCommand {
+// Head command class. Validates input parameters and obtains the asset headers.
+export class HeadCommand extends BaseCommand{
     private readonly api: any;
     private readonly storageNodeUrl: string;
     private readonly contentId: string;
 
     constructor(api: any, storageNodeUrl: string, contentId: string) {
+        super();
+
         this.api = api;
         this.storageNodeUrl = storageNodeUrl;
         this.contentId = contentId;
@@ -29,7 +32,7 @@ export class HeadCommand {
         if (!this.validateHeadParameters(this.storageNodeUrl, this.contentId)) {
             return this.showHeadUsage();
         }
-        const assetUrl = createAndLogAssetUrl(this.storageNodeUrl, this.contentId);
+        const assetUrl = this.createAndLogAssetUrl(this.storageNodeUrl, this.contentId);
 
         try {
             const response = await axios.head(assetUrl);
@@ -38,7 +41,7 @@ export class HeadCommand {
             console.log(chalk.green(`Content length: ${response.headers['content-length']}`));
 
         } catch (err) {
-            fail(`Colossus request failed: ${err.message}`);
+            this.fail(`Colossus request failed: ${err.message}`);
         }
     }
 }

+ 16 - 13
storage-node/packages/cli/src/commands/upload.ts

@@ -4,7 +4,7 @@ import ipfsHash from "ipfs-only-hash";
 import { ContentId, DataObject } from '@joystream/types/media';
 import BN from "bn.js";
 import { Option } from '@polkadot/types/codec';
-import {fail, createAndLogAssetUrl} from "./common";
+import {BaseCommand} from "./base";
 import {discover} from "@joystream/service-discovery/discover";
 import Debug from "debug";
 const debug = Debug('joystream:storage-cli:upload');
@@ -22,7 +22,8 @@ interface AddContentParams {
     memberId: number
 }
 
-export class UploadCommand {
+// Upload command class. Validates input parameters and uploads the asset to the storage node and runtime.
+export class UploadCommand extends BaseCommand{
     private readonly api: any;
     private readonly mediaSourceFilePath: string;
     private readonly dataObjectTypeId: string;
@@ -37,6 +38,8 @@ export class UploadCommand {
                 passPhrase: string,
                 memberId: string
     ) {
+        super();
+
         this.api = api;
         this.mediaSourceFilePath = mediaSourceFilePath;
         this.dataObjectTypeId = dataObjectTypeId;
@@ -49,7 +52,7 @@ export class UploadCommand {
     async computeIpfsHash(): Promise<string> {
         const file = fs.createReadStream(this.mediaSourceFilePath)
             .on('error', (err) => {
-                fail(`File read failed: ${err}`);
+                this.fail(`File read failed: ${err}`);
             });
 
         return await ipfsHash.of(file);
@@ -68,12 +71,12 @@ export class UploadCommand {
 
         let dataObjectTypeId: number = parseInt(this.dataObjectTypeId);
         if (isNaN(dataObjectTypeId)) {
-            fail(`Cannot parse dataObjectTypeId: ${this.dataObjectTypeId}`);
+            this.fail(`Cannot parse dataObjectTypeId: ${this.dataObjectTypeId}`);
         }
 
         let memberId: number = parseInt(this.memberId);
         if (isNaN(dataObjectTypeId)) {
-            fail(`Cannot parse memberIdString: ${this.memberId}`);
+            this.fail(`Cannot parse memberIdString: ${this.memberId}`);
         }
 
         return {
@@ -99,12 +102,12 @@ export class UploadCommand {
             );
 
             if (dataObject.isNone) {
-                fail("Cannot create data object: got None object");
+                this.fail("Cannot create data object: got None object");
             }
 
             return dataObject.unwrap();
         } catch (err) {
-            fail(`Cannot create data object: ${err}`);
+            this.fail(`Cannot create data object: ${err}`);
         }
     }
 
@@ -113,7 +116,7 @@ export class UploadCommand {
         // Create file read stream and set error handler.
         const file = fs.createReadStream(this.mediaSourceFilePath)
             .on('error', (err) => {
-                fail(`File read failed: ${err}`);
+                this.fail(`File read failed: ${err}`);
             });
 
         // Upload file from the stream.
@@ -130,7 +133,7 @@ export class UploadCommand {
 
             console.log("File uploaded.");
         } catch (err) {
-            fail(err.toString());
+            this.fail(err.toString());
         }
     }
 
@@ -140,7 +143,7 @@ export class UploadCommand {
             const serviceInfo = await discover(storageProviderId, this.api);
 
             if (serviceInfo === null) {
-                fail("Storage node discovery failed.");
+                this.fail("Storage node discovery failed.");
             }
             debug(`Discovered service info object: ${serviceInfo}`);
 
@@ -149,7 +152,7 @@ export class UploadCommand {
 
             return assetWrapper.asset.endpoint;
         } catch (err) {
-            fail(`Could not get asset endpoint: ${err}`);
+            this.fail(`Could not get asset endpoint: ${err}`);
         }
     }
 
@@ -158,7 +161,7 @@ export class UploadCommand {
         try {
             await fs.promises.access(this.keyFile);
         } catch (error) {
-            fail(`Cannot read file "${this.keyFile}".`)
+            this.fail(`Cannot read file "${this.keyFile}".`)
         }
 
         return this.api.identities.loadUnlock(this.keyFile, this.passPhrase);
@@ -177,7 +180,7 @@ export class UploadCommand {
         let colossusEndpoint = await this.discoverStorageProviderEndpoint(dataObject.liaison.toString());
         debug(`Discovered storage node endpoint: ${colossusEndpoint}`);
 
-        let assetUrl = createAndLogAssetUrl(colossusEndpoint, addContentParams.contentId);
+        let assetUrl = this.createAndLogAssetUrl(colossusEndpoint, addContentParams.contentId);
         await this.uploadFile(assetUrl);
     }
 }