分散型IPFS音楽プレーヤーの作成







この記事では、IPFSを使用した2か月の実験の結果について説明します。 これらの実験の主な結果は、メタデータ(アルバム名、トラックリスト、カバー)で始まり、オーディオファイルで直接終わる分散IPFSネットワークで公開された情報のみに基づいて音楽ライブラリを作成できる概念実証ストリーミングオーディオプレーヤーの作成でした。







したがって、デスクトップ電子アプリケーションであるため、プレーヤーは集中リソースに依存しません。







IPFS



仕組み



一見したところ、このテクノロジーはBitTorrent、DC、git、ブロックチェーンのクロスに似ています。 2番目は、IPFSが上記のプロトコルのいずれかのオブジェクトを保存および配布できることを明らかにしています。







まず、IPFSは、データを交換するコンピューターのピアツーピアネットワークです。 その形成のために、さまざまなネットワーク技術の組み合わせが使用され、個別のlibp2pプロジェクトの一部として開発されています。 各コンピューターには特別なキャッシュがあり、しばらくの間、ユーザーが公開またはダウンロードしたデータが保存されます。 IPFSキャッシュの情報はブロックに保存され、デフォルトでは固定されていません。 十分なスペースがなくなると、ローカルガベージコレクターは、長時間アクセスされていないブロックをクリーンアップします。 固定/固定解除メソッドは、キャッシュ内の情報を固定/固定解除します。







ブロックごとに、そのコンテンツの一意の暗号化フィンガープリントが計算され、IPFSスペースでこのコンテンツへのリンクとして機能します。 ブロックを結合してマークルツリーオブジェクトを作成することができ、そのノードには独自のフィンガープリントがあり、下位ノード/ブロックのフィンガープリントに基づいて計算されます。 ここから最も興味深いことが始まります。







IPLD-DAG



IPFSは、IPLD(InterPlanetary Linked Data)と呼ばれる多数の小規模なプロトコルラボプロジェクトで構成されています。 本質を正しく説明できるかどうかはわかりませんので興味のある人のために仕様へのリンクを残します。







つまり、前の段落で説明したアーキテクチャは非常に柔軟であるため、ブロックチェーン、unixライクなファイルシステム、gitリポジトリなど、より複雑な構造を再作成するために使用できます。 このために、適切なインターフェース/プラグインが使用されます。







これまでのところ、通常のJSONオブジェクトをIPFSに公開できるdag



インターフェイスのみを使用してきました。







 const obj = { simple: 'object' } const dagParams = { format: 'dag-cbor', hashAlg: 'sha3-512' } const cid = await ipfs.dag.put(obj, dagParams)
      
      





成功すると、コンテンツ識別子(CID)オブジェクトが返され、その中に公開された情報の一意のフィンガープリントと、それをさまざまな形式に変換するメソッドが格納されます。 これにより、ベース文字列を取得できます。







 const cidString = cid.toBaseEncodedString() console.log(cidString) // zdpuAzE1oAAMpsfdoexcJv6PmL9UhE8nddUYGU32R98tzV5fv
      
      





この行は、 get



メソッドを使用してデータを取得するために使用できます。 同時に、使用されるデータ形式と暗号化アルゴリズムに関する情報が行に含まれているため、追加のパラメーターは必要ありません。







 const obj = await ipfs.dag.get(cidString) console.log(obj.value) // { // simple: 'object' // }
      
      





もっともっと。 2番目のオブジェクトを公開できます。フィールドの1つは最初のオブジェクトを参照します。







 const obj2 = { complex: 'object', link: { '/' : cidString // cid-   } } const cid2 = await ipfs.dag.put(obj2, dagParams) const cid2String = cid2.toBaseEncodedString()
      
      





obj2を取り戻そうとすると、特別なパラメーターが反対を指定しない限り、すべての内部リンクが解決されます。







 const obj2 = await ipfs.dag.get(cid2String) console.log(obj2.value) // { // complex: "object", // link: { // "simple" : "object" // } // }
      
      





個々のフィールドの値を要求できます。そのためには、CIDフィールドに/_



field_nameという形式の接尾辞を追加する必要があります。







 const result = await ipfs.dag.get(cid2String+"/complex") console.log(result.value) // object
      
      





したがって、他のオブジェクトへのリンクを含むオブジェクト全体を、あたかも1つの大きなオブジェクトであるかのように「歩く」ことができます。 リンクはコンテンツの暗号化ハッシュであるため、オブジェクトにはそれ自体へのリンクを含めることはできません。







IPLDの概念は、他のDAGオブジェクトだけでなく、他のIPLD構造も参照できることを意味します。 したがって、オブジェクトの1つのフィールドはgitコミットを参照でき、もう1つのフィールドはビットコイントランザクションを参照できます。


パブ/サブ



pubsub



インターフェースは、計画された機能の実装において基本的な役割を果たしました。 これを使用すると、特別な回線キーで結合されたp2p-roomsにサブスクライブし、メッセージを送信して見知らぬ人を受信できます。







 const topic = ' ' const receiveMsg = (msg) => { //      } await ipfs.pubsub.subscribe(topic, receiveMsg) const msg = new Buffer('') await ipfs.pubsub.publish(topic, msg)
      
      





最初のpubsubベースのアプリの1つは、ircに似たp2pチャット軌道でした(もしそうなら、 まだ動作しています)。 チャンネルを購読し、メッセージを受信すると、ストーリーは参加者間に保存され、徐々に「忘れられて」しまいます。 インターネット全体のこのようなvypress。







IPFSのgoバージョンとjsバージョンの両方で、pubsubインターフェイスはまだ実験的な技術と見なされているため、特別なパラメーターによって有効になります。


アイデア



オーディオ愛好家の生活のある時点で、私は長い間Google Musicだけで音楽を聴いていました。 そして、電話だけでなく、すでにデスクトップ上でも。 いくつかの理由がありますが、主な理由は、同じ急流と比較して、ほとんどの日常の状況で「聞きたい」と「聞く」間のクリック数が大幅に少ないことです。 2番目の理由は、利用可能な音楽ライブラリのサイズです。 ごくまれに、探しているものが見つかりません(多くの場合、地域の制限に適合しています)。 しかし、これはトレントに対する利点ではなく、他のストリーミングサービスにとっては利点です。













分散データソースのみに基づいた使い勝手の良いアプリケーションを作成できるかどうかが不思議になりました。 時間が経つにつれて、このタスクが実行可能になる2つの主な条件が策定されました。









BitTorrentエコシステムでは、誰かが何かをダウンロードしたい場合、ほとんどの場合、最初にtorrentディレクトリ(通常のドメインの下の通常のIPの背後にある通常のサーバーにある通常のサイト)にアクセスする必要があります。 最初の条件は、アプリケーションが集中型リソースを使用せずにローカルデータベースを自動的に作成できるようにするために必要です。







2番目の条件が最も重要です。 その実装には、分散ネットワークの参加者によって公開された情報が、事前に知られている残りのモデル/スキームに従って作成される必要があります。 これにより、分散データスペースを検索およびフィルタリングシステムで使用できるようになり、その有効性が向上します。







判明したように、IPFSを使用すると、これらの両方の条件を非常に効果的に提供できます。







実装



今日、「グラモフォン」は、原始的なプレーヤー音楽ライブラリです。 ほとんどすべての機能があります:









出版物から始めましょう。 前の章で、分散ネットワーク内の情報を何らかの方法で標準化する方法について説明しました。 「Gramophone」では、アルバムのjsonスキームによってこのタスクが達成されます。







 const albumSchema = { type: "object", properties: { title: { type: "string" }, artist: { type: "string" }, cover: { type: "string" }, tracks: { type: "array" items: { type: "object", properties: { title: { type: "string" }, artist: { type: "string" }, hash: { type: "string" } } } } } }
      
      





このスキームに従って、特定のインスタンスがチェックされてから公開されます。 通常の入力フォームがこれを担当します。













最初は、公開はファイルシステムから直接行われると想定されていました。 データの標準化は、特別な.meta



ファイルを使用して.meta



ます。このファイルには、インスタンスに必要なすべてのプロパティと関係が記述されます。 しかし、少し実験して、アプリケーション自体のインターフェイスを介してこれを行うと、より便利で、視覚的で、効率的になるという結論に達しました。













重要な詳細-添付ファイルはipfs.files.add()



を使用してipfs.files.add()



公開されます。 返されるCIDは、対応する入力に個別の行として挿入されます。 ファイルが手元にない場合でも入力は残されますが、そのCIDは既知です。

フォームに入力し、「ADD ALBUM」を押すと、最終的なJSONデータが最初にスキームに準拠しているかどうかがチェックされ、次にDAGインターフェイスを使用して公開されます。その後、受信したCIDは特別なpubsubルームのバッファーとして送信されます







 const isValid = validateAlbumObj(albumObj) //       if (isValid) { const albumCid = await ipfs.dag.put(albumObj, dagParams) //      dag await ipfs.pubsub.publish(albumSchemaCidString, albumCid.buffer) //  CID   pubsub    }
      
      





明らかな解決策は、アプリケーション内でネットワークを分離する場合、ルームキーとして「アルバム」、「音楽アルバム」、または極端な場合には「パスフォン」などを使用することです。 しかし、その後、もっと賢いアイデアが思い浮かびました-アルバムのjson-schemeのCID文字列をキーとして使用すること。 最終的に、アプリケーションのすべてのコピーを真に統合するのはデータスキーマです。 さらに、受信したすべてのメッセージにこのスキームの検証済みインスタンスが含まれることを期待できるのはこの部屋からです。







 const handleReceivedMessage = async (message) => { try { const { data, from } = message // data -   , from - id  const cid = new CID(data).toBaseEncodedString() // ,     CID-,     CID-      base- const { value } = await ipfs.dag.get(cid) const isValid = validateAlbumObj(value) //        if (isValid) { // value -   ,    ,    } else { throw new Error('invalid schema instance received') } } catch (error) { //   } } const albumSchemaCid = await ipfs.dag.put(albumSchema, dagParams) const albumSchemaCidString = albumSchemaCid.toBaseEncodedString() await ipfs.pubsub.subscribe( albumSchemaCidString, handleReceivedMessage )
      
      





ご覧のとおり、各「到着」オブジェクトはスキームへの準拠をチェックされます。これは、キーを知っているネットワーク参加者に誰も干渉せず、意図的に部屋にあふれ始めるためです。 同時に、キーの一意性により、偶発的な干渉の可能性が最小限に抑えられます。 一方、他のアプリケーションがGramophoneと同じスキームの使用を開始すると、それらは同じデータスペースを形成して使用し始めます。これはプラスになる可能性があります。







括弧の中には、オブジェクトをデータベースに保存するなど、アプリケーション固有のものがいくつかありました。







あるコンピューターでアルバムを公開し、別のコンピューターでアルバムを取得するプロセスは、ビデオで見ることができます 。 速度はほぼ瞬時ですが、多くの要因に依存します。 コンピューターが同じ「群れ」になっていないため、転送を完了できない場合がありました。


メタビンゲート



上記のすべてを@metabin/gate



と呼ばれるnpmモジュールとして説明しました。 詳細を隠し、開発者はipfsノードとjsonスキームを渡すだけにします。







 const gate = await openGate( ipfsNode, //   js-ipfs  js-ipfs-api schema //  json-schema, (instance, cid) => { // instance -     // cid - base-encoded   } ) await gate.send(instance) //   await gate.close()
      
      





結論



IPFSは、分散情報交換のための最も先進的な技術の1つです。 両方のバージョン(およびgoおよびjavascript)がアルファ段階にあるという事実にもかかわらず、それらはOpenBazaarやd.tubeなどの比較的人気のあるアプリケーションで既に使用されています。 もう1つは、主にファイルストレージとしてのみ使用することです。







これは、IPFSが主にBitTorrentの一種として考えられていることを考えると理解できます。 IPLDの概念と対応するインターフェイスの機能が注目されることはめったにありません。 私の意見では、これはプロトコルラボの最も有望な開発であり、IPFSを介して通常のデータオブジェクトを配布することを可能にします。







そして、 files



dag



、およびpubsub



インターフェースを簡単な方法で組み合わせることにより、開発者は自分のアプリケーション用の無料の自己組織化データソースを取得します。 Electronを追加して、かなり魅力的な技術スタックを取得します。









もちろん、すべてのアプリケーションがこのような自律性を必要とするわけではありません。コンテンツの制御を失うことになります。 これらすべてが非常に実験的な分野であるという事実は言うまでもありません。 そのようなネットワークがどのようにスケーリングするか、生産性にどのように影響するか、このプロセスに影響を与えることができるかどうか-多くの質問があり、それ以上に定式化されていません。







それにもかかわらず、好奇心をそそる機会と展望が開かれています。







参照資料






All Articles