From cee488bb70005a5c708831ab56e43e2d0a3d631d Mon Sep 17 00:00:00 2001 From: dbth <1097224+believethehype@users.noreply.github.com> Date: Thu, 2 Jan 2025 03:39:07 +0100 Subject: [PATCH] introduce framework class, introduce autodelete announcement on shutdown --- nostr_dvm/dvm.py | 82 ++++++++------- nostr_dvm/framework.py | 29 ++++++ nostr_dvm/interfaces/dvmtaskinterface.py | 34 ++++++- nostr_dvm/utils/backend_utils.py | 8 -- nostr_dvm/utils/dvmconfig.py | 5 + nostr_dvm/utils/nip89_utils.py | 20 +++- tests/discovery.py | 62 +++++++++--- ...y.py => discovery_on_this_day_and_olas.py} | 99 ++++++++++++++++++- 8 files changed, 272 insertions(+), 67 deletions(-) create mode 100644 nostr_dvm/framework.py rename tests/{discovery_on_this_day.py => discovery_on_this_day_and_olas.py} (58%) diff --git a/nostr_dvm/dvm.py b/nostr_dvm/dvm.py index caf2a26..c91e57e 100644 --- a/nostr_dvm/dvm.py +++ b/nostr_dvm/dvm.py @@ -1,6 +1,7 @@ import asyncio import json import os +import sys from sys import platform from nostr_sdk import PublicKey, Keys, Client, Tag, Event, EventBuilder, Filter, HandleNotification, Timestamp, \ @@ -27,6 +28,7 @@ from nostr_dvm.utils.zap_utils import check_bolt11_ln_bits_is_paid, create_bolt1 #os.environ["RUST_BACKTRACE"] = "full" + class DVM: dvm_config: DVMConfig admin_config: AdminConfig @@ -34,15 +36,23 @@ class DVM: client: Client job_list: list jobs_on_hold_list: list + stop_thread = False - def __init__(self, dvm_config, admin_config=None): - asyncio.run(self.run_dvm(dvm_config, admin_config)) - uniffi_set_event_loop(asyncio.get_running_loop()) + def __init__(self, dvm_config, admin_config=None, stop_thread=False): + try: + asyncio.run(self.run_dvm(dvm_config, admin_config, stop_thread)) + #uniffi_set_event_loop(asyncio.get_running_loop()) + except Exception as e: + print(e) - async def run_dvm(self, dvm_config, admin_config): + + + + async def run_dvm(self, dvm_config, admin_config, stop_thread): self.dvm_config = dvm_config self.admin_config = admin_config self.keys = Keys.parse(dvm_config.PRIVATE_KEY) + self.stop_thread = stop_thread relaylimits = RelayLimits.disable() opts = Options().relay_limits(relaylimits) #.difficulty(28) @@ -913,44 +923,46 @@ class DVM: asyncio.create_task(self.client.handle_notifications(NotificationHandler())) + try: + while not self.stop_thread: + for dvm in self.dvm_config.SUPPORTED_DVMS: + await dvm.schedule(self.dvm_config) + 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: + ispaid = check_bolt11_ln_bits_is_paid(job.payment_hash, self.dvm_config) + if ispaid and job.is_paid is False: + print("is paid") + job.is_paid = True + amount = parse_amount_from_bolt11_invoice(job.bolt11) - while True: - for dvm in self.dvm_config.SUPPORTED_DVMS: - await dvm.schedule(self.dvm_config) + job.is_paid = True + await send_job_status_reaction(job.event, "processing", True, 0, + content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, + client=self.client, + dvm_config=self.dvm_config) + print("[" + self.dvm_config.NIP89.NAME + "] doing work from joblist") + await do_work(job.event, amount) + elif ispaid is None: # invoice expired + self.job_list.remove(job) - 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: - ispaid = check_bolt11_ln_bits_is_paid(job.payment_hash, self.dvm_config) - if ispaid and job.is_paid is False: - print("is paid") - job.is_paid = True - amount = parse_amount_from_bolt11_invoice(job.bolt11) - - job.is_paid = True - await send_job_status_reaction(job.event, "processing", True, 0, - content=self.dvm_config.CUSTOM_PROCESSING_MESSAGE, - client=self.client, - dvm_config=self.dvm_config) - print("[" + self.dvm_config.NIP89.NAME + "] doing work from joblist") - await do_work(job.event, amount) - elif ispaid is None: # invoice expired + if Timestamp.now().as_secs() > job.expires: self.job_list.remove(job) - if Timestamp.now().as_secs() > job.expires: - self.job_list.remove(job) + for job in self.jobs_on_hold_list: + if await check_event_has_not_unfinished_job_input(job.event, False, client=self.client, + dvmconfig=self.dvm_config): + await handle_nip90_job_event(nip90_event=job.event) + try: + self.jobs_on_hold_list.remove(job) + except: + print("[" + self.dvm_config.NIP89.NAME + "] Error removing Job on Hold from List after expiry") - for job in self.jobs_on_hold_list: - if await check_event_has_not_unfinished_job_input(job.event, False, client=self.client, - dvmconfig=self.dvm_config): - await handle_nip90_job_event(nip90_event=job.event) - try: + if Timestamp.now().as_secs() > job.timestamp + 60 * 20: # remove jobs to look for after 20 minutes.. self.jobs_on_hold_list.remove(job) - except: - print("[" + self.dvm_config.NIP89.NAME + "] Error removing Job on Hold from List after expiry") - 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) + except BaseException: + print("ende") - await asyncio.sleep(1) diff --git a/nostr_dvm/framework.py b/nostr_dvm/framework.py new file mode 100644 index 0000000..1b9823b --- /dev/null +++ b/nostr_dvm/framework.py @@ -0,0 +1,29 @@ +import os +import signal +import time + + +class DVMFramework: + dvms = [] + + def __init__(self): + self.dvms = [] + + + def add(self, dvm): + self.dvms.append(dvm) + + def run(self): + for dvm in self.dvms: + dvm.run() + + try: + while True: + time.sleep(0.1) + except KeyboardInterrupt: + for dvm in self.dvms: + dvm.join() + print("All DVMs shut down.") + os.kill(os.getpid(), signal.SIGKILL) + exit(1) + diff --git a/nostr_dvm/interfaces/dvmtaskinterface.py b/nostr_dvm/interfaces/dvmtaskinterface.py index 5614393..da3dae8 100644 --- a/nostr_dvm/interfaces/dvmtaskinterface.py +++ b/nostr_dvm/interfaces/dvmtaskinterface.py @@ -1,8 +1,10 @@ import asyncio import json import os +import signal import subprocess import sys +import time from subprocess import run from sys import platform from threading import Thread @@ -14,7 +16,7 @@ from nostr_dvm.dvm import DVM from nostr_dvm.utils.admin_utils import AdminConfig from nostr_dvm.utils.dvmconfig import DVMConfig, build_default_config from nostr_dvm.utils.nip88_utils import NIP88Config -from nostr_dvm.utils.nip89_utils import NIP89Config +from nostr_dvm.utils.nip89_utils import NIP89Config, delete_nip_89 from nostr_dvm.utils.output_utils import post_process_result @@ -36,6 +38,8 @@ class DVMTaskInterface: def __init__(self, name, dvm_config: DVMConfig, nip89config: NIP89Config, nip88config: NIP88Config = None, admin_config: AdminConfig = None, options=None, task=None): + self.stop_threads = False + self.nostr_dvm_thread = None if options is None: self.options = {} else: @@ -108,10 +112,21 @@ class DVMTaskInterface: pass def run(self, join=False): - nostr_dvm_thread = Thread(target=self.DVM, args=[self.dvm_config, self.admin_config], daemon=False) - nostr_dvm_thread.start() - if join: - nostr_dvm_thread.join() + + + try: + self.nostr_dvm_thread = Thread(target=self.DVM, args=[self.dvm_config, self.admin_config, lambda: self.stop_threads], daemon=False) + self.nostr_dvm_thread.start() + if join: + self.nostr_dvm_thread.join() + except BaseException as e: + print("gone") + + + def join(self): + self.stop_threads = True + self.nostr_dvm_thread.join(1) + dvm_shutdown(self.dvm_config) async def schedule(self, dvm_config): """schedule something, e.g. define some time to update or to post, does nothing by default""" @@ -178,3 +193,12 @@ def process_venv(identifier): DVMTaskInterface.write_output(result, args.output) except Exception as e: DVMTaskInterface.write_output("Error: " + str(e), args.output) + +def dvm_shutdown(dvm_config): + if dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN: + print(dvm_config.NIP89.NAME) + asyncio.run(delete_nip_89(dvm_config, dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN_POW)) + + + + diff --git a/nostr_dvm/utils/backend_utils.py b/nostr_dvm/utils/backend_utils.py index 7a93ccc..52fe3af 100644 --- a/nostr_dvm/utils/backend_utils.py +++ b/nostr_dvm/utils/backend_utils.py @@ -192,11 +192,3 @@ def get_amount_per_task(task, dvm_config, duration=1): 0].NAME + "] Task " + task + " is currently not supported by this instance, skipping") return None - -def keep_alive(): - try: - while True: - time.sleep(10) - except KeyboardInterrupt: - os.kill(os.getpid(), signal.SIGKILL) - exit(1) diff --git a/nostr_dvm/utils/dvmconfig.py b/nostr_dvm/utils/dvmconfig.py index b23cca0..11b1d8c 100644 --- a/nostr_dvm/utils/dvmconfig.py +++ b/nostr_dvm/utils/dvmconfig.py @@ -40,6 +40,11 @@ class DVMConfig: AVOID_OUTBOX_RELAY_LIST = outbox_utils.AVOID_OUTBOX_RELAY_LIST # If a DVM has a paid subscription, overwrite list without the paid one. + DELETE_ANNOUNCEMENT_ON_SHUTDOWN = False + # remove the announcement when the DVM stops. Recommended. Will be True later. + # Make sure to set admin_utils.REBROADCAST_NIP89 = True on start. + + DELETE_ANNOUNCEMENT_ON_SHUTDOWN_POW = False RELAY_TIMEOUT = 5 RELAY_LONG_TIMEOUT = 30 EXTERNAL_POST_PROCESS_TYPE = 0 # Leave this on None, except the DVM is external diff --git a/nostr_dvm/utils/nip89_utils.py b/nostr_dvm/utils/nip89_utils.py index 66c76aa..d07fbb4 100644 --- a/nostr_dvm/utils/nip89_utils.py +++ b/nostr_dvm/utils/nip89_utils.py @@ -1,9 +1,10 @@ import os +from datetime import timedelta from hashlib import sha256 from pathlib import Path import dotenv -from nostr_sdk import Tag, Keys, EventBuilder, Filter, Alphabet, PublicKey, Client, EventId, SingleLetterTag, Kind +from nostr_sdk import Tag, Keys, EventBuilder, Filter, Alphabet, PublicKey, Client, EventId, SingleLetterTag, Kind, NostrSigner from nostr_dvm.utils.definitions import EventDefinitions, relay_timeout from nostr_dvm.utils.nostr_utils import send_event, print_send_result @@ -142,3 +143,20 @@ def create_amount_tag(cost=None): return "free" else: return str(cost) + + +async def delete_nip_89(dvm_config, pow=True): + keys = Keys.parse(dvm_config.PRIVATE_KEY) + client = Client(NostrSigner.keys(keys)) + for relay in dvm_config.RELAY_LIST: + await client.add_relay(relay) + await client.connect() + filter = Filter().kind(EventDefinitions.KIND_ANNOUNCEMENT).author(keys.public_key()) + events = await client.fetch_events([filter], timedelta(seconds=5)) + + if len(events.to_vec()) == 0: + print("Couldn't find note on relays. Seems they are gone.") + return + for event in events.to_vec(): + await fetch_nip89_parameters_for_deletion(keys, event.id().to_hex(), client, dvm_config, pow) + diff --git a/tests/discovery.py b/tests/discovery.py index 1401859..7e46444 100644 --- a/tests/discovery.py +++ b/tests/discovery.py @@ -7,6 +7,7 @@ from pathlib import Path import dotenv from nostr_sdk import init_logger, LogLevel, Keys +from nostr_dvm.framework import DVMFramework # os.environ["RUST_BACKTRACE"] = "full" from nostr_dvm.subscription import Subscription from nostr_dvm.tasks.content_discovery_currently_latest_longform import DicoverContentLatestLongForm @@ -34,6 +35,7 @@ from nostr_dvm.utils.zap_utils import check_and_set_ln_bits_keys rebroadcast_NIP89 = False # Announce NIP89 on startup Only do this if you know what you're doing. rebroadcast_NIP65_Relay_List = True update_profile = False +delete_announcement_on_shutdown = False global_update_rate = 180 # set this high on first sync so db can fully sync before another process trys to. use_logger = True @@ -121,6 +123,7 @@ def build_example_tweets(name, identifier, admin_config, options, image, descrip dvm_config.RELAY_LIST = RELAY_LIST dvm_config.DATABASE = database dvm_config.SEND_FEEDBACK_EVENTS = False + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -164,6 +167,7 @@ def build_example_gallery(name, identifier, admin_config, options, image, cost=0 dvm_config.SEND_FEEDBACK_EVENTS = False dvm_config.FIX_COST = cost dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -201,6 +205,7 @@ def build_example_nostrband(name, identifier, admin_config, image, about, custom dvm_config.RELAY_LIST = RELAY_LIST dvm_config.LOGLEVEL = LogLevel.INFO dvm_config.SEND_FEEDBACK_EVENTS = False + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -238,6 +243,7 @@ def build_longform(name, identifier, admin_config, options, cost=0, update_rate= # dvm_config.SUBSCRIPTION_DAILY_COST = 1 dvm_config.FIX_COST = cost dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS image = "https://image.nostr.build/d30a75c438a8b0815b5c65b494988da26fce719f4138058929fa52d2a2dc3433.jpg" @@ -290,6 +296,7 @@ def build_wiki(name, identifier, admin_config, options, cost=0, update_rate=180, dvm_config.FIX_COST = cost dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg dvm_config.SEND_FEEDBACK_EVENTS = False + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS image = "https://i.nostr.build/ctfc5o47ICm56TOv.jpg" @@ -340,6 +347,7 @@ def build_example_topic(name, identifier, admin_config, options, image, descript dvm_config.RELAY_LIST = RELAY_LIST dvm_config.DATABASE = database dvm_config.SEND_FEEDBACK_EVENTS = False + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -382,6 +390,7 @@ def build_example_popular(name, identifier, admin_config, options, image, cost=0 dvm_config.RELAY_LIST = RELAY_LIST dvm_config.DATABASE = database dvm_config.SEND_FEEDBACK_EVENTS = False + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -423,6 +432,7 @@ def build_example_popular_followers(name, identifier, admin_config, options, ima dvm_config.AVOID_OUTBOX_RELAY_LIST = AVOID_OUTBOX_RELAY_LIST dvm_config.SYNC_DB_RELAY_LIST = SYNC_DB_RELAY_LIST dvm_config.RELAY_LIST = RELAY_LIST + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS @@ -471,6 +481,7 @@ def build_example_popular_non_followers(name, identifier, admin_config, options, dvm_config.SYNC_DB_RELAY_LIST = SYNC_DB_RELAY_LIST dvm_config.RELAY_LIST = RELAY_LIST dvm_config.SUBSCRIPTION_REQUIRED = False + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS admin_config.REBROADCAST_NIP88 = False # admin_config.REBROADCAST_NIP89 = True @@ -540,6 +551,7 @@ def build_example_top_zapped(name, identifier, admin_config, options, image, cos dvm_config.RELAY_LIST = RELAY_LIST dvm_config.DATABASE = database dvm_config.SEND_FEEDBACK_EVENTS = False + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -588,6 +600,7 @@ def build_example_mostr(name, identifier, admin_config, options, image, cost=0, dvm_config.FIX_COST = cost dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -630,6 +643,7 @@ def build_example_oneperfollow(name, identifier, admin_config, options, image, c dvm_config.SYNC_DB_RELAY_LIST = SYNC_DB_RELAY_LIST dvm_config.RELAY_LIST = RELAY_LIST dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_announcement_on_shutdown admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -659,6 +673,10 @@ def build_example_oneperfollow(name, identifier, admin_config, options, image, c def playground(): + + framework = DVMFramework() + + main_db = "db/nostr_recent_notes.db" main_db_limit = 1024 # in mb @@ -682,7 +700,9 @@ def playground(): cost=0, update_db=True, database=DATABASE) - db_scheduler.run() + + framework.add(db_scheduler) + #db_scheduler.run() admin_config_gallery = AdminConfig() admin_config_gallery.REBROADCAST_NIP89 = rebroadcast_NIP89 @@ -741,7 +761,7 @@ def playground(): processing_msg=custom_processing_msg, update_db=update_db) - latest_longform.run() + framework.add(latest_longform) # Latest Wiki admin_config_wiki = AdminConfig() @@ -769,7 +789,7 @@ def playground(): processing_msg=custom_processing_msg, update_db=update_db) - latest_wiki.run() + framework.add(latest_wiki) # Popular top zapped admin_config_top_zaps = AdminConfig() @@ -802,7 +822,7 @@ def playground(): update_db=update_db, database=DATABASE) - discovery_topzaps.run() + framework.add(discovery_topzaps) # Popular NOSTR.band admin_config_trending_nostr_band = AdminConfig() @@ -822,7 +842,7 @@ def playground(): about=about, admin_config=admin_config_trending_nostr_band, custom_processing_msg=custom_processing_msg) - trending_nb.run() + framework.add(trending_nb) admin_config_mostr = AdminConfig() admin_config_mostr.REBROADCAST_NIP89 = rebroadcast_NIP89 @@ -879,7 +899,8 @@ def playground(): processing_msg=custom_processing_msg, update_db=update_db, database=DATABASE) - discovery_asknostr.run() + + framework.add(discovery_asknostr) # Popular Garden&Plants admin_config_mining = AdminConfig() @@ -912,7 +933,8 @@ def playground(): processing_msg=custom_processing_msg, update_db=update_db, database=DATABASE) - discovery_mining.run() + + framework.add(discovery_mining) # Popular Garden&Plants admin_config_gm = AdminConfig() @@ -945,8 +967,8 @@ def playground(): processing_msg=custom_processing_msg, update_db=update_db, database=DATABASE) - discovery_gm.run() + framework.add(discovery_gm) @@ -1007,7 +1029,8 @@ def playground(): update_db=update_db, database=DATABASE) - discovery_animals.run() + + framework.add(discovery_animals) # Popular Garden&Plants admin_config_plants = AdminConfig() @@ -1055,7 +1078,8 @@ def playground(): processing_msg=custom_processing_msg, update_db=update_db, database=DATABASE) - discovery_garden.run() + + framework.add(discovery_garden) # Popular Followers admin_config_followers = AdminConfig() @@ -1088,7 +1112,8 @@ def playground(): update_rate=global_update_rate, processing_msg=custom_processing_msg, update_db=update_db) - discovery_followers.run() + + framework.add(discovery_followers) # Popular Followers admin_config_nonfollowers = AdminConfig() @@ -1121,7 +1146,9 @@ def playground(): processing_msg=custom_processing_msg, update_db=update_db, database=DATABASE) - discovery_non_followers.run() + + framework.add(discovery_non_followers) + admin_config_opf = AdminConfig() admin_config_opf.REBROADCAST_NIP89 = rebroadcast_NIP89 @@ -1150,7 +1177,7 @@ def playground(): update_rate=global_update_rate, processing_msg=custom_processing_msg, update_db=update_db) - discovery_one_per_follow.run() + framework.add(discovery_one_per_follow) # Popular Tweets admin_config = AdminConfig() @@ -1181,7 +1208,7 @@ def playground(): update_db=update_db, database=DATABASE) - discovery_tweets.run() + framework.add(discovery_tweets) @@ -1215,7 +1242,8 @@ def playground(): processing_msg=custom_processing_msg, update_db=update_db, database=DATABASE) - discovery_global.run() + + framework.add(discovery_global) # discovery_test_sub = content_discovery_currently_popular.build_example_subscription("Currently Popular Notes DVM (with Subscriptions)", "discovery_content_test", admin_config) # discovery_test_sub.run() @@ -1262,6 +1290,10 @@ def playground(): # update_db=update_db) # discovery_nostriga.run() + + framework.run() + + # Subscription Manager DVM subscription_config = DVMConfig() subscription_config.PRIVATE_KEY = check_and_set_private_key("dvm_subscription") diff --git a/tests/discovery_on_this_day.py b/tests/discovery_on_this_day_and_olas.py similarity index 58% rename from tests/discovery_on_this_day.py rename to tests/discovery_on_this_day_and_olas.py index fd332ca..74c370c 100644 --- a/tests/discovery_on_this_day.py +++ b/tests/discovery_on_this_day_and_olas.py @@ -1,22 +1,29 @@ import asyncio import datetime import json +import os +import signal +import time from pathlib import Path +from time import sleep import dotenv from nostr_sdk import init_logger, LogLevel +from nostr_dvm.framework import DVMFramework +from nostr_dvm.tasks.content_discovery_currently_popular_gallery import DicoverContentCurrentlyPopularGallery # os.environ["RUST_BACKTRACE"] = "full" from nostr_dvm.tasks.content_discovery_on_this_day import DicoverContentOnThisDay from nostr_dvm.utils.admin_utils import AdminConfig from nostr_dvm.utils.database_utils import init_db from nostr_dvm.utils.dvmconfig import build_default_config -from nostr_dvm.utils.nip89_utils import create_amount_tag, NIP89Config, check_and_set_d_tag +from nostr_dvm.utils.nip89_utils import create_amount_tag, NIP89Config, check_and_set_d_tag, delete_nip_89 from nostr_dvm.utils.outbox_utils import AVOID_OUTBOX_RELAY_LIST -rebroadcast_NIP89 = False # Announce NIP89 on startup Only do this if you know what you're doing. +rebroadcast_NIP89 = True # Announce NIP89 on startup Only do this if you know what you're doing. rebroadcast_NIP65_Relay_List = True update_profile = True +delete_nip_89_on_shutdown = False global_update_rate = 60*60 # set this high on first sync so db can fully sync before another process trys to. use_logger = True @@ -36,6 +43,41 @@ SYNC_DB_RELAY_LIST = ["wss://relay.damus.io", ] +def build_example_gallery(name, identifier, admin_config, options, image, cost=0, update_rate=180, processing_msg=None, + update_db=True): + dvm_config = build_default_config(identifier) + dvm_config.SCHEDULE_UPDATES_SECONDS = update_rate # Every 10 minutes + dvm_config.UPDATE_DATABASE = update_db + dvm_config.FIX_COST = cost + dvm_config.CUSTOM_PROCESSING_MESSAGE = processing_msg + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_nip_89_on_shutdown + admin_config.LUD16 = dvm_config.LN_ADDRESS + + # Add NIP89 + nip89info = { + "name": name, + "picture": image, + "about": "I show popular pictures from the Olas feed", + "lud16": dvm_config.LN_ADDRESS, + "supportsEncryption": True, + "acceptsNutZaps": dvm_config.ENABLE_NUTZAP, + "personalized": False, + "amount": create_amount_tag(cost), + "nip90Params": { + "max_results": { + "required": False, + "values": [], + "description": "The number of maximum results to return (default currently 200)" + } + } + } + + nip89config = NIP89Config() + nip89config.DTAG = check_and_set_d_tag(identifier, name, dvm_config.PRIVATE_KEY, nip89info["picture"]) + nip89config.CONTENT = json.dumps(nip89info) + return DicoverContentCurrentlyPopularGallery(name=name, dvm_config=dvm_config, nip89config=nip89config, + admin_config=admin_config, options=options) + def build_example_on_this_day(name, identifier, admin_config, options, image, description, update_rate=600, cost=0, processing_msg=None, update_db=True, database=None): @@ -53,6 +95,9 @@ def build_example_on_this_day(name, identifier, admin_config, options, image, de dvm_config.RELAY_LIST = RELAY_LIST dvm_config.DATABASE = database dvm_config.SEND_FEEDBACK_EVENTS = False + dvm_config.DELETE_ANNOUNCEMENT_ON_SHUTDOWN = delete_nip_89_on_shutdown + + admin_config.LUD16 = dvm_config.LN_ADDRESS # Add NIP89 @@ -83,6 +128,10 @@ def build_example_on_this_day(name, identifier, admin_config, options, image, de def playground(): + + framework = DVMFramework() + + main_db = "db/nostr_on_this_day.db" main_db_limit = 1024 # in mb @@ -123,7 +172,46 @@ def playground(): update_db=update_db, database=database) - discovery_onthisday.run() + framework.add(discovery_onthisday) + + + admin_config_global_gallery = AdminConfig() + admin_config_global_gallery.REBROADCAST_NIP89 = rebroadcast_NIP89 + admin_config_global_gallery.REBROADCAST_NIP65_RELAY_LIST = rebroadcast_NIP65_Relay_List + admin_config_global_gallery.UPDATE_PROFILE = update_profile + admin_config_global_gallery.DELETE_NIP89 = False + admin_config_global_gallery.PRIVKEY = "" + admin_config_global_gallery.EVENTID = "" + admin_config_global_gallery.POW = False + custom_processing_msg = ["Looking for popular Gallery entries"] + update_db = True + + options_gallery = { + "db_name": "db/nostr_olas.db", + "db_since": 60 * 60 * 24 * 4, # 2d since gmt, + } + + + cost = 0 + image = "https://image.nostr.build/f5901156825ef1d9dad557890020ce9c5d917f52bc31863226b980fa232a9c23.png" + discover_olas = build_example_gallery("Popular on Olas", + "discovery_gallery_entries", + admin_config=admin_config_global_gallery, + options=options_gallery, + image=image, + cost=cost, + update_rate=global_update_rate, + processing_msg=custom_processing_msg, + update_db=update_db) + + + framework.add(discover_olas) + + framework.run() + + + + if __name__ == '__main__': @@ -138,3 +226,8 @@ if __name__ == '__main__': else: raise FileNotFoundError(f'.env file not found at {env_path} ') playground() + + + + +