搭建EOS水龍頭 (Express+MongoDB)

  • 大致思路吐葱,在服務(wù)器后端綁定一個(gè)很有足夠多EOS的賬戶盒延。
  • 接收前端提交過(guò)來(lái)的用戶名和公鑰,幫忙在EOS網(wǎng)絡(luò)上注冊(cè)賬戶滤港。
  • 服務(wù)端用MVC模型處理請(qǐng)求廊蜒。
  • 數(shù)據(jù)庫(kù)用于儲(chǔ)存注冊(cè)新用戶的信息,用戶名溅漾、公鑰匙山叮、費(fèi)用之類的。
  • 這里使用的是EOS公測(cè)網(wǎng)絡(luò)
  • 總體邏輯不算復(fù)雜添履, 這是全部代碼屁倔。

MongoDB的設(shè)置

// mongodb安裝比較簡(jiǎn)單,這里就不介紹了, 大致上就是官網(wǎng)下載個(gè)安裝包,雙擊運(yùn)行
// https://docs.mongodb.com/manual/installation/

// 啟動(dòng)數(shù)據(jù)庫(kù) (窗口不能關(guān))
// 啟動(dòng)mongodb的時(shí)候可能會(huì)遇到 /data/db/ 文件夾權(quán)限不夠的情況暮胧,運(yùn)行以下命令提權(quán)
// sudo chmod -R 0777 /data/db
$ mongod

// 開(kāi)啟另外一個(gè)命令行窗口汰现,進(jìn)入數(shù)據(jù)庫(kù)
$ mongo

// 創(chuàng)建一個(gè)名為 faucet 的數(shù)據(jù)庫(kù)
use faucet 

// 創(chuàng)建一個(gè)名為 faucet 的集合
db.createCollection('faucet')

// 切換至admin數(shù)據(jù)庫(kù)
use admin

// 創(chuàng)建admin數(shù)據(jù)庫(kù)管理員,只是為了方便以后管理叔壤,不一定需要設(shè)置。
// 用戶名tmd口叙,密碼123炼绘,權(quán)限:讀寫(xiě)、用戶管理
db.createUser({user:'tmd',pwd:'123',roles:[{role:'readWrite',db:'admin'},{role:'userAdminAnyDatabase',db:'admin'}]})

// 創(chuàng)建faucet數(shù)據(jù)庫(kù)的可讀寫(xiě)賬號(hào)
// 要記住自己創(chuàng)建的用戶與密碼
db.createUser({user:'eos',pwd:'eos',roles:[{role:'readWrite',db:'faucet'}]})

到目前為止妄田,數(shù)據(jù)庫(kù)設(shè)置大致完成俺亮,現(xiàn)在需要把剛剛開(kāi)啟mongod 和 mongo 進(jìn)程關(guān)閉,帶認(rèn)證參數(shù)重新啟動(dòng)一次

// --auth 參數(shù)是設(shè)置  (窗口不能關(guān))
$ mongod --auth

// 如果是在linux環(huán)境下運(yùn)行
// 編輯 /etc/mongod.conf文件疟呐,mongodb默認(rèn)的配置文件
// 修改以下代碼脚曾,設(shè)置成enabled。(這是3.0以上版的設(shè)置方式启具,舊版本就不介紹了)

security:
    authorization: "enabled"

// linux環(huán)境下本讥,在后臺(tái)啟動(dòng)mongodb (窗口可以關(guān))
$ sudo service mongod start

// 開(kāi)啟一個(gè)新命令行窗口進(jìn)入數(shù)據(jù)庫(kù)
$ mongo

// 進(jìn)入數(shù)據(jù)庫(kù)后,賬號(hào)都需要進(jìn)入admin數(shù)據(jù)庫(kù)中進(jìn)行驗(yàn)證, 
use admin

// 這里輸入剛才設(shè)置的用戶名和密碼,如果返回1表示認(rèn)證通過(guò)
db.auth('eos','eos')

// 切換至faucet數(shù)據(jù)庫(kù)
use faucet

// 展示集合,一切順利的話會(huì)展示集合列表
show collections

mongodb數(shù)據(jù)庫(kù)設(shè)置完成

附錄

mongodb配置文件設(shè)置
https://docs.mongodb.com/manual/reference/configuration-options/


Express安裝與項(xiàng)目初始化

// 全局安裝一個(gè) express-generator
$ npm install express-generator -g

// 初始化一個(gè)名為eos_faucet的項(xiàng)目
$ express eos_faucet

// 安裝依賴包
$ cd eos_faucet
$ npm install eosjs@beta node-fetch text-encoding eosjs-ecc
  • 編輯/eos_faucet/app.js文件萌腿,
//  在所有路由前面拖刃,設(shè)置允許跨域請(qǐng)求
app.all('*', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type");
  res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
  res.header("X-Powered-By",' 3.2.1');
  res.header("Content-Type", "application/json;charset=utf-8");
  next();
});
  • 編輯/eos_faucet/routes/index.js文件
const express = require('express');
const router = express.Router();
const registerController = require('../controllers/register');

/* 保留get請(qǐng)求荔燎,測(cè)試服務(wù)器成功開(kāi)啟. */
router.get('/', function(req, res) {
  res.send('you shall not pass')
});

// 增加一個(gè)post請(qǐng)求的路由,用于處理注冊(cè)請(qǐng)求
router.post('/',registerController.register);

module.exports = router;
  • 創(chuàng)建并編輯 /eos_faucet/controllers/register.js文件
  • 以下api調(diào)用涉及到eosjs庫(kù)的調(diào)用秧了,如果不熟悉請(qǐng)參考我的前一篇文章 NODE.JS 調(diào)用EOS API
const { Api, JsonRpc, JsSignatureProvider } = require('eosjs');
const fetch = require('node-fetch');
const { TextDecoder, TextEncoder } = require('text-encoding');
const registerModel = new require('../models/register');
// 設(shè)置一個(gè)賬號(hào),用于創(chuàng)建賬號(hào)的序无,這個(gè)賬號(hào)一定是存在并且有足夠的EOS在里面的验毡。
const admin = 'tmd555555555';
// 賬號(hào)的私鑰
const privateKey = "5KX4fnaQWhc6Coz9uqk9GWkjiA8q8R8ditSTDjKcHqsHCwnhJpR";
const signatureProvider = new JsSignatureProvider([privateKey]);
const rpc = new JsonRpc('http://junglehistory.cryptolions.io:18888', { fetch });
const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });

exports.register = async (req, res) => {
  try{
    const result = await api.transact({
      actions: [{
        account: 'eosio',
        name: 'newaccount',
        authorization: [{
          actor: admin,
          permission: 'active',
        }],
        data: {
          creator: admin,
          name: req.body.username,
          newact:req.body.username,
          owner: {
            threshold: 1,
            keys: [{
              key: req.body.publicKey,
              weight: 1
            }],
            accounts: [],
            waits: []
          },
          active: {
            threshold: 1,
            keys: [{
              key: req.body.publicKey,
              weight: 1
            }],
            accounts: [],
            waits: []
          },
        },
      }, {
        account: 'eosio',
        name: 'buyrambytes',
        authorization: [{
          actor: admin,
          permission: 'active',
        }],
        data: {
          payer: admin,
          receiver: req.body.username,
          bytes: 3000,
        },
      }, {
        account: 'eosio',
        name: 'delegatebw',
        authorization: [{
          actor: admin,
          permission: 'active',
        }],
        data: {
          from: admin,
          receiver: req.body.username,
          stake_net_quantity: '1.0000 EOS',
          stake_cpu_quantity: '1.0000 EOS',
          transfer: false,
        }
      }]
    }, {
      blocksBehind: 3,
      expireSeconds: 30,
    });
    // 合約運(yùn)行成功后把結(jié)果發(fā)給前端。
    res.send(JSON.stringify(result))

  }catch(err){
    // 如果運(yùn)行失敗帝嗡,把錯(cuò)誤信息返回給前端晶通。并且退出函數(shù)。
    if(!!err.json){
      res.send(JSON.stringify(err.json));
    }else{
      res.send(JSON.stringify(err));
    }
    return;
  }

  // 如果運(yùn)行成功丈探,把新用戶信息存入數(shù)據(jù)庫(kù)录择。運(yùn)行失敗的話,不會(huì)執(zhí)行到這一步碗降。
  await registerModel.create({
    username: req.body.username,
    publicKey: req.body.publicKey,
    creator: admin,
    cost:'',
    bytes:3000
  });
};
  • 創(chuàng)建并編輯/eos_faucet/models/register.js
const mongoose = require('mongoose');
// 用賬號(hào)和密碼登錄連接數(shù)據(jù)庫(kù)隘竭,eos:eos這里的賬號(hào)和密碼都是eos,
// 地址127.0.0.1讼渊,mongodb默認(rèn)設(shè)置了只能本地訪問(wèn)
// faucet动看,表示連接到faucet這個(gè)數(shù)據(jù)庫(kù)
// 數(shù)據(jù)庫(kù)的賬號(hào)名是在admin數(shù)據(jù)庫(kù)中建立的 所以需要添加 ?authSource=admin
mongoose.connect('mongodb://eos:eos@127.0.0.1/faucet?authSource=admin',{ useNewUrlParser: true } );
mongoose.Promise = global.Promise;

// 設(shè)置schema,雖然mongodb是非關(guān)系型數(shù)據(jù)庫(kù)爪幻,但是一般都會(huì)給它設(shè)置模式
const registerSchema = new mongoose.Schema({
  username:String,
  publicKey:String,
  creator: String,
  cost:String,
  bytes:Number,
  // 創(chuàng)建日期菱皆,默認(rèn)值寫(xiě)成當(dāng)前時(shí)間
  date:{type:Date, default:new Date()}
});

// 設(shè)置靜態(tài)方法,給外外層調(diào)用
registerSchema.statics.save = async function({username, publicKey, creator, cost, bytes}){
  return this.create({username, publicKey, creator, cost, bytes})
};

// 三個(gè)參數(shù)挨稿,第一個(gè)只是schema的名字仇轻,可以隨便寫(xiě),第二個(gè)是schema對(duì)象奶甘,第三個(gè)是數(shù)據(jù)庫(kù)中集合的名字
module.exports = mongoose.model('register', registerSchema, 'faucet');

  • 到目前Express設(shè)置完成篷店,可以跑起來(lái)了
  • 注意:服務(wù)器的端口可以在./bin/www設(shè)置,我把端口設(shè)置了5000
  • 如果在產(chǎn)品環(huán)境運(yùn)行臭家,可以用pm2做進(jìn)程守護(hù)疲陕,并且打開(kāi)多線程模式,提高性能钉赁。
    如果不了解蹄殃,可以參考我這篇文章 部署node服務(wù)器到產(chǎn)品環(huán)境
// 只用于本地測(cè)試
$ npm start

// 產(chǎn)品環(huán)境開(kāi)啟進(jìn)程守護(hù)和多線程
$ pm2 start ./bin/www -i max --env production

you shall not pass

在瀏覽器測(cè)試服務(wù)器是否開(kāi)啟成功,成功展示我們?cè)O(shè)置文本you shall not pass你踩,表示服務(wù)器已經(jīng)正常開(kāi)啟

success

在postman測(cè)試一下請(qǐng)求诅岩,并收到成功的返回信息讳苦,表示流程沒(méi)問(wèn)題。

QQ20181101-164850@2x.png

mongo shell 中運(yùn)行db.faucet.find({},{_id:0,__v:0}).sort({date:-1}).pretty()查到最近一條記錄是我剛剛在前端請(qǐng)求存入的信息按厘,說(shuō)明儲(chǔ)存流程沒(méi)問(wèn)題医吊。

最后附上 項(xiàng)目全部代碼
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市逮京,隨后出現(xiàn)的幾起案子卿堂,更是在濱河造成了極大的恐慌,老刑警劉巖懒棉,帶你破解...
    沈念sama閱讀 212,599評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件草描,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡策严,警方通過(guò)查閱死者的電腦和手機(jī)穗慕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)妻导,“玉大人逛绵,你說(shuō)我怎么就攤上這事【缶拢” “怎么了术浪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,084評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)寿酌。 經(jīng)常有香客問(wèn)我胰苏,道長(zhǎng),這世上最難降的妖魔是什么醇疼? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,708評(píng)論 1 284
  • 正文 為了忘掉前任硕并,我火速辦了婚禮,結(jié)果婚禮上秧荆,老公的妹妹穿的比我還像新娘倔毙。我一直安慰自己,他們只是感情好乙濒,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,813評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布普监。 她就那樣靜靜地躺著,像睡著了一般琉兜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毙玻,一...
    開(kāi)封第一講書(shū)人閱讀 50,021評(píng)論 1 291
  • 那天豌蟋,我揣著相機(jī)與錄音,去河邊找鬼桑滩。 笑死梧疲,一個(gè)胖子當(dāng)著我的面吹牛允睹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播幌氮,決...
    沈念sama閱讀 39,120評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼缭受,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了该互?” 一聲冷哼從身側(cè)響起米者,我...
    開(kāi)封第一講書(shū)人閱讀 37,866評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎宇智,沒(méi)想到半個(gè)月后蔓搞,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,308評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡随橘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,633評(píng)論 2 327
  • 正文 我和宋清朗相戀三年喂分,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片机蔗。...
    茶點(diǎn)故事閱讀 38,768評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蒲祈,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萝嘁,到底是詐尸還是另有隱情梆掸,我是刑警寧澤,帶...
    沈念sama閱讀 34,461評(píng)論 4 333
  • 正文 年R本政府宣布酿愧,位于F島的核電站沥潭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏嬉挡。R本人自食惡果不足惜钝鸽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,094評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庞钢。 院中可真熱鬧拔恰,春花似錦、人聲如沸基括。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,850評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)风皿。三九已至河爹,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間桐款,已是汗流浹背咸这。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,082評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留魔眨,地道東北人媳维。 一個(gè)月前我還...
    沈念sama閱讀 46,571評(píng)論 2 362
  • 正文 我出身青樓酿雪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親侄刽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子指黎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,666評(píng)論 2 350

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