《Nodejs开发加密货币》之八:一个精巧的p2p网络实现
来源:互联网 发布:c c 程序员面试指南 编辑:程序博客网 时间:2024/06/05 14:37
关于
《Nodejs开发加密货币》,是一个加密货币产品的详细开发文档,涉及到使用Nodejs开发产品的方方面面,从前端到后台、从服务器到客户端、从PC到移动、加密解密、区款链等各个环节。代码完全开源、文章免费分享。 相关资源见 http://ebookchain.org
QQ交流群: 185046161
前言
加密货币都是去中心化的应用,去中心化的基础就是P2P网络,其作用和地位不言而喻,无可替代。
事实上,P2P网络不是什么新技术。但是,使用Nodejs开发的P2P网络,确实值得围观。这一篇,我们就来看看Ebookcoin的点对点网络是如何实现的。
源码
主要源码地址:
peer.js: https://github.com/Ebookcoin/ebookcoin/blob/master/modules/peer.js
transport.js: https://github.com/Ebookcoin/ebookcoin/blob/master/modules/transport.js
router.js: https://github.com/Ebookcoin/ebookcoin/blob/master/helpers/router.js
类图
流程图
解读
基于http的web应用,抓住路由的定义、设计与实现,是快速弄清业务逻辑的简单方法。目前,分析的是modules
文件夹下的各个模块文件,这些模块基本都是独立的Express微应用,在开发和设计上相互独立,各不冲突,逻辑清晰,这为学习分析,提供了便利。
1.路由扩展
任何应用,只要提供Web访问能力或第三方访问的Api,都需要提供从地址到逻辑的请求分发功能,这就是路由。Ebookcoin是基于http协议的Express应用,Express底层基于Nodejs的connect模块,因此其路由设计简单而灵活。
前面,在入门部分,已经讲到对路由的分拆调用,这里是其简单实现。先看看helper/router.js
吧。
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">// <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">27</span>行var Router = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> () { var router = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">require</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'express'</span>).Router(); router.use(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (req, res, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">next</span>) { res.header(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Access-Control-Allow-Origin"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"*"</span>); res.header(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Access-Control-Allow-Headers"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Origin, X-Requested-With, Content-Type, Accept"</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">next</span>(); }); router.map = map; <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> router;}<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>
这段代码定义了一个Express路由器Router
,并扩展了两个功能:
- 允许任何客户端调用。其实,就是设置了跨域请求,选项
Access-Control-Allow-Origin
设置为*
,自然任何IP和端口的节点都可以访问和被访问。 - 添加了地址映射方法。该方法的主要内容如下:
<code class="hljs javascript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3行</span><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">map</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(root, config)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> router = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>; <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>.keys(config).forEach(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(params)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> route = params.split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" "</span>); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (route.length != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> || [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"post"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"get"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"put"</span>].indexOf(route[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]) == -<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">throw</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Error</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"wrong map config"</span>); } router[route[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]](route[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>], <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(req, res, next)</span> {</span> root[config[params]]({<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"body"</span>: route[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] == <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"get"</span> ? req.query : req.body}, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(err, response)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (err) { res.json({<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"success"</span>: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">false</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"error"</span>: err}); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> res.json(extend({}, {<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"success"</span>: <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">true</span>}, response)); } }); }); });}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
该方法,接受两个对象作为参数:
- root: 定义了所要开放Api的逻辑函数;
- config: 定义了路由和root定义的函数的对应关系。
其运行的结果,就相当于:
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">router.get(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/peers'</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span>(req, res, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">next</span>){ root.getPeers(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>);})</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>
这里关键的小技巧是,在js代码中,对象也是hash值,root.getPeers() 与 root‘getPeers’ 是一致的。不过后者可以用字符串变量代替,更加灵活,有点像ruby里的元编程。这是脚本语言的优势(简单的字符串拼接处理)。
扩展一下,在类似sails的框架(基于express)里,很多都是可以使用类似config.json
的文件直接配置的,包括路由。参考这个函数,很容易理解和实现。
2.节点路由
很轻松就能在peer.js
里找到上述map方法的使用:
<code class="hljs php has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3行</span>Router = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">require</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'../helpers/router.js'</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 25</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>.attachApi = <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> router = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> Router(); router.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">use</span>(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(req, res, next)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (modules) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> next(); res.status(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">500</span>).send({success: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>, error: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Blockchain is loading"</span>}); }); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 34行</span> router.map(shared, { <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"get /"</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"getPeers"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"get /version"</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"version"</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"get /get"</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"getPeer"</span> }); router.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">use</span>(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(req, res)</span> {</span> res.status(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">500</span>).send({success: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>, error: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"API endpoint not found"</span>}); }); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 44行</span> library.network.app.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">use</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/api/peers'</span>, router); library.network.app.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">use</span>(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(err, req, res, next)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!err) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> next(); library.logger.error(req.url, err.toString()); res.status(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">500</span>).send({success: <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">false</span>, error: err.toString()}); });};</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li></ul>
上面代码的34行,可以直观想象到,会有类似/version
的路由出现,44行是express应用,这里就是将定义好的路由放在/api/peers
前缀之下,可以确信peer.js
文件提供了下面3个公共Api地址:
http://ip:port/api/peers/
http://ip:port/api/peers/version
http://ip:port/api/peers/get
当然,是不是可以直接这么调用,要看具体对应的函数是否还有其他的参数要求,比如:/api/peers/get
,按照restful的api设计原则,可以理解为是获得具体某个节点信息,那么总该给个id
之类的限定条件吧。看源码:
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">// <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">455</span>行library.scheme.validate(query, { type: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"object"</span>, properties: { ip_str: { type: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"string"</span>, minLength: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span> }, port: { type: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"integer"</span>, minimum: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, maximum: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">65535</span> } }, required: [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'ip_str'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'port'</span>] }, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (err) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">480</span>行 private.getByFilter({ <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> }); });</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li></ul>
这里,在具体运行过程中,library就是app.js
里传过来的scope
,该参数包含的scheme代表了一个z_schema
实例。
z_schema
是一个第三方组件,具体请看参考链接。该组件提供了json数据格式验证功能。上述代码的意思是:对请求参数query
进行验证,验证规则是:object类型,属性ip_str
要求长度不小于1的字符串,属性port
要求0~65535之间的整数,并且都不能空(必需)。
这就说明,我们应该这样请求http://ip:port/api/peers/get?ip_str=0.0.0.0&port=1234
,不然会返回错误信息。回头看看getPeers
方法的实现,没有required
字段,对应可以直接访问http://ip:port/api/peers/
。
看480行,上面的地址,都会调用private.getByFilter()
,并由它从sqlite数据库里查询数据表peers
。这里涉及到 dblite第三方组件 (请看参考链接),对请求操作sqlite数据库进行了简单封装。
3.节点保存
大多数应用,读数据相对简单,难在写数据。上面的代码,都是get
请求,可以查寻节点及其信息。我们自然会问,查询的信息从哪里来?初始的节点在哪里?节点变更了,怎么办?
(1)初始化节点
从现实角度考虑,在一个P2P网络中,一个孤立的节点,在没有其他任何节点信息的情况下,仅仅靠网络扫描去寻找其他节点,将是一件很难完成的事情,更别提高效和安全了。
因此,在运行软件之前,初始化一些节点供联网使用,是最简单直接的解决方案。这个在配置文件config.json
里,有直接体现:
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">// config.json <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>行<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"peers"</span>: { <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"list"</span>: [], <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"blackList"</span>: [], <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"options"</span>: { <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"timeout"</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4000</span> }},<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>
list的数据格式为:
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">[ { ip: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.0</span><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.0</span><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.0</span>, port: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7000</span> }, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>]</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
当然,也可以在启动的时候,通过参数--peers 1.2.3.4:70001, 2.1.2.3:7002
提供(代码见app.js
47行)。
(2)写入节点
写入节点,就是持久化,或者保存到数据库,或者保存到某个文件。这里保存到sqlite3数据库里的peers
表了,代码如下:
<code class="hljs php has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// peer.js 347行</span>Peer.prototype.onBlockchainReady = <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> async.eachSeries(library.config.peers.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">list</span>, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(peer, cb)</span> {</span> library.dbLite.query(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"INSERT OR IGNORE INTO peers(ip, port, state, sharePort) VALUES($ip, $port, $state, $sharePort)"</span>, { ip: ip.toLong(peer.ip), port: peer.port, state: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//初始状态为2,都是健康的节点</span> sharePort: Number(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">true</span>) }, cb); }, <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(err)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (err) { library.logger.error(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'onBlockchainReady'</span>, err); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>.count(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(err, count)</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (count) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>.updatePeerList(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(err)</span> {</span> err && library.logger.error(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'updatePeerList'</span>, err); library.bus.message(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'peerReady'</span>); }) library.logger.info(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Peers ready, stored '</span> + count); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { library.logger.warn(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Peers list is empty'</span>); } }); });}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>
这段代码的意思是,当区块链(后面篇章分析)加载完毕的时候(触发事件),依次将配置的节点写入数据库,如果数据库已经存在相同的记录就忽略,然后更新节点列表,触发节点加载完毕事件。
这里对数据库Sqlite
的插入操作,插入语句是library.dbLite.query("INSERT OR IGNORE INTO peers
,有意思的是IGNORE
操作字符串,是sqlite3支持的(见参考),当数据库有相同记录的时候,该记录被忽略,继续往下执行。
执行成功,就会调用library.bus.message('peerReady')
,进而触发peerReady
事件。该事件的功能就是:
(3)更新节点
事件onPeerReady
函数,如下:
<code class="hljs php has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// peer.js 374行</span>Peer.prototype.onPeerReady = <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> setImmediate(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">nextUpdatePeerList</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>.updatePeerList(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(err)</span> {</span> err && library.logger.error(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'updatePeerList timer'</span>, err); setTimeout(nextUpdatePeerList, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">60</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>); }) }); setImmediate(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">nextBanManager</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span>.banManager(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(err)</span> {</span> err && library.logger.error(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'banManager timer'</span>, err); setTimeout(nextBanManager, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">65</span> * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1000</span>) }); });}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
两个setImmediate
函数的调用,一个循环更新节点列表,一个循环更新节点状态。
第一个循环调用
看看第一个循环调用的函数updatePeerList
,
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">private.updatePeerList = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (cb) { // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">53</span>行 modules.transport.getFromRandomPeer({ api: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/list'</span>, method: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'GET'</span> }, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (err, data) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> library.scheme.validate(data.body, { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">124</span>行 self.update(peer, cb); }); }, cb); }); });};</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
看53行,我们知道,程序通过transport
模块的.getFromRandomPeer
方法,逐个随机的验证节点信息,并将其做删除和更新处理。如此一来,各种调用关系更加清晰,看流程图更加直观。.getFromRandomPeer
的代码:
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">// transport.js <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">474</span>行Transport.prototype.getFromRandomPeer = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (config, options, cb) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">481</span>行 async.retry(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (cb) { modules.peer.list(config, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (err, peers) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!err && peers.length) { var peer = peers[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]; // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">485</span>行 self.getFromPeer(peer, options, cb); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> cb(err || <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No peers in db"</span>); } }); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span>};</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>
代码很简单,重要的是理解async.retry
的用法(下篇技术分享,详细学习),该方法就是要重复调用第一个task函数20次,有正确返回结果就传给回调函数。这里,只要查到一个节点,就会传给485行的getFromPeer
函数,该函数是检验处理现存节点的核心函数,代码如下:
<code class="hljs r has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;">// transport.js <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">500</span>行Transport.prototype.getFromPeer = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (peer, options, cb) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> var req = { // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">519</span>行: 获得节点地址 url: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'http://'</span> + ip.fromLong(peer.ip) + <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">':'</span> + peer.port + url, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> }; // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">532</span>行: 使用`request`组件发送请求 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> request(req, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (err, response, body) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (err || response.statusCode != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (peer) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (err && (err.code == <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"ETIMEDOUT"</span> || err.code == <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"ESOCKETTIMEDOUT"</span> || err.code == <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"ECONNREFUSED"</span>)) { // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">542</span>行: 对于无法请求的,自然要删除 modules.peer.remove(peer.ip, peer.port, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (err) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> }); } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span> { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (!options.not_ban) { // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">549</span>行: 对于状态码不是<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">200</span>的,比如<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">304</span>等禁止状态,就要更改其状态 modules.peer.state(peer.ip, peer.port, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">600</span>, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> (err) { <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> }); } } } cb && cb(err || (<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'request status code'</span> + response.statusCode)); <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span>; } <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (port > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span> && port <= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">65535</span> && response.headers[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'version'</span>] == library.config.version) { // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">595</span>行: 一切问题都不存在 modules.peer.update({ ip: peer.ip, port: port, state: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>, // <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">598</span>行: 看来健康的节点状态为<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">...</span> });}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li></ul>
这里最重要的是532行,request
第三方组件的使用,请看参考链接。官方定义为简单的http客户端,功能足够强大,可以模拟浏览器访问信息,经常被用来做测试。
第二个循环调用
第二个循环调用的函数很简单,就是循环更改state
和clock
字段,主要是将禁止的状态state=0
,修改为1
,如下:
<code class="hljs javascript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 142行</span>private.banManager = <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(cb)</span> {</span> library.dbLite.query(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"UPDATE peers SET state = 1, clock = null where (state = 0 and clock - $now < 0)"</span>, {now: <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Date</span>.now()}, cb);}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
综上,整个P2P网络的读写和更新都已经清楚,回头再看活动图和类图,就更加明朗了。
最后,补充一下数据库里,节点表格peers
的字段信息:
<code class="hljs applescript has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-property" style="box-sizing: border-box;">id</span>,ip,port,state,os,sharePort,<span class="hljs-property" style="box-sizing: border-box;">version</span>,clock</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
总结
本篇,重点阅读了peer.js
文件,学习了一个使用Nodejs开发的P2P网络架构,其特点是:
- 产品提供初始节点列表,保障了初始化节点快速完成,不至于成为孤立节点;
- 节点具备跨域访问能力,任何节点之间都可以自由访问;
- 节点具备自我更新能力,定期查询和更新死掉的节点,保障网络始终畅通;
一旦达到一定的节点数量,就会形成一个互联互通的不死网络
。搭建在这种网络上的服务,会充满怎样的诱惑?加密货币为什么会被认为是下一代互联网?这加起来不足千行的代码,可以给我们足够多的遐想空间。
这部分代码,涉及到dblite,request,z_schema
等第三方组件,以及Ebookcoin自行实现的事件处理方法library.bus
(在app.js
文件的行),都很简单,不再分享或赘述,请自行查阅。本篇涉及的代码中,关于回调的设计很多,值得总结和研究。async
组件,被反复使用,有必须汇总一下,请关注后续的技术分享。
链接
本系列文章即时更新,若要掌握最新内容,请关注下面的链接
本源文地址: https://github.com/imfly/bitcoin-on-nodejs
电子书阅读: http://bitcoin-on-nodejs.ebookchain.org
参考
z_schema组件: https://github.com/Ebookcoin/z_schema
dblite组件: https://github.com/Ebookcoin/dblite
request组件: http://github.com/request/request
SQL As Understood By SQLite: https://www.sqlite.org/lang_conflict.html
- 《Nodejs开发加密货币》之八:一个精巧的p2p网络实现
- 《Nodejs开发加密货币》之八:一个精巧的p2p网络实现
- 《Nodejs开发加密货币》之十五:加密货币就是货币
- 《Nodejs开发加密货币》之十三:亿书,一个面向未来的自出版平台
- 《Nodejs开发加密货币》之十八:地址
- 《Nodejs开发加密货币》之三:Nodejs让您的前端开发像子弹飞一样
- 《Nodejs开发加密货币》之五:您必须知道的几个Nodejs编码习惯
- 《Nodejs开发加密货币》之二十七:开发通用的HTML组件
- 《Nodejs开发加密货币》之六:Commander介绍
- 《Nodejs开发加密货币》之十九:签名和多重签名
- 《Nodejs开发加密货币》之二十一:交易
- 《Nodejs开发加密货币》之二十三:区块链
- 《Nodejs开发加密货币》之十四:Js处理数据计算的缺陷和解决方案
- 《Nodejs开发加密货币》之十六:利益,魔鬼与天使的共同目标
- 《Nodejs开发加密货币》之十七:共识机制,可编程的利益转移规则
- 《Nodejs开发加密货币》之二十:关于时间处理的相关问题
- 《Nodejs开发加密货币》之九:在Nodejs中使用加密解密技术
- 《Nodejs开发加密货币》之四:Nodejs让后台开发像前端一样简单
- android低版本(4.4以下)sip无法接受
- Log4Net——典型的使用方式Log4Net
- 一篇文章带你了解Cloud Native
- JAVA增删改查XML文件
- Permission Denial: not allowed to send broadcast in android
- 《Nodejs开发加密货币》之八:一个精巧的p2p网络实现
- Android自定义ViewGroup (选择照片或者拍照)
- 大搬家
- Android,找工作,月薪2万怎么做?
- build 并deploy saiku-query0.1到nexus
- 快速检测一个字符数组中是否有重复的字符
- 直线检测透视变换
- stdlib.h
- 设计模式-工厂方法模式