Skip to content

Commit 4103611

Browse files
async wallet balance works great
1 parent 02f6820 commit 4103611

File tree

2 files changed

+75
-27
lines changed

2 files changed

+75
-27
lines changed

internal_filesystem/apps/com.lightningpiggy.displaywallet/assets/displaywallet.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,15 @@ def redraw_balance_cb(timer):
217217
balance_label.set_text(str(wallet.last_known_balance))
218218

219219
def janitor_cb(timer):
220+
global wallet
220221
if lv.screen_active() != main_screen and lv.screen_active() != settings_screen:
221222
print("app backgrounded, cleaning up...")
222223
janitor.delete()
223-
redraw_timer.delete()
224+
wallet.destroy()
224225
if settings_screen:
225226
settings_screen.delete()
227+
if main_screen:
228+
main_screen.delete()
226229

227230
build_main_ui()
228231

@@ -242,7 +245,6 @@ def janitor_cb(timer):
242245
else:
243246
print(f"No or unsupported wallet type configured: '{wallet_type}'")
244247

245-
wallet.start_refresh_balance()
246-
redraw_timer = lv.timer_create(redraw_balance_cb, 1000, None)
248+
wallet.start_refresh_balance(lambda : balance_label.set_text(str(wallet.last_known_balance)))
247249

248250
janitor = lv.timer_create(janitor_cb, 1000, None)

internal_filesystem/apps/com.lightningpiggy.displaywallet/assets/wallet.py

Lines changed: 70 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,13 @@ def __str__(self):
2828
elif isinstance(self, NWCWallet):
2929
return "NWCWallet"
3030

31-
def start_refresh_balance(self):
31+
def start_refresh_balance(self, balance_updated_cb):
3232
_thread.stack_size(mpos.apps.good_stack_size())
33-
_thread.start_new_thread(self.fetch_balance_thread, ())
33+
_thread.start_new_thread(self.fetch_balance_thread, (balance_updated_cb,))
34+
35+
def destroy(self):
36+
# optional to inherit
37+
pass
3438

3539

3640
class LNBitsWallet(Wallet):
@@ -40,7 +44,7 @@ def __init__(self, lnbits_url, lnbits_readkey):
4044
self.lnbits_url = lnbits_url
4145
self.lnbits_readkey = lnbits_readkey
4246

43-
def fetch_balance_thread(self):
47+
def fetch_balance_thread(self, balance_updated_cb):
4448
print("fetch_balance_thread")
4549
walleturl = self.lnbits_url + "/api/v1/wallet"
4650
headers = {
@@ -61,6 +65,7 @@ def fetch_balance_thread(self):
6165
balance_msat = balance_reply['balance']
6266
self.last_known_balance = round(balance_msat / 1000)
6367
#self.last_known_balance_timestamp = mpos.time.epoch_seconds()
68+
balance_updated_cb()
6469
except Exception as e:
6570
print(f"Could not parse reponse text '{response_text}' as JSON: {e}")
6671

@@ -74,49 +79,97 @@ def __init__(self, nwc_url):
7479
self.private_key = PrivateKey(bytes.fromhex(self.secret))
7580
self.relay_manager = RelayManager()
7681
self.relay_manager.add_relay(self.relay)
77-
print(f"DEBUG: Opening relay connections")
78-
self.relay_manager.open_connections({"cert_reqs": ssl.CERT_NONE})
82+
self.connected = False
83+
84+
def destroy(self):
85+
self.relay_manager.close_connections()
86+
87+
def fetch_balance_thread(self, balance_updated_cb) :
88+
# make sure connected to relay (otherwise connect)
89+
if self.relay_manager.relays[self.relay].connected != True:
90+
print(f"DEBUG: Opening relay connections")
91+
self.relay_manager.open_connections({"cert_reqs": ssl.CERT_NONE})
92+
self.connected = False
93+
for _ in range(20):
94+
time.sleep(0.5)
95+
if self.relay_manager.relays[self.relay].connected is True:
96+
self.connected = True
97+
break
98+
print("Waiting for relay connection...")
99+
if not self.connected:
100+
print("Failed to connect, aborting...")
101+
return
79102
# Set up subscription to receive response
80103
self.subscription_id = "nwc_balance_" + str(round(time.time()))
81-
#print(f"DEBUG: Setting up subscription with ID: {self.subscription_id}")
104+
print(f"DEBUG: Setting up subscription with ID: {self.subscription_id}")
82105
self.filters = Filters([Filter(
83106
kinds=[23195], # NWC replies
84107
authors=[self.wallet_pubkey],
85108
pubkey_refs=[self.private_key.public_key.hex()]
86109
)])
87-
#print(f"DEBUG: Subscription filters: {filters.to_json_array()}")
110+
print(f"DEBUG: Subscription filters: {self.filters.to_json_array()}")
88111
self.relay_manager.add_subscription(self.subscription_id, self.filters)
89-
time.sleep(5)
90-
91-
92-
def start_refresh_balance(self) :
93-
# TODO: make sure connected to relay (otherwise connect)
94-
112+
time.sleep(1)
95113
# Create get_balance request
96114
balance_request = {
97115
"method": "get_balance",
98116
"params": {}
99117
}
100118
print(f"DEBUG: Created balance request: {balance_request}")
101-
102119
print(f"DEBUG: Creating encrypted DM to wallet pubkey: {self.wallet_pubkey}")
103120
dm = EncryptedDirectMessage(
104121
recipient_pubkey=self.wallet_pubkey,
105122
cleartext_content=json.dumps(balance_request)
106123
)
107-
108124
print(f"DEBUG: Signing DM {json.dumps(dm)} with private key")
109125
self.private_key.sign_event(dm) # sign also does encryption if it's a encrypted dm
110126
print(f"DEBUG: DM created with ID: {dm.id}")
111-
112127
# Publish request
113128
print(f"DEBUG: Publishing subscription request")
114129
request_message = [ClientMessageType.REQUEST, self.subscription_id]
115130
request_message.extend(self.filters.to_json_array())
116131
self.relay_manager.publish_message(json.dumps(request_message))
117132
print(f"DEBUG: Publishing encrypted DM")
118133
self.relay_manager.publish_event(dm)
119-
134+
# only accept events after the time it was published
135+
after_time = mpos.time.epoch_seconds()
136+
after_time -= 60 # go back a bit because server clocks might be drifting
137+
print(f"will only consider events after {after_time}")
138+
139+
# Wait for response
140+
print(f"DEBUG: Waiting for response...")
141+
print(f"starting at {time.localtime()}")
142+
start_time = mpos.time.epoch_seconds()
143+
balance = None
144+
while mpos.time.epoch_seconds() - start_time < 60 * 2:
145+
while self.relay_manager.message_pool.has_events():
146+
print(f"DEBUG: Event received from message pool")
147+
event_msg = self.relay_manager.message_pool.get_event()
148+
event_created_at = event_msg.event.created_at
149+
print(f"Received at {time.localtime()} a message with timestamp {event_created_at}")
150+
#if event_created_at < after_time:
151+
# print("Skipping event because it's too old!")
152+
# continue
153+
#print(f"event_msg content {event_msg.event.content}")
154+
try:
155+
#print(f"DEBUG: Decrypting event from public_key: {event_msg.event.public_key}")
156+
decrypted_content = self.private_key.decrypt_message(
157+
event_msg.event.content,
158+
event_msg.event.public_key
159+
)
160+
print(f"DEBUG: Decrypted content: {decrypted_content}")
161+
response = json.loads(decrypted_content)
162+
print(f"DEBUG: Parsed response: {response}")
163+
self.last_known_balance = round(int(response["result"]["balance"]) / 1000)
164+
print(f"Got balance: {self.last_known_balance}")
165+
balance_updated_cb()
166+
break
167+
except Exception as e:
168+
print(f"DEBUG: Error processing response: {e}")
169+
if balance is not None:
170+
break
171+
time.sleep(1)
172+
120173
def parse_nwc_url(self, nwc_url):
121174
"""Parse Nostr Wallet Connect URL to extract pubkey, relay, secret, and lud16."""
122175
print(f"DEBUG: Starting to parse NWC URL: {nwc_url}")
@@ -131,18 +184,14 @@ def parse_nwc_url(self, nwc_url):
131184
else:
132185
print(f"DEBUG: No recognized prefix found in URL")
133186
raise ValueError("Invalid NWC URL: missing 'nostr+walletconnect://' or 'nwc:' prefix")
134-
135187
print(f"DEBUG: URL after prefix removal: {nwc_url}")
136-
137188
# Split into pubkey and query params
138189
parts = nwc_url.split('?')
139190
pubkey = parts[0]
140191
print(f"DEBUG: Extracted pubkey: {pubkey}")
141-
142192
# Validate pubkey (should be 64 hex characters)
143193
if len(pubkey) != 64 or not all(c in '0123456789abcdef' for c in pubkey):
144194
raise ValueError("Invalid NWC URL: pubkey must be 64 hex characters")
145-
146195
# Extract relay, secret, and lud16 from query params
147196
relay = None
148197
secret = None
@@ -162,14 +211,11 @@ def parse_nwc_url(self, nwc_url):
162211
print(f"DEBUG: Extracted lud16: {lud16}")
163212
else:
164213
print(f"DEBUG: No query parameters found")
165-
166214
if not pubkey or not relay or not secret:
167215
raise ValueError("Invalid NWC URL: missing required fields (pubkey, relay, or secret)")
168-
169216
# Validate secret (should be 64 hex characters)
170217
if len(secret) != 64 or not all(c in '0123456789abcdef' for c in secret):
171218
raise ValueError("Invalid NWC URL: secret must be 64 hex characters")
172-
173219
print(f"DEBUG: Parsed NWC data - Relay: {relay}, Pubkey: {pubkey}, Secret: {secret}, lud16: {lud16}")
174220
return relay, pubkey, secret, lud16
175221
except Exception as e:

0 commit comments

Comments
 (0)