2024-06-06 02:25:34 +02:00
import asyncio
2023-11-23 11:53:57 +01:00
import json
2023-11-29 10:46:51 +01:00
import os
import signal
2023-11-23 11:53:57 +01:00
import time
2023-11-23 13:30:09 +01:00
from datetime import timedelta
2023-11-23 11:53:57 +01:00
2023-11-24 22:07:00 +01:00
from nostr_sdk import ( Keys , Client , Timestamp , Filter , nip04_decrypt , HandleNotification , EventBuilder , PublicKey ,
2024-03-18 19:44:44 +01:00
Options , Tag , Event , nip04_encrypt , NostrSigner , EventId , Nip19Event , Kind , KindEnum ,
2024-04-15 13:39:22 +02:00
UnsignedEvent , UnwrappedGift )
2023-11-23 11:53:57 +01:00
2023-12-13 20:00:03 +01:00
from nostr_dvm . utils . admin_utils import admin_make_database_updates
from nostr_dvm . utils . database_utils import get_or_add_user , update_user_balance , create_sql_table , update_sql_table
2024-06-17 16:33:02 +02:00
from nostr_dvm . utils . definitions import EventDefinitions , InvoiceToWatch
2023-12-13 20:00:03 +01:00
from nostr_dvm . utils . nip89_utils import nip89_fetch_events_pubkey , NIP89Config
from nostr_dvm . utils . nostr_utils import send_event
2024-01-04 14:33:34 +01:00
from nostr_dvm . utils . output_utils import PostProcessFunctionType , post_process_list_to_users , \
post_process_list_to_events
2024-06-17 16:33:02 +02:00
from nostr_dvm . utils . zap_utils import parse_zap_event_tags , pay_bolt11_ln_bits , zaprequest , create_bolt11_ln_bits , \
check_bolt11_ln_bits_is_paid , parse_amount_from_bolt11_invoice
2023-12-13 20:00:03 +01:00
from nostr_dvm . utils . cashu_utils import redeem_cashu
2023-11-23 11:53:57 +01:00
class Bot :
2023-11-26 10:31:38 +01:00
job_list : list
2024-06-17 16:33:02 +02:00
invoice_list : list
2023-11-29 15:09:35 +01:00
2023-11-26 10:31:38 +01:00
# This is a simple list just to keep track which events we created and manage, so we don't pay for other requests
2024-06-06 13:55:47 +02:00
def __init__ ( self , dvm_config , admin_config = None ) :
asyncio . run ( self . run_bot ( dvm_config , admin_config ) )
# add_sql_table_column(dvm_config.DB)
2024-06-17 16:33:02 +02:00
2024-06-06 13:55:47 +02:00
async def run_bot ( self , dvm_config , admin_config ) :
self . NAME = " Bot "
dvm_config . DB = " db/ " + self . NAME + " .db "
self . dvm_config = dvm_config
nip89config = NIP89Config ( )
2024-06-18 08:39:50 +02:00
nip89config . PK = self . dvm_config . PRIVATE_KEY
2024-06-06 13:55:47 +02:00
self . dvm_config . NIP89 = nip89config
self . admin_config = admin_config
self . keys = Keys . parse ( dvm_config . PRIVATE_KEY )
2023-11-23 13:30:09 +01:00
wait_for_send = True
skip_disconnected_relays = True
opts = ( Options ( ) . wait_for_send ( wait_for_send ) . send_timeout ( timedelta ( seconds = self . dvm_config . RELAY_TIMEOUT ) )
. skip_disconnected_relays ( skip_disconnected_relays ) )
2024-02-17 20:40:56 +01:00
signer = NostrSigner . keys ( self . keys )
2024-01-05 14:54:21 +01:00
self . client = Client . with_opts ( signer , opts )
2024-06-17 16:33:02 +02:00
self . invoice_list = [ ]
2023-11-23 11:53:57 +01:00
pk = self . keys . public_key ( )
2023-11-26 10:31:38 +01:00
self . job_list = [ ]
2024-06-17 16:33:02 +02:00
print ( " Nostr BOT public key: " + str ( pk . to_bech32 ( ) ) + " Hex: " + str ( pk . to_hex ( ) ) + " Name: " + self . NAME ) # +
# " Supported DVM tasks: " +
# ', '.join(p.NAME + ":" + p.TASK for p in self.dvm_config.SUPPORTED_DVMS) + "\n")
2023-11-23 11:53:57 +01:00
for relay in self . dvm_config . RELAY_LIST :
2024-06-06 02:25:34 +02:00
await self . client . add_relay ( relay )
await self . client . connect ( )
2023-11-23 11:53:57 +01:00
2023-11-24 17:20:29 +01:00
zap_filter = Filter ( ) . pubkey ( pk ) . kinds ( [ EventDefinitions . KIND_ZAP ] ) . since ( Timestamp . now ( ) )
2023-11-24 21:29:24 +01:00
dm_filter = Filter ( ) . pubkey ( pk ) . kinds ( [ EventDefinitions . KIND_DM ] ) . since ( Timestamp . now ( ) )
2024-06-20 15:58:51 +02:00
nip17_filter = Filter ( ) . pubkey ( pk ) . kinds ( [ Kind . from_enum ( KindEnum . GIFT_WRAP ( ) ) ] ) . limit ( 0 )
2023-11-26 10:31:38 +01:00
kinds = [ EventDefinitions . KIND_NIP90_GENERIC , EventDefinitions . KIND_FEEDBACK ]
for dvm in self . dvm_config . SUPPORTED_DVMS :
if dvm . KIND not in kinds :
2024-03-18 19:44:44 +01:00
kinds . append ( Kind ( dvm . KIND . as_u64 ( ) + 1000 ) )
2023-11-26 10:31:38 +01:00
dvm_filter = ( Filter ( ) . kinds ( kinds ) . since ( Timestamp . now ( ) ) )
2023-11-24 17:20:29 +01:00
2024-06-20 15:58:51 +02:00
await self . client . subscribe ( [ zap_filter , dm_filter , nip17_filter , dvm_filter ] , None )
2023-11-23 11:53:57 +01:00
2023-11-23 13:30:09 +01:00
create_sql_table ( self . dvm_config . DB )
2024-06-06 02:25:34 +02:00
await admin_make_database_updates ( adminconfig = self . admin_config , dvmconfig = self . dvm_config , client = self . client )
2024-04-15 17:31:51 +02:00
2023-11-23 11:53:57 +01:00
class NotificationHandler ( HandleNotification ) :
client = self . client
dvm_config = self . dvm_config
keys = self . keys
2024-06-06 02:25:34 +02:00
async def handle ( self , relay_url , subscription_id , nostr_event ) :
2024-03-18 19:44:44 +01:00
if ( EventDefinitions . KIND_NIP90_EXTRACT_TEXT . as_u64 ( ) + 1000 < = nostr_event . kind ( ) . as_u64 ( )
< = EventDefinitions . KIND_NIP90_GENERIC . as_u64 ( ) + 1000 ) :
2024-06-06 02:25:34 +02:00
await handle_nip90_response_event ( nostr_event )
2024-04-15 11:06:46 +02:00
elif nostr_event . kind ( ) == EventDefinitions . KIND_FEEDBACK :
2024-06-06 02:25:34 +02:00
await handle_nip90_feedback ( nostr_event )
2024-03-18 19:44:44 +01:00
2024-04-15 11:06:46 +02:00
elif nostr_event . kind ( ) == EventDefinitions . KIND_ZAP :
2024-06-06 02:25:34 +02:00
await handle_zap ( nostr_event )
2023-11-23 11:53:57 +01:00
2024-04-15 11:06:46 +02:00
elif nostr_event . kind ( ) == EventDefinitions . KIND_DM :
2024-03-18 19:44:44 +01:00
try :
2024-06-06 02:25:34 +02:00
await handle_dm ( nostr_event , False )
2024-03-18 19:44:44 +01:00
except Exception as e :
print ( f " Error during content NIP04 decryption: { e } " )
2024-06-18 08:39:50 +02:00
elif nostr_event . kind ( ) . as_enum ( ) == KindEnum . GIFT_WRAP ( ) :
2024-03-18 19:44:44 +01:00
try :
2024-06-17 16:33:02 +02:00
await handle_dm ( nostr_event , True )
2024-03-18 19:44:44 +01:00
except Exception as e :
print ( f " Error during content NIP59 decryption: { e } " )
2024-06-06 02:25:34 +02:00
async def handle_msg ( self , relay_url , msg ) :
2023-11-23 11:53:57 +01:00
return
2024-06-06 02:25:34 +02:00
async def handle_dm ( nostr_event , giftwrap ) :
2024-01-19 18:19:28 +01:00
sender = nostr_event . author ( ) . to_hex ( )
2023-12-29 23:11:04 +01:00
if sender == self . keys . public_key ( ) . to_hex ( ) :
return
2024-04-15 17:31:51 +02:00
decrypted_text = " "
2023-11-23 11:53:57 +01:00
try :
2024-04-15 13:39:22 +02:00
sealed = " "
if giftwrap :
try :
# Extract rumor
unwrapped_gift = UnwrappedGift . from_gift_wrap ( self . keys , nostr_event )
2024-04-15 17:31:51 +02:00
sender = unwrapped_gift . sender ( ) . to_hex ( )
2024-04-15 13:39:22 +02:00
rumor : UnsignedEvent = unwrapped_gift . rumor ( )
2024-06-18 08:39:50 +02:00
# client.send_sealed_msg(sender, f"Echo: {msg}", None)
2024-04-15 13:39:22 +02:00
if rumor . created_at ( ) . as_secs ( ) > = Timestamp . now ( ) . as_secs ( ) :
2024-06-18 08:39:50 +02:00
if rumor . kind ( ) . as_enum ( ) == KindEnum . PRIVATE_DIRECT_MESSAGE ( ) :
2024-04-15 13:39:22 +02:00
print ( f " Received new msg [sealed]: { decrypted_text } " )
2024-06-18 08:39:50 +02:00
decrypted_text = rumor . content ( )
2024-04-15 13:39:22 +02:00
sealed = " [sealed] "
else :
print ( f " { rumor . as_json ( ) } " )
2024-06-18 08:39:50 +02:00
2024-04-15 13:39:22 +02:00
except Exception as e :
print ( f " Error during content NIP59 decryption: { e } " )
else :
2024-04-15 17:31:51 +02:00
try :
decrypted_text = nip04_decrypt ( self . keys . secret_key ( ) , nostr_event . author ( ) ,
nostr_event . content ( ) )
except Exception as e :
print ( f " Error during content NIP04 decryption: { e } " )
2024-04-15 13:39:22 +02:00
2024-04-15 17:31:51 +02:00
if decrypted_text != " " :
2024-06-06 02:25:34 +02:00
user = await get_or_add_user ( db = self . dvm_config . DB , npub = sender , client = self . client ,
2024-06-17 16:33:02 +02:00
config = self . dvm_config )
2023-11-24 17:20:29 +01:00
2024-04-15 17:31:51 +02:00
print ( " [ " + self . NAME + " ] " + sealed + " Message from " + user . name + " : " + decrypted_text )
2023-11-28 20:33:30 +01:00
2024-04-15 17:31:51 +02:00
# if user selects an index from the overview list...
if decrypted_text != " " and decrypted_text [ 0 ] . isdigit ( ) :
2023-11-28 20:33:30 +01:00
2024-04-15 17:31:51 +02:00
split = decrypted_text . split ( ' ' )
index = int ( split [ 0 ] ) - 1
# if user sends index info, e.g. 1 info, we fetch the nip89 information and reply with it.
if len ( split ) > 1 and split [ 1 ] . lower ( ) == " info " :
2024-06-07 23:45:26 +02:00
await answer_nip89 ( nostr_event , index , giftwrap , sender )
2024-04-15 17:31:51 +02:00
# otherwise we probably have to do some work, so build an event from input and send it to the DVM
2023-11-28 20:33:30 +01:00
else :
2024-04-15 17:31:51 +02:00
task = self . dvm_config . SUPPORTED_DVMS [ index ] . TASK
print ( " [ " + self . NAME + " ] Request from " + str ( user . name ) + " ( " + str ( user . nip05 ) +
" , Balance: " + str ( user . balance ) + " Sats) Task: " + str ( task ) )
2023-11-30 10:49:08 +01:00
2024-04-15 17:31:51 +02:00
if user . isblacklisted :
# If users are blacklisted for some reason, tell them.
answer_blacklisted ( nostr_event , giftwrap , sender )
2023-11-27 23:37:44 +01:00
2024-04-15 17:31:51 +02:00
else :
# Parse inputs to params
2024-04-21 11:03:52 +02:00
tags = build_params ( decrypted_text , sender , index )
2024-04-15 17:31:51 +02:00
p_tag = Tag . parse ( [ ' p ' , self . dvm_config . SUPPORTED_DVMS [ index ] . PUBLIC_KEY ] )
if self . dvm_config . SUPPORTED_DVMS [ index ] . SUPPORTS_ENCRYPTION :
tags_str = [ ]
for tag in tags :
tags_str . append ( tag . as_vec ( ) )
params_as_str = json . dumps ( tags_str )
print ( params_as_str )
# and encrypt them
encrypted_params = nip04_encrypt ( self . keys . secret_key ( ) ,
PublicKey . from_hex (
self . dvm_config . SUPPORTED_DVMS [
index ] . PUBLIC_KEY ) ,
params_as_str )
# add encrypted and p tag on the outside
encrypted_tag = Tag . parse ( [ ' encrypted ' ] )
# add the encrypted params to the content
nip90request = ( EventBuilder ( self . dvm_config . SUPPORTED_DVMS [ index ] . KIND ,
encrypted_params , [ p_tag , encrypted_tag ] ) .
to_event ( self . keys ) )
else :
tags . append ( p_tag )
nip90request = ( EventBuilder ( self . dvm_config . SUPPORTED_DVMS [ index ] . KIND ,
" " , tags ) .
to_event ( self . keys ) )
# remember in the job_list that we have made an event, if anybody asks for payment,
# we know we actually sent the request
entry = { " npub " : user . npub , " event_id " : nip90request . id ( ) . to_hex ( ) ,
2024-06-17 16:33:02 +02:00
" dvm_key " : self . dvm_config . SUPPORTED_DVMS [ index ] . PUBLIC_KEY , " is_paid " : False ,
" giftwrap " : giftwrap }
2024-04-15 17:31:51 +02:00
self . job_list . append ( entry )
# send the event to the DVM
2024-06-07 23:45:26 +02:00
await send_event ( nip90request , client = self . client , dvm_config = self . dvm_config )
2024-04-15 17:31:51 +02:00
# print(nip90request.as_json())
2024-06-17 16:33:02 +02:00
elif decrypted_text . lower ( ) . startswith ( " invoice " ) :
2024-06-17 17:31:39 +02:00
requests_rq = False
2024-06-17 16:33:02 +02:00
amount_str = decrypted_text . lower ( ) . split ( " " ) [ 1 ]
2024-06-17 17:31:39 +02:00
if amount_str == " qr " :
amount_str = decrypted_text . lower ( ) . split ( " " ) [ 2 ]
requests_rq = True
2024-06-17 16:33:02 +02:00
try :
amount = int ( amount_str )
except :
amount = 100
invoice , hash = create_bolt11_ln_bits ( amount , self . dvm_config )
expires = nostr_event . created_at ( ) . as_secs ( ) + ( 60 * 60 * 24 )
2024-06-18 08:39:50 +02:00
qr_code = " https://qrcode.tec-it.com/API/QRCode?data= " + invoice + " &backcolor= %23f fffff&size=small&quietzone=1&errorcorrection=H "
2024-06-17 16:33:02 +02:00
2024-06-18 08:39:50 +02:00
self . invoice_list . append (
InvoiceToWatch ( sender = sender , bolt11 = invoice , payment_hash = hash , is_paid = False ,
expires = expires , amount = amount ) )
2024-06-17 17:31:39 +02:00
if requests_rq :
message = invoice + " \n " + qr_code
else :
message = invoice
2024-06-17 16:33:02 +02:00
if giftwrap :
await self . client . send_private_msg ( PublicKey . parse ( sender ) , message , None )
else :
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2024-06-17 16:33:02 +02:00
evt = EventBuilder . encrypted_direct_msg ( self . keys , PublicKey . parse ( sender ) ,
message , None ) . to_event ( self . keys )
await send_event ( evt , client = self . client , dvm_config = dvm_config )
2024-04-15 17:31:51 +02:00
elif decrypted_text . lower ( ) . startswith ( " balance " ) :
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2024-06-17 16:43:12 +02:00
message = " Your current balance is " + str ( user . balance ) + ( " Sats. Zap me to add to your "
2024-04-15 17:31:51 +02:00
" balance. I will use your "
" balance interact with the DVMs "
2024-06-17 16:33:02 +02:00
" for you. \n I support both "
2024-04-15 17:31:51 +02:00
" public and private Zaps, "
" as well as "
2024-06-17 16:33:02 +02:00
" Zapplepay. \n Or write \" invoice "
" 100 \" to receive an invoice of "
" 100 sats (or any other amount) "
" to top up your balance " )
2024-04-15 17:31:51 +02:00
if giftwrap :
2024-06-07 23:45:26 +02:00
await self . client . send_private_msg ( PublicKey . parse ( sender ) , message , None )
2024-04-15 17:31:51 +02:00
else :
evt = EventBuilder . encrypted_direct_msg ( self . keys , PublicKey . parse ( sender ) ,
2024-06-17 16:33:02 +02:00
message , None ) . to_event ( self . keys )
2024-06-06 02:25:34 +02:00
await send_event ( evt , client = self . client , dvm_config = dvm_config )
2024-04-15 17:31:51 +02:00
elif decrypted_text . startswith ( " cashuA " ) :
print ( " Received Cashu token: " + decrypted_text )
2024-06-06 02:25:34 +02:00
cashu_redeemed , cashu_message , total_amount , fees = await redeem_cashu ( decrypted_text ,
2024-06-17 16:33:02 +02:00
self . dvm_config ,
self . client )
2024-04-15 17:31:51 +02:00
print ( cashu_message )
if cashu_message == " success " :
2024-06-07 23:45:26 +02:00
await update_user_balance ( self . dvm_config . DB , sender , total_amount , client = self . client ,
2024-06-17 16:33:02 +02:00
config = self . dvm_config )
2024-04-15 17:31:51 +02:00
else :
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2024-04-15 17:31:51 +02:00
message = " Error: " + cashu_message + " . Token has not been redeemed. "
2023-11-23 11:53:57 +01:00
2024-04-15 17:31:51 +02:00
if giftwrap :
2024-06-07 23:45:26 +02:00
await self . client . send_private_msg ( PublicKey . parse ( sender ) , message , None )
2024-04-15 17:31:51 +02:00
else :
evt = EventBuilder . encrypted_direct_msg ( self . keys , PublicKey . from_hex ( sender ) , message ,
None ) . to_event ( self . keys )
2024-06-07 23:45:26 +02:00
await send_event ( evt , client = self . client , dvm_config = self . dvm_config )
2024-04-15 17:31:51 +02:00
elif decrypted_text . lower ( ) . startswith ( " what ' s the second best " ) :
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2024-04-15 17:31:51 +02:00
message = " No, there is no second best. \n \n https://cdn.nostr.build/p/mYLv.mp4 "
if giftwrap :
2024-06-07 23:45:26 +02:00
await self . client . send_private_msg ( PublicKey . parse ( sender ) , message , None )
2024-04-15 17:31:51 +02:00
else :
2024-06-07 23:45:26 +02:00
evt = await EventBuilder . encrypted_direct_msg ( self . keys , PublicKey . parse ( sender ) ,
2024-06-17 16:33:02 +02:00
message ,
nostr_event . id ( ) ) . to_event ( self . keys )
2024-06-07 23:45:26 +02:00
await send_event ( evt , client = self . client , dvm_config = self . dvm_config )
2023-11-23 11:53:57 +01:00
2023-12-02 21:27:29 +01:00
else :
2024-04-15 17:31:51 +02:00
# Build an overview of known DVMs and send it to the user
2024-06-07 23:45:26 +02:00
await answer_overview ( nostr_event , giftwrap , sender )
2023-11-30 08:07:30 +01:00
except Exception as e :
2023-11-24 21:29:24 +01:00
print ( " Error in bot " + str ( e ) )
2023-11-24 22:07:00 +01:00
2024-06-06 02:25:34 +02:00
async def handle_nip90_feedback ( nostr_event ) :
2024-04-15 17:31:51 +02:00
# print(nostr_event.as_json())
2023-11-26 10:31:38 +01:00
try :
2023-11-27 23:37:44 +01:00
is_encrypted = False
2023-11-26 10:31:38 +01:00
status = " "
etag = " "
ptag = " "
2023-11-30 08:07:30 +01:00
content = nostr_event . content ( )
2023-11-26 10:31:38 +01:00
for tag in nostr_event . tags ( ) :
if tag . as_vec ( ) [ 0 ] == " status " :
status = tag . as_vec ( ) [ 1 ]
2023-11-30 08:07:30 +01:00
if len ( tag . as_vec ( ) ) > 2 :
content = tag . as_vec ( ) [ 2 ]
2023-11-26 10:31:38 +01:00
elif tag . as_vec ( ) [ 0 ] == " e " :
etag = tag . as_vec ( ) [ 1 ]
elif tag . as_vec ( ) [ 0 ] == " p " :
ptag = tag . as_vec ( ) [ 1 ]
2023-11-27 23:37:44 +01:00
elif tag . as_vec ( ) [ 0 ] == " encrypted " :
is_encrypted = True
if is_encrypted :
2023-11-28 10:08:43 +01:00
if ptag == self . keys . public_key ( ) . to_hex ( ) :
2024-02-17 20:40:56 +01:00
tags_str = nip04_decrypt ( Keys . parse ( dvm_config . PRIVATE_KEY ) . secret_key ( ) ,
2024-01-19 18:19:28 +01:00
nostr_event . author ( ) , nostr_event . content ( ) )
2023-11-27 23:37:44 +01:00
params = json . loads ( tags_str )
params . append ( Tag . parse ( [ " p " , ptag ] ) . as_vec ( ) )
params . append ( Tag . parse ( [ " encrypted " ] ) . as_vec ( ) )
event_as_json = json . loads ( nostr_event . as_json ( ) )
event_as_json [ ' tags ' ] = params
event_as_json [ ' content ' ] = " "
nostr_event = Event . from_json ( json . dumps ( event_as_json ) )
for tag in nostr_event . tags ( ) :
if tag . as_vec ( ) [ 0 ] == " status " :
status = tag . as_vec ( ) [ 1 ]
2023-11-30 08:07:30 +01:00
if len ( tag . as_vec ( ) ) > 2 :
content = tag . as_vec ( ) [ 2 ]
2023-11-27 23:37:44 +01:00
elif tag . as_vec ( ) [ 0 ] == " e " :
etag = tag . as_vec ( ) [ 1 ]
elif tag . as_vec ( ) [ 0 ] == " content " :
content = tag . as_vec ( ) [ 1 ]
else :
return
2023-11-26 10:31:38 +01:00
2023-11-30 08:07:30 +01:00
if status == " success " or status == " error " or status == " processing " or status == " partial " and content != " " :
2023-11-26 10:31:38 +01:00
entry = next ( ( x for x in self . job_list if x [ ' event_id ' ] == etag ) , None )
2024-01-19 18:19:28 +01:00
if entry is not None and entry [ ' dvm_key ' ] == nostr_event . author ( ) . to_hex ( ) :
2024-06-06 02:25:34 +02:00
user = await get_or_add_user ( db = self . dvm_config . DB , npub = entry [ ' npub ' ] ,
2024-06-17 16:33:02 +02:00
client = self . client , config = self . dvm_config )
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2024-04-15 17:31:51 +02:00
if entry [ " giftwrap " ] :
2024-06-07 23:45:26 +02:00
await self . client . send_private_msg ( PublicKey . parse ( entry [ " npub " ] ) , content , None )
2024-04-15 17:31:51 +02:00
else :
reply_event = EventBuilder . encrypted_direct_msg ( self . keys ,
2023-12-30 20:36:38 +01:00
PublicKey . from_hex ( entry [ ' npub ' ] ) ,
2023-11-27 23:37:44 +01:00
content ,
2023-11-26 10:31:38 +01:00
None ) . to_event ( self . keys )
2024-04-15 17:31:51 +02:00
2024-06-07 23:45:26 +02:00
await send_event ( reply_event , client = self . client , dvm_config = dvm_config )
2023-11-27 23:37:44 +01:00
print ( status + " : " + content )
2023-11-26 10:31:38 +01:00
print (
2024-01-19 18:19:28 +01:00
" [ " + self . NAME + " ] Received reaction from " + nostr_event . author ( ) . to_hex ( ) + " message to orignal sender " + user . name )
2023-11-26 10:31:38 +01:00
elif status == " payment-required " or status == " partial " :
for tag in nostr_event . tags ( ) :
if tag . as_vec ( ) [ 0 ] == " amount " :
amount_msats = int ( tag . as_vec ( ) [ 1 ] )
2023-11-26 13:10:19 +01:00
amount = int ( amount_msats / 1000 )
entry = next ( ( x for x in self . job_list if x [ ' event_id ' ] == etag ) , None )
2023-11-29 15:09:35 +01:00
if entry is not None and entry [ ' is_paid ' ] is False and entry [
2024-01-19 18:19:28 +01:00
' dvm_key ' ] == nostr_event . author ( ) . to_hex ( ) :
2023-11-27 23:37:44 +01:00
# if we get a bolt11, we pay and move on
2024-06-06 02:25:34 +02:00
user = await get_or_add_user ( db = self . dvm_config . DB , npub = entry [ " npub " ] ,
2024-06-17 16:33:02 +02:00
client = self . client , config = self . dvm_config )
2023-12-01 12:12:46 +01:00
if user . balance > = amount :
2023-11-28 08:16:34 +01:00
balance = max ( user . balance - amount , 0 )
update_sql_table ( db = self . dvm_config . DB , npub = user . npub , balance = balance ,
iswhitelisted = user . iswhitelisted , isblacklisted = user . isblacklisted ,
nip05 = user . nip05 , lud16 = user . lud16 , name = user . name ,
2024-03-18 19:44:44 +01:00
lastactive = Timestamp . now ( ) . as_secs ( ) , subscribed = user . subscribed )
2023-11-28 08:16:34 +01:00
2024-06-17 16:33:02 +02:00
message = " Paid " + str (
amount ) + " Sats from balance to DVM. New balance is " + str (
balance ) + " Sats. \n "
2024-04-15 17:31:51 +02:00
if entry [ " giftwrap " ] :
2024-06-17 16:33:02 +02:00
await self . client . send_private_msg ( PublicKey . parse ( entry [ " npub " ] ) , message ,
None )
2024-04-15 17:31:51 +02:00
else :
evt = EventBuilder . encrypted_direct_msg ( self . keys ,
PublicKey . parse ( entry [ " npub " ] ) ,
message ,
None ) . to_event ( self . keys )
2024-06-06 02:25:34 +02:00
await send_event ( evt , client = self . client , dvm_config = dvm_config )
2023-11-29 15:09:35 +01:00
print (
" [ " + self . NAME + " ] Replying " + user . name + " with \" scheduled \" confirmation " )
2024-04-15 17:31:51 +02:00
2023-11-28 08:16:34 +01:00
else :
print ( " Bot payment-required " )
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2024-01-19 18:19:28 +01:00
evt = EventBuilder . encrypted_direct_msg ( self . keys ,
2024-04-15 17:31:51 +02:00
PublicKey . parse ( entry [ " npub " ] ) ,
" Current balance: " + str (
user . balance ) + " Sats. Balance of " + str (
amount ) + " Sats required. Please zap me with at least " +
str ( int ( amount - user . balance ) )
+ " Sats, then try again. " ,
None ) . to_event ( self . keys )
2024-06-06 02:25:34 +02:00
await send_event ( evt , client = self . client , dvm_config = dvm_config )
2023-11-28 08:16:34 +01:00
return
2023-11-27 23:37:44 +01:00
2023-11-26 13:10:19 +01:00
if len ( tag . as_vec ( ) ) > 2 :
bolt11 = tag . as_vec ( ) [ 2 ]
# else we create a zap
else :
2024-06-17 16:33:02 +02:00
user = await get_or_add_user ( db = self . dvm_config . DB ,
npub = nostr_event . author ( ) . to_hex ( ) ,
client = self . client , config = self . dvm_config )
2023-11-27 23:37:44 +01:00
print ( " Paying: " + user . name )
2024-01-04 14:33:34 +01:00
bolt11 = zaprequest ( user . lud16 , amount , " Zap " , nostr_event , self . keys ,
self . dvm_config ,
" private " )
2024-06-21 16:10:43 +02:00
if bolt11 is None :
2023-11-26 13:10:19 +01:00
print ( " Receiver has no Lightning address " )
return
try :
2023-12-09 23:58:15 +01:00
print ( bolt11 )
2023-11-26 13:10:19 +01:00
payment_hash = pay_bolt11_ln_bits ( bolt11 , self . dvm_config )
self . job_list [ self . job_list . index ( entry ) ] [ ' is_paid ' ] = True
print ( " [ " + self . NAME + " ] payment_hash: " + payment_hash +
2023-11-26 20:56:48 +01:00
" Forwarding payment of " + str ( amount ) + " Sats to DVM " )
2023-11-26 13:10:19 +01:00
except Exception as e :
print ( e )
2023-11-26 10:31:38 +01:00
except Exception as e :
2024-06-21 16:10:43 +02:00
print ( str ( e ) )
2023-11-26 10:31:38 +01:00
2024-06-06 02:25:34 +02:00
async def handle_nip90_response_event ( nostr_event : Event ) :
2023-11-26 10:31:38 +01:00
try :
2023-11-27 23:37:44 +01:00
ptag = " "
2023-11-30 08:07:30 +01:00
etag = " "
2023-11-26 10:31:38 +01:00
is_encrypted = False
for tag in nostr_event . tags ( ) :
if tag . as_vec ( ) [ 0 ] == " e " :
etag = tag . as_vec ( ) [ 1 ]
elif tag . as_vec ( ) [ 0 ] == " p " :
ptag = tag . as_vec ( ) [ 1 ]
elif tag . as_vec ( ) [ 0 ] == " encrypted " :
is_encrypted = True
entry = next ( ( x for x in self . job_list if x [ ' event_id ' ] == etag ) , None )
2023-12-10 20:16:01 +01:00
if entry is not None and entry [
2024-01-19 18:19:28 +01:00
' dvm_key ' ] == nostr_event . author ( ) . to_hex ( ) :
2023-11-26 10:31:38 +01:00
print ( entry )
2024-06-06 02:25:34 +02:00
user = await get_or_add_user ( db = self . dvm_config . DB , npub = entry [ ' npub ' ] ,
2024-06-17 16:33:02 +02:00
client = self . client , config = self . dvm_config )
2023-11-26 10:31:38 +01:00
self . job_list . remove ( entry )
content = nostr_event . content ( )
if is_encrypted :
2023-11-28 10:08:43 +01:00
if ptag == self . keys . public_key ( ) . to_hex ( ) :
2024-01-19 18:19:28 +01:00
content = nip04_decrypt ( self . keys . secret_key ( ) , nostr_event . author ( ) , content )
2023-11-27 23:37:44 +01:00
else :
return
2023-11-26 10:31:38 +01:00
2023-12-01 12:12:46 +01:00
dvms = [ x for x in self . dvm_config . SUPPORTED_DVMS if
2024-03-19 00:06:04 +01:00
x . PUBLIC_KEY == nostr_event . author ( ) . to_hex ( ) and x . KIND . as_u64 ( ) == nostr_event . kind ( ) . as_u64 ( ) - 1000 ]
2023-12-01 12:12:46 +01:00
if len ( dvms ) > 0 :
2023-12-10 20:16:01 +01:00
dvm = dvms [ 0 ]
if dvm . dvm_config . EXTERNAL_POST_PROCESS_TYPE != PostProcessFunctionType . NONE :
if dvm . dvm_config . EXTERNAL_POST_PROCESS_TYPE == PostProcessFunctionType . LIST_TO_EVENTS :
content = post_process_list_to_events ( content )
elif dvm . dvm_config . EXTERNAL_POST_PROCESS_TYPE == PostProcessFunctionType . LIST_TO_USERS :
content = post_process_list_to_users ( content )
2023-12-01 12:12:46 +01:00
2023-11-26 10:31:38 +01:00
print ( " [ " + self . NAME + " ] Received results, message to orignal sender " + user . name )
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2024-04-15 17:31:51 +02:00
if entry [ " giftwrap " ] :
2024-06-07 23:45:26 +02:00
await self . client . send_private_msg ( PublicKey . parse ( user . npub ) , content , None )
2024-04-15 17:31:51 +02:00
else :
reply_event = EventBuilder . encrypted_direct_msg ( self . keys ,
PublicKey . parse ( user . npub ) ,
2023-11-26 10:31:38 +01:00
content ,
None ) . to_event ( self . keys )
2024-06-06 02:25:34 +02:00
await send_event ( reply_event , client = self . client , dvm_config = dvm_config )
2023-11-26 10:31:38 +01:00
except Exception as e :
print ( e )
2024-06-06 02:25:34 +02:00
async def handle_zap ( zap_event ) :
2023-11-24 21:29:24 +01:00
print ( " [ " + self . NAME + " ] Zap received " )
2023-11-23 11:53:57 +01:00
try :
2024-06-14 19:55:23 +02:00
invoice_amount , zapped_event , sender , message , anon = await parse_zap_event_tags ( zap_event ,
2024-06-17 16:33:02 +02:00
self . keys , self . NAME ,
self . client ,
self . dvm_config )
2023-11-24 21:29:24 +01:00
2023-12-09 23:58:15 +01:00
etag = " "
2024-05-13 10:37:32 +02:00
print ( zap_event . tags ( ) )
print ( zapped_event . tags ( ) )
for tag in zapped_event . tags ( ) :
2023-12-09 23:58:15 +01:00
if tag . as_vec ( ) [ 0 ] == " e " :
etag = tag . as_vec ( ) [ 1 ]
2024-06-06 02:25:34 +02:00
user = await get_or_add_user ( self . dvm_config . DB , sender , client = self . client , config = self . dvm_config )
2023-11-23 11:53:57 +01:00
2023-12-09 23:58:15 +01:00
entry = next ( ( x for x in self . job_list if x [ ' event_id ' ] == etag ) , None )
print ( entry )
2023-12-10 20:16:01 +01:00
# print(entry['dvm_key'])
2024-01-19 18:19:28 +01:00
# print(str(zapped_event.author().to_hex()))
# print(str(zap_event.author().to_hex()))
2023-12-09 23:58:15 +01:00
print ( sender )
if entry is not None and entry [ ' is_paid ' ] is True and entry [ ' dvm_key ' ] == sender :
# if we get a bolt11, we pay and move on
2024-06-06 02:25:34 +02:00
user = await get_or_add_user ( db = self . dvm_config . DB , npub = entry [ " npub " ] ,
2024-06-17 16:33:02 +02:00
client = self . client , config = self . dvm_config )
2023-12-09 23:58:15 +01:00
sender = user . npub
if zapped_event is not None :
2023-12-10 20:16:01 +01:00
if not anon :
print ( " [ " + self . NAME + " ] Note Zap received for Bot balance: " + str (
invoice_amount ) + " Sats from " + str (
user . name ) )
2024-06-07 23:45:26 +02:00
await update_user_balance ( self . dvm_config . DB , sender , invoice_amount , client = self . client ,
2024-06-17 16:33:02 +02:00
config = self . dvm_config )
2023-12-10 20:16:01 +01:00
# a regular note
2023-11-23 11:53:57 +01:00
elif not anon :
2023-11-24 22:07:00 +01:00
print ( " [ " + self . NAME + " ] Profile Zap received for Bot balance: " + str (
invoice_amount ) + " Sats from " + str (
2023-11-23 11:53:57 +01:00
user . name ) )
2024-06-07 23:45:26 +02:00
await update_user_balance ( self . dvm_config . DB , sender , invoice_amount , client = self . client ,
2024-06-17 16:33:02 +02:00
config = self . dvm_config )
2023-11-23 11:53:57 +01:00
except Exception as e :
2023-11-24 21:29:24 +01:00
print ( " [ " + self . NAME + " ] Error during content decryption: " + str ( e ) )
2023-11-23 11:53:57 +01:00
2024-06-07 23:45:26 +02:00
async def answer_overview ( nostr_event , giftwrap , sender ) :
2023-11-30 08:07:30 +01:00
message = " DVMs that I support: \n \n "
index = 1
for p in self . dvm_config . SUPPORTED_DVMS :
if p . PER_UNIT_COST != 0 and p . PER_UNIT_COST is not None :
2024-01-04 14:33:34 +01:00
message + = ( str ( index ) + " " + p . NAME + " " + p . TASK + " \n \t " + str ( p . FIX_COST ) +
" Sats + " + str ( p . PER_UNIT_COST ) + " Sats per Second \n \n " )
2023-11-30 08:07:30 +01:00
else :
2024-01-04 14:33:34 +01:00
message + = ( str ( index ) + " " + p . NAME + " " + p . TASK + " \n \t " + str ( p . FIX_COST ) +
" Sats \n \n " )
2023-11-30 08:07:30 +01:00
index + = 1
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2024-04-15 17:31:51 +02:00
2024-06-17 16:33:02 +02:00
text = message + " \n Select an Index and provide an input (e.g. \" 2 A purple ostrich \" ) \n Type \" index info \" to learn more about each DVM. (e.g. \" 2 info \" ) \n \n Type \" balance \" to see your current balance "
2024-04-15 17:31:51 +02:00
if giftwrap :
2024-06-07 23:45:26 +02:00
await self . client . send_private_msg ( PublicKey . parse ( sender ) , text , None )
2024-04-15 17:31:51 +02:00
else :
evt = EventBuilder . encrypted_direct_msg ( self . keys , PublicKey . parse ( sender ) ,
text ,
2023-11-30 08:07:30 +01:00
nostr_event . id ( ) ) . to_event ( self . keys )
2024-06-07 23:45:26 +02:00
await send_event ( evt , client = self . client , dvm_config = dvm_config )
2023-11-30 08:07:30 +01:00
2024-04-15 17:31:51 +02:00
def answer_blacklisted ( nostr_event , giftwrap , sender ) :
message = " Your are currently blocked from this service. "
if giftwrap :
self . client . send_sealed_msg ( PublicKey . parse ( sender ) , message , None )
else :
2024-06-17 16:33:02 +02:00
# For some reason an admin might blacklist npubs, e.g. for abusing the service
2024-04-15 17:31:51 +02:00
evt = EventBuilder . encrypted_direct_msg ( self . keys , nostr_event . author ( ) ,
message , None ) . to_event ( self . keys )
send_event ( evt , client = self . client , dvm_config = dvm_config )
2023-11-30 08:07:30 +01:00
2024-06-07 23:45:26 +02:00
async def answer_nip89 ( nostr_event , index , giftwrap , sender ) :
2024-06-08 20:13:01 +02:00
info = await print_dvm_info ( self . client , index )
2024-04-15 17:31:51 +02:00
if info is None :
2024-06-08 20:13:01 +02:00
info = " No NIP89 Info found for " + self . dvm_config . SUPPORTED_DVMS [ index ] . NAME
2024-06-18 08:39:50 +02:00
await asyncio . sleep ( 2.0 )
2023-11-30 08:07:30 +01:00
2024-04-15 17:31:51 +02:00
if giftwrap :
2024-06-07 23:45:26 +02:00
await self . client . send_private_msg ( PublicKey . parse ( sender ) , info , None )
2024-04-15 17:31:51 +02:00
else :
2024-06-17 16:33:02 +02:00
evt = EventBuilder . encrypted_direct_msg ( self . keys , nostr_event . author ( ) ,
info , None ) . to_event ( self . keys )
await send_event ( evt , client = self . client , dvm_config = dvm_config )
2023-11-30 08:07:30 +01:00
2024-04-21 11:03:52 +02:00
def build_params ( decrypted_text , author , index ) :
2023-11-30 08:07:30 +01:00
tags = [ ]
2024-01-04 14:33:34 +01:00
splitzero = decrypted_text . split ( ' - ' )
split = splitzero [ 0 ] . split ( ' ' )
2023-11-30 08:07:30 +01:00
# If only a command without parameters is sent, we assume no input is required, and that means the dvm might take in the user as input (e.g. for content discovery)
if len ( split ) == 1 :
2024-01-04 14:33:34 +01:00
remaining_text = decrypted_text . replace ( split [ 0 ] , " " )
params = remaining_text . split ( " - " )
2024-04-21 11:03:52 +02:00
tag = Tag . parse ( [ " param " , " user " , author ] )
2023-11-30 08:07:30 +01:00
tags . append ( tag )
2024-01-04 14:33:34 +01:00
for i in params :
print ( i )
if i != " " :
try :
split = i . split ( " " )
if len ( split ) > 1 :
param = str ( split [ 0 ] )
print ( str ( param ) )
value = str ( split [ 1 ] )
print ( str ( value ) )
if param == " cashu " :
tag = Tag . parse ( [ param , value ] )
else :
if param == " user " :
if value . startswith ( " @ " ) or value . startswith ( " nostr: " ) or value . startswith (
" npub " ) :
value = PublicKey . from_bech32 (
value . replace ( " @ " , " " ) . replace ( " nostr: " , " " ) ) . to_hex ( )
tag = Tag . parse ( [ " param " , param , value ] )
tags . append ( tag )
except Exception as e :
print ( e )
print ( " Couldn ' t add " + str ( i ) )
output = Tag . parse ( [ " output " , " text/plain " ] )
tags . append ( output )
relay_list = [ " relays " ]
for relay in self . dvm_config . RELAY_LIST :
relay_list . append ( relay )
2024-06-19 13:10:03 +02:00
relays = Tag . parse ( relay_list )
tags . append ( relays )
2024-01-04 14:33:34 +01:00
2023-11-30 08:07:30 +01:00
return tags
2023-12-01 21:17:32 +01:00
tags = [ ]
2023-11-30 08:07:30 +01:00
command = decrypted_text . replace ( split [ 0 ] + " " , " " )
split = command . split ( " - " )
input = split [ 0 ] . rstrip ( )
if input . startswith ( " http " ) :
2023-12-01 21:17:32 +01:00
temp = input . split ( " " )
if len ( temp ) > 1 :
input_type = " url "
i_tag1 = Tag . parse ( [ " i " , temp [ 0 ] , input_type ] )
tags . append ( i_tag1 )
input_type = " text "
i_tag2 = Tag . parse ( [ " i " , input . replace ( temp [ 0 ] , " " ) . lstrip ( ) , input_type ] )
tags . append ( i_tag2 )
else :
input_type = " url "
i_tag = Tag . parse ( [ " i " , input , input_type ] )
tags . append ( i_tag )
2024-01-06 23:05:28 +01:00
elif ( input . startswith ( " nevent " ) or input . startswith ( " nostr:nevent " ) or input . startswith ( " note " ) or
input . startswith ( " nostr:note " ) ) :
input_type = " event "
if str ( input ) . startswith ( ' note ' ) :
event_id = EventId . from_bech32 ( input )
elif str ( input ) . startswith ( " nevent " ) :
event_id = Nip19Event . from_bech32 ( input ) . event_id ( )
elif str ( input ) . startswith ( ' nostr:note ' ) :
event_id = EventId . from_nostr_uri ( input )
elif str ( input ) . startswith ( " nostr:nevent " ) :
event_id = Nip19Event . from_nostr_uri ( input ) . event_id ( )
else :
event_id = EventId . from_hex ( input )
i_tag = Tag . parse ( [ " i " , event_id . to_hex ( ) , input_type ] )
tags . append ( i_tag )
2023-12-01 21:17:32 +01:00
else :
print ( input )
input_type = " text "
i_tag = Tag . parse ( [ " i " , input , input_type ] )
tags . append ( i_tag )
2023-11-30 08:07:30 +01:00
alt_tag = Tag . parse ( [ " alt " , self . dvm_config . SUPPORTED_DVMS [ index ] . TASK ] )
tags . append ( alt_tag )
relaylist = [ " relays " ]
for relay in self . dvm_config . RELAY_LIST :
relaylist . append ( relay )
relays_tag = Tag . parse ( relaylist )
2023-12-01 21:17:32 +01:00
tags . append ( relays_tag )
2023-12-02 17:01:29 +01:00
output_tag = Tag . parse ( [ " output " , " text/plain " ] )
tags . append ( output_tag )
2023-11-30 08:07:30 +01:00
remaining_text = command . replace ( input , " " )
print ( remaining_text )
2023-12-01 21:17:32 +01:00
2023-11-30 08:07:30 +01:00
params = remaining_text . rstrip ( ) . split ( " - " )
for i in params :
print ( i )
if i != " " :
try :
split = i . split ( " " )
if len ( split ) > 1 :
param = str ( split [ 0 ] )
print ( str ( param ) )
value = str ( split [ 1 ] )
print ( str ( value ) )
if param == " cashu " :
tag = Tag . parse ( [ param , value ] )
else :
2023-12-02 17:01:29 +01:00
if param == " user " :
if value . startswith ( " @ " ) or value . startswith ( " nostr: " ) or value . startswith ( " npub " ) :
2023-12-10 20:16:01 +01:00
value = PublicKey . from_bech32 (
value . replace ( " @ " , " " ) . replace ( " nostr: " , " " ) ) . to_hex ( )
2023-11-30 08:07:30 +01:00
tag = Tag . parse ( [ " param " , param , value ] )
tags . append ( tag )
print ( " Added params: " + str ( tag . as_vec ( ) ) )
except Exception as e :
print ( e )
print ( " Couldn ' t add " + str ( i ) )
return tags
2023-11-29 10:46:51 +01:00
2024-06-08 20:13:01 +02:00
async def print_dvm_info ( client , index ) :
2023-11-29 15:09:35 +01:00
pubkey = self . dvm_config . SUPPORTED_DVMS [ index ] . dvm_config . PUBLIC_KEY
kind = self . dvm_config . SUPPORTED_DVMS [ index ] . KIND
2024-06-08 20:13:01 +02:00
nip89content_str = await nip89_fetch_events_pubkey ( client , pubkey , kind )
2023-11-29 15:09:35 +01:00
print ( nip89content_str )
if nip89content_str is not None :
nip89content = json . loads ( nip89content_str )
info = " "
2023-12-03 22:05:53 +01:00
cashu_accepted = False
encryption_supported = False
2023-11-29 15:09:35 +01:00
if nip89content . get ( " name " ) :
info + = " Name: " + nip89content . get ( " name " ) + " \n "
2023-12-03 22:05:53 +01:00
if nip89content . get ( " image " ) :
2023-11-29 15:09:35 +01:00
info + = nip89content . get ( " image " ) + " \n "
2023-12-03 22:05:53 +01:00
if nip89content . get ( " about " ) :
info + = " About: \n " + nip89content . get ( " about " ) + " \n \n "
2023-12-03 22:10:43 +01:00
if nip89content . get ( " cashuAccepted " ) :
cashu_accepted = str ( nip89content . get ( " cashuAccepted " ) )
2023-12-03 22:05:53 +01:00
if nip89content . get ( " encryptionSupported " ) :
encryption_supported = str ( nip89content . get ( " encryptionSupported " ) )
info + = " Encryption supported: " + str ( encryption_supported ) + " \n "
info + = " Cashu accepted: " + str ( cashu_accepted ) + " \n \n "
if nip89content . get ( " nip90Params " ) :
2023-11-29 15:09:35 +01:00
params = nip89content [ " nip90Params " ]
info + = " \n Parameters: \n "
for param in params :
info + = " - " + param + ' \n '
info + = " Required: " + str ( params [ param ] [ ' required ' ] ) + ' \n '
info + = " Possible Values: " + json . dumps ( params [ param ] [ ' values ' ] ) + ' \n \n '
2023-12-03 22:18:03 +01:00
return info
2023-11-29 15:09:35 +01:00
return None
2024-06-07 23:45:26 +02:00
asyncio . create_task ( self . client . handle_notifications ( NotificationHandler ( ) ) )
2023-11-30 08:07:30 +01:00
2023-11-29 10:46:51 +01:00
try :
while True :
2024-06-17 16:33:02 +02:00
for invoice in self . invoice_list :
if invoice . bolt11 != " " and invoice . payment_hash != " " and not invoice . payment_hash is None and not invoice . is_paid :
ispaid = check_bolt11_ln_bits_is_paid ( invoice . payment_hash , self . dvm_config )
if ispaid and invoice . is_paid is False :
print ( " is paid " )
invoice . is_paid = True
2024-06-18 08:39:50 +02:00
await update_user_balance ( self . dvm_config . DB , invoice . sender , invoice . amount ,
client = self . client ,
2024-06-17 16:33:02 +02:00
config = self . dvm_config )
print ( " [ " + self . dvm_config . NIP89 . NAME + " ] updating balance from invoice list " )
elif ispaid is None : # invoice expired
self . invoice_list . remove ( invoice )
2024-06-17 16:40:40 +02:00
elif Timestamp . now ( ) . as_secs ( ) > invoice . expires :
self . invoice_list . remove ( invoice )
2024-06-17 16:33:02 +02:00
2024-06-07 23:45:26 +02:00
await asyncio . sleep ( 1.0 )
2023-11-29 10:46:51 +01:00
except KeyboardInterrupt :
print ( ' Stay weird! ' )
2023-11-29 11:00:15 +01:00
os . kill ( os . getpid ( ) , signal . SIGTERM )