mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-08 19:59:33 +00:00
ui: Improved wallets page.
This commit is contained in:
parent
4475e5b643
commit
062283c31a
6 changed files with 130 additions and 4 deletions
|
@ -1,3 +1,3 @@
|
|||
name = "basicswap"
|
||||
|
||||
__version__ = "0.0.21"
|
||||
__version__ = "0.0.22"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import zmq
|
||||
import json
|
||||
import time
|
||||
|
@ -20,6 +21,7 @@ import threading
|
|||
import traceback
|
||||
import sqlalchemy as sa
|
||||
import collections
|
||||
import concurrent.futures
|
||||
|
||||
from enum import IntEnum, auto
|
||||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
|
@ -83,6 +85,7 @@ from .db import (
|
|||
XmrOffer,
|
||||
XmrSwap,
|
||||
XmrSplitData,
|
||||
Wallets,
|
||||
)
|
||||
from .base import BaseApp
|
||||
from .explorers import (
|
||||
|
@ -462,6 +465,8 @@ class BasicSwap(BaseApp):
|
|||
self._last_checked_events = 0
|
||||
self._last_checked_xmr_swaps = 0
|
||||
self._possibly_revoked_offers = collections.deque([], maxlen=48) # TODO: improve
|
||||
self._updating_wallets_info = {}
|
||||
self._last_updated_wallets_info = 0
|
||||
|
||||
# TODO: Adjust ranges
|
||||
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.threads = []
|
||||
self.thread_pool = concurrent.futures.ThreadPoolExecutor(max_workers=4, thread_name_prefix='bsp')
|
||||
|
||||
# Encode key to match network
|
||||
wif_prefix = chainparams[Coins.PART][self.chain]['key_prefix']
|
||||
|
@ -573,6 +579,11 @@ class BasicSwap(BaseApp):
|
|||
for t in self.threads:
|
||||
t.join()
|
||||
|
||||
if sys.version_info[1] >= 9:
|
||||
self.thread_pool.shutdown(cancel_futures=True)
|
||||
else:
|
||||
self.thread_pool.shutdown()
|
||||
|
||||
close_all_sessions()
|
||||
self.engine.dispose()
|
||||
|
||||
|
@ -828,6 +839,9 @@ class BasicSwap(BaseApp):
|
|||
created_at BIGINT,
|
||||
PRIMARY KEY (record_id))''')
|
||||
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:
|
||||
self.db_version = db_version
|
||||
|
@ -5093,6 +5107,46 @@ class BasicSwap(BaseApp):
|
|||
|
||||
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):
|
||||
rv = {}
|
||||
for c in Coins:
|
||||
|
@ -5105,6 +5159,44 @@ class BasicSwap(BaseApp):
|
|||
rv[c] = {'name': chainparams[c]['name'].capitalize(), 'error': str(ex)}
|
||||
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):
|
||||
self.mxDB.acquire()
|
||||
try:
|
||||
|
|
|
@ -12,7 +12,7 @@ from enum import IntEnum, auto
|
|||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
|
||||
CURRENT_DB_VERSION = 9
|
||||
CURRENT_DB_VERSION = 10
|
||||
Base = declarative_base()
|
||||
|
||||
|
||||
|
@ -360,6 +360,7 @@ class Wallets(Base):
|
|||
record_id = sa.Column(sa.Integer, primary_key=True, autoincrement=True)
|
||||
coin_id = sa.Column(sa.Integer)
|
||||
wallet_name = sa.Column(sa.String)
|
||||
wallet_data = sa.Column(sa.String)
|
||||
balance_type = sa.Column(sa.Integer)
|
||||
amount = sa.Column(sa.BigInteger)
|
||||
updated_at = sa.Column(sa.BigInteger)
|
||||
|
|
|
@ -279,11 +279,16 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||
messages.append('Withdrew {} {} to address {}<br/>In txid: {}'.format(value, ticker, address, txid))
|
||||
except Exception as 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 = []
|
||||
for k, w in wallets.items():
|
||||
sk = sorted(wallets.keys())
|
||||
|
||||
for k in sk:
|
||||
w = wallets[k]
|
||||
if 'error' in w:
|
||||
wallets_formatted.append({
|
||||
'cid': str(int(k)),
|
||||
|
@ -291,6 +296,14 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||
})
|
||||
continue
|
||||
|
||||
if 'balance' not in w:
|
||||
wallets_formatted.append({
|
||||
'name': w['name'],
|
||||
'havedata': False,
|
||||
'updating': w['updating'],
|
||||
})
|
||||
continue
|
||||
|
||||
ci = swap_client.ci(k)
|
||||
fee_rate, fee_src = swap_client.getFeeRateForCoin(k)
|
||||
est_fee = swap_client.estimateWithdrawFee(k, fee_rate)
|
||||
|
@ -308,11 +321,16 @@ class HttpHandler(BaseHTTPRequestHandler):
|
|||
'deposit_address': w['deposit_address'],
|
||||
'expected_seed': w['expected_seed'],
|
||||
'balance_all': float(w['balance']) + float(w['unconfirmed']),
|
||||
'updating': w['updating'],
|
||||
'lastupdated': format_timestamp(w['lastupdated']),
|
||||
'havedata': True,
|
||||
}
|
||||
if float(w['unconfirmed']) > 0.0:
|
||||
wf['unconfirmed'] = w['unconfirmed']
|
||||
|
||||
if k == Coins.PART:
|
||||
|
||||
wf['stealth_address'] = w['stealth_address']
|
||||
wf['blind_balance'] = w['blind_balance']
|
||||
if float(w['blind_unconfirmed']) > 0.0:
|
||||
wf['blind_unconfirmed'] = w['blind_unconfirmed']
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
{% include 'header.html' %}
|
||||
|
||||
<p><a href="/wallets">refresh</a></p>
|
||||
|
||||
<h3>Wallets</h3>
|
||||
{% if refresh %}
|
||||
<p>Page Refresh: {{ refresh }} seconds</p>
|
||||
|
@ -13,10 +15,15 @@
|
|||
|
||||
{% for w in wallets %}
|
||||
<h4>{{ w.name }} {{ w.version }}</h4>
|
||||
{% if w.updating %}
|
||||
<h5>Updating</h5>
|
||||
{% endif %}
|
||||
{% if w.havedata %}
|
||||
{% if w.error %}
|
||||
<p>Error: {{ w.error }}</p>
|
||||
{% else %}
|
||||
<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>
|
||||
|
||||
|
||||
|
@ -50,6 +57,7 @@
|
|||
<tr><td>Fee Rate:</td><td>{{ w.fee_rate }}</td><td>Est Fee:</td><td>{{ w.est_fee }}</td></tr>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endif %} <!-- havedata -->
|
||||
{% endfor %}
|
||||
|
||||
<input type="hidden" name="formid" value="{{ form_id }}">
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
0.0.22
|
||||
==============
|
||||
- Improved wallets page
|
||||
- Consistent wallet order
|
||||
- Separated RPC calls into threads.
|
||||
|
||||
|
||||
0.0.21
|
||||
==============
|
||||
- Raised Particl and Monero daemon versions.
|
||||
|
|
Loading…
Reference in a new issue