Browse Source

integrate with ipfs backend storage

Mokhtar Naamani 5 years ago
parent
commit
78e908117c

+ 2 - 1
packages/joy-media/package.json

@@ -8,11 +8,12 @@
   "maintainers": [],
   "dependencies": {
     "@babel/runtime": "^7.4.3",
+    "@polkadot/joy-utils": "^0.1.1",
     "@polkadot/ui-app": "^0.31.0-beta.18",
     "@types/mime-types": "^2.1.0",
-    "@polkadot/joy-utils": "^0.1.1",
     "aplayer": "^1.10.1",
     "dplayer": "^1.25.0",
+    "ipfs-only-hash": "^1.0.2",
     "mime-types": "^2.1.22",
     "react-aplayer": "^1.0.0",
     "react-dplayer": "^0.2.3"

+ 1 - 1
packages/joy-media/src/EditMeta.tsx

@@ -235,7 +235,7 @@ function withGetContentIdFromUrl (Component: React.ComponentType<OuterProps>) {
   return function (props: UrlHasContentIdProps) {
     const { match: { params: { assetName } } } = props;
     try {
-      const contentId = ContentId.fromAddress(assetName);
+      const contentId = ContentId.decode(assetName);
       return <Component contentId={contentId} />;
     } catch (err) {
       return <em>Invalid content ID: {assetName}</em>;

+ 10 - 6
packages/joy-media/src/Upload.tsx

@@ -19,6 +19,7 @@ import { MyAccountProps, withOnlyMembers } from '@polkadot/joy-utils/MyAccount';
 import { DiscoveryProviderProps } from './DiscoveryProvider';
 import EditMeta from './EditMeta';
 import TxButton from '@polkadot/joy-utils/TxButton';
+import IpfsHash from 'ipfs-only-hash';
 
 const MAX_FILE_SIZE_MB = 100;
 const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024;
@@ -28,6 +29,7 @@ type Props = ApiProps & I18nProps & MyAccountProps & DiscoveryProviderProps;
 type State = {
   error?: any,
   file?: File,
+  ipfs_cid?: string,
   newContentId: ContentId,
   discovering: boolean,
   uploading: boolean,
@@ -167,7 +169,7 @@ class Component extends React.PureComponent<Props, State> {
     </div>;
   }
 
-  private onFileSelected = (data: Uint8Array, file: File) => {
+  private onFileSelected = async (data: Uint8Array, file: File) => {
     if (!data || data.length === 0) {
       this.setState({ error: `You cannot upload an empty file.` });
     } else if (data.length > MAX_FILE_SIZE_BYTES) {
@@ -175,19 +177,21 @@ class Component extends React.PureComponent<Props, State> {
         `You cannot upload a file that is more than ${MAX_FILE_SIZE_MB} MB.`
       });
     } else {
+      const ipfs_cid = await IpfsHash.of(Buffer.from(data));
+      console.log('computed IPFS hash:', ipfs_cid)
       // File size is valid and can be uploaded:
-      this.setState({ file });
+      this.setState({ file, ipfs_cid });
     }
   }
 
   private buildTxParams = () => {
-    const { file, newContentId } = this.state;
-    if (!file) return [];
+    const { file, newContentId, ipfs_cid } = this.state;
+    if (!file || !ipfs_cid) return [];
 
     // TODO get corresponding data type id based on file content
     const dataObjectTypeId = new BN(1);
 
-    return [ newContentId, dataObjectTypeId, new BN(file.size) ];
+    return [ newContentId, dataObjectTypeId, new BN(file.size), ipfs_cid];
   }
 
   private onDataObjectCreated = async (_txResult: SubmittableResult) => {
@@ -226,7 +230,7 @@ class Component extends React.PureComponent<Props, State> {
     const { file, newContentId, cancelSource } = this.state;
     if (!file) return;
 
-    const contentId = newContentId.toAddress();
+    const contentId = newContentId.encode();
     const config = {
       headers: {
         // TODO uncomment this once the issue fixed:

+ 5 - 5
packages/joy-media/src/View.tsx

@@ -69,7 +69,7 @@ class InnerView extends React.PureComponent<ViewProps> {
 
     const asset = {
       iAmOwner,
-      contentId: this.props.contentId.toAddress(),
+      contentId: this.props.contentId.encode(),
       data: dataObjectOpt.unwrap(),
       meta
     };
@@ -219,7 +219,7 @@ class InnerPlay extends React.PureComponent<PlayProps, PlayState> {
   async resolveAsset () {
     const { discoveryProvider, api } = this.props;
     const { match: { params: { assetName } } } = this.props;
-    const contentId = ContentId.fromAddress(assetName);
+    const contentId = ContentId.decode(assetName);
 
     if (!contentId) {
       this.setState({
@@ -254,10 +254,10 @@ class InnerPlay extends React.PureComponent<PlayProps, PlayState> {
       }
 
       try {
-        var resolvedAssetUrl = await discoveryProvider.resolveAssetEndpoint(provider, contentId.toAddress(), cancelSource.token)
+        var resolvedAssetUrl = await discoveryProvider.resolveAssetEndpoint(provider, contentId.encode(), cancelSource.token)
       } catch (err) {
         if (axios.isCancel(err)){
-          break;
+          return;
         } else {
           continue;
         }
@@ -270,7 +270,7 @@ class InnerPlay extends React.PureComponent<PlayProps, PlayState> {
         return
       } catch (err) {
         if (axios.isCancel(err)){
-          break;
+          return;
         } else {
           // try next provider
           continue;

+ 1 - 1
packages/joy-types/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@joystream/types",
-  "version": "0.2.0",
+  "version": "0.2.1",
   "description": "Joystream types for Substrate modules",
   "main": "lib/index.js",
   "scripts": {

+ 14 - 23
packages/joy-types/src/media.ts

@@ -4,39 +4,25 @@ import { OptionText } from './';
 
 import { randomAsU8a } from '@polkadot/util-crypto';
 import { encodeAddress, decodeAddress } from '@polkadot/keyring';
-import { u8aToString, stringToU8a } from '@polkadot/util';
+// import { u8aToString, stringToU8a } from '@polkadot/util';
 
 export class ContentId extends Hash {
-
   static generate (): ContentId {
     // randomAsU8a uses https://www.npmjs.com/package/tweetnacl#random-bytes-generation
     return new ContentId(randomAsU8a());
   }
 
-  /** This function is for backward-compatibility with content ids that were generated as UUID. */
-  // TODO Delete this backward-compatibility when a new version of blockchain launched.
-  static isUuidFormat (contentId: string | Uint8Array): boolean {
-    return typeof contentId === 'string'
-        ? contentId.indexOf('-') > 0
-        : contentId.indexOf('-'.charCodeAt(0)) > 0;
-  }
-
-  static fromAddress (contentId: string): ContentId {
-    return new ContentId(
-      ContentId.isUuidFormat(contentId)
-        ? stringToU8a(contentId)
-        : decodeAddress(contentId)
-    );
+  static decode (contentId: string): ContentId {
+    return new ContentId(decodeAddress(contentId));
   }
 
-  static toAddress (contentId: Uint8Array): string {
-    return ContentId.isUuidFormat(contentId)
-      ? u8aToString(contentId)
-      : encodeAddress(contentId);
+  static encode (contentId: Uint8Array): string {
+    // console.log('contentId:', Buffer.from(contentId).toString('hex'))
+    return encodeAddress(contentId);
   }
 
-  toAddress (): string {
-    return ContentId.toAddress(this);
+  encode (): string {
+    return ContentId.encode(this);
   }
 }
 
@@ -171,7 +157,8 @@ export class DataObject extends Struct {
       type_id: DataObjectTypeId,
       size: u64,
       liaison: AccountId,
-      liaison_judgement: LiaisonJudgement
+      liaison_judgement: LiaisonJudgement,
+      ipfs_content_id: Text,
     }, value);
   }
 
@@ -199,6 +186,10 @@ export class DataObject extends Struct {
   get liaison_judgement (): LiaisonJudgement {
     return this.get('liaison_judgement') as LiaisonJudgement;
   }
+
+  get ipfs_content_id () : Text {
+    return this.get('ipfs_content_id') as Text
+  }
 }
 
 export class DataObjectStorageRelationship extends Struct {

+ 1 - 0
src/@types/ipfs-only-hash/index.d.ts

@@ -0,0 +1 @@
+declare module 'ipfs-only-hash';

+ 2 - 1
tsconfig.json

@@ -68,7 +68,8 @@
     },
     "typeRoots": [
       "./node_modules/@polkadot/ts",
-      "./node_modules/@types"
+      "./node_modules/@types",
+      "src/@types"
     ]
   }
 }

File diff suppressed because it is too large
+ 613 - 11
yarn.lock


Some files were not shown because too many files changed in this diff