diff --git a/requirements.txt b/requirements.txt index bf8ea7d..1fe4077 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ immutables==0.15 pytest-mock==3.6.1 pytest==6.2.4 scrypt==0.8.18 +flask==2.0.1 \ No newline at end of file diff --git a/setup.py b/setup.py index f1f4a36..70b64a5 100644 --- a/setup.py +++ b/setup.py @@ -35,6 +35,7 @@ 'skepticoin-repl=skepticoin.scripts.repl:main', 'skepticoin-run=skepticoin.scripts.run:main', 'skepticoin-balance=skepticoin.scripts.balance:main', + 'skepticoin-gui=skepticoin.scripts.gui:main', ], }, diff --git a/skepticoin/gui/http_handler.py b/skepticoin/gui/http_handler.py new file mode 100644 index 0000000..d9afbbf --- /dev/null +++ b/skepticoin/gui/http_handler.py @@ -0,0 +1,42 @@ +from typing import Dict, Tuple +from flask import Flask +from .services import SkepticoinService +from .web_app_loader import WEB_APP_LOADER + + +app = Flask(__name__) +skeptis = SkepticoinService() + + +@app.route("/") +def webRoot() -> str: + return WEB_APP_LOADER # type: ignore # mypy bug!? + + +@app.route('/event-stream') +def event_stream() -> Tuple[str, int, Dict[str, str]]: + msg = skeptis.event_queue.pop() if skeptis.event_queue else 'Nothing Is Happening' + return ('data: %s\n\n' % msg, 200, { + 'Content-Type': 'text/event-stream', + 'Cache-Control': 'no-cache' + }) + + +@app.route('/wallet') +def get_wallet() -> Dict[str, int]: + return {'size': len(skeptis.wallet.keypairs)} + + +@app.route('/height') +def get_height() -> Dict[str, int]: + height = len(skeptis.thread.local_peer.chain_manager.coinstate.block_by_hash) + return {'height': height} + + +class HttpHandler: + + @staticmethod + def server_loop() -> None: + app.run() + + server_address = ('127.0.0.1', 5000) # this is the flask default diff --git a/skepticoin/gui/services.py b/skepticoin/gui/services.py new file mode 100644 index 0000000..8c8750c --- /dev/null +++ b/skepticoin/gui/services.py @@ -0,0 +1,45 @@ +from skepticoin.wallet import Wallet +from threading import Thread + +from skepticoin.scripts.utils import ( + open_or_init_wallet, + create_chain_dir, + read_chain_from_disk, + configure_logging_from_args, + start_networking_peer_in_background, + check_for_fresh_chain, + DefaultArgumentParser, +) + + +class SkepticoinService(): + + def __init__(self) -> None: + + self.event_queue = ['Initializing'] + + initThread = Thread(target=lambda: self.run()) + initThread.start() + + def run(self) -> None: + + self.event_queue.append('Doing some busywork') + parser = DefaultArgumentParser() + args = parser.parse_args() + configure_logging_from_args(args) + + self.event_queue.append('Creating chain dir') + create_chain_dir() + + self.event_queue.append('Reading chain from disk') + coinstate = read_chain_from_disk() + + self.event_queue.append('Reading wallet') + self.wallet: Wallet = open_or_init_wallet() + + # start our own peer so the GUI can have fresh blockchain + self.thread = start_networking_peer_in_background(args, coinstate) + + self.event_queue.append('Waiting for Fresh Chain') + check_for_fresh_chain(self.thread) + self.event_queue.append("Chain up to date") diff --git a/skepticoin/gui/web_app_loader.py b/skepticoin/gui/web_app_loader.py new file mode 100644 index 0000000..dd2334c --- /dev/null +++ b/skepticoin/gui/web_app_loader.py @@ -0,0 +1,39 @@ +# Load the browser side of the GUI. 100% totally temporary code to demonstrate the architecture. +WEB_APP_LOADER: str = """ + + + + + +(please don't click these until initialization is complete): +show wallet | show height +

IMPORTANT: Do not launch more than one browser window.

+
Loading...
+ + +""" diff --git a/skepticoin/scripts/gui.py b/skepticoin/scripts/gui.py new file mode 100644 index 0000000..1f936d3 --- /dev/null +++ b/skepticoin/scripts/gui.py @@ -0,0 +1,22 @@ +import webbrowser +from threading import Thread +from time import sleep + +from skepticoin.gui.http_handler import HttpHandler + + +def main() -> None: + + print('Starting local GUI server...') + serverThread = Thread(target=HttpHandler.server_loop) + serverThread.start() + + print('Sleeping') + sleep(2) + + print('Starting browser...') + webbrowser.open('http://%s:%d' % HttpHandler.server_address) + + print('Waiting...') + # serverThread.stop() ??? + serverThread.join()