ui: Improved wallets page.

This commit is contained in:
tecnovert 2021-10-14 22:17:37 +02:00
parent 4475e5b643
commit 062283c31a
No known key found for this signature in database
GPG key ID: 8ED6D8750C4E3F93
6 changed files with 130 additions and 4 deletions

View file

@ -1,3 +1,3 @@
name = "basicswap" name = "basicswap"
__version__ = "0.0.21" __version__ = "0.0.22"

View file

@ -6,6 +6,7 @@
import os import os
import re import re
import sys
import zmq import zmq
import json import json
import time import time
@ -20,6 +21,7 @@ import threading
import traceback import traceback
import sqlalchemy as sa import sqlalchemy as sa
import collections import collections
import concurrent.futures
from enum import IntEnum, auto from enum import IntEnum, auto
from sqlalchemy.orm import sessionmaker, scoped_session from sqlalchemy.orm import sessionmaker, scoped_session
@ -83,6 +85,7 @@ from .db import (
XmrOffer, XmrOffer,
XmrSwap, XmrSwap,
XmrSplitData, XmrSplitData,
Wallets,
) )
from .base import BaseApp from .base import BaseApp
from .explorers import ( from .explorers import (
@ -462,6 +465,8 @@ class BasicSwap(BaseApp):
self._last_checked_events = 0 self._last_checked_events = 0
self._last_checked_xmr_swaps = 0 self._last_checked_xmr_swaps = 0
self._possibly_revoked_offers = collections.deque([], maxlen=48) # TODO: improve self._possibly_revoked_offers = collections.deque([], maxlen=48) # TODO: improve
self._updating_wallets_info = {}
self._last_updated_wallets_info = 0
# TODO: Adjust ranges # TODO: Adjust ranges
self.min_delay_event = self.settings.get('min_delay_event', 10) self.min_delay_event = self.settings.get('min_delay_event', 10)
@ -480,6 +485,7 @@ class BasicSwap(BaseApp):
self.SMSG_SECONDS_IN_HOUR = 60 * 60 # Note: Set smsgsregtestadjust=0 for regtest self.SMSG_SECONDS_IN_HOUR = 60 * 60 # Note: Set smsgsregtestadjust=0 for regtest
self.threads = [] self.threads = []
self.thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=4, thread_name_prefix='bsp')
# Encode key to match network # Encode key to match network
wif_prefix = chainparams[Coins.PART][self.chain]['key_prefix'] wif_prefix = chainparams[Coins.PART][self.chain]['key_prefix']
@ -573,6 +579,11 @@ class BasicSwap(BaseApp):
for t in self.threads: for t in self.threads:
t.join() t.join()
if sys.version_info[1] >= 9:
self.thread_pool.shutdown(cancel_futures=True)
else:
self.thread_pool.shutdown()
close_all_sessions() close_all_sessions()
self.engine.dispose() self.engine.dispose()
@ -828,6 +839,9 @@ class BasicSwap(BaseApp):
created_at BIGINT, created_at BIGINT,
PRIMARY KEY (record_id))''') PRIMARY KEY (record_id))''')
db_version += 1 db_version += 1
elif current_version == 9:
session.execute('ALTER TABLE wallets ADD COLUMN wallet_data VARCHAR')
db_version += 1
if current_version != db_version: if current_version != db_version:
self.db_version = db_version self.db_version = db_version
@ -5093,6 +5107,46 @@ class BasicSwap(BaseApp):
return rv return rv
def updateWalletInfo(self, coin):
wi = self.getWalletInfo(coin)
# Store wallet info to db so it's available after startup
self.mxDB.acquire()
try:
rv = []
now = int(time.time())
session = scoped_session(self.session_factory)
session.add(Wallets(coin_id=coin, wallet_data=json.dumps(wi), created_at=now))
coin_id = int(coin)
query_str = f'DELETE FROM wallets WHERE coin_id = {coin_id} AND record_id NOT IN (SELECT record_id FROM wallets WHERE coin_id = {coin_id} ORDER BY created_at DESC LIMIT 3 )'
session.execute(query_str)
session.commit()
except Exception as e:
self.log.error(f'updateWalletInfo {e}')
finally:
session.close()
session.remove()
self._updating_wallets_info[int(coin)] = False
self.mxDB.release()
def updateWalletsInfo(self, force_update=False, only_coin=None):
now = int(time.time())
if not force_update and now - self._last_updated_wallets_info < 30:
return
for c in Coins:
if only_coin is not None and c != only_coin:
continue
if c not in chainparams:
continue
if self.coin_clients[c]['connection_type'] == 'rpc':
self._updating_wallets_info[int(c)] = True
self.thread_pool.submit(self.updateWalletInfo, c)
if only_coin is None:
self._last_updated_wallets_info = int(time.time())
def getWalletsInfo(self, opts=None): def getWalletsInfo(self, opts=None):
rv = {} rv = {}
for c in Coins: for c in Coins:
@ -5105,6 +5159,44 @@ class BasicSwap(BaseApp):
rv[c] = {'name': chainparams[c]['name'].capitalize(), 'error': str(ex)} rv[c] = {'name': chainparams[c]['name'].capitalize(), 'error': str(ex)}
return rv return rv
def getCachedWalletsInfo(self, opts=None):
rv = {}
# Requires? self.mxDB.acquire()
try:
session = scoped_session(self.session_factory)
inner_str = 'SELECT coin_id, MAX(created_at) as max_created_at FROM wallets GROUP BY coin_id'
query_str = 'SELECT a.coin_id, wallet_data, created_at FROM wallets a, ({}) b WHERE a.coin_id = b.coin_id AND a.created_at = b.max_created_at'.format(inner_str)
q = session.execute(query_str)
for row in q:
coin_id = row[0]
wallet_data = json.loads(row[1])
wallet_data['lastupdated'] = row[2]
wallet_data['updating'] = self._updating_wallets_info.get(coin_id, False)
# Ensure the latest deposit address is displayed
q = session.execute('SELECT value FROM kv_string WHERE key = "receive_addr_{}"'.format(chainparams[coin_id]['name']))
for row in q:
wallet_data['deposit_address'] = row[0]
rv[coin_id] = wallet_data
finally:
session.close()
session.remove()
for c in Coins:
if c not in chainparams:
continue
if self.coin_clients[c]['connection_type'] == 'rpc':
coin_id = int(c)
if coin_id not in rv:
rv[coin_id] = {
'name': chainparams[c]['name'].capitalize(),
'updating': self._updating_wallets_info.get(coin_id, False),
}
return rv
def countAcceptedBids(self, offer_id=None): def countAcceptedBids(self, offer_id=None):
self.mxDB.acquire() self.mxDB.acquire()
try: try:

View file

@ -12,7 +12,7 @@ from enum import IntEnum, auto
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.declarative import declarative_base
CURRENT_DB_VERSION = 9 CURRENT_DB_VERSION = 10
Base = declarative_base() Base = declarative_base()
@ -360,6 +360,7 @@ class Wallets(Base):
record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True) record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
coin_id = sa.Column(sa.Integer) coin_id = sa.Column(sa.Integer)
wallet_name = sa.Column(sa.String) wallet_name = sa.Column(sa.String)
wallet_data = sa.Column(sa.String)
balance_type = sa.Column(sa.Integer) balance_type = sa.Column(sa.Integer)
amount = sa.Column(sa.BigInteger) amount = sa.Column(sa.BigInteger)
updated_at = sa.Column(sa.BigInteger) updated_at = sa.Column(sa.BigInteger)

View file

@ -279,11 +279,16 @@ class HttpHandler(BaseHTTPRequestHandler):
messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid)) messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
except Exception as e: except Exception as e:
messages.append('Error: {}'.format(str(e))) messages.append('Error: {}'.format(str(e)))
swap_client.updateWalletsInfo(True, c)
wallets = swap_client.getWalletsInfo() swap_client.updateWalletsInfo()
wallets = swap_client.getCachedWalletsInfo()
wallets_formatted = [] wallets_formatted = []
for k, w in wallets.items(): sk = sorted(wallets.keys())
for k in sk:
w = wallets[k]
if 'error' in w: if 'error' in w:
wallets_formatted.append({ wallets_formatted.append({
'cid': str(int(k)), 'cid': str(int(k)),
@ -291,6 +296,14 @@ class HttpHandler(BaseHTTPRequestHandler):
}) })
continue continue
if 'balance' not in w:
wallets_formatted.append({
'name': w['name'],
'havedata': False,
'updating': w['updating'],
})
continue
ci = swap_client.ci(k) ci = swap_client.ci(k)
fee_rate, fee_src = swap_client.getFeeRateForCoin(k) fee_rate, fee_src = swap_client.getFeeRateForCoin(k)
est_fee = swap_client.estimateWithdrawFee(k, fee_rate) est_fee = swap_client.estimateWithdrawFee(k, fee_rate)
@ -308,11 +321,16 @@ class HttpHandler(BaseHTTPRequestHandler):
'deposit_address': w['deposit_address'], 'deposit_address': w['deposit_address'],
'expected_seed': w['expected_seed'], 'expected_seed': w['expected_seed'],
'balance_all': float(w['balance']) + float(w['unconfirmed']), 'balance_all': float(w['balance']) + float(w['unconfirmed']),
'updating': w['updating'],
'lastupdated': format_timestamp(w['lastupdated']),
'havedata': True,
} }
if float(w['unconfirmed']) > 0.0: if float(w['unconfirmed']) > 0.0:
wf['unconfirmed'] = w['unconfirmed'] wf['unconfirmed'] = w['unconfirmed']
if k == Coins.PART: if k == Coins.PART:
wf['stealth_address'] = w['stealth_address']
wf['blind_balance'] = w['blind_balance'] wf['blind_balance'] = w['blind_balance']
if float(w['blind_unconfirmed']) > 0.0: if float(w['blind_unconfirmed']) > 0.0:
wf['blind_unconfirmed'] = w['blind_unconfirmed'] wf['blind_unconfirmed'] = w['blind_unconfirmed']

View file

@ -1,5 +1,7 @@
{% include 'header.html' %} {% include 'header.html' %}
<p><a href="/wallets">refresh</a></p>
<h3>Wallets</h3> <h3>Wallets</h3>
{% if refresh %} {% if refresh %}
<p>Page Refresh: {{ refresh }} seconds</p> <p>Page Refresh: {{ refresh }} seconds</p>
@ -13,10 +15,15 @@
{% for w in wallets %} {% for w in wallets %}
<h4>{{ w.name }} {{ w.version }}</h4> <h4>{{ w.name }} {{ w.version }}</h4>
{% if w.updating %}
<h5>Updating</h5>
{% endif %}
{% if w.havedata %}
{% if w.error %} {% if w.error %}
<p>Error: {{ w.error }}</p> <p>Error: {{ w.error }}</p>
{% else %} {% else %}
<table> <table>
<tr><td>Last updated:</td><td>{{ w.lastupdated }}</td></tr>
<tr><td>Balance:</td><td>{{ w.balance }}</td>{% if w.unconfirmed %}<td>Unconfirmed:</td><td>{{ w.unconfirmed }}</td>{% endif %}</tr> <tr><td>Balance:</td><td>{{ w.balance }}</td>{% if w.unconfirmed %}<td>Unconfirmed:</td><td>{{ w.unconfirmed }}</td>{% endif %}</tr>
@ -50,6 +57,7 @@
<tr><td>Fee Rate:</td><td>{{ w.fee_rate }}</td><td>Est Fee:</td><td>{{ w.est_fee }}</td></tr> <tr><td>Fee Rate:</td><td>{{ w.fee_rate }}</td><td>Est Fee:</td><td>{{ w.est_fee }}</td></tr>
</table> </table>
{% endif %} {% endif %}
{% endif %} <!-- havedata -->
{% endfor %} {% endfor %}
<input type="hidden" name="formid" value="{{ form_id }}"> <input type="hidden" name="formid" value="{{ form_id }}">

View file

@ -1,3 +1,10 @@
0.0.22
==============
- Improved wallets page
- Consistent wallet order
- Separated RPC calls into threads.
0.0.21 0.0.21
============== ==============
- Raised Particl and Monero daemon versions. - Raised Particl and Monero daemon versions.