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 :发布数据到相应的主题。

ipfs pubsub sub :订阅主题。

下面将通过一个实例说明IPFS Pubsub的使用方法,并动手搭建两个跨越不同网络、不同地域的IPFS节点,通过Pubsub功能进行节点间消息通信。

a) 准备节点环境

对于A节点(本地节点),我们需要进行如下准备:

对于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))进行如下准备。

对B节(亚马逊AWS)进行如下准备。

对C节点(亚马逊AWS)进行如下准备。

对D节点(亚马逊AWS)进行如下准备。

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

$ 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信息输入的元素及承载视频媒体的元素,并设置了对应的CSS样式。

切换至工程根目录,在终端中键入npm install 安装依赖包,键入npm start命令,启动项目预览。

在浏览器中打开http://localhost:8888,如图8-7所示。一个简易的播放器模块效果已经显示在浏览器网页中。

简易流媒体播放器

d) 开发状态栏模块

完成播放器页面模块的编写之后,需要再编写一个状态栏页面模块,通过统一事件流输出,并渲染至页面

文本元素中,来实时观察显示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 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可能不是这场革命的导火索,但是,它至少能带领大家去学习和认识这种思维,这是一件非常有意义的事情。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190818A0GLZF00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券