1414import mpos .time
1515import mpos .util
1616
17+ # keeps a list of items
18+ # The .add() method ensures the list remains unique (via __eq__)
19+ # and sorted (via __lt__) by inserting new items in the correct position.
20+ class UniqueSortedList :
21+ def __init__ (self ):
22+ self ._items = []
23+
24+ def add (self , item ):
25+ # Check if item already exists (using __eq__)
26+ if item not in self ._items :
27+ # Insert item in sorted position (using __lt__)
28+ for i , existing_item in enumerate (self ._items ):
29+ if item < existing_item :
30+ self ._items .insert (i , item )
31+ return
32+ # If item is larger than all existing items, append it
33+ self ._items .append (item )
34+
35+ def __iter__ (self ):
36+ # Return iterator for the internal list
37+ return iter (self ._items )
38+
39+ def get (self , index_nr ):
40+ # Retrieve item at given index, raise IndexError if invalid
41+ try :
42+ return self ._items [index_nr ]
43+ except IndexError :
44+ raise IndexError ("Index out of range" )
45+
46+ def __len__ (self ):
47+ # Return the number of items for len() calls
48+ return len (self ._items )
49+
50+ def __str__ (self ):
51+ print ("UniqueSortedList tostring called" )
52+ return "\n " .join (str (item ) for item in self ._items )
53+
54+ def __eq__ (self , other ):
55+ if len (self ._items ) != len (other ):
56+ return False
57+ return all (p1 == p2 for p1 , p2 in zip (self ._items , other ))
58+
59+
60+
1761class Wallet :
1862
1963 # These values could be loading from a cache.json file at __init__
2064 last_known_balance = - 1
2165 #last_known_balance_timestamp = 0
22- payment_list = []
66+ payment_list = UniqueSortedList ()
2367
2468 def __init__ (self ):
2569 self .keep_running = True
@@ -30,11 +74,6 @@ def __str__(self):
3074 elif isinstance (self , NWCWallet ):
3175 return "NWCWallet"
3276
33- def are_payment_lists_equal (self , list1 , list2 ):
34- if len (list1 ) != len (list2 ):
35- return False
36- return all (p1 == p2 for p1 , p2 in zip (list1 , list2 ))
37-
3877 def handle_new_balance (self , new_balance ):
3978 if new_balance != self .last_known_balance :
4079 self .last_known_balance = new_balance
@@ -44,14 +83,11 @@ def handle_new_balance(self, new_balance):
4483
4584 def handle_new_payments (self , new_payments ):
4685 print ("handle_new_payments" )
47- if not self .are_payment_lists_equal ( self . payment_list , new_payments ) :
86+ if self .payment_list != new_payments :
4887 print ("new list of payments" )
4988 self .payment_list = new_payments
5089 self .payments_updated_cb ()
5190
52- def payment_list_string (self ):
53- return "\n " .join (f"{ payment .amount_sats } sats: { payment .comment } " for payment in self .payment_list )
54-
5591 # Need callbacks for:
5692 # - started (so the user can show the UI)
5793 # - stopped (so the user can delete/free it)
@@ -128,19 +164,20 @@ def fetch_payments(self):
128164 try :
129165 payments_reply = json .loads (response_text )
130166 #print(f"Got payments: {payments_reply}")
131- new_payments = []
167+ new_payments = UniqueSortedList ()
132168 for payment in payments_reply :
133169 #print(f"Got payment: {payment}")
134170 amount = payment ["amount" ]
135171 amount = round (amount / 1000 )
136172 comment = payment ["memo" ]
173+ epoch_time = payment ["time" ]
137174 extra = payment ["extra" ]
138175 if extra :
139176 extracomment = extra ["comment" ]
140177 if extracomment :
141178 comment = extracomment
142- payment = Payment (amount , comment )
143- new_payments .append (payment )
179+ payment = Payment (epoch_time , amount , comment )
180+ new_payments .add (payment )
144181 return new_payments
145182 except Exception as e :
146183 print (f"Could not parse reponse text '{ response_text } ' as JSON: { e } " )
@@ -183,6 +220,10 @@ def wallet_manager_thread(self):
183220 )])
184221 print (f"DEBUG: Subscription filters: { self .filters .to_json_array ()} " )
185222 self .relay_manager .add_subscription (self .subscription_id , self .filters )
223+ print (f"DEBUG: Publishing subscription request" )
224+ request_message = [ClientMessageType .REQUEST , self .subscription_id ]
225+ request_message .extend (self .filters .to_json_array ())
226+ self .relay_manager .publish_message (json .dumps (request_message ))
186227 time .sleep (1 )
187228
188229 self .fetch_balance ()
@@ -235,16 +276,23 @@ def fetch_balance(self):
235276 )
236277 print (f"DEBUG: Signing DM { json .dumps (dm )} with private key" )
237278 self .private_key .sign_event (dm ) # sign also does encryption if it's a encrypted dm
238- print (f"DEBUG: Publishing subscription request" )
239- request_message = [ClientMessageType .REQUEST , self .subscription_id ]
240- request_message .extend (self .filters .to_json_array ())
241- self .relay_manager .publish_message (json .dumps (request_message ))
242279 print (f"DEBUG: Publishing encrypted DM" )
243280 self .relay_manager .publish_event (dm )
244281
245282 def fetch_payments (self ):
246- # just send the message to request payments and they'll be handled by the main loop
247- pass
283+ # Create get_balance request
284+ list_transactions = {
285+ "method" : "list_transactions" ,
286+ "params" : {
287+ "limit" : 6
288+ }
289+ }
290+ dm = EncryptedDirectMessage (
291+ recipient_pubkey = self .wallet_pubkey ,
292+ cleartext_content = json .dumps (list_transactions )
293+ )
294+ self .private_key .sign_event (dm ) # sign also does encryption if it's a encrypted dm
295+ self .relay_manager .publish_event (dm )
248296
249297 def parse_nwc_url (self , nwc_url ):
250298 """Parse Nostr Wallet Connect URL to extract pubkey, relay, secret, and lud16."""
@@ -303,14 +351,39 @@ def parse_nwc_url(self, nwc_url):
303351
304352class Payment :
305353
306- def __init__ (self , amount_sats , comment ):
354+ def __init__ (self , epoch_time , amount_sats , comment ):
355+ self .epoch_time = epoch_time
307356 self .amount_sats = amount_sats
308357 self .comment = comment
309358
310359 def __str__ (self ):
311- return f"Payment(amount_sats={ self .amount_sats } , comment='{ self .comment } ')"
360+ sattext = "sats"
361+ if self .amount_sats is 1 :
362+ sattext = "sat"
363+ return f"{ self .amount_sats } { sattext } : { self .comment } "
312364
313365 def __eq__ (self , other ):
314366 if not isinstance (other , Payment ):
315367 return False
316- return self .amount_sats == other .amount_sats and self .comment == other .comment
368+ return self .epoch_time == other .epoch_time and self .amount_sats == other .amount_sats and self .comment == other .comment
369+
370+ def __lt__ (self , other ):
371+ if not isinstance (other , Payment ):
372+ return NotImplemented
373+ return (self .epoch_time , self .amount_sats , self .comment ) < (other .epoch_time , other .amount_sats , other .comment )
374+
375+ def __le__ (self , other ):
376+ if not isinstance (other , Payment ):
377+ return NotImplemented
378+ return (self .epoch_time , self .amount_sats , self .comment ) <= (other .epoch_time , other .amount_sats , other .comment )
379+
380+ def __gt__ (self , other ):
381+ if not isinstance (other , Payment ):
382+ return NotImplemented
383+ return (self .epoch_time , self .amount_sats , self .comment ) > (other .epoch_time , other .amount_sats , other .comment )
384+
385+ def __ge__ (self , other ):
386+ if not isinstance (other , Payment ):
387+ return NotImplemented
388+ return (self .epoch_time , self .amount_sats , self .comment ) >= (other .epoch_time , other .amount_sats , other .comment )
389+
0 commit comments