9012年了,我不允許你還不會玩IPFS!

買賣虛擬貨幣

來源 | 《IPFS原理與實踐》

作者 |  董天一、戴嘉樂、黃禹銘

責編 | Carol

出品 | 區塊鏈大本營(blockchain_camp)

#參與文末討論,有機會免費獲得紙質書籍一本

區塊鏈技術愛好者,應該對IPFS(InterPlanetary File System 星際檔案系統)不陌生。在2018年,EOS和IPFS可謂是火爆到一度霸屏,甚至有人稱IPFS將取代HTTP。

IPFS這門技術誕生於2014年,由協議實驗室(Protocol Labs)建立。但是,直到2017年年中才逐漸走入大眾視野,因為其能與區塊鏈完美結合,所以使得其成為近幾年最火熱的技術之一。

IPFS是在區塊鏈技術蓬勃發展的情況下得到廣泛認可的,但國內卻沒有與IPFS技術相關、利於國人閱讀、知識體系結構相對系統全面的中文學習資料。

本文就IPFS開發基礎上提供了大量的專案例項,這些專案例項能夠幫助讀者更好地理解IPFS技術和應對一些業務場景。

一起開啟IPFS開發進階之路吧!

一、IPFS開發進階

本章內容主要涉及如何在IPFS中釋出動態內容,如何持久儲存IPFS網路中的資料,如何操作MerkleDAG物件,如何利用IPFS Pubsub功能釋出訊息,以及私有IPFS網路的搭建過程。希望讀者在讀完本章內容後,能使IPFS的開發技能得到更多提升。

1.在IPFS中釋出動態內容

3.7節曾介紹過IPFS命名層的設計原理,也介紹了一種能在易變環境中保持固定命名的方案—星際檔案命名系統(IPNS),它允許節點ID為限定的名稱空間提供一個指向具體IPFS檔案或目錄的指標,透過改變這個指標,每次都指向最新的檔案內容,可以使所有查詢請求始終訪問最新的內容。

本節將應用IPNS的方案實現一種能在IPFS中釋出動態內容而不影響命名固定性的方法。

我們透過IPFS命令釋出一個內容,並賦予其動態變化,如下所示:

使用ipfs name publish命令掛載目標檔案。

這裡的QmeUG……是節點ID,可以透過ipfs id驗證。

使用命令ipfs name resolve繫結節點ID資訊。

在瀏覽器中透過IPNS訪問內容驗證效果如下圖所示:

IPNS訪問檔案內容

接下來,我們對test-ipns.txt檔案進行修改,並將其新增到IPFS網路中。

再修改節點ID與IPFS檔案的繫結關係,對映到新的內容檔案上。

我們再次訪問之前的定址路徑http://localhost:8080/ipns/QmeUGXG4K4hbNPbKDUycmNsWrU3nDN69LLgHkWU2yUN6FZ可以看到新版本的內容,如下圖所示:

新版本的test-ipns.txt檔案內容

至此,我們已經實現了一種能在IPFS中釋出動態內容而不影響命名固定性的方法。值得注意的是,節點ID只有一個,假設需要同時保留多個這樣的對映例項,那該怎麼辦?

其實IPNS的對映關係除了節點ID繫結檔案內容,還有一種是透過RSA公鑰繫結檔案內容。透過ipfs key list -l命令可以看到本節點的所有公鑰key值。

由此可見,節點預設具有一個名為self的Key,它的值正是節點ID。ipfs name publish命令的完整形式如下:

是節點ID。如果我們要用新的Key公鑰繫結檔案內容,就需要使用ipfs key gen建立新的RSA公鑰。

嘗試用新的RSA公鑰對映一個新的IPFS檔案內容。

這樣就成功透過新的RSA公鑰繫結檔案內容,並透過IPNS的新公鑰ID形式定址到內容,如下圖所示。

新公鑰繫結的another.txt檔案內容

2.持久儲存IPFS網路資料

在IPFS網路中,固定資源是一個非常重要的概念,類似於一些微信聊天置頂、重要文章內容的收藏或標記等概念。因為IPFS具有快取機制,我們透過ipfs get或ipfs cat對資料資源進行訪問讀取操作後,將使資源短期內保持在本地。但是這些資源可能會定期進行垃圾回收。要防止垃圾回收,需要對其進行ipfs pin(固定)操作。

透過該操作,每個倉庫節點都能將IPFS網路中的資料隨時固定儲存在本地且不被進行垃圾回收,從而在體驗上做到讓使用者感覺每個資源都是從本地讀取的,不像傳統C/S架構從遠端伺服器為使用者檢索這個檔案的場景。

這樣做的好處是,可以提高部署在IPFS檔案系統上眾多應用的資料資源訪問效率,同時保證應用中珍貴資料的全網冗餘度,使其不會因為單點故障和垃圾回收策略而丟失,達到持久儲存IPFS網路資料的效果。

預設情況下,透過ipfs add新增的資源是自動固定在本地倉庫空間的。下面體驗一下IPFS中的固定操作機制。

固定操作機制具有新增、查詢、刪除等功能,我們可以透過ipfs pin ls、ipfs pin rm、ipfs pin ls等具體命令來操作。如下所示,我們透過新建了一個testfile本地資源,並加入IPFS網路,使用ipfs pin ls驗證固定資源的存在性,並透過ipfs pin rm -r遞迴刪除固定資源。

在熟悉了固定操作機制的具體用法後,檢視資料資源固定前後垃圾回收情況的對比效果。

3.操作IPFS Merkle DAG

Merkle Tree和有向無環圖DAG技術是IPFS的核心概念,也是Git、Bitcoin和Dat等技術的核心。在IPFS檔案系統中,資料的儲存結構大部分足以MerkleDAG的形式構成,第2章對MerkleDAG、MerkleTree、DAG概念的原理和內在區別有過專門的介紹,本節重點介紹如何操作IPFS中的MerkleDAG物件。

這部分知識在基於IPFS上構建更細粒度的資料型應用需求時(例如:分散式資料庫、分散式版本控制軟體),顯得尤為重要。

a)建立Merkle DAG結構

本節準備了一張大於256KB的樣例圖merkle-tree-demo.jpg(863KB),來作為講解案例,如下所示。常用的ipfs add命令將預設為檔案建立MerkleDAG結構物件。

透過ipfs object links -v命令,可以驗證MerkleDAG的建立情況,並從內部檢視該檔案的MerkleDAG結構資訊和子物件資訊。

如下圖所示,與檔案merkle-tree-demo.jpg對應的內容雜湊QmUNqu是DAG結構中根塊的雜湊包含了4個子塊,子塊和根塊形成了一種樹狀結構,且同時具有Merkle Tree和DAG結構的特性,因此被稱為Merkle DAG。

IPFS Merkle DAG結構

b) 組裝子塊資料

我們可以透過ipfs cat命令來讀取整個檔案的內容,也可以單獨讀取每個Merkle DAG塊的內容,按照特定需求手動拼接子塊資料,更細粒度地控制原始檔或者原始檔的資料內容。

如下所示,我們將QmPH、QmPC、QmS7、QmQQ子塊資料透過ipfs cat命令重新組裝成了新影象manually-rebuilt-tree-in-cosmos.jpg。

當然,圖片的拼合只是一個很小的案例,我們可以針對不同業務來活用子塊資料重組的功能。比如,想要製作一個語音密碼身份校驗系統,可以將校驗碼音訊資料分為多個子塊A、B、C、D,透過AB子塊重新組裝出的子塊資料可以校驗一級身份,透過ABC重新組裝出的子塊資料可以校驗二級身份,透過ABCD組裝出的全塊資料可以校驗最高階身份。

c)塊與物件的區別

在IPFS中,塊(Block)指的是由其金鑰(雜湊)標識的單個資料單元。塊可以是任何型別的資料,並且不一定具有與之關聯的任何格式。

而物件(Object)是指遵循Merkle DAG Protobuf資料格式的塊。它可以透過ipfs object命令解析和操作,ipfs object資訊包含了除Block塊資訊外更多的資料資訊,包括物件的links數量、塊大小、資料大小等。

而且,任何給定的雜湊可以標識物件資訊,也可以標識塊資訊。如下所示,我們可以透過ipfs block stat和ipfs object stat命令來檢視Merkle DAG塊和物件資料資訊的區別。

d)操作Block

當我們在處理一些小資料的時候,可以不必透過ipfs add檔案切片的形式,而是直接操作IPFS塊結構來進行資料的新增。尤其在處理海量小檔案的場景需求下,可以顯著提高處理效率,如下所示:

e) 操作Object

在c小節介紹了IPFS物件的定義。如下所示,我們可以透過ipfs object命令來直接操作DAG物件,以實現塊資料和物件的資訊查詢、修改新增等效果。

值得注意的是:IPFS Object的分片思想和Block分片類似,檔案儲存於Block之中,預設超出256KB會自動觸發分片機制,生成新Block。而對於Object而言,預設子物件Links數量值超過174個也將生成新Object。如下所示:

當然,除了上述幾種常用的物件操作示例外,還有很多關於ipfs object的用法、功能等待我們發掘,我們可以在實際開發中,根據自身需求動手嘗試。

4. IPFS Pubsub功能的使用

Pubsub,Publish-subscribe pattern釋出訂閱模式,最早是由蘋果公司在 Mac OS中引入的。即訊息的傳送者(publisher)不直接將訊息傳送給接收者(subscriber),而是將訊息分成多個類別,傳送者並不知道也無須知道接收者的存在。

而接收者只需要訂閱一個或多個類別的訊息類,只接收感興趣的訊息,不知道也無須知道釋出者的存在。

寫程式碼的朋友對於觀察者模式(Observer)並不陌生。Pubsub類似於軟體設計模式中的觀察者模式,但又不完全相同,Pubsub比Observer更加松耦合。

Pubsub功能目前還屬於IPFS的一個實驗性質的功能,如果要開啟Pubsub功能,在啟動ipfs daempon的時候需要指定引數:--enable-pubsub-experiment。

Pubsub相關的命令如下。

  • ipfs pubsub ls:列出本節點訂閱的全部主題。

  • ipfs pubsub peers:列出與本節點相連線的開通pubsub功能的節點。

  • ipfs pubsub pub <topic> <data>:釋出資料到相應的主題。

  • ipfs pubsub sub <topic>:訂閱主題。

下面將透過一個例項說明IPFS Pubsub的使用方法,並動手搭建兩個跨越不同網路、不同地域的IPFS節點,透過Pubsub功能進行節點間訊息通訊。

a) 準備節點環境

對於A節點(本地節點),我們需要進行如下準備:

  • IPFS節點ID:QmTrRNgt6M9syRq8ZqM4o92Fgh6avK8v862n2QZLyDPywY

  • IPFS地址:192.168.162.129(保護隱私,沒有使用公網IP)

對於B節點(亞馬遜AWS),我們需要進行如下準備:

  • IPFS地址:13.231.198.154

  • IPFS節點地址:/ip4/13.231.198.154/tcp/4001/ipfs/QmXL2h6Y51BHZMaypzjCnNc1MiVk2H5EZJxWgAuRkLanaK

b)啟動節點B

啟動B節點的方法如下:

ipfs daemon --enable-pubsub-experiment

注意這裡需要使用引數 –enable-pubsub-experiment。

c) 將節點A與B直連

刪除節點A全部的bootstrap地址。

ipfs bootstrap rm all

在A節點處新增B節點為bootstrap節點。

ipfs bootstrap add

/ip4/13.231.198.154/tcp/4001/ipfs/QmXL2h6Y51BHZMaypzjCnNc1MiVk2H5EZJxWgAuRkLanaK

d) 啟動節點A

啟動A節點的方法如下:

ipfs daemon --enable-pubsub-experiment

同上,需要使用引數 –enable-pubsub-experiment。

e) Pubsub訊息

在A節點上新開一個命令列,執行如下命令:

localhost:aws tt$ ipfs pubsub sub IPFS-Book

上述命令的含義是,我們在節點A訂閱了訊息主題:IPFS-Book。凡是發往這個訊息主題的訊息都會被A節點接收。

在B節點對訊息主題 IPFS-Book傳送以下訊息:

ubuntu@ip-172-31-22-177:$ ipfs pubsub pub IPFS-Book

"Author:TianyiDong,JialeDai,YumingHuang!"

這時候就可以在A節點的命令列看到如下訊息輸出:

Author:TianyiDong,JialeDai,YumingHuang!

localhost:aws tt$ ipfs pubsub sub IPFS-Book

Author:TianyiDong,JialeDai,YumingHuang!

我們看到了兩個跨越不同網路、不同地域的IPFS節點進行Pubsub功能的通訊。實際上,Pubsub功能不只限於兩個直連的節點間,還可以透過中間節點進行中轉。

例如:有A、B、C三個節點,A連線到B,B連線到C,A與C並不直接連線,那麼A仍然可以訂閱並且收到來自於C的訊息。這在一些複雜的網路環境裡面非常有用,比如一些NAT不太友好的網路環境。

Pubsub的功能有很多用途,目前IPFS上有兩個標杆應用是基於Pubsub功能進行搭建的,一個是分散式資料庫orbit-db,一個是點對點的聊天工具Orbit。大家也可以發揮自己的想象,將這項功能使用在更多應用場景中。

5. 私有IPFS網路的搭建與使用

我們知道HTTP可以搭建專屬私網,那麼IPFS是否也可以搭建自己的私有網路呢?答案是肯定的。本節我們將學習IPFS私有網路的搭建步驟和私有網路的傳輸效果。

要想搭建一個私有網路,首先需要進行網路環境的前期準備,這裡計劃使用3臺雲主機和一臺本地機器來進行構建。同時,生成私網金鑰,隔離與外網環境的通訊。之後,驗證網路的連通情況,並在私網中進行檔案傳輸測試,觀察傳輸效果。

a) 環境準備

對A節點(本地節點(Mac))進行如下準備。

  • IP:動態IP。

  • IPFS節點ID:QmTrRNgt6M9syRq8ZqM4o92Fgh6avK8v862n2QZLyDPywY。

對B節(亞馬遜AWS)進行如下準備。

  • IP:13.230.162.124。

  • IPFS節點ID:QmRQH6TCCq1zpmjdPKg2m7BrbVvkJ4UwnNHWD6ANLqrdws。

對C節點(亞馬遜AWS)進行如下準備。

  • IP:13.231.247.2。

  • IPFS節點ID:QmTTEkgUpZJypqw2fXKagxFxxhvoNsqfs5YJ9zHLBoEE29。

對D節點(亞馬遜AWS)進行如下準備。

  • IP:13.114.30.87。

  • IPFS節點ID:Qmc2AH2MkZtwa11LcpHGE8zW4noQrn6xue7VcZCMNYTpuP。

b) 共享金鑰

私有網路所有的節點必須共享同一個金鑰,首先使用金鑰建立工具建立一個金鑰,該工具的安裝下載需要使用Go環境。關於Go語言的安裝此處不過多介紹,可以登入Go語言官網下載安裝配置。

go get -u http://github.com/Kubuxu/go-ipfs-swarm-key-gen/ipfs-swarm-key-gen

建立金鑰:

ipfs-swarm-key-gen > ~/.ipfs/swarm.key

建立完成後,將金鑰檔案放在自己的IPFS預設配置資料夾中(~/.ipfs/)。

c) 上傳金鑰至節點

使用了scp上傳金鑰檔案至遠端伺服器。

d)新增啟動節點

執行ipfs init命令後預設啟動的節點是連線IPFS公網的節點。如果要連線私有網路,在每一個節點執行如下操作,刪除所有的預設啟動節點。

ipfs bootstrap rm -all

然後新增一個自己的預設節點(私有網路中的一個節點),預設節點可以是A、B、C、D中的任何一個。

我們選取D節點作為啟動節點,在A、B、C節點執行如下操作,把D節點的地址新增到A、B、C節點中。

e)啟動並檢視各個節點

配置好各自的節點資訊後,分別啟動各個節點,並透過ipfs swarm peers命令檢視節點彼此的線上連通情況。A節點成功繫結並連線上B、C、D節點,如圖7-5所示。

A節點成功與其他節點相連

B節點成功繫結並連線上A、C、D節點,如圖7-6所示。

B節點成功與其他節點相連

C節點成功繫結並連線上A、B、D節點,如圖7-7所示。

C節點成功與其他節點相連

D節點已成功繫結並連線上A、B、C節點,如圖7-8所示。

D節點成功與其他節點相連

我們發現4個節點相互連在了一起,這就是我們的私有IPFS網路。下面將在私有網路中做一些簡單的測試,看看私有網路的效能到底如何。

在本地節點A上新增資料。

在其他幾個節點處下載資料。

從上面的測試可以看出,我們首先在本地節點(位於中國的北京)上add了檔案QmbZ……。然後在亞馬遜的伺服器節點(位於日本東京區域)進行檔案下載,150MB的檔案在B、C節點上下載使用了2分58秒,而在D節點上下載僅用了2秒。

這是因為B、C節點設定了同時啟動ipfs get來從A下載檔案,而D節點等前面B、C節點下載完成後才啟動ipfs get命令。D節點透過從A、B、C節點分別非同步傳輸進行下載,且B、C節點都在亞馬遜機房,內網傳輸會使速度快上加快,所以D節點下載該檔案瞬間完成。

透過本節的介紹可以看見,運用IPFS搭建的私有網路對於一些大型企業內部的資料分發和加速會是一個很好的應用點。

本章小結

本章我們學習了更多關於IPFS進階開發的案例,也透過這些案例帶著大家熟悉了更多IPFS命令的使用。我們可以基於IPFS釋出動態內容,持久化儲存資料,直接操作Merkle DAG物件,利用Pubsub實現訊息訂閱,以及搭建專屬IPFS私有網路等。

相信在閱讀完本章內容後,你已經能體會到IPFS不僅是一個檔案儲存系統,它還自帶很多強大的功能和應用特性。基於這些,我們可以充分發揮自己的想象,構建屬於自己的上層應用。下一章將基於此,拋磚引玉,為大家開發兩個實戰應用。

二、IPFS專案實戰

掌握了IPFS的基本原理和使用方法之後,我們即將進入實戰環節。我們將透過兩個工程專案,分別為大家介紹如何基於go-ipfs最佳化Git分散式服務,以及如何利用js-ipfs搭建流媒體播放器。

我們將整合更多前後端技術參與應用開發,並引導讀者在實踐案例中更加靈活地使用IPFS技術。

1. 利用go-ipfs最佳化Git分散式服務

Git是目前世界上最流行的分散式版本控制系統,用於敏捷高效地處理任何專案。它與常用的版本控制工具CVS、Subversion等不同,它採用了分散式版本庫的方式,在本地即可支援大部分的控制操作,凡是進行軟體工程研發的工作人員應該都熟悉這個工具。

在平常的開發工作中,我們除了要使用本地Git服務外,還經常需要同步資料至遠端倉庫,這樣有利於備份工程檔案和團隊協作。

基於這種場景,我們會自己搭建並維護一臺Git伺服器作為私有遠端倉庫使用。當然,如果覺得自己搭建比較煩瑣,為了便捷,也可使用類似Github、CitLab這類的第三方雲平臺來管理。

本專案期望將我們之前常維護在私有伺服器或第三方雲平臺上的Git遠端倉庫下沉部署到端側,並透過IPFS網路分發倉庫映象,快速、便捷地實現一個無伺服器架構(Serverless)的Git叢集。對於團隊來說,成員的工作空間既可以作為本地倉庫,也可以作為服務於其他成員的Git Server,這也將充分擴大Git系統的分散式服務效果,避免第三方雲平臺帶來的成本開銷和資料安全隱患。

接下來,我們藉助go-ipfs來搭建一個更加分散式化的版本控制服務模型,如下圖所示。

基於IPFS的Git分散式版本控制服務模型

a)依賴安裝

在開始工程之前,我們需要先確保在本地已安裝好了以下兩個重要的工具:Git和go-ipfs。go-ipfs的具體安裝過程可以參考第6章,這裡不再詳細描述,主要介紹一下Git的安裝過程。

登入Git的官方網站https://git-scm.com/downloads ,讀者根據自身的作業系統選擇對應版本,下載Git工具的安裝包。

如果是Mac OSX系統的使用者,也可以透過brew包管理工具進行安裝。

brew install git

如果是Centos系統的使用者,也可以透過yum包管理工具進行安裝。

yum install git

本專案安裝的依賴版本資訊如下:

- git version 2.16.0 - go-ipfs version 0.4.17

b) 初始化Git倉庫

首先,我們可以新建或者從遠端抓取一個我們想要掛載在IPFS網路中的Git倉庫。本專案將以名為ipfs-md-wiki的遠端倉庫為例。

這裡選取了一個之前託管在Github上的程式碼倉庫ipfs-md-wiki作為本例中的遷移物件,如下圖所示。

首先透過git clone --bare命令將遠端倉庫(Remote)的裸倉庫複製到本地,裸倉庫是一個不包含當前工作目錄的倉庫,因為即將掛載到IPFS中的Git倉庫將作為服務共享的角色,模擬Git伺服器。

同時,對於一個bare型Git裸倉庫,想要透過HTTP的方式以便其他人獲取和複製,還需要配置一個特定的PoSt-update hook,Git附帶的PoSt-update hook會預設執行命令git update-server-info來確保倉庫能被複制和使用。

倉庫遷移物件例項

$ cd ipfs-md-wiki.git

$ git update-server-info

之後,我們開啟Git倉庫物件包,將大的packfile分解成所有的單獨物件,以便Git倉庫中存在多分支版本情況時,也能一一被IPFS網路識別並新增。

$ cp objects/pack/*.pack .

$ git unpack-objects < ./*.pack

$ rm ./*.pack

c)IPFS網路掛載

本地倉庫環境準備好了之後,剩下要做的就是把它新增到IPFS檔案系統中,併發布至IPFS網路中更多線上節點上。

我們已經將ipfs-md-wiki.git新增到了本地IPFS檔案倉庫中,並獲取其對應的CID資訊:“QmS...ny”。接下來,我們還需要做的就是將CID為“QmS...ny”的內容釋出至IPFS網路中的更多節點上。具體有如下兩種方式。

1)透過新節點pin add

我們按照之前的方式,再部署一個新的IPFS節點,並啟動daemon程序,透過ipfs pin add QmS..ny命令掛載一份Git Remote倉庫服務。

當然,這種透過新節點pin add的方式往往需要我們自己維護,以保障新節點的穩定性。這樣做和自己部署多個Git Remote至多臺伺服器的效果類似,並沒有完全利用到IPFS網路的便捷性。

那麼,接下來,我們將介紹另一種方式,來提升最佳化優勢。

2)透過第三方閘道器掛載

IPFS內建了以HTTP形式對外提供介面服務的功能,而對於很多提供了閘道器服務的第三方IPFS節點(如:配置檔案Bootstrap中的官方節點、Cloudflare的全球CDN節點、Infura的測試節點等),都會預設響應外部HTTP的請求而主動掛載資料。我們可以開啟瀏覽器,透過HTTP Get請求一些主流的第三方閘道器服務。

  • https://cloudflare-ipfs.com/ipfs/QmS..ny

  • https://ipfs.io/ipfs/QmS..ny

  • https://ipfs.infura.io/ipfs/QmS..ny

效果類似第三方節點主動發起ipfs get以及ipfs pin add操作。

最後,當我們將Git Remote CID資訊釋出至多個IPFS網路節點後,我們可以透過ipfs dht findprovs命令根據CID資訊來反向查詢節點資訊,從而驗證Git Remote目前的分散式部署情況。

d)用Git從IPFS網路克隆倉庫

現在,我們用Git工具,對剛才新增進IPFS網路中的Git Remote倉庫進行克隆操作。

我們將抓取到本地的倉庫重新命名為ipfs-md-wiki-repo,以便和遠端倉庫ipfs-md-wiki做區分。比較下方的圖1和圖2,我們檢視一下ipfs-md-wiki-repo的倉庫結構,和原先託管於Github的原遠端倉庫對比,資料一致性得到了很好的保障,工程檔案也均同步過來了。

至此,我們利用go-ipfs最佳化了Git分散式服務模型。如果未來大部分Git的倉庫工程檔案都廣泛地部署於IPFS網路之中,那將會誕生很多有意思的場景。

例如:當我們在編寫程式碼程式時候,匯入的依賴庫經常使用的是Git原始碼庫,而且原始碼庫經常會因其他人的提交而改變,從而影響我們本地的開發環境編譯。如下面的例子:

圖1 ipfs-md-wiki-repo本地倉庫結構

圖2 ipfs-md-wiki遠端倉庫結構

這是一個Go語言的程式塊,執行的是匯入依賴包的命令,透過本專案所搭建的Git分散式服務模型,用IPFS的CID指紋唯一標識了每個版本的Git原始碼庫,可以避免一些變更風險。需要更新版本時,也可根據CID來自由切換、指定匯入。

8.2 基於js-ipfs搭建一個流媒體播放系統

在上一節中,我們嘗試利用go-ipfs最佳化現有的Git倉庫模型。本節我們將解析官方例項,介紹如何基於js-ipfs(星際檔案系統的另一個協議實現庫)來搭建一個輕量級的流媒體影片Web應用。如今,已經是短影片和直播應用的天下,我們將在這一節探索一下如何利用IPFS技術服務流媒體資料。

a) 構建Node.js開發環境

在進行本專案開發之前,我們需要先準備一下基礎開發環境,大部分依賴在於前端,我們為此需要先行安裝Node.js開發環境。

Node.js是一個事件驅動I/O的服務端JavaScript環境,基於Google的V8引擎,執行JavaScript的速度非常快,效能非常好。它釋出於2009年5月,由Ryan Dahl開發,其並不是一個JavaScript框架,不同於CakePHP、Django、Rails;更不是瀏覽器端的庫,不能與 jQuery、ExtJS 相提並論。

Node.js是一個讓JavaScript執行在服務端的開發平臺,它讓JavaScript成為像PHP、Python、Perl、Ruby等服務端指令碼語言一樣,用來開發服務端應用程式。

Node.js的下載安裝十分簡單、快速,靈活,如圖8-5所示。我們可以在Node.js的官網下載適合自己作業系統的安裝包:

https://nodejs.org/zh-cn/download/

安裝完成後,我們可以在終端中鍵入npm -v和node -v來驗證環境是否部署成功。如下所示。本專案採用的是6.4.1版本的npm包管理工具和11.0.0的Node.js環境。

Node.js下載

之後,新建專案資料夾video-stream-ipfs,並在資料夾根目錄下透過npm init命令建立專案描述檔案package.json。

本例專案目錄結構如下所示:

b)使用Webpack構建專案

什麼是Webpack?Webpack可以看作模組打包機,它做的事情是分析你的專案結構,找到JavaScript模組及其他的一些瀏覽器不能直接執行的拓展語言(如Scss、TypeScript等),並將其轉換和打包為合適的格式供瀏覽器使用。

如下圖所示,Webpack的工作方式是:把你的專案當作一個整體,透過一個給定的主檔案(如:index.js),Webpack將從這個檔案開始找到你的專案的所有依賴檔案,使用loaders處理它們,最後打包為一個(或多個)瀏覽器可識別的JavaScript檔案。

Webpack的工作方式

1) Webpack配置工程

在開始之前,請確保安裝了Node.js的長期支援版本(Long Term Support,LTS)。若使用舊版本,可能將遇到因缺少Webpack相關Package包而出現的問題。

在本例中,我們考慮到用CLI這種方式來執行本地的Webpack不是特別方便,我們將在package.json中新增Webpack的devDependencies和npm script來安裝和啟動Webpack,同時也指定專案執行指令碼命令、構建命令,以及分配測試環境網路埠。

Webpack會假定專案的入口起點為src/index,然後在dist/main.js輸出結果,並且在生產環境開啟壓縮和最佳化,開箱即用,可以無須使用任何配置檔案。我們可以在專案根目錄下建立一個webpack.config.js檔案來深度定製配置,Webpack會自動使用它。本專案的webpack.config.js配置如下:

=

c) 開發播放器模組

本小節將開始動手開發基於瀏覽器的播放器模組,播放器模組主要由影片源輸入框、播放響應按鈕、影片播放視窗三部分組成。首先,我們在入口檔案index.html中編寫播放器模組的前端元素和樣式程式碼。

至此,我們已經編寫了好了id值為container、支援拖拽上傳媒體檔案的塊元素容器,並在塊元素容器中引入了id值為gobutton的播放響應按鈕、承載CID資訊輸入的<input>元素及承載影片媒體的<video>元素,並設定了對應的CSS樣式。

切換至工程根目錄,在終端中鍵入npm install 安裝依賴包,鍵入npm start命令,啟動專案預覽。

在瀏覽器中開啟http://localhost:8888,如圖8-7所示。一個簡易的播放器模組效果已經顯示在瀏覽器網頁中。

簡易流媒體播放器

d) 開發狀態列模組

完成播放器頁面模組的編寫之後,需要再編寫一個狀態列頁面模組,透過統一事件流輸出,並渲染至頁面<pre>文字元素中,來實時觀察顯示IPFS網路的連線狀態及流媒體的播放狀態。我們將在index.html中新增如下程式碼:

同時,我們需要統一事件流的輸出格式。為此,我們新建utils.js檔案和箭頭函式log(),並將工具函式都集合在utils.js中管理。

log()函式的職能是將所傳入的訊息資料統一換行顯示在pre頁面元素之下。

至此,狀態列頁面模組也已經準備完成,待主邏輯事件開發完成後,就能看到圖8-8所示的狀態列效果,即可以實時顯示IPFS網路的連線狀態及流媒體的播放狀態。

狀態列頁面模組

e) 引入js-ipfs模組

js-ipfs於2018年年中釋出,這是一個完全用JavaScript編寫、可以執行在Node.js和Web瀏覽器之上的完整實現,是除了Go語言實現版本之外,蘊含IPFS所有特性和功能最為完整的原生庫,如下方圖1所示。它為開發者在瀏覽器及Web應用中整合IPFS協議、啟動、執行、操作IPFS節點提供了強有力的支援。

這也是本專案的重點模組,我們將使用js-ipfs來讀寫和存取流媒體資料,並在Web瀏覽器中播放。

我們可以透過npm包管理工具來快速安裝js-ipfs。

本例中整合的是0.33.1版本,其他版本可以在 https://github.com/ipfs/js-ipfs中獲取到。

圖1 js-ipfs

f)實現拖拽上傳

在utils.js中定義箭頭函式drapDrop(),職能是處理拖放檔案至瀏覽器之中的響應事件,並將檔案新增至IPFS中。

g)從IPFS中讀取流媒體至播放器

在index.js中定義全域性業務流程,職能是初始化IPFS服務,初始化拖放方法,並設定從IPFS中讀取流媒體至瀏覽器播放器的按鈕事件。

h)處理流媒體播放狀態

在utils.js中定義箭頭函式createVideoElement(),職能是在頁面<video>元素內設定針對不同播放器狀態(如播放、暫停、等待、載入、結束等)事件的監聽響應,並將所有狀態進行輸出顯示在狀態列之中。當獲取到流媒體資料時,設定video DOM開始播放,當產生錯誤時,捕獲並輸出。

i)開發總結

至此,基於js-ipfs的流媒體播放系統的核心模組已經搭建完成。我們可以試著切換至工程根目錄,重新執行專案。

在瀏覽器中開啟http://localhost:8888,播放器效果如下圖所示。我們可以透過瀏覽器視窗拖拽上傳流媒體檔案(例如:test.mp4)至IPFS,獲取其對應的CID資訊,顯示在播放器中,並透過CID資訊從IPFS中讀取流資料至瀏覽器中,實時控制播放狀態和流資料狀態。

基於js-ipfs的流媒體播放器效果演示

希望透過對這個專案的講解,讓大家瞭解js-ipfs在前端專案中的使用方式,尤其注意如何使用videoStream和ReadableStream將影片資料從IPFS中動態寫入和讀出。如果大家需要下載原始碼舉一反三,可以在官方例項中獲取,網址如下:

https://github.com/ipfs/js-ipfs/tree/master/examples/browser-readablestream

本章總結

IPFS協議最早是由Go語言完整實現的,go-ipfs也是目前為止迭代最頻繁、使用最多的原生庫。

在本章第2個實戰專案中,特意補充了js-ipfs原生庫的知識,這是一個完全由JavaScript編寫、可以執行在Node.js和Web瀏覽器之上的完整實現,於2018年年中釋出。它是除了Go語言實現版本之外,蘊含IPFS特性和功能最為完整的原生庫。

在這一章裡,我們分別基於go-ipfs和js-ipfs兩個不同的IPFS原生庫,設計了兩個不同型別的實戰專案,一個是利用go-ipfs對既有系統進行最佳化,另一個是利用js-ipfs獨立開發流媒體Web應用。

希望讀者透過對本章內容的學習,可以親自上手使用IPFS相關技術進行程式設計開發,在專案實踐中加深對IPFS知識的功能和用法的理解。

IPFS這門技術還在不斷演化中,它引導的是一場真正的網路協議革命,是一種全球化思維的碰撞,是一種突破傳統的海量資料共享的模式。IPFS可能不是這場革命的導火索,但是,它至少能帶領大家去學習和認識這種思維,這是一件非常有意義的事情。

你對IPFS有什麼理解或實戰經驗?歡迎留言告訴我們,營長將選出3條精選留言,免費送書3本!!!截止時間8月22日中午12點哦~

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;