Skip to content

Commit

Permalink
GUI with cherrypy and bootstrap
Browse files Browse the repository at this point in the history
  • Loading branch information
JahPowerBit authored and JahPowerBit committed Feb 11, 2014
1 parent 5d9e652 commit 0f4c4d5
Show file tree
Hide file tree
Showing 39 changed files with 9,168 additions and 2 deletions.
54 changes: 52 additions & 2 deletions counterpartyd.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,18 @@
# Units
from lib import (config, api, util, exceptions, bitcoin, blocks)
from lib import (send, order, btcpay, issuance, broadcast, bet, dividend, burn, cancel, callback)

from lib import gui

if os.name == 'nt':
from lib import util_windows

json_print = lambda x: print(json.dumps(x, sort_keys=True, indent=4))

def set_options (data_dir=None, bitcoind_rpc_connect=None, bitcoind_rpc_port=None,
bitcoind_rpc_user=None, bitcoind_rpc_password=None, rpc_host=None, rpc_port=None,
rpc_user=None, rpc_password=None, log_file=None, database_file=None, testnet=False, testcoin=False, unittest=False):
rpc_user=None, rpc_password=None, gui_host=None, gui_port=None, gui_user=None,
gui_password=None, log_file=None, database_file=None, testnet=False, testcoin=False, unittest=False):

# Unittests always run on testnet.
if unittest and not testnet:
Expand Down Expand Up @@ -152,6 +156,38 @@ def set_options (data_dir=None, bitcoind_rpc_connect=None, bitcoind_rpc_port=Non
else:
raise exceptions.ConfigurationError('RPC password not set. (Use configuration file or --rpc-password=PASSWORD)')

#GUI host:
if gui_host:
config.GUI_HOST = gui_host
elif has_config and 'gui-host' in configfile['Default'] and configfile['Default']['gui-host']:
config.GUI_HOST = configfile['Default']['gui-host']
else:
config.GUI_HOST = config.RPC_HOST

#GUI port:
if gui_port:
config.GUI_PORT = gui_port
elif has_config and 'gui-port' in configfile['Default'] and configfile['Default']['gui-port']:
config.GUI_PORT = configfile['Default']['gui-port']
else:
config.GUI_PORT = 8080

# GUI user
if gui_user:
config.GUI_USER = gui_user
elif has_config and 'gui-user' in configfile['Default'] and configfile['Default']['gui-user']:
config.GUI_USER = configfile['Default']['gui-user']
else:
config.GUI_USER = config.RPC_USER

# GUI password
if gui_password:
config.GUI_PASSWORD = gui_password
elif has_config and 'gui-password' in configfile['Default'] and configfile['Default']['gui-password']:
config.GUI_PASSWORD = configfile['Default']['gui-password']
else:
config.GUI_PASSWORD = config.RPC_PASSWORD

# Log
if log_file:
config.LOG = log_file
Expand Down Expand Up @@ -356,6 +392,12 @@ def format_feed (feed):
parser.add_argument('--rpc-user', help='required username to use the counterpartyd JSON-RPC API (via HTTP basic auth)')
parser.add_argument('--rpc-password', help='required password (for rpc-user) to use the counterpartyd JSON-RPC API (via HTTP basic auth)')

parser.add_argument('--activate-gui', action='store_true', help='run GUI web server')
parser.add_argument('--gui-host', help='the host to provide the counterpartyd GUI')
parser.add_argument('--gui-port', type=int, help='port on which to provide the counterpartyd GUI')
parser.add_argument('--gui-user', help='required username to use the counterpartyd GUI (via HTTP basic auth)')
parser.add_argument('--gui-password', help='required password (for gui-user) to use the counterpartyd GUI (via HTTP basic auth)')

subparsers = parser.add_subparsers(dest='action', help='the action to be taken')

parser_server = subparsers.add_parser('server', help='run the server (WARNING: not thread‐safe)')
Expand Down Expand Up @@ -451,7 +493,9 @@ def format_feed (feed):
# Configuration
set_options(data_dir=args.data_dir, bitcoind_rpc_connect=args.bitcoind_rpc_connect, bitcoind_rpc_port=args.bitcoind_rpc_port,
bitcoind_rpc_user=args.bitcoind_rpc_user, bitcoind_rpc_password=args.bitcoind_rpc_password, rpc_host=args.rpc_host, rpc_port=args.rpc_port,
rpc_user=args.rpc_user, rpc_password=args.rpc_password, log_file=args.log_file, database_file=args.database_file, testnet=args.testnet, testcoin=args.testcoin, unittest=False)
rpc_user=args.rpc_user, rpc_password=args.rpc_password, gui_host=args.gui_host, gui_port=args.gui_port, gui_user=args.gui_user,
gui_password=args.gui_password, log_file=args.log_file, database_file=args.database_file, testnet=args.testnet,
testcoin=args.testcoin, unittest=False)

# Database
db = util.connect_to_db()
Expand Down Expand Up @@ -684,6 +728,12 @@ def format_feed (feed):
api_server = api.APIServer()
api_server.daemon = True
api_server.start()

if args.activate_gui:
gui_server = gui.XCPGUI()
gui_server.daemon = True
gui_server.start()

blocks.follow(db)

elif args.action == 'help':
Expand Down
218 changes: 218 additions & 0 deletions lib/gui.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
import sys
import os.path
import cherrypy
import decimal
import json
import threading

from . import (config, api, util, exceptions, bitcoin, blocks)
from . import (send, order, btcpay, issuance, broadcast, bet, dividend, burn, cancel, callback)

D = decimal.Decimal

#set_options()

class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super(DecimalEncoder, self).default(o)

class XCPGUI(threading.Thread):

def __init__ (self):
threading.Thread.__init__(self)

def run(self):

current_dir = os.path.dirname(os.path.abspath(__file__))
db = util.connect_to_db()

def get_param(key):
return cherrypy.request.params[key]

def index():
path = os.path.abspath(os.path.join(current_dir, '..', 'static/gui.html'))
return cherrypy.lib.static.serve_file(path)

def wallet():
wallet = {'addresses': {}}
totals = {}

for group in bitcoin.rpc('listaddressgroupings', []):
for bunch in group:
address, btc_balance = bunch[:2]
#print(address)
get_address = util.get_address(db, address=address)

balances = get_address['balances']
assets = {}
empty = True
if btc_balance:
assets['BTC'] = btc_balance
if 'BTC' in totals.keys(): totals['BTC'] += btc_balance
else: totals['BTC'] = btc_balance
empty = False
for balance in balances:
asset = balance['asset']
balance = D(util.devise(db, balance['amount'], balance['asset'], 'output'))
if balance:
if asset in totals.keys(): totals[asset] += balance
else: totals[asset] = balance
#table.add_row([asset, balance])
assets[asset] = balance
empty = False
if not empty:
wallet['addresses'][address] = assets

wallet['totals'] = totals
#print(wallet)

cherrypy.response.headers['Content-Type'] = 'application/json'
return json.dumps(wallet, cls=DecimalEncoder).encode("utf-8")

def action(**kwargs):

unsigned = True if get_param('unsigned')!=None and get_param('unsigned')=="1" else False
#print("unsigned:"+str(unsigned))
try:
action = get_param('action')

if action=='send':
source = get_param('source')
destination = get_param('destination')
asset = get_param('asset')
quantity = util.devise(db, get_param('quantity'), asset, 'input')
unsigned_tx_hex = send.create(db, source, destination, quantity, asset, unsigned=unsigned)
result = {'success':True, 'message':str(unsigned_tx_hex)}

elif action=='order':
source = get_param('source')
give_asset = get_param('give_asset')
get_asset = get_param('get_asset')
give_quantity = util.devise(db, get_param('give_quantity'), give_asset, 'input')
get_quantity = util.devise(db, get_param('get_quantity'), get_asset, 'input')
expiration = int(get_param('expiration'))
fee_required = 0
fee_provided = config.MIN_FEE
if give_asset == 'BTC':
fee_required = 0
fee_provided = util.devise(db, get_param('fee_provided'), 'BTC', 'input')
elif get_asset == 'BTC':
fee_required = util.devise(db, get_param('fee_required'), 'BTC', 'input')
fee_provided = config.MIN_FEE

unsigned_tx_hex = order.create(db, source, give_asset,
give_quantity, get_asset,
get_quantity, expiration,
fee_required, fee_provided,
unsigned=unsigned)

result = {'success':True, 'message':str(unsigned_tx_hex)}

elif action=='btcpay':
order_match_id = get_param('order_match_id')
unsigned_tx_hex = btcpay.create(db, order_match_id, unsigned=unsigned)
result = {'success':True, 'message':str(unsigned_tx_hex)}

elif action=='cancel':
offer_hash = get_param('offer_hash')
unsigned_tx_hex = cancel.create(db, offer_hash, unsigned=unsigned)
result = {'success':True, 'message':str(unsigned_tx_hex)}

elif action=='issuance':
source = get_param('source')
destination = get_param('destination')
asset_name = get_param('asset_name')
divisible = True if get_param('divisible')=="1" else False
quantity = util.devise(db, get_param('quantity'), None, 'input', divisible=divisible)

callable_ = True if get_param('callable')=="1" else False
call_date = get_param('call_date')
call_price = get_param('call_price')
description = get_param('description')

if callable_:
call_date = round(datetime.timestamp(dateutil.parser.parse(call_date)))
call_price = float(call_price)
else:
call_date, call_price = 0, 0

issuance.create(db, source, destination, asset_name, quantity, divisible,
callable_, call_date, call_price, description, unsigned=unsigned)
result = {'success':True, 'message':str(unsigned_tx_hex)}

elif action=='dividend':
source = get_param('source')
asset = get_param('asset')
quantity_per_share = util.devise(db, get_param('quantity_per_share'), 'XCP', 'input')
unsigned_tx_hex = dividend.create(db, source, quantity_per_share, asset, unsigned=unsigned)
result = {'success':True, 'message':str(unsigned_tx_hex)}

elif action=='callback':
source = get_param('source')
asset = get_param('asset')
fraction_per_share = float(get_param('fraction_per_share'))
unsigned_tx_hex = callback.create(db, source, fraction_per_share, asset, unsigned=unsigned)
result = {'success':True, 'message':str(unsigned_tx_hex)}

elif action=='broadcast':
source = get_param('source')
text = get_param('text')
value = util.devise(db, get_param('value'), 'value', 'input')
fee_multiplier = get_param('fee_multiplier')
unsigned_tx_hex = broadcast.create(db, source, int(time.time()), value, fee_multiplier, text, unsigned=unsigned)
result = {'success':True, 'message':str(unsigned_tx_hex)}

elif action=='bet':
source = get_param('source')
feed_address = get_param('feed_address')
bet_type = int(get_param('bet_type'))
deadline = calendar.timegm(dateutil.parser.parse(get_param('deadline')).utctimetuple())
wager = util.devise(db, get_param('wager'), 'XCP', 'input')
counterwager = util.devise(db, get_param('counterwager'), 'XCP', 'input')
target_value = util.devise(db, get_param('target_value'), 'value', 'input')
leverage = util.devise(db, get_param('leverage'), 'leverage', 'input')

expiration = get_param('expiration')
unsigned_tx_hex = bet.create(db, source, feed_address, bet_type, deadline,
wager, counterwager, target_value,
leverage, expiration, unsigned=unsigned)
result = {'success':True, 'message':str(unsigned_tx_hex)}

else:
result = {'success':False, 'message':'Unknown action.'}

if result['success']==True and unsigned==False:
tx_hash = bitcoin.transmit(unsigned_tx_hex, ask=False);
result['message'] = "Transaction transmited: "+tx_hash

except Exception as e:
result = {'success':False, 'message':str(e)}

cherrypy.response.headers['Content-Type'] = 'application/json'
return json.dumps(result, cls=DecimalEncoder).encode("utf-8")


d = cherrypy.dispatch.RoutesDispatcher()
d.connect(name='index', route='/', controller=index)
d.connect(name='wallet', route='/wallet', controller=wallet)
d.connect(name='action', route='/action', controller=action)

conf = {
'/': {'request.dispatch': d},
'/static': {
'tools.staticdir.on': True,
'tools.staticdir.dir': os.path.join(current_dir, '..', 'static')
}
}
cherrypy.tree.mount(self, '/', config=conf)

cherrypy.config.update({
'server.socket_host': config.GUI_HOST,
'server.socket_port': config.GUI_PORT
})

cherrypy.engine.start()

#XCPGUI().run()
Binary file added static/.DS_Store
Binary file not shown.
Binary file added static/._.DS_Store
Binary file not shown.
Binary file added static/._bootstrap-3.1.0
Binary file not shown.
Binary file added static/bootstrap-3.1.0/._css
Binary file not shown.
Binary file added static/bootstrap-3.1.0/._fonts
Binary file not shown.
Binary file added static/bootstrap-3.1.0/._js
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added static/bootstrap-3.1.0/css/._bootstrap.css
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading

0 comments on commit 0f4c4d5

Please sign in to comment.