《Nodejs开发加密货币》之七:入口程序app.js解读
来源:互联网 发布:深思考人工智能怎么样 编辑:程序博客网 时间:2024/05/18 03:11
关于
《Nodejs开发加密货币》,是一个加密货币产品的详细开发文档,涉及到使用Nodejs开发产品的方方面面,从前端到后台、从服务器到客户端、从PC到移动、加密解密、区款链等各个环节。代码完全开源、文章免费分享。 相关资源见 http://ebookchain.org
QQ交流群: 185046161
前言
在入门文章部分,我们已经知道,Nodejs的应用最终都可以合并成一个文件,为了开发方便,才将其拆分成多个文件。
被拆分的那个文件,自然是我们重点研究的对象,通常这个文件就是App.js或server.js,大家称之为入口程序
。
显然Ebookcoin用的就是app.js。这一篇,我们就来阅读一下该文件,学习研究它的整体架构流程。
源码
地址: https://github.com/Ebookcoin/ebookcoin/blob/master/app.js
类图
js原本无类,因此它的类图并不好处理,仅能大致给出它与其他模块的关联关系。
解读
直接读代码看看。
1.配置处理
任何一个应用,都会提供一些参数。对这些参数的处理,有很多种方案。但总的来说,通常需要提供一种理想环境,即默认配置,同时给你一种方法自行修改。
(1)全局默认配置
通常默认参数较少时,可以硬编码到代码里。但更灵活的方式,就是使用单独文件。这里就使用了文件 ./config.json
来保存全局配置,如:
{ "port": 7000, "address": "0.0.0.0", "serveHttpAPI": true, "serveHttpWallet": true, "version": "0.1.1", "fileLogLevel": "info", "consoleLogLevel": "log", "sharePort": true, ...
使用时,只需要require
就可以了。源码:
var appConfig = require("./config.json"); // app.js 4行
不过,为了灵活性,默认值通常允许用户修改。
(2)使用commander
组件,引入命令行选项
上一篇已经分享,commander
是Nodejs第三方组件(使用npm安装),常被用来开发命令行工具,用法极为简单。源码:
// 1行var program = require('commander');// 19行program .version(packageJson.version) .option('-c, --config <path>', 'Config file path') .option('-p, --port <port>', 'Listening port number') .option('-a, --address <ip>', 'Listening host name or ip') .option('-b, --blockchain <path>', 'Blockchain db path') .option('-x, --peers [peers...]', 'Peers list') .option('-l, --log <level>', 'Log level') .parse(process.argv);
这样,就可以在命令行执行命令时,加带-c
,-p
等选项,例如:
node app.js -p 8888
这时,该选项就以program.port
的形式被保存,于是手动修改一下:
// 39行if (program.port) { appConfig.port = program.port;}
这是处理Nodejs应用全局配置的一种常用且简单的方式,值得学习。
更多内容,请阅读上一篇对commander
组件的详细介绍。
2.异常捕捉
我们在第一部分总结时,特意提到异常要捕捉
,这里我们很轻松就可以看出来,代码对全局异常处理的方式。
注意:对于domain
模块,已经不提倡使用,这部分代码将再后续的更新中去除,这里仅做了解就是了。
(1)使用uncaughtException
捕捉进程异常
// 65行process.on('uncaughtException', function (err) { // handle the error safely logger.fatal('System error', { message: err.message, stack: err.stack }); process.emit('cleanup');});
(2)使用domain
模块捕获全局异常
// 96行var d = require('domain').create();d.on('error', function (err) { logger.fatal('Domain master', { message: err.message, stack: err.stack }); process.exit(0);});d.run(function () {...
另外,对各个模块,也使用了domain
// 415行var d = require('domain').create();d.on('error', function (err) {scope.logger.fatal('domain ' + name, {message: err.message, stack: err.stack});});...
3.模块加载
这才是真正的重点,不过看过代码,发现一切都那么干净利略,也没有多层回调
那些大坑
,其实是用了async
流程管理组件。
整体使用async.auto
进行顺序调用
;在加载modules
时,又使用async.parallel
,使其并行运作;当发生错误时,清理工作用到了async.eachSeries
。
下图是手工简单画的,说明了从代码103-438行之间,各模块的加载运行顺序。后面针对具体代码会使用UML图来代替。
下篇,我们也有必要对async
组件进行详解梳理。这里,您只要能猜出代码意图,就不用太操心async的用法。下面,读读有关源码:
(1)初始网络
从packages.json
里看到使用了Express
框架。通过前面部分的介绍,知道必须在入口程序里,初始化才对。具体如何调用的?下面的代码,显然十分熟悉。
Express是Nodejs重要的web开发框架,这里的网络network
本质上就是以Express为基础的web应用,自然白皮书
才会宣扬基于Http协议
。
// 215行network: ['config', function (cb, scope) { var express = require('express'); var app = express(); var server = require('http').createServer(app); var io = require('socket.io')(server); if (scope.config.ssl.enabled) { var privateKey = fs.readFileSync(scope.config.ssl.options.key); var certificate = fs.readFileSync(scope.config.ssl.options.cert); var https = require('https').createServer({ ...
说明:这是async.auto
常用的方法,network
用到的任何需要回调的方法(这里是config
),都放在这个数组里,最后的回调函数(function (cb, scope) {//code}
),可以巧妙的调用,如: scope.config
。
这里的代码,仅仅初始化服务,没有做太多实质的事情,真正的动作在下面。
(2)构建链接
从下面的代码开始,我们才能看到这个应用的本质。270行代码用到了network
等,如下:
// 270行connect: ['config', 'public', 'genesisblock', 'logger', 'build', 'network', function (cb, scope) {
接着,下面的代码,加载了几个中间件,告诉我们,该应用接受ejs
模板驱动的html文件。视图文件和图片、样式等静态文件都在public
文件夹等,这些信息绝对比官方文档还有用。
// 277行scope.network.app.engine('html', require('ejs').renderFile);scope.network.app.use(require('express-domain-middleware'));scope.network.app.set('view engine', 'ejs');scope.network.app.set('views', path.join(__dirname, 'public'));scope.network.app.use(scope.network.express.static(path.join(__dirname, 'public')));...
再下来,就是对请求参数和响应数据的处理,包括对节点peers
中黑名单、白名单的过滤等,最后启动服务操作:
// 336行scope.network.server.listen(scope.config.port, scope.config.address, function (err) {
(3)加载逻辑
看代码知道,其核心逻辑功能应该是:账户管理、交易和区块链。这些模块,有其执行顺序,我们需要在后面的篇章中,分别单独介绍。
// 379行logic: ['dbLite', 'bus', 'scheme', 'genesisblock', function (cb, scope) { // 嵌套了async.auto async.auto({ ... account: ["dbLite", "bus", "scheme", 'genesisblock', function (cb, scope) { new Account(scope, cb); }], transaction: ["dbLite", "bus", "scheme", 'genesisblock', "account", function (cb, scope) { new Transaction(scope, cb); }], block: ["dbLite", "bus", "scheme", 'genesisblock', "account", "transaction", function (cb, scope) { new Block(scope, cb); }] }, cb); ...
(4)加载模块
上面所有代码的执行结果,都要被这里的各模块共享。下面的代码说明,各个模块都采用一致(不一定一样)的参数和处理方法,这样处理起来简单方便:
// 411行modules: ['network', 'connect', 'config', 'logger', 'bus', 'sequence', 'dbSequence', 'balancesSequence', 'dbLite', 'logic', function (cb, scope) { // 对每个模块都使用`domain`监控其错误 Object.keys(config.modules).forEach(function (name) { tasks[name] = function (cb) { var d = require('domain').create(); d.on('error', function (err) { ... }); d.run(function () { ... }); } }); // 让各个模块并行运行 async.parallel(tasks, function (err, results) { cb(err, results); });
这里的模块既然都是并行处理,研究它们就不需要分先后了。
总结
这篇文章开始深入代码,但是仍然较为粗略。不过,对整个应用的基本架构已经了然。继续深入研究,方向路线也已然清晰。
代码中还有很多细节,我们并没有逐行介绍。个人认为,读代码就像看文章,先要概览,逐步深入,不一定一开始就逐字逐句去读,那样效率低、效果差。
对于这个app.js文件,成手读它可能就是分分钟的事情,而写出来却要罗嗦这么多。如果,你并没有觉得很轻松,甚至理解很困难,那么可能缺少对commander
、domain
和async
等组件或模块的了解,请看相关分享或官方文档。
链接
本系列文章即时更新,若要掌握最新内容,请关注下面的链接
本源文地址: https://github.com/imfly/bitcoin-on-nodejs
电子书阅读: http://bitcoin-on-nodejs.ebookchain.org
电子书下载: 下载页面 PDF文件 ePub文件 Mobi文件
- 《Nodejs开发加密货币》之七:入口程序app.js解读
- 《Nodejs开发加密货币》之十五:加密货币就是货币
- 《Nodejs开发加密货币》之十八:地址
- 《Nodejs开发加密货币》之十四:Js处理数据计算的缺陷和解决方案
- 《Nodejs开发加密货币》之二十六:轻松从Js文件生成UML类图
- 《Nodejs开发加密货币》之六:Commander介绍
- 《Nodejs开发加密货币》之十九:签名和多重签名
- 《Nodejs开发加密货币》之二十一:交易
- 《Nodejs开发加密货币》之二十三:区块链
- 《Nodejs开发加密货币》之九:在Nodejs中使用加密解密技术
- 《Nodejs开发加密货币》之三:Nodejs让您的前端开发像子弹飞一样
- 《Nodejs开发加密货币》之四:Nodejs让后台开发像前端一样简单
- 《Nodejs开发加密货币》之二:Nodejs原来在币圈如此流行?
- 《Nodejs开发加密货币》之五:您必须知道的几个Nodejs编码习惯
- 《Nodejs开发加密货币》之十:三张图让你全面掌握加密解密技术
- 《Node.js开发加密货币》之二十二:自序
- 《Nodejs开发加密货币》之十二:静态网站开发全景扫描
- 《Nodejs开发加密货币》之二十七:开发通用的HTML组件
- PHP分页原理+代码实现
- oc 播放gif动画
- 【HUSTOJ】1013: 成绩等级
- centos6.5环境基于corosync+cman+rgmanager实现RHCS及iscsi+gfs2+clvm的文件系统集群
- 奋斗吧,程序员——第二十四章 想佳人、妆楼凝望,误几回、天际识归舟
- 《Nodejs开发加密货币》之七:入口程序app.js解读
- Binder service入门–创建native binder service
- 如何对PDF格式文档编辑
- 字符串性质
- Object与String的切换
- (置顶)POJ题目分类
- 图像处理(〇)直方图修改基础
- 模拟21cn邮箱登陆,获取邮件
- 错误、调试和测试