send heartbeats, expire all events (heartbeat 5 min, other events 10 min)

This commit is contained in:
Tobias Baur
2025-08-13 20:50:41 +02:00
parent 12d618e189
commit 1d6970f28f
7 changed files with 54 additions and 13 deletions

View File

@@ -15,6 +15,7 @@ from nostr_dvm.utils.database_utils import create_sql_table, get_or_add_user, up
update_user_subscription
from nostr_dvm.utils.definitions import EventDefinitions, RequiredJobToWatch, JobToWatch
from nostr_dvm.utils.dvmconfig import DVMConfig
from nostr_dvm.utils.heartbeat import beat
from nostr_dvm.utils.mediasource_utils import input_data_file_duration
from nostr_dvm.utils.nip88_utils import nip88_has_active_subscription
from nostr_dvm.utils.nostr_utils import get_event_by_id, get_referenced_event_by_id, check_and_decrypt_tags, \
@@ -52,6 +53,7 @@ class DVM:
self.dvm_config = dvm_config
self.admin_config = admin_config
self.keys = Keys.parse(dvm_config.PRIVATE_KEY)
self.heartbeat_frequency = 300
relaylimits = RelayLimits.disable()
opts = Options().relay_limits(relaylimits) #.difficulty(28)
@@ -79,6 +81,7 @@ class DVM:
ping_filter= Filter().pubkey(pk).kind(EventDefinitions.KIND_NIP90_PING).since(Timestamp.now())
create_sql_table(self.dvm_config.DB)
await admin_make_database_updates(adminconfig=self.admin_config, dvmconfig=self.dvm_config, client=self.client)
await beat(self.dvm_config, self.client, self.heartbeat_frequency )
await self.client.subscribe(dvm_filter, None)
await self.client.subscribe(zap_filter, None)
await self.client.subscribe(ping_filter, None)
@@ -638,8 +641,10 @@ class DVM:
if tag.as_vec()[0] == "i":
if not encrypted:
reply_tags.append(tag)
elif tag.as_vec()[0] == "expiration":
reply_tags.append(tag)
expiration_tag = Tag.parse(["expiration", str(Timestamp.now().as_secs() + dvm_config.EXPIRATION_DURATION)])
reply_tags.append(expiration_tag)
if encrypted:
encryption_tags.append(p_tag)
@@ -708,15 +713,12 @@ class DVM:
encrypted = False
is_legacy_encryption = False
expiration_tag = None
for tag in original_event.tags().to_vec():
if tag.as_vec()[0] == "encrypted":
encrypted = True
encrypted_tag = Tag.parse(["encrypted"])
encryption_tags.append(encrypted_tag)
#_, is_legacy_encryption = check_and_decrypt_tags(original_event, dvm_config)
elif tag.as_vec()[0] == "expiration":
expiration_tag = tag
if encrypted:
encryption_tags.append(p_tag)
@@ -797,8 +799,10 @@ class DVM:
else:
content = reaction
if expiration_tag is not None:
reply_tags.append(expiration_tag)
expiration_tag = Tag.parse(["expiration", str(Timestamp.now().as_secs() + dvm_config.EXPIRATION_DURATION)])
reply_tags.append(expiration_tag)
keys = Keys.parse(dvm_config.PRIVATE_KEY)
reaction_event = EventBuilder(EventDefinitions.KIND_FEEDBACK, str(content)).tags(reply_tags).sign_with_keys(keys)
@@ -941,10 +945,14 @@ class DVM:
asyncio.create_task(self.client.handle_notifications(NotificationHandler()))
try:
heartbeatsignal = 0
sleep = 1
while self.stop_thread is False:
for dvm in self.dvm_config.SUPPORTED_DVMS:
await dvm.schedule(self.dvm_config)
if heartbeatsignal >= self.heartbeat_frequency :
heartbeatsignal = 0
await beat(self.dvm_config, self.client, self.heartbeat_frequency )
for job in self.job_list:
if job.bolt11 != "" and job.payment_hash != "" and not job.payment_hash is None and not job.is_paid:
@@ -979,7 +987,8 @@ class DVM:
if Timestamp.now().as_secs() > job.timestamp + 60 * 20: # remove jobs to look for after 20 minutes..
self.jobs_on_hold_list.remove(job)
await asyncio.sleep(1)
await asyncio.sleep(sleep)
heartbeatsignal += sleep
except BaseException:
print("end")

View File

@@ -67,6 +67,7 @@ class EventDefinitions:
KIND_ZAP = Kind(9735)
KIND_RELAY_ANNOUNCEMENT = Kind(10002)
KIND_ANNOUNCEMENT = Kind(31990)
KIND_HEARTBEAT = Kind(11998)
KIND_WIKI = Kind(30818)
KIND_LONGFORM = Kind(30023)
KIND_NIP88_TIER_EVENT = Kind(37001)

View File

@@ -70,6 +70,7 @@ class DVMConfig:
CUSTOM_PROCESSING_MESSAGE = None
LOGLEVEL = LogLevel.INFO
KIND = None
EXPIRATION_DURATION = 600
DVM_KEY = None
CHATBOT = None

View File

@@ -0,0 +1,22 @@
from nostr_dvm.utils.definitions import EventDefinitions
from nostr_dvm.utils.nostr_utils import send_event
from nostr_dvm.utils.print_utils import bcolors
from nostr_sdk import Tag, Keys, EventBuilder, Timestamp
async def beat(dvm_config, client, frequency=300):
status_tag = Tag.parse(["status", "My heart keeps beating like a hammer"])
d_tag = Tag.parse(["d", dvm_config.NIP89.DTAG])
expiration_tag = Tag.parse(["expiration", str(Timestamp.now().as_secs() + frequency)])
tags = [status_tag, d_tag, expiration_tag]
keys = Keys.parse(dvm_config.NIP89.PK)
content = "Alive and kicking"
event = EventBuilder(EventDefinitions.KIND_HEARTBEAT, content).tags(tags).sign_with_keys(keys)
response_status = await send_event(event, client=client, dvm_config=dvm_config, broadcast=True)
print(bcolors.BRIGHT_RED + "[" + dvm_config.NIP89.NAME + "] Sent heartbeat for " + dvm_config.NIP89.NAME + ". Success: " + str(response_status.success) + " Failed: " + str(response_status.failed) + " EventID: "
+ response_status.id.to_hex() + " / " + response_status.id.to_bech32())

View File

@@ -12,4 +12,12 @@ class bcolors:
MAGENTA = '\033[95m'
GREY = '\033[90m'
BLACK = '\033[90m'
BRIGHT_BLACK = '\033[90m'
BRIGHT_RED = '\033[91m'
BRIGHT_GREEN = '\033[92m'
BRIGHT_YELLOW = '\033[93m'
BRIGHT_BLUE = '\033[94m'
BRIGHT_MAGENTA = '\033[95m'
BRIGHT_CYAN = '\033[96m'
BRIGHT_WHITE = '\033[97m'
DEFAULT = '\033[99m'

View File

@@ -1,6 +1,6 @@
from setuptools import setup, find_packages
VERSION = '1.1.2'
VERSION = '1.1.3'
DESCRIPTION = 'A framework to build and run Nostr NIP90 Data Vending Machines'
LONG_DESCRIPTION = ('A framework to build and run Nostr NIP90 Data Vending Machines. See the github repository for more information')
@@ -17,7 +17,7 @@ setup(
install_requires=["nostr-sdk==0.39.0",
"bech32==1.2.0",
"pycryptodome==3.20.0",
"yt-dlp==2024.11.04",
"yt-dlp==2025.7.21",
"python-dotenv==1.0.0",
"emoji==2.12.1",
"ffmpegio==0.9.1",
@@ -27,7 +27,7 @@ setup(
"requests==2.32.3",
"moviepy==2.0.0",
"zipp==3.19.1",
"urllib3==2.2.2",
"urllib3==2.5.0",
"networkx==3.3",
"scipy==1.13.1",
"typer==0.15.1",

View File

@@ -51,7 +51,7 @@ def playground(announce=False):
return result
dvm.process = process # overwrite the process function with the above one
dvm.run(True)
dvm.run()
if __name__ == '__main__':