integrate docker to wallet creation and connection

mm-logging
lza_menace 4 years ago
parent e260b8f269
commit 1cecd043e4

@ -6,6 +6,7 @@ from wowstash.blueprints.auth import auth_bp
from wowstash.forms import Register, Login from wowstash.forms import Register, Login
from wowstash.models import User from wowstash.models import User
from wowstash.factory import db, bcrypt from wowstash.factory import db, bcrypt
from wowstash.library.docker import docker
@auth_bp.route("/register", methods=["GET", "POST"]) @auth_bp.route("/register", methods=["GET", "POST"])
@ -69,7 +70,7 @@ def login():
@auth_bp.route("/logout") @auth_bp.route("/logout")
def logout(): def logout():
if current_user.is_authenticated: if current_user.is_authenticated:
current_user.kill_wallet() docker.stop_container(current_user.wallet_container)
current_user.clear_wallet_data() current_user.clear_wallet_data()
logout_user() logout_user()
return redirect(url_for('meta.index')) return redirect(url_for('meta.index'))

@ -1,4 +1,4 @@
import subprocess from time import sleep
from io import BytesIO from io import BytesIO
from base64 import b64encode from base64 import b64encode
from qrcode import make as qrcode_make from qrcode import make as qrcode_make
@ -9,6 +9,7 @@ from flask_login import login_required, current_user
from socket import socket from socket import socket
from datetime import datetime from datetime import datetime
from wowstash.blueprints.wallet import wallet_bp from wowstash.blueprints.wallet import wallet_bp
from wowstash.library.docker import docker
from wowstash.library.jsonrpc import Wallet, to_atomic from wowstash.library.jsonrpc import Wallet, to_atomic
from wowstash.library.cache import cache from wowstash.library.cache import cache
from wowstash.forms import Send from wowstash.forms import Send
@ -21,6 +22,7 @@ from wowstash import config
@login_required @login_required
def loading(): def loading():
if current_user.wallet_connected and current_user.wallet_created: if current_user.wallet_connected and current_user.wallet_created:
sleep(1)
return redirect(url_for('wallet.dashboard')) return redirect(url_for('wallet.dashboard'))
return render_template('wallet/loading.html') return render_template('wallet/loading.html')
@ -46,7 +48,7 @@ def dashboard():
for tx in transfers[type]: for tx in transfers[type]:
all_transfers.append(tx) all_transfers.append(tx)
balances = wallet.get_balances() balances = wallet.get_balances()
qr_uri = f'wownero:{address}?tx_description="{current_user.email}"' qr_uri = f'wownero:{address}?tx_description={current_user.email}'
address_qr = qrcode_make(qr_uri).save(_address_qr) address_qr = qrcode_make(qr_uri).save(_address_qr)
qrcode = b64encode(_address_qr.getvalue()).decode() qrcode = b64encode(_address_qr.getvalue()).decode()
return render_template( return render_template(
@ -63,42 +65,33 @@ def dashboard():
@login_required @login_required
def connect(): def connect():
if current_user.wallet_connected is False: if current_user.wallet_connected is False:
tcp = socket() wallet = docker.start_wallet(current_user.id)
tcp.bind(('', 0)) port = docker.get_port(wallet)
_, port = tcp.getsockname() current_user.wallet_connected = docker.container_exists(wallet)
tcp.close() current_user.wallet_port = port
command = f"""wownero-wallet-rpc \ current_user.wallet_container = wallet
--detach \ db.session.commit()
--non-interactive \
--rpc-bind-port {port} \ return 'ok'
--wallet-file {config.WALLET_DIR}/{current_user.id}.wallet \
--rpc-login {current_user.id}:{current_user.wallet_password} \ @wallet_bp.route('/wallet/create')
--password {current_user.wallet_password} \ @login_required
--daemon-address {config.DAEMON_PROTO}://{config.DAEMON_HOST}:{config.DAEMON_PORT} \ def create():
--daemon-login {config.DAEMON_USER}:{config.DAEMON_PASS} \ if current_user.wallet_created is False:
--log-file {config.WALLET_DIR}/{current_user.id}.log docker.create_wallet(current_user.id)
""" current_user.wallet_created = True
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE) db.session.commit()
outs, errs = proc.communicate()
# print(outs) return 'ok'
if proc.returncode == 0:
print(f'Successfully started RPC for {current_user}!')
current_user.wallet_connected = True
current_user.wallet_port = port
current_user.wallet_pid = proc.pid
current_user.wallet_connect_date = datetime.now()
db.session.commit()
return "ok"
@wallet_bp.route('/wallet/status') @wallet_bp.route('/wallet/status')
@login_required @login_required
def status(): def status():
data = { data = {
"created": current_user.wallet_created, 'created': current_user.wallet_created,
"connected": current_user.wallet_connected, 'connected': current_user.wallet_connected,
"port": current_user.wallet_port, 'port': current_user.wallet_port,
"date": current_user.wallet_connect_date 'container': current_user.wallet_container
} }
return jsonify(data) return jsonify(data)

@ -57,6 +57,7 @@ def create_app():
login_manager = LoginManager() login_manager = LoginManager()
login_manager.init_app(app) login_manager.init_app(app)
login_manager.login_view = 'auth.login' login_manager.login_view = 'auth.login'
login_manager.logout_view = 'auth.logout'
@login_manager.user_loader @login_manager.user_loader
def load_user(user_id): def load_user(user_id):
@ -73,7 +74,16 @@ def create_app():
@app.template_filter('from_atomic') @app.template_filter('from_atomic')
def from_atomic(a): def from_atomic(a):
from wowstash.library.jsonrpc import from_atomic from wowstash.library.jsonrpc import from_atomic
return from_atomic(a) atomic = from_atomic(a)
if atomic == 0:
return 0
else:
return float(atomic)
@app.cli.command('clean_containers')
def clean_containers():
from wowstash.library.docker import docker
docker.cleanup()
# Routes # Routes
from wowstash.blueprints.auth import auth_bp from wowstash.blueprints.auth import auth_bp

@ -9,7 +9,7 @@ class Docker(object):
def __init__(self): def __init__(self):
self.client = from_env() self.client = from_env()
self.wownero_image = getattr(config, 'WOWNERO_IMAGE', 'lalanza808/wownero') self.wownero_image = getattr(config, 'WOWNERO_IMAGE', 'lalanza808/wownero')
self.wallet_dir = getattr(config, 'WALLET_DIR', './data/wallets') self.wallet_dir = getattr(config, 'WALLET_DIR', '/tmp/wallets')
self.listen_port = 34569 self.listen_port = 34569
def create_wallet(self, user_id): def create_wallet(self, user_id):
@ -45,6 +45,8 @@ class Docker(object):
command = f"""wownero-wallet-rpc \ command = f"""wownero-wallet-rpc \
--non-interactive \ --non-interactive \
--rpc-bind-port {self.listen_port} \ --rpc-bind-port {self.listen_port} \
--rpc-bind-ip 0.0.0.0 \
--confirm-external-bind \
--wallet-file /wallet/{u.id}.wallet \ --wallet-file /wallet/{u.id}.wallet \
--rpc-login {u.id}:{u.wallet_password} \ --rpc-login {u.id}:{u.wallet_password} \
--password {u.wallet_password} \ --password {u.wallet_password} \
@ -60,7 +62,7 @@ class Docker(object):
remove=True, remove=True,
detach=True, detach=True,
ports={ ports={
f'{self.listen_port}/tcp': None f'{self.listen_port}/tcp': ('127.0.0.1', None)
}, },
volumes={ volumes={
f'{self.wallet_dir}/{u.id}': { f'{self.wallet_dir}/{u.id}': {
@ -83,3 +85,18 @@ class Docker(object):
return True return True
except NotFound: except NotFound:
return False return False
def stop_container(self, container_id):
if self.container_exists(container_id):
c = self.client.containers.get(container_id)
c.stop()
def cleanup(self):
users = User.query.all()
for u in users:
if u.wallet_container:
if not self.container_exists(u.wallet_container):
u.clear_wallet_data()
docker = Docker()

@ -18,8 +18,7 @@ class User(db.Model):
wallet_created = db.Column(db.Boolean, default=False) wallet_created = db.Column(db.Boolean, default=False)
wallet_connected = db.Column(db.Boolean, default=False) wallet_connected = db.Column(db.Boolean, default=False)
wallet_port = db.Column(db.Integer, nullable=True) wallet_port = db.Column(db.Integer, nullable=True)
wallet_pid = db.Column(db.Integer, nullable=True) wallet_container = db.Column(db.String(30), nullable=True)
wallet_connect_date = db.Column(db.DateTime, nullable=True)
@property @property
def is_authenticated(self): def is_authenticated(self):
@ -40,17 +39,10 @@ class User(db.Model):
def get_id(self): def get_id(self):
return self.id return self.id
def kill_wallet(self):
try:
kill(self.wallet_pid, 9)
except Exception as e:
print('could kill:', e)
def clear_wallet_data(self): def clear_wallet_data(self):
self.wallet_connected = False self.wallet_connected = False
self.wallet_port = None self.wallet_port = None
self.wallet_pid = None self.wallet_container = None
self.wallet_connect_date = None
db.session.commit() db.session.commit()
def __repr__(self): def __repr__(self):

@ -41,7 +41,7 @@
xhr.send(); xhr.send();
} }
{% if current_user.wallet_connected == False %} {% if current_user.wallet_connected == False and current_user.wallet_created == True %}
document.addEventListener("DOMContentLoaded", function(){ document.addEventListener("DOMContentLoaded", function(){
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for("wallet.connect") }}'); xhr.open('GET', '{{ url_for("wallet.connect") }}');
@ -49,6 +49,14 @@
}); });
{% endif %} {% endif %}
{% if current_user.wallet_connected == False and current_user.wallet_created == False %}
document.addEventListener("DOMContentLoaded", function(){
var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for("wallet.create") }}');
xhr.send();
});
{% endif %}
window.setInterval(function(){ window.setInterval(function(){
{% if current_user.wallet_connected == False %} {% if current_user.wallet_connected == False %}
check_wallet_status('connected'); check_wallet_status('connected');