EOS 源碼分析 -- cleos

從 main 函數(shù)開始

首先注冊 command, option 以及 subcommand ,每個 command 都是一個 App 對象狞山,并為每個 App 對象設置回調set_callback从媚。
獲取程序啟動時的指定參數(shù)筒繁,解析參數(shù)胖烛,從 App 對象的樹形結構中产雹,找到指定的command 的谬莹,然后執(zhí)行對應的回調函數(shù)檩奠。

設置命令及參數(shù)

  • 聲名第一個App類的對象,相當于cleos,再看指針附帽,通過App的成員函數(shù)add_subcommand()實現(xiàn)埠戳,成功地實現(xiàn)了鏈表
  • add_subcommand 函數(shù) 將 option 添加到 vector subcommands_ 里,返回一個 App對象, 返回的 App 對象可以繼續(xù) add_subcommand,形成一個樹型結構蕉扮。
  • require_subcommand 函數(shù)指定該 command 不是一個單獨有效的命令整胃,需要一個subcommand.
  • add_option 函數(shù)將 創(chuàng)建 Option 對象,并將指針保存在 vector options_ 中喳钟,每個對象可以無限擴展配置選項屁使。
  • option 調用 required() 方法,表示這個option需要一個參數(shù)
  • add_flag 添加flag (不帶參數(shù))奔则,內(nèi)部會調用 add_option 方法蛮寂。
  • set_callback 函數(shù)給每個 App 對象設置一個回調.

option 對象

屬性

  • expected_ :該 option 需要幾個參數(shù)
  • required_ : 是否需要參數(shù)
  • pname_ : 參數(shù)名,且不含前綴---
  • snames_ : 參數(shù)名易茬,以- 為前綴
  • lnames_ : 參數(shù)名酬蹋,以-- 為前綴

解析參數(shù)

解析參數(shù)調用 app.parse(argc, argv);

parse

將命令行參數(shù),存放在vector args 中,

std::vector<std::string> parse(int argc, char **argv) {
        name_ = argv[0];
        std::vector<std::string> args;
        for(int i = argc - 1; i > 0; i--)
            args.emplace_back(argv[i]);
        return parse(args);
    }

調用另一個parse方法

/// The real work is done here. Expects a reversed vector.
    /// Changes the vector to the remaining options.
    std::vector<std::string> &parse(std::vector<std::string> &args) {
        _validate();
        _parse(args);
        run_callback();
        return args;
    }

_validate

首先_validate這個方法里檢查option選項有沒有沖突的

/// Check the options to make sure there are no conficts.
    ///
    /// Currenly checks to see if mutiple positionals exist with -1 args
    void _validate() const {
        auto count = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
            return opt->get_expected() == -1 && opt->get_positional();
        });
        if(count > 1)
            throw InvalidError(name_ + ": Too many positional arguments with unlimited expected args");
        for(const App_p &app : subcommands_)
            app->_validate();
    }

expected 解釋如下

/// The number of expected values, 0 for flag, -1 for unlimited vector
    int expected_{1};

即疾呻, 0 代表的是添加的 flag 選項除嘹, -1 代表無限制的vector 選項
如果有相同名字的 vector 類型參數(shù)被指定,回拋出異常岸蜗。

_parse

  • 函數(shù) void _parse(std::vector<std::string> &args) 中尉咕, 首先循環(huán)調用 _parse_single 方法,處理參數(shù)所有參數(shù)璃岳。
  • 處理當前app對象的所有 option 對象年缎,當該option被解析過后,調用該option的回調函數(shù)铃慷,將 解析后的 results_ 作為參數(shù)单芜,如下
/// Process the callback
    void run_callback() const {
        if(!callback_(results_))
            throw ConversionError(get_name() + "=" + detail::join(results_));
        if(!validators_.empty()) {
            for(const std::string &result : results_)
                for(const std::function<bool(std::string)> &vali : validators_)
                    if(!vali(result))
                        throw ValidationError(get_name() + "=" + result);
        }
    }

_parse_single

_parse_single 函數(shù)將參數(shù)分成POSITIONAL_MARK、SUBCOMMAND犁柜、LONG洲鸠、SHORT、NONE五個種類。

  • SUBCOMMAND 代表解析的該參數(shù)在subcommands列表中
  • LONG 代表參數(shù) --XXX
  • SHORT 代表參數(shù) -XXX
  • NONE 代表參數(shù) XXX
  • POSITIONAL_MARK 攢不知什么作用

_parse_subcommand

如果找到對應名字的 subcommand (com)對象,彈出最后一個參數(shù)扒腕,執(zhí)行 com->_parse(args)

_parse_long

取出當前參數(shù)绢淀,--name=value 格式,找出對應的option瘾腰,設置給result 屬性

_parse_short

取出當前參數(shù)皆的,-name 格式, 查找對應 option 對象,根據(jù) option 對象的 expected 字段蹋盆,接受剩余的 參數(shù)费薄,并設置給 optionresult 屬性

_parse_positional

如果當前已接受的option 參數(shù)個數(shù)還未到達expected的數(shù)量,添加到vector parse_order_ 中栖雾。

callback

每個 command 或者 option 都可以設置一個回調楞抡, 解析命令行的參數(shù)后,會依次調用這些 callback

以新建一個賬戶為例:

createAccount->set_callback([this] {
    if( !active_key_str.size() )
       active_key_str = owner_key_str;
    public_key_type owner_key, active_key;
    try {
       owner_key = public_key_type(owner_key_str);
    } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid owner public key: ${public_key}", ("public_key", owner_key_str));
    try {
       active_key = public_key_type(active_key_str);
    } EOS_RETHROW_EXCEPTIONS(public_key_type_exception, "Invalid active public key: ${public_key}", ("public_key", active_key_str));
    auto create = create_newaccount(creator, account_name, owner_key, active_key);
    if (!simple) {
       if ( buy_ram_eos.empty() && buy_ram_bytes_in_kbytes == 0) {
            .......
          send_actions( { create, buyram, delegate } );
       } else {
          send_actions( { create, buyram } );
       }
    } else {
       send_actions( { create } );
    }
});

這段回調最終走到 send_actions , 再到 push_actions

void send_actions(std::vector<chain::action>&& actions, int32_t extra_kcpu = 1000, packed_transaction::compression_type compression = packed_transaction::none ) {
   auto result = push_actions( move(actions), extra_kcpu, compression);

   if( tx_print_json ) {
      cout << fc::json::to_pretty_string( result ) << endl;
   } else {
      print_result( result );
   }
}

fc::variant push_actions(std::vector<chain::action>&& actions, int32_t extra_kcpu, packed_transaction::compression_type compression = packed_transaction::none ) {
   signed_transaction trx;
   trx.actions = std::forward<decltype(actions)>(actions);

   return push_transaction(trx, extra_kcpu, compression);
}

打包交易數(shù)據(jù)后岩灭,然后會走到push_transaction

fc::variant push_transaction( signed_transaction& trx, int32_t extra_kcpu = 1000, packed_transaction::compression_type compression = packed_transaction::none ) {
   
   ......
   
   if (!tx_dont_broadcast) {
      return call(push_txn_func, packed_transaction(trx, compression));
   } else {
      return fc::variant(trx);
   }
}

最終會走到 call(push_txn_func, packed_transaction(trx, compression));
跟蹤push_txn_func會發(fā)現(xiàn)是個字符串

   const string chain_func_base = "/v1/chain";
   const string push_txn_func = chain_func_base + "/push_transaction";

call 函數(shù)最終調用:

template<typename T>
fc::variant call( const std::string& url,
                  const std::string& path,
                  const T& v ) {
   try {
      eosio::client::http::connection_param *cp = new eosio::client::http::connection_param(context, parse_url(url) + path,
              no_verify ? false : true, headers);

      return eosio::client::http::do_http_call( *cp, fc::variant(v), print_request, print_response );
   }
   catch(boost::system::system_error& e) {
        ......   
   }
}

do_http_call 函數(shù)就將打包好的參數(shù)拌倍,path 信息以http請求的形式發(fā)送出去了,返回值給cleos在命令行輸出

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末噪径,一起剝皮案震驚了整個濱河市柱恤,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌找爱,老刑警劉巖梗顺,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異车摄,居然都是意外死亡寺谤,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門吮播,熙熙樓的掌柜王于貴愁眉苦臉地迎上來变屁,“玉大人,你說我怎么就攤上這事意狠∷诠兀” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵环戈,是天一觀的道長闷板。 經(jīng)常有香客問我,道長院塞,這世上最難降的妖魔是什么遮晚? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮拦止,結果婚禮上县遣,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好艺玲,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布括蝠。 她就那樣靜靜地躺著,像睡著了一般饭聚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上搁拙,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天秒梳,我揣著相機與錄音,去河邊找鬼箕速。 笑死酪碘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的盐茎。 我是一名探鬼主播兴垦,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼字柠!你這毒婦竟也來了探越?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤窑业,失蹤者是張志新(化名)和其女友劉穎钦幔,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體常柄,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡鲤氢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了西潘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片卷玉。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖喷市,靈堂內(nèi)的尸體忽然破棺而出相种,到底是詐尸還是另有隱情,我是刑警寧澤东抹,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布蚂子,位于F島的核電站,受9級特大地震影響缭黔,放射性物質發(fā)生泄漏食茎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一馏谨、第九天 我趴在偏房一處隱蔽的房頂上張望别渔。 院中可真熱鬧,春花似錦、人聲如沸哎媚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拨与。三九已至稻据,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間买喧,已是汗流浹背捻悯。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淤毛,地道東北人今缚。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像低淡,于是被迫代替她去往敵國和親姓言。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內(nèi)容