区块天下 区块链新闻 精通IPFS:IPFS 保存内容之下篇

精通IPFS:IPFS 保存内容之下篇

put

来保存 DAG 节点。

ipld.put(node, {        version: cidVersion,        hashAlg: hashAlg,        format: codec    }, (error, cid) => {    callback(error, {        cid,        node    })})

下面我们来看 put方法,看它是怎么来保存 DAG 对象的。它的主体是调用内部方法获取当前 DAG 对象编码用的格式,然后使用与这种格式相匹配的cid方法来取得对象的 CID 对象,然后调用内部的_put来保存数据。

this._getFormat(options.format, (err, format) => {  if (err) return callback(err)

format.util.cid(node, options, (err, cid) => { if (err) { return callback(err) }

if (options.onlyHash) {  return callback(null, cid)}

this._put(cid, node, callback)

  })})

接下来,我们来看这个内部

_put

方法,这个方法主体是一个

waterfall

函数,它内部的几个函数分别根据 CID 对象获得对应的编码格式,然后使用编码格式对应的方法序列化 DAG 节点对象,最后生成区块

Block

对象,并调用区块服务对象的

put

方法来保存区块。

区块服务对象定义于 ipfs-block-service 库,它的 put方法,根据是否有 bitswap 对象(初始化是这个对象为空)来决定是调用仓库对象来保存区块,还是调用 bitswap 来保存区块。对于我们的例子来说,它会调用 bitswap 来保存区块。

bitswap 对象的 put方法,不仅会把区块保存在底层的 blockstore 中,还会把它发送给那些需要它的节点。它的主体是一个waterfall函数,其中第一个函数检查本地区块存储是否有这个区块,第二个根据本地是否有这个区块来确定是否忽略调用,还是真正来保存区块。

waterfall([  (cb) => this.blockstore.has(block.cid, cb),  (has, cb) => {    if (has) {      return nextTick(cb)    }
this._putBlock(block, cb)
  }], callback)

bitswap 对象的

_putBlock

方法调用区块存储对象的

put

方法在本地仓库中保存区块对象,并在成功之后触发一个收到区块的事件,同时通过网络对象的

provide

方法,从而把 CID 保存在最近的节点中,然后调用引擎对象的

receivedBlocks

方法,把接收到的区块对象发送到所有想要这个区块的所有节点中。

this.blockstore.put(block, (err) => {  if (err) {    return callback(err)  }

this.notifications.hasBlock(block) this.network.provide(block.cid, (err) => { if (err) { this._log.error('Failed to provide: %s', err.message) } })

this.engine.receivedBlocks([block.cid]) callback})

bitswap 对象中有两个重要的对象,一个是网络对象,一个是引擎对象。

网络对象的 provide方法直接调用 libp2p 对象的内容路由的同名方法来处理区块的 CID。libp2p 对象的内容路由中保存所有具体的路由方法,默认情况下,是空的,即没有任何路由方法,而我们通过在配置文件中,指定libp2p.config.dht.enabled为真,为内容路由指定了 DHT 路由,所以最终区块的 CID 会被保存在最合适的节点中。

网络对象在初始方法中,指定了自身的两个方法作为 libp2p 对象的节点连接与断开事件的处理器,从而在连接与断开时获得相应的通知,并且还调用了 libp2p 对象的 handle方法,从而使自己成为 libp2p 对象/ipfs/bitswap/1.0.0/ipfs/bitswap/1.1.0这两种协义的处理对象,从而当 libp2p 收到这两种消息时,会调用网络对象对象的相应方法进行处理。

网络对象处理 bitswap 协义是通过 pull函数处理的,大致流程如下:从连接对象中获取消息,然后反序列化成为消息对象,然后通过连接对象获取它的节点信息对象,再然后调用 bitswap 对象的内部方法_receiveMessage处理传递进来的消息,而这个方法又会调用引擎对象的messageReceived方法来处理接收到的消息。

引擎对象的 messageReceived方法的大致流程如下:

1)调用内部方法 _findOrCreate,找到或创建远程对等节点的总账本对象 Ledger,如果是新创建的总账本对象,还要放入内部映射集合中,key 为远程对等节点的 Base58 字符串;

2)如果这个消息是完全的消息,则生成一个新的想要请求列表。

3)调用内部方法 _processBlocks,处理消息中的区块对象。

4)如果消息中的想要列表为空的,则退出方法。

5)遍历消息中的想要列表,如果当前想要的实体被取消,则从对应的节点的总账本中去掉对应项,同时保存在取消项列表中;否则,把当前项保存在对应节点的总账本中,同时保存在想要列表中。

6)调用内部方法 _cancelWants,把任务中已经取消的过滤掉,即删除任务中已经取消的任务。

7)调用内部方法 _addWants,处理远程对等节点所有想要的列表。调用区块存储对象判断想要的项本地仓库中是否已经有,如果已经有,则生成相应的任务。

引擎对象的 receivedBlocks方法在收到具体区块时,检查所有已连接的远程节点(总账本对象),看它们是否想要这个区块,如果是则生成一个任务,在后台进行处理。

返回顶部