/ blockchain

EOSIO Blockchain dApp Step by Step: Part 3 - Webapp

Preface

This is the 3rd part (final) of the blog: EOSIO dApp on Blockchain Step-by-Step: Part 1. In the last part, I've developed a Smart Contract for EOSIO platform to simulate an election. This part I will develop a webapp which allows visitors to vote a candidate.

Below is a quick preview of the webapp:

Source Code Explanation

Firstly, please see below for the overview diagram:

system-diagram-1

The Frontend

The frontend consists of HTML, CSS and Javascript. I used Semantic-UI as CSS framework for nicely appearance. JQuery is heavily used in Javascript for easy development.

There has only one page (homepage HTML) for this webapp. The homepage has divided into four portions. Below is the screenshot of the portions:

scr01-1

Below is the code fragment of the homepage index.html:

...
  <body>
    <div class="ui container">
      <div class="ui grid">
    ...
        <div id="hints_portion" class="sixteen wide column">
        ...
        </div>
        <div id="input_portion" class="sixteen wide column">
        ...
        </div>
        <div id="voting_portion" class="sixteen wide column">
        ...
        </div>
        <div id="voted_portion" class="sixteen wide column">
        ...
        </div>
    ...
      </div>
    </div>
...

*Click here for the full source code of index.html

The app.js covers the frontend logic. Below is the highlight:

...
// Main Application Object
function App() {
  ...
}
...
// Ajax calls
App.prototype.getInfo = function() {
  return $.ajax({
    type: 'GET',
    dataType: 'json',
    url: '/api/getinfo'
  });
}
App.prototype.unlockWallet = function() {
  return $.ajax({
    type: 'POST',
    dataType: 'json',
    url: '/api/unlock_wallet'
  });
}
...
// Event handlers
App.prototype.onBtnInputNameClicked = function(evt) {
  ...
}
...
// Program startup
App.prototype.start = function() {
  self.getInfo().then(function() {
    return self.unlockWallet();
  }).done(function() {
    ...
  }
}
...

*Click here for the full source code of app.js

As you can see, I used jQuery ajax() and then() to perform several asynchronous calls to the backend. The following section will mention the backend code.

The Backend

The backend is programmed in Python and Flask as the web framework. Flask not only allows us very easy to create a powerful web application but quickly develop RESTful API services. Below is the code highlights of the server.py code:

import subprocess
from flask import Flask
from flask import render_template
...
def cleos(args):
    if isinstance(args, list):
        command = ['cleos', '--wallet-url=http://localhost:8899']
        command.extend(args)
        command = ' '.join(command)
    else:
        command = 'cleos ' + args

    results = subprocess.run(command, stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=True, check=False)
    return results
...
app = Flask(__name__)
...
@app.route('/')
@app.route('/index')
def index():
    return render_template('index.html')
...
# RESTful API functions
@app.route('/api/getinfo', methods=['GET'])
def get_info():
    result = cleos(['get', 'info'])
    rstmsg = result.stderr.decode('ascii')
    if not rstmsg.startswith('Fail'):
        return result.stdout
    else:
        return 'nodeos connection failed', 500
...

*Click here for the full source code of server.py

As mentioned above, inside the cleos() function, it spawns new processes to launch cleos command just like in command line. You may wonder that why not use EOSJS. The fact is there was a problem to create EOSIO accounts in EOSJS. Actually, I tried all efforts in NodeJS codes to create an account in EOSJS but all failed. So I gave up and switched to Python Flask. Although subprocess is slow and has scalability issue. I think it is appropriate for demonstration purpose though.

This approach makes me easy to invoke the EOSIO Smart Contract. Below code fragment in server.py illustrated how to invoke vote action which the smart contract developed in the last part of the blog:

...
@app.route('/api/vote_candidate', methods=['POST'])
def vote_candidate():
    account = request.form.get('account')
    candidate = request.form.get('candidate')
    param = '\'["' + account + '", ' + candidate + ']\''
    # Invoke the Smart Contract "vote" action
    result = cleos(['push', 'action', 'election', 'vote', param, '-p', account])
    print(result.stderr)
    if result.returncode == 0:
        return jsonify({'result': result.stderr.decode('ascii')})
    else:
        return result.stderr, 500
...

Thus the frontend code app.js to invoke that:

...
App.prototype.voteCandidate = function(account, candidate) {
  return $.ajax({
    type: 'POST',
    data: {
      account: account,
      candidate: candidate
    },
    dataType: 'json',
    url: '/api/vote_candidate'
  });
}
...
  this.voteCandidate(this._account, val).done(function(resp) {
    console.info('Vote AJAX call result');
    console.log(resp);
...

Try It Yourself

I've setup a demo server lets you have a taste of EOSIO blockchain. Browse to http://demo.simonho.net:5000 to try it yourself. But I cannot guarantee the server is available anytime and long-lasting. It just a virtual machine of my home PC though 😊

Conclusion

That's all for the series of my EOSIO blockchain experiment. The hyperlinks of prior parts: part 1 and part 2.

(Bonus Part 4 is available: Which I used Google App Maker as frontend instead of HTML/CSS/JS used in this part.)

Hope You Enjoy!

The project full source code is hosting on this github repo