EbookCoin 源码 0x1

这次的一个period是基于《Nodejs区块链开发》这本书的的区块链项目–亿书,的源码学习笔记

EbookCoin项目地址

app.js

这个 app.js 是在node.js 中的入口程序文件,在其他情况下也可能是 server.js 。类似以python的顺序执行的模式。没有(可以用)一个main。

模块依赖

下面的代码是 app.js 1~15 主要的是导入的模块。这里,一个个的search这些模块的功能

var program = require('commander');                // 命令行框架开源包 commander.jsvar packageJson = require('./package.json');    // 定义了这个项目所需要的各种模块var Logger = require('./logger.js');            // 日志模块var appConfig = require("./config.json");        // 全局默认配置var genesisblock = require('./genesisBlock.json');    // 创世区块的设置var async = require('async');                    //    异步编程包var extend = require('extend');                    // 实现Obj的重载var path = require('path');                        // 处理路径的包var https = require('https');                    // TLS/SSL的包var fs = require('fs');                            // 文件系统包var z_schema = require('z-schema');                // 同步异步?var util = require('util');                        // 模块支持包var Sequence = require('./helpers/sequence.js');    // 
  • config.json

    在导入文件中,config.json 是全局配置文件。当参数少的时候,可以硬编码到代码里,当参数多的时候就是需要 全局配置文件。

    {    "port": 7000,    "address": "0.0.0.0",    "serveHttpAPI": true,    "serveHttpWallet": true,    "version": "0.1.3",    ...
  • commander.js

    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);    // 参数在这里

    这里是使用 commander 模块对输入的启动参数(process.argv)进行解析。

    $ node app.js -p 8080 # 这里是启动进程的参数# 这样的话参数就被按序的保存在了program里program.port == '8080' // True

功能实现

  • 20~70 实现了一个对于启动参数的解析和保存功能。

  • 35 周期性的调用,setInterval 可以对设置的函数进行周期性调用。

    if (typeof gc !== 'undefined') {    setInterval(function () {        gc();    }, 60000);    // 1 min}
  • 72 103 异常处理

    这里是对于这个app的异常处理的函数,一样的是回调。报一个 fatal 并且发送消息

    process.on('uncaughtException', function (err) {    // handle the error safely    logger.fatal('System error', { message: err.message, stack: err.stack });    process.emit('cleanup');    // 发送信号给handler});

    这里,应该应该也是个异常处理,应该是同时会log异常产生的域

    var d = require('domain').create();d.on('error', function (err) {    logger.fatal('Domain master', { message: err.message, stack: err.stack });    process.exit(0);});
  • 101 logger的初始化

  • 78 缺省的硬编码配置,应该挺重要所以贴出

    var config = {    "db": program.blockchain || "./blockchain.db",    "modules": {        "server": "./modules/server.js",        "accounts": "./modules/accounts.js",        "transactions": "./modules/transactions.js",        "blocks": "./modules/blocks.js",        "signatures": "./modules/signatures.js",        "transport": "./modules/transport.js",        "loader": "./modules/loader.js",        "system": "./modules/system.js",        "peer": "./modules/peer.js",        "delegates": "./modules/delegates.js",        "round": "./modules/round.js",        "contacts": "./modules/contacts.js",        "multisignatures": "./modules/multisignatures.js",        "dapps": "./modules/dapps.js",        "sia": "./modules/sia.js",        "crypto": "./modules/crypto.js",        "sql": "./modules/sql.js"    }};

    这里基本上是描述了功能所对应的模块

  • 108 这里的一个 d.run() 可能是打开了大门

    前面得知,d是我们创建的一个域,这里应该就是我们的域开始的时候了。这部分书中称为是模块加载。
    这里有个十分重要的东西 async

    Async is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript.

    官方的描述,是该模块提供了一个处理异步的功能。这里的async.auto意味着代码的顺序执行.

    function auto<R extends async.Dictionary<any>, E>(tasks: async.AsyncAutoTasks<R, E>, concurrency?: number, callback?: async.AsyncResultCallback<R, E>): void

    这个是auto函数的定义,可以看见, 在后面的如同 logger: function (cb) {
    这种形式的,实际上 logger 就是成为了一个任务task(这里本来就是要发生调度的)。那么这里就相当于定义了一组task。

  • 222 网络的初始化

    在书中,是直接跳过了前面的调度说明(虽说有点理解),直接到了网络这个任务。

    下面是网络加载的部分代码:

    var express = require('express');var app = express();var server = require('http').createServer(app);var io = require('socket.io')(server);

    这里使用了 express 模块,这个是一个web 应用的开发框架.上面这段代码,算是对于网络服务的初始化,框架绑定 服务(HTTP),服务绑定 io(SOCKET).

    这里的Scope到底是怎么来的???可能是对这个执行原理是不清楚.不过书中是直接让理解成为从 config.js 的内容包含(即前面的所有模块).

    • 228 这里是对是否使用 SSL 的一个判断

      if (scope.config.ssl.enabled) {

      可以在 Config.json 里找到对应的配置

      "ssl": {    "enabled": false,    "options": {        "port": 443,        "address": "0.0.0.0",        "key": "./ssl/ebookcoin.key",        "cert": "./ssl/ebookcoin.crt"    }
  • 277 构建链接 实际上是网络模块直接的链接

    这里可以看到使用的模块,就会很多了.所以这里是实现模块间的功能链接

    connect: ['config', 'public', 'genesisblock', 'logger', 'build', 'network', function (cb, scope) {

    这部分,是真的有点模糊,什么中间价之类的…实际上这里的app是我们的express的框架,那么这里的use,理应是对框架所使用的功能的配置.

    • 310 这里可能是对我们的http请求的解析

      var parts = req.url.split('/');

      这里分割 url ,把请求分词存在part里面.这里是解析的函数.

      if (parts.length > 1) {    if (parts[1] == 'api') {        if (scope.config.api.access.whiteList.length > 0) {            if (scope.config.api.access.whiteList.indexOf(ip) < 0) {                    res.sendStatus(403);                } else {                    next();                }            } else {                next();            }        } else if (parts[1] == 'peer') {            if (scope.config.peers.blackList.length > 0) {                if (scope.config.peers.blackList.indexOf(ip) >= 0) {                    res.sendStatus(403);                } else {                    next();                }            } else {                next();            }        } else {            next();        }    } else {        next();    }});
    • 343 开始服务监听

      这个 Listen 我当然懂..终于由开的明白的了,在指定地址,和端口进行监听

      scope.network.server.listen(scope.config.port, scope.config.address, function (err) {

      “Ebookcoin started”

  • 386 逻辑加载 ,可能是针对模块间的逻辑,进行的 New.
  • 418 模块加载, 卒

Todo

文件总结

app.js 是第一个启动文件, 也是最重要的一个,这里实现了模块的加载,功能的初始化,最重要的是实现了全部的 任务的调度, 由于对于async的不熟悉,和网络框架的不了解,对全局上的实现,还是理解较弱,不过,随着后面的学习,理解程度肯定会加深,来补充 TODO

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注