diff --git a/.gitignore b/.gitignore index 01a374d..62c7f1b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ plugins/signatures.json .venv/ user_data/ -customPlugins/ \ No newline at end of file +customPlugins/ +cache/ \ No newline at end of file diff --git a/FireWalletBrowser.bsdesign b/FireWalletBrowser.bsdesign index 44990d5..cc21836 100644 Binary files a/FireWalletBrowser.bsdesign and b/FireWalletBrowser.bsdesign differ diff --git a/account.py b/account.py index 359c561..fe44113 100644 --- a/account.py +++ b/account.py @@ -6,7 +6,7 @@ import requests import re import domainLookup import json - +import time dotenv.load_dotenv() @@ -22,6 +22,7 @@ if show_expired is None: hsd = api.hsd(APIKEY,ip) hsw = api.hsw(APIKEY,ip) +cacheTime = 3600 # Verify the connection response = hsd.getInfo() @@ -30,6 +31,17 @@ exclude = ["primary"] if os.getenv("exclude") is not None: exclude = os.getenv("exclude").split(",") +def hsdConnected(): + if hsdVersion() == -1: + return False + return True + +def hsdVersion(): + info = hsd.getInfo() + if 'error' in info: + return -1 + return float('.'.join(info['version'].split(".")[:2])) + def check_account(cookie: str): if cookie is None: return False @@ -61,12 +73,15 @@ def check_password(cookie: str, password: str): return True def createWallet(account: str, password: str): + if not hsdConnected(): + return { + "error": { + "message": "Node not connected" + } + } # Create the account # Python wrapper doesn't support this yet response = requests.put(f"http://x:{APIKEY}@{ip}:12039/wallet/{account}") - print(response) - print(response.json()) - if response.status_code != 200: return { "error": { @@ -82,7 +97,6 @@ def createWallet(account: str, password: str): # Encrypt the wallet (python wrapper doesn't support this yet) response = requests.post(f"http://x:{APIKEY}@{ip}:12039/wallet/{account}/passphrase", json={"passphrase": password}) - print(response) return { "seed": seed, @@ -91,6 +105,13 @@ def createWallet(account: str, password: str): } def importWallet(account: str, password: str,seed: str): + if not hsdConnected(): + return { + "error": { + "message": "Node not connected" + } + } + # Import the wallet data = { "passphrase": password, @@ -98,9 +119,6 @@ def importWallet(account: str, password: str,seed: str): } response = requests.put(f"http://x:{APIKEY}@{ip}:12039/wallet/{account}",json=data) - print(response) - print(response.json()) - if response.status_code != 200: return { "error": { @@ -127,6 +145,16 @@ def listWallets(): return response return ['Wallet not connected'] +def selectWallet(account: str): + # Select wallet + response = hsw.rpc_selectWallet(account) + if response['error'] is not None: + return { + "error": { + "message": response['error']['message'] + } + } + def getBalance(account: str): # Get the total balance info = hsw.getBalance('default',account) @@ -204,13 +232,97 @@ def getDomains(account,own=True): return domains -def getTransactions(account): - # Get the transactions - info = hsw.getWalletTxHistory(account) - if 'error' in info: - return [] - return info +def getPageTXCache(account,page): + page = str(page) + if not os.path.exists(f'cache'): + os.mkdir(f'cache') + if not os.path.exists(f'cache/{account}_page.json'): + with open(f'cache/{account}_page.json', 'w') as f: + f.write('{}') + with open(f'cache/{account}_page.json') as f: + pageCache = json.load(f) + + if page in pageCache and pageCache[page]['time'] > int(time.time()) - cacheTime: + return pageCache[page]['txid'] + return None + +def pushPageTXCache(account,page,txid): + page = str(page) + if not os.path.exists(f'cache/{account}_page.json'): + with open(f'cache/{account}_page.json', 'w') as f: + f.write('{}') + with open(f'cache/{account}_page.json') as f: + pageCache = json.load(f) + + pageCache[page] = { + 'time': int(time.time()), + 'txid': txid + } + with open(f'cache/{account}_page.json', 'w') as f: + json.dump(pageCache, f,indent=4) + + return pageCache[page]['txid'] + +def getTXFromPage(account,page): + if page == 1: + return getTransactions(account)[-1]['hash'] + + cached = getPageTXCache(account,page) + if cached: + return getPageTXCache(account,page) + previous = getTransactions(account,page) + if len(previous) == 0: + return None + hash = previous[-1]['hash'] + pushPageTXCache(account,page,hash) + return hash + + + +def getTransactions(account,page=1,limit=100): + # Get the transactions + if hsdVersion() < 7: + info = hsw.getWalletTxHistory(account) + if 'error' in info: + return [] + return info[::-1] + + lastTX = None + if page < 1: + return [] + if page > 1: + lastTX = getTXFromPage(account,page-1) + + if lastTX: + response = requests.get(f'http://x:{APIKEY}@{ip}:12039/wallet/{account}/tx/history?reverse=true&limit={limit}&after={lastTX}') + elif page == 1: + response = requests.get(f'http://x:{APIKEY}@{ip}:12039/wallet/{account}/tx/history?reverse=true&limit={limit}') + else: + return [] + + if response.status_code != 200: + print(response.text) + return [] + data = response.json() + + # Refresh the cache if the next page is different + nextPage = getPageTXCache(account,page) + if nextPage is not None and nextPage != data[-1]['hash']: + print(f'Refreshing page {page}') + pushPageTXCache(account,page,data[-1]['hash']) + return data + +def getAllTransactions(account): + # Get the transactions + page = 0 + txs = [] + while True: + txs += getTransactions(account,page) + if len(txs) == 0: + break + page += 1 + return txs def check_address(address: str, allow_name: bool = True, return_address: bool = False): # Check if the address is valid diff --git a/main.py b/main.py index de66604..9b866ce 100644 --- a/main.py +++ b/main.py @@ -125,14 +125,23 @@ def transactions(): return redirect("/login") account = account_module.check_account(request.cookies.get("account")) - # Get the transactions - transactions = account_module.getTransactions(account) + page = request.args.get('page') + try: + page = int(page) + except: + page = 1 + + if page < 1: + page = 1 + + transactions = account_module.getTransactions(account,page) + txCount = len(transactions) transactions = render.transactions(transactions) - return render_template("tx.html", account=account, sync=account_module.getNodeSync(), - wallet_status=account_module.getWalletStatus(),tx=transactions) - + wallet_status=account_module.getWalletStatus(),tx=transactions, + page=page,txCount=txCount) + @app.route('/send') def send_page(): @@ -1435,6 +1444,12 @@ def send_assets(path): # Try path @app.route('/') def try_path(path): + # Check if node connected + if not account_module.hsdConnected(): + return redirect("/login?message=Node not connected") + + + if os.path.isfile("templates/" + path + ".html"): return render_template(path + ".html") else: diff --git a/plugins/txcount.py b/plugins/txcount.py index 7a1fcf8..c07579b 100644 --- a/plugins/txcount.py +++ b/plugins/txcount.py @@ -29,7 +29,14 @@ functions = { def main(params, authentication): wallet = authentication.split(":")[0] - txs = account.getTransactions(wallet) + txCount = 0 + page = 1 + while True: + txs = account.getTransactions(wallet,page) + if len(txs) == 0: + break + txCount += len(txs) + page += 1 - return {"txs": f'Total TXs: {len(txs)}'} + return {"txs": f'Total TXs: {txCount}'} \ No newline at end of file diff --git a/render.py b/render.py index 5b98f27..6a7b697 100644 --- a/render.py +++ b/render.py @@ -29,11 +29,10 @@ def domains(domains, mobile=False): return html def transactions(txs): + + if len(txs) == 0: + return 'No transactions found' html = '' - - # Reverse the list - txs = txs[::-1] - for tx in txs: action = "HNS Transfer" address = tx["outputs"][0]["address"] diff --git a/templates/tx.html b/templates/tx.html index 397b81f..4466fb4 100644 --- a/templates/tx.html +++ b/templates/tx.html @@ -65,8 +65,17 @@

Transactions

-
-

Transactions

+
+
+

Transactions

+ {% if page != 1 %} + Prev + {% endif %} + {% if txCount == 100 %} + Next + {% endif %} +
+