搭建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)用之類(lè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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容