Browse Source

storage node: cli: Convert upload command to class.

Shamil Gadelshin 4 years ago
parent
commit
49149da050
2 changed files with 139 additions and 127 deletions
  1. 4 2
      storage-node/packages/cli/src/cli.ts
  2. 135 125
      storage-node/packages/cli/src/commands/upload.ts

+ 4 - 2
storage-node/packages/cli/src/cli.ts

@@ -27,7 +27,7 @@ import _ from "lodash"
 import * as dev from "./commands/dev"
 import {HeadCommand} from "./commands/head";
 import {DownloadCommand} from "./commands/download";
-import * as uploadCommand from "./commands/upload";
+import {UploadCommand} from "./commands/upload";
 
 
 // Parse CLI
@@ -134,7 +134,9 @@ const commands = {
   },
 
   upload: async (api: any, filePath: string, dataObjectTypeId: string, keyFile: string, passPhrase: string, memberId: string) => {
-    await uploadCommand.run(api, filePath, dataObjectTypeId, keyFile, passPhrase, memberId)
+    let uploadCmd = new UploadCommand(api, filePath, dataObjectTypeId, keyFile, passPhrase, memberId);
+
+    await uploadCmd.run();
   },
   // needs to be updated to take a content id and resolve it a potential set
   // of providers that has it, and select one (possibly try more than one provider)

+ 135 - 125
storage-node/packages/cli/src/commands/upload.ts

@@ -12,22 +12,6 @@ const debug = Debug('joystream:storage-cli:upload');
 // Defines maximum content length for the assets (files). Limits the upload.
 const MAX_CONTENT_LENGTH = 500 * 1024 * 1024; // 500Mb
 
-// Reads the file from the filesystem and computes IPFS hash.
-async function computeIpfsHash(filePath: string): Promise<string> {
-    const file = fs.createReadStream(filePath)
-        .on('error', (err) => {
-            fail(`File read failed: ${err}`);
-        });
-
-    return await ipfsHash.of(file);
-}
-
-// Read the file size from the file system.
-function getFileSize(filePath: string): number {
-    const stats = fs.statSync(filePath);
-    return stats.size;
-}
-
 // Defines the necessary parameters for the AddContent runtime tx.
 interface AddContentParams {
     accountId: string,
@@ -38,136 +22,162 @@ interface AddContentParams {
     memberId: number
 }
 
-// Creates parameters for the AddContent runtime tx.
-async function getAddContentParams(
-    api: any,
-    filePath: string,
-    dataObjectTypeIdString: string,
-    keyFile: string,
-    passPhrase: string,
-    memberIdString: string
-): Promise<AddContentParams> {
-    const identity = await loadIdentity(api, keyFile, passPhrase);
-    const accountId = identity.address;
-
-    let dataObjectTypeId: number = parseInt(dataObjectTypeIdString);
-    if (isNaN(dataObjectTypeId)) {
-        fail(`Cannot parse dataObjectTypeId: ${dataObjectTypeIdString}`);
+export class UploadCommand {
+    private readonly api: any;
+    private readonly mediaSourceFilePath: string;
+    private readonly dataObjectTypeId: string;
+    private readonly keyFile: string;
+    private readonly passPhrase: string;
+    private readonly memberId: string;
+
+    constructor(api: any,
+                mediaSourceFilePath: string,
+                dataObjectTypeId: string,
+                keyFile: string,
+                passPhrase: string,
+                memberId: string
+    ) {
+        this.api = api;
+        this.mediaSourceFilePath = mediaSourceFilePath;
+        this.dataObjectTypeId = dataObjectTypeId;
+        this.keyFile = keyFile;
+        this.passPhrase = passPhrase;
+        this.memberId = memberId;
     }
 
-    let memberId: number = parseInt(memberIdString);
-    if (isNaN(dataObjectTypeId)) {
-        fail(`Cannot parse memberIdString: ${memberIdString}`);
+    // Reads the file from the filesystem and computes IPFS hash.
+    async computeIpfsHash(): Promise<string> {
+        const file = fs.createReadStream(this.mediaSourceFilePath)
+            .on('error', (err) => {
+                fail(`File read failed: ${err}`);
+            });
+
+        return await ipfsHash.of(file);
     }
 
-    return {
-        accountId,
-        ipfsCid: await computeIpfsHash(filePath),
-        contentId: ContentId.generate().encode(),
-        fileSize: new BN(getFileSize(filePath)),
-        dataObjectTypeId,
-        memberId
-    };
-}
+    // Read the file size from the file system.
+    getFileSize(): number {
+        const stats = fs.statSync(this.mediaSourceFilePath);
+        return stats.size;
+    }
 
-// Creates the DataObject in the runtime.
-async function createContent(api: any, p: AddContentParams) : Promise<DataObject> {
-    try {
-        const dataObject: Option<DataObject> = await api.assets.createDataObject(
-            p.accountId,
-            p.memberId,
-            p.contentId,
-            p.dataObjectTypeId,
-            p.fileSize,
-            p.ipfsCid
-        );
-
-        if (dataObject.isNone) {
-            fail("Cannot create data object: got None object");
+    // Creates parameters for the AddContent runtime tx.
+    async getAddContentParams(): Promise<AddContentParams> {
+        const identity = await this.loadIdentity();
+        const accountId = identity.address;
+
+        let dataObjectTypeId: number = parseInt(this.dataObjectTypeId);
+        if (isNaN(dataObjectTypeId)) {
+            fail(`Cannot parse dataObjectTypeId: ${this.dataObjectTypeId}`);
         }
 
-        return dataObject.unwrap();
-    } catch (err) {
-        fail(`Cannot create data object: ${err}`);
-    }
-}
+        let memberId: number = parseInt(this.memberId);
+        if (isNaN(dataObjectTypeId)) {
+            fail(`Cannot parse memberIdString: ${this.memberId}`);
+        }
 
-// Uploads file to given asset URL.
-async function uploadFile(assetUrl: string, filePath: string) {
-    // Create file read stream and set error handler.
-    const file = fs.createReadStream(filePath)
-        .on('error', (err) => {
-            fail(`File read failed: ${err}`);
-        });
-
-    // Upload file from the stream.
-    try {
-        const fileSize = getFileSize(filePath);
-        const config: AxiosRequestConfig = {
-            headers: {
-                'Content-Type': '', // https://github.com/Joystream/storage-node-joystream/issues/16
-                'Content-Length': fileSize.toString()
-            },
-            'maxContentLength': MAX_CONTENT_LENGTH,
+        return {
+            accountId,
+            ipfsCid: await this.computeIpfsHash(),
+            contentId: ContentId.generate().encode(),
+            fileSize: new BN(this.getFileSize()),
+            dataObjectTypeId,
+            memberId
         };
-        await axios.put(assetUrl, file, config);
-
-        console.log("File uploaded.");
-    } catch (err) {
-        fail(err.toString());
     }
-}
 
-// Requests the runtime and obtains the storage node endpoint URL.
-async function discoverStorageProviderEndpoint(api: any, storageProviderId: string) : Promise<string> {
-    try {
-        const serviceInfo = await discover(storageProviderId, api);
+    // Creates the DataObject in the runtime.
+    async createContent(p: AddContentParams): Promise<DataObject> {
+        try {
+            const dataObject: Option<DataObject> = await this.api.assets.createDataObject(
+                p.accountId,
+                p.memberId,
+                p.contentId,
+                p.dataObjectTypeId,
+                p.fileSize,
+                p.ipfsCid
+            );
+
+            if (dataObject.isNone) {
+                fail("Cannot create data object: got None object");
+            }
+
+            return dataObject.unwrap();
+        } catch (err) {
+            fail(`Cannot create data object: ${err}`);
+        }
+    }
 
-        if (serviceInfo === null) {
-            fail("Storage node discovery failed.");
+    // Uploads file to given asset URL.
+    async uploadFile(assetUrl: string) {
+        // Create file read stream and set error handler.
+        const file = fs.createReadStream(this.mediaSourceFilePath)
+            .on('error', (err) => {
+                fail(`File read failed: ${err}`);
+            });
+
+        // Upload file from the stream.
+        try {
+            const fileSize = this.getFileSize();
+            const config: AxiosRequestConfig = {
+                headers: {
+                    'Content-Type': '', // https://github.com/Joystream/storage-node-joystream/issues/16
+                    'Content-Length': fileSize.toString()
+                },
+                'maxContentLength': MAX_CONTENT_LENGTH,
+            };
+            await axios.put(assetUrl, file, config);
+
+            console.log("File uploaded.");
+        } catch (err) {
+            fail(err.toString());
         }
-        debug(`Discovered service info object: ${serviceInfo}`);
+    }
 
-        const dataWrapper = JSON.parse(serviceInfo);
-        const assetWrapper = JSON.parse(dataWrapper.serialized);
+    // Requests the runtime and obtains the storage node endpoint URL.
+    async discoverStorageProviderEndpoint(storageProviderId: string): Promise<string> {
+        try {
+            const serviceInfo = await discover(storageProviderId, this.api);
 
-        return assetWrapper.asset.endpoint;
-    }catch (err) {
-        fail(`Could not get asset endpoint: ${err}`);
-    }
-}
+            if (serviceInfo === null) {
+                fail("Storage node discovery failed.");
+            }
+            debug(`Discovered service info object: ${serviceInfo}`);
+
+            const dataWrapper = JSON.parse(serviceInfo);
+            const assetWrapper = JSON.parse(dataWrapper.serialized);
 
-// Loads and unlocks the runtime identity using the key file and pass phrase.
-async function loadIdentity(api, filename, passphrase) : Promise<any> {
-    try {
-        await fs.promises.access(filename);
-    } catch (error) {
-        fail(`Cannot read file "${filename}".`)
+            return assetWrapper.asset.endpoint;
+        } catch (err) {
+            fail(`Could not get asset endpoint: ${err}`);
+        }
     }
 
-    return api.identities.loadUnlock(filename, passphrase);
-}
+    // Loads and unlocks the runtime identity using the key file and pass phrase.
+    async loadIdentity(): Promise<any> {
+        try {
+            await fs.promises.access(this.keyFile);
+        } catch (error) {
+            fail(`Cannot read file "${this.keyFile}".`)
+        }
+
+        return this.api.identities.loadUnlock(this.keyFile, this.passPhrase);
+    }
 
 
-// Command executor.
-export async function run(
-    api: any,
-    filePath: string,
-    dataObjectTypeId: string,
-    keyFile: string,
-    passPhrase: string,
-    memberId: string
-){
-    let addContentParams = await getAddContentParams(api, filePath, dataObjectTypeId, keyFile, passPhrase, memberId);
-    debug(`AddContent Tx params: ${JSON.stringify(addContentParams)}`);
-    debug(`Decoded CID: ${ContentId.decode(addContentParams.contentId).toString()}`);
+    // Command executor.
+    async run() {
+        let addContentParams = await this.getAddContentParams();
+        debug(`AddContent Tx params: ${JSON.stringify(addContentParams)}`);
+        debug(`Decoded CID: ${ContentId.decode(addContentParams.contentId).toString()}`);
 
-    let dataObject = await createContent(api, addContentParams);
-    debug(`Received data object: ${dataObject.toString()}`);
+        let dataObject = await this.createContent(addContentParams);
+        debug(`Received data object: ${dataObject.toString()}`);
 
-    let colossusEndpoint = await discoverStorageProviderEndpoint(api, dataObject.liaison.toString());
-    debug(`Discovered storage node endpoint: ${colossusEndpoint}`);
+        let colossusEndpoint = await this.discoverStorageProviderEndpoint(dataObject.liaison.toString());
+        debug(`Discovered storage node endpoint: ${colossusEndpoint}`);
 
-    let assetUrl = createAndLogAssetUrl(colossusEndpoint, addContentParams.contentId);
-    await uploadFile(assetUrl, filePath);
+        let assetUrl = createAndLogAssetUrl(colossusEndpoint, addContentParams.contentId);
+        await this.uploadFile(assetUrl);
+    }
 }