Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skepticoin GUI (coming in 18 months) #83

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Expand Up @@ -3,3 +3,4 @@ immutables==0.15
pytest-mock==3.6.1
pytest==6.2.4
scrypt==0.8.18
flask==2.0.1
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -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',
],
},

Expand Down
42 changes: 42 additions & 0 deletions 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
45 changes: 45 additions & 0 deletions 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")
39 changes: 39 additions & 0 deletions 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 = """
<html>
<head>
<script>
if(typeof(EventSource)!="undefined") {
let source = new EventSource("/event-stream");
source.onmessage=function(event) {
console.log(event);
document.getElementById("result").innerHTML += event.data + "<br>";
}
}
else {
document.getElementById("result").innerHTML="No EventSource. Please upgrade your browser and try again.";
}
function showWallet() {
// simple function to demonstrate API call with browser-side processing
fetch('/wallet')
.then((response) => response.json())
.then(data => document.getElementById("result").innerHTML +=
'Your wallet has this many keys: ' + data.size + "<br>")
}
function showHeight() {
// simple function to demonstrate API call with browser-side processing
fetch('/height')
.then((response) => response.json())
.then(data => document.getElementById("result").innerHTML +=
'Your current blockchain height: ' + data.height + "<br>")
}
</script>
</head>
<body>
(please don't click these until initialization is complete):
<a href="javascript:showWallet()">show wallet</a> | <a href="javascript:showHeight()">show height</a>
<p>IMPORTANT: Do not launch more than one browser window.</p>
<div id="result">Loading...</div>
</body>
</html>
"""
22 changes: 22 additions & 0 deletions 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()