From 3bb17ec0bbdac6755fc1622d5a87235fc95d2d6a Mon Sep 17 00:00:00 2001 From: freqnik Date: Tue, 1 Oct 2024 21:58:35 -0400 Subject: [PATCH] Add background threading to Subscribe and Subscriptions screen. SubResult now in NodeTree. Change font size on sub expiration --- src/cli/sentinel.py | 5 ++- src/cli/wallet.py | 55 +++++++++++++++++++++-------- src/kv/meile.kv | 1 + src/typedef/konstants.py | 21 ++++++++++-- src/ui/screens.py | 74 ++++++++++++++++++++++++++++++++-------- src/ui/widgets.py | 22 ++++++++---- 6 files changed, 139 insertions(+), 39 deletions(-) diff --git a/src/cli/sentinel.py b/src/cli/sentinel.py index e1690a5..72cfd70 100755 --- a/src/cli/sentinel.py +++ b/src/cli/sentinel.py @@ -9,6 +9,7 @@ import time from urllib.parse import urlparse import copy +from copy import deepcopy import random from treelib import Tree @@ -32,6 +33,7 @@ class NodeTreeData(): BackupNodeTree = None NodeTree = None + SubResult = None NodeScores = {} NodeLocations = {} NodeTypes = {} @@ -493,7 +495,8 @@ def get_subscriptions(self, ADDRESS): }) k += 1 - return SubsFinalResult + #return SubsFinalResult + self.SubResult = deepcopy(SubsFinalResult) def GetQuota(self, id): diff --git a/src/cli/wallet.py b/src/cli/wallet.py index 0fda324..f24d5b0 100755 --- a/src/cli/wallet.py +++ b/src/cli/wallet.py @@ -383,7 +383,9 @@ def send_2plan_wallet(self, KEYNAME, plan_id, DENOM, amount_required): if tx.get("log", None) is None: try: tx_response = sdk.nodes.wait_for_tx(tx["hash"], timeout=25) - except mospy.exceptions.clients.TransactionTimeout as e: + except (mospy.exceptions.clients.TransactionTimeout, + mospy.exceptions.clients.NodeException, + mospy.exceptions.clients.NodeTimeoutException) as e: return (False, {'hash' : None, 'success' : False, 'message' : "GRPC Error"}) tx_height = tx_response.get("txResponse", {}).get("height", 0) if isinstance(tx_response, dict) else tx_response.tx_response.height @@ -427,7 +429,9 @@ def subscribe(self, KEYNAME, NODE, DEPOSIT, GB, hourly): status_code = e.code() if status_code == StatusCode.NOT_FOUND: - return(False, "Wallet not found on blockchain. Please verify you have sent coins to your wallet to activate it. Then try your subscription again") + #return(False, "Wallet not found on blockchain. Please verify you have sent coins to your wallet to activate it. Then try your subscription again") + self.returncode = (False, "Wallet not found on blockchain. Please verify you have sent coins to your wallet to activate it. Then try your subscription again") + return balance = self.get_balance(sdk._account.address) amount_required = float(DEPOSIT.replace(DENOM, "")) @@ -436,8 +440,9 @@ def subscribe(self, KEYNAME, NODE, DEPOSIT, GB, hourly): ubalance = balance.get(token_ibc[DENOM][1:], 0) * IBCTokens.SATOSHI if ubalance < amount_required: - return(False, f"Balance is too low, required: {round(amount_required / IBCTokens.SATOSHI, 4)}{token_ibc[DENOM][1:]}") - + #return(False, f"Balance is too low, required: {round(amount_required / IBCTokens.SATOSHI, 4)}{token_ibc[DENOM][1:]}") + self.returncode = (False, f"Balance is too low, required: {round(amount_required / IBCTokens.SATOSHI, 4)}{token_ibc[DENOM][1:]}") + return tx_params = TxParams( # denom="udvpn", # TODO: from ConfParams # fee_amount=20000, # TODO: from ConfParams @@ -456,23 +461,39 @@ def subscribe(self, KEYNAME, NODE, DEPOSIT, GB, hourly): if tx.get("log", None) is not None: print(tx["log"]) - return(False, tx["log"]) - + #return(False, tx["log"]) + self.returncode = (False, tx["log"]) + return + + ''' + Here you need to also check for gRPC Exceptions, + if the user is offline or disconnected to not make Meile crash + on these rare casees. + ''' if tx.get("hash", None) is not None: try: tx_response = sdk.nodes.wait_for_tx(tx["hash"], timeout=25) - except mospy.exceptions.clients.TransactionTimeout as e: + + + except (mospy.exceptions.clients.TransactionTimeout, + mospy.exceptions.clients.NodeException, + mospy.exceptions.clients.NodeTimeoutException) as e: print(str(e)) - return(False, "GRPC Error") + #return(False, "GRPC Error") + self.returncode = (False, "GRPC Error") + return print(tx_response) subscription_id = search_attribute( tx_response, "sentinel.node.v2.EventCreateSubscription", "id" ) if subscription_id: - return (True, subscription_id) - - return(False, "Tx error") + #return (True, subscription_id) + self.returncode = (True, subscription_id) + return + #return(False, "Tx error") + self.returncode = (False, "Tx error") + return def DetermineDenom(self, deposit): for key,value in IBCTokens.IBCUNITTOKEN.items(): @@ -531,7 +552,9 @@ def unsubscribe(self, subId): if tx.get("log", None) is None: try: tx_response = sdk.plans.wait_for_tx(tx["hash"], timeout=25) - except mospy.exceptions.clients.TransactionTimeout as e: + except (mospy.exceptions.clients.TransactionTimeout, + mospy.exceptions.clients.NodeException, + mospy.exceptions.clients.NodeTimeoutException) as e: print(str(e)) return {'hash' : "0x0", 'success' : False, 'message' : "GRPC Error"} tx_height = tx_response.get("txResponse", {}).get("height", 0) if isinstance(tx_response, dict) else tx_response.tx_response.height @@ -585,7 +608,9 @@ def connect(self, ID, address, type): tx = sdk.sessions.EndSession(session_id=session.id, rating=0, tx_params=tx_params) try: tx_response = sdk.sessions.wait_for_tx(tx["hash"], timeout=25) - except mospy.exceptions.clients.TransactionTimeout as e: + except (mospy.exceptions.clients.TransactionTimeout, + mospy.exceptions.clients.NodeException, + mospy.exceptions.clients.NodeTimeoutException) as e: print(str(e)) conndesc.write("GRPC Error... Exiting") conndesc.flush() @@ -605,7 +630,9 @@ def connect(self, ID, address, type): try: tx_response = sdk.sessions.wait_for_tx(tx["hash"], timeout=25) - except mospy.exceptions.clients.TransactionTimeout as e: + except (mospy.exceptions.clients.TransactionTimeout, + mospy.exceptions.clients.NodeException, + mospy.exceptions.clients.NodeTimeoutException) as e: print(str(e)) conndesc.write("GRPC Error... Exiting") conndesc.flush() diff --git a/src/kv/meile.kv b/src/kv/meile.kv index 8fac0b9..cc02646 100755 --- a/src/kv/meile.kv +++ b/src/kv/meile.kv @@ -969,6 +969,7 @@ WindowManager: markup: True size_hint_x: 1 font_name: root.get_font() + font_size: sp(11) HSeparator: HSeparator: HSeparator: diff --git a/src/typedef/konstants.py b/src/typedef/konstants.py index 3b77abb..cb02089 100755 --- a/src/typedef/konstants.py +++ b/src/typedef/konstants.py @@ -545,8 +545,8 @@ class IBCTokens(): #mu_coins = ["tsent", "udvpn", "uscrt", "uosmo", "uatom", "udec"] class TextStrings(): dash = "-" - VERSION = "v2.0.0-beta5.1" - BUILD = "1726810350798" + VERSION = "2.0.0-beta6" + BUILD = "1727851832347" RootTag = "SENTINEL" PassedHealthCheck = "Passed Sentinel Health Check" FailedHealthCheck = "Failed Sentinel Health Check" @@ -644,6 +644,23 @@ class NodeKeys(): + + + + + + + + + + + + + + + + + diff --git a/src/ui/screens.py b/src/ui/screens.py index 7b9d2e3..a9c9155 100755 --- a/src/ui/screens.py +++ b/src/ui/screens.py @@ -343,7 +343,7 @@ class MainWindow(Screen): dnscrypt = False warpd_disconnected = True NodeTree = None - SubResult = None + #SubResult = None MeileConfig = None ConnectedNode = None menu = None @@ -393,6 +393,7 @@ def __init__(self, node_tree, **kwargs): super(MainWindow, self).__init__() self.NodeTree = node_tree + #self.SubResult = self.NodeTree.SubResult self.MeileLand = OurWorld() self.MeileConfig = MeileGuiConfig() @@ -1257,7 +1258,7 @@ def Refresh(self): pass # Clear out Subscriptions - self.SubResult = None + self.NodeTree.SubResult = None # Redraw Map Pins self.AddCountryNodePins(False) self.refresh_country_recycler() @@ -1676,17 +1677,18 @@ def set_previous_screen(self): class SubscriptionScreen(MDBoxLayout): - SubResult = None def __init__(self, node_tree, **kwargs): super(SubscriptionScreen, self).__init__() self.NodeTree = node_tree self.get_config(None) - self.add_loading_popup("Loading...") - + #self.add_loading_popup("Loading...") + self.cd = ConnectionDialog() + self.set_conn_dialog(self.cd, "Loading Subscriptions...") + if self.address: - Clock.schedule_once(self.subs_callback, 0.25) + self.subs_callback(None) return else: self.remove_loading_widget(None) @@ -1696,16 +1698,33 @@ def __init__(self, node_tree, **kwargs): def GetSubscriptions(self): mw = Meile.app.root.get_screen(WindowNames.MAIN_WINDOW) + + ''' Make this a background thread and not on main loop Remove ThreadWtithResult dep. Add loading bar or spinning wheel ''' try: - thread = ThreadWithResult(target=self.NodeTree.get_subscriptions, args=(self.address,)) - thread.start() - thread.join() - mw.SubResult = thread.result + print("Staring thread...") + #self.NodeTree.get_subscriptions(self.address) + + t = Thread(target=lambda: self.NodeTree.get_subscriptions(self.address)) + t.start() + l = 13 + pool = l*100 + inc = float(1/pool) + while t.is_alive(): + yield 0.0165 + self.cd.ids.pb.value += inc + print("Thread completed.") + self.cd.ids.pb.value = 1 + #thread = ThreadWithResult(target=self.NodeTree.get_subscriptions, args=(self.address,)) + #thread.start() + #thread.join() + + mw.NodeTree.SubResult = deepcopy(self.NodeTree.SubResult) + print(mw.NodeTree.SubResult) except Exception as e: print(str(e)) return None @@ -1715,10 +1734,24 @@ def subs_callback(self, dt): yield 0.314 mw = Meile.app.root.get_screen(WindowNames.MAIN_WINDOW) - if not mw.SubResult: - self.GetSubscriptions() + if mw.NodeTree.SubResult is None: + try: + t = Thread(target=lambda: self.NodeTree.get_subscriptions(self.address)) + t.start() + l = 13 + pool = l*100 + inc = float(1/pool) + while t.is_alive(): + yield 0.0165 + self.cd.ids.pb.value += inc + self.cd.ids.pb.value = 1 + mw.NodeTree.SubResult = deepcopy(self.NodeTree.SubResult) + print(mw.NodeTree.SubResult) + except Exception as e: + print(str(e)) + return None try: - for sub in mw.SubResult: + for sub in mw.NodeTree.SubResult: self.add_sub_rv_data(sub) except TypeError: print("Connection Error") @@ -1729,7 +1762,7 @@ def subs_callback(self, dt): # Auto-connect from NodeCarousel if sub found if mw.SubCaller: - for sub in mw.SubResult: + for sub in mw.NodeTree.SubResult: print(sub) if mw.NodeCarouselData['address'] == sub[NodeKeys.FinalSubsKeys[2]]: mw.SelectedSubscription['id'] = sub[NodeKeys.FinalSubsKeys[0]] @@ -1816,7 +1849,18 @@ def add_loading_popup(self, title_text): self.dialog = None self.dialog = MDDialog(title=title_text,md_bg_color=get_color_from_hex(MeileColors.BLACK)) self.dialog.open() - + + @mainthread + def set_conn_dialog(self, cd, title): + self.dialog = None + self.dialog = MDDialog( + title=title, + type="custom", + content_cls=cd, + md_bg_color=get_color_from_hex(MeileColors.BLACK), + ) + self.dialog.open() + @mainthread def remove_loading_widget(self, dt): try: diff --git a/src/ui/widgets.py b/src/ui/widgets.py index d705519..3afa1f5 100755 --- a/src/ui/widgets.py +++ b/src/ui/widgets.py @@ -19,7 +19,7 @@ from kivymd.uix.menu import MDDropdownMenu from kivymd.uix.list import OneLineIconListItem from kivymd.uix.behaviors import HoverBehavior -from kivymd.theming import ThemableBehavior +#from kivymd.theming import ThemableBehavior from kivymd.uix.behaviors.elevation import RectangularElevationBehavior from kivyoav.delayed import delayable @@ -38,6 +38,7 @@ from requests.auth import HTTPBasicAuth import json import webbrowser +import sys from typedef.konstants import IBCTokens, HTTParams, MeileColors, NodeKeys from typedef.win import CoinsList, WindowNames @@ -1474,9 +1475,16 @@ def subscribe(self, subscribe_dialog, *kwargs): KEYNAME = CONFIG['wallet'].get('keyname', '') hwf = HandleWalletFunctions() - returncode = hwf.subscribe(KEYNAME, sub_node[1], deposit, sub_node[3], sub_node[4]) + t = Thread(target=lambda: hwf.subscribe(KEYNAME, sub_node[1], deposit, sub_node[3], sub_node[4])) + t.start() - if returncode[0]: + while t.is_alive(): + print(".", end="") + sys.stdout.flush() + yield 0.5 + #returncode = hwf.subscribe(KEYNAME, sub_node[1], deposit, sub_node[3], sub_node[4]) + + if hwf.returncode[0]: self.dialog.dismiss() self.dialog = MDDialog( title="Successful!", @@ -1544,7 +1552,7 @@ def closeDialogReturnToSubscriptions(self,inst): self.dialog.dismiss() self.dialog = None mw = Meile.app.root.get_screen(WindowNames.MAIN_WINDOW) - mw.SubResult = None + mw.NodeTree.SubResult = None if mw.SubCaller: mw.switch_to_sub_window() @@ -1561,7 +1569,7 @@ def closeDialog(self, inst): self.dialog = None #class WalletCoinRow(MDCard,RectangularElevationBehavior,ThemableBehavior, HoverBehavior): -class WalletCoinRow(MDCard,ThemableBehavior, HoverBehavior): +class WalletCoinRow(MDCard,HoverBehavior): logo = StringProperty('') text = StringProperty('') @@ -1573,7 +1581,7 @@ class RowContainer(MDBoxLayout): Recycler of the node cards after clicking country ''' #class RecycleViewRow(MDCard,RectangularElevationBehavior,ThemableBehavior, HoverBehavior): -class RecycleViewRow(MDCard,ThemableBehavior, HoverBehavior): +class RecycleViewRow(MDCard, HoverBehavior): dialog = None node_data = ObjectProperty() #node_types = ObjectProperty() @@ -1614,7 +1622,7 @@ def switch_to_node_carousel(self, node_data): mw.carousel.add_widget(NodeWidget) mw.carousel.load_slide(NodeWidget) -class MDMapCountryButton(MDFillRoundFlatButton,ThemableBehavior, HoverBehavior): +class MDMapCountryButton(MDFillRoundFlatButton,HoverBehavior): def on_enter(self, *args): self.md_bg_color = get_color_from_hex("#fcb711") Window.set_system_cursor('arrow')