Second nostr-transport handler on this branch. Returns paid + registered counts plus the per-ticket roster (id, name, registered status, timestamp) for one calendar event, organizer-only. Backs the door scanner's counts strip and "scanned" list with backend truth so a second organizer scanning on another device, an operator switching from mobile to laptop mid-event, or a refresh in incognito all see the same numbers instead of diverging from a per-device localStorage cache. Same authorisation posture as events_ticket_register: dispatcher binds caller pubkey to wallet via AUTH_WALLET, handler verifies the event's wallet is in the caller's wallet set. Only paid tickets land in the response — proposed/unpaid rows are irrelevant at the door. Webapp consumes this in aiolabs/webapp#73.
114 lines
3.6 KiB
Python
114 lines
3.6 KiB
Python
import asyncio
|
|
|
|
from fastapi import APIRouter
|
|
from loguru import logger
|
|
|
|
from .crud import db
|
|
from .tasks import wait_for_paid_invoices
|
|
from .views import events_generic_router
|
|
from .views_api import events_api_router, tickets_api_router
|
|
|
|
events_ext: APIRouter = APIRouter(prefix="/events", tags=["Events"])
|
|
events_ext.include_router(events_generic_router)
|
|
events_ext.include_router(events_api_router)
|
|
events_ext.include_router(tickets_api_router)
|
|
|
|
events_static_files = [
|
|
{
|
|
"path": "/events/static",
|
|
"name": "events_static",
|
|
}
|
|
]
|
|
|
|
scheduled_tasks: list[asyncio.Task] = []
|
|
|
|
# Module-level NostrClient — None when nostrclient is unavailable. Set by the
|
|
# bootstrap task in events_start() and read via dynamic attribute lookup
|
|
# from nostr_hooks.publish_or_delete_nostr_event.
|
|
nostr_client = None
|
|
|
|
|
|
def events_stop():
|
|
for task in scheduled_tasks:
|
|
try:
|
|
task.cancel()
|
|
except Exception as ex:
|
|
logger.warning(ex)
|
|
|
|
global nostr_client
|
|
if nostr_client:
|
|
asyncio.get_event_loop().create_task(nostr_client.stop())
|
|
|
|
|
|
def events_start():
|
|
from lnbits.tasks import create_permanent_unique_task
|
|
|
|
task1 = create_permanent_unique_task("ext_events", wait_for_paid_invoices)
|
|
scheduled_tasks.append(task1)
|
|
|
|
# Register nostr-transport RPCs. Swallow ImportError on older LNbits
|
|
# versions that pre-date the transport (the events extension still
|
|
# works fine via HTTP without it).
|
|
try:
|
|
from lnbits.core.services.nostr_transport.dispatcher import (
|
|
AUTH_WALLET,
|
|
register_rpc,
|
|
)
|
|
|
|
from .transport_rpcs import (
|
|
handle_events_list_event_tickets,
|
|
handle_events_ticket_register,
|
|
)
|
|
|
|
register_rpc(
|
|
"events_ticket_register", handle_events_ticket_register, AUTH_WALLET
|
|
)
|
|
register_rpc(
|
|
"events_list_event_tickets",
|
|
handle_events_list_event_tickets,
|
|
AUTH_WALLET,
|
|
)
|
|
logger.info(
|
|
"[EVENTS] Registered nostr-transport RPCs: "
|
|
"events_ticket_register, events_list_event_tickets"
|
|
)
|
|
except ImportError:
|
|
logger.info(
|
|
"[EVENTS] nostr_transport not available on this LNbits — "
|
|
"ticket scanner over Nostr disabled, HTTP endpoint still works"
|
|
)
|
|
|
|
async def _start_nostr_client():
|
|
global nostr_client
|
|
await asyncio.sleep(10) # Wait for nostrclient to be ready
|
|
try:
|
|
from .nostr.nostr_client import NostrClient
|
|
|
|
nostr_client = NostrClient()
|
|
logger.info("[EVENTS] Starting NostrClient for NIP-52 sync")
|
|
await nostr_client.run_forever()
|
|
except Exception as exc:
|
|
logger.warning(f"[EVENTS] NostrClient failed to start: {exc}")
|
|
logger.info("[EVENTS] Events will work without Nostr sync")
|
|
|
|
task2 = create_permanent_unique_task("ext_events_nostr", _start_nostr_client)
|
|
scheduled_tasks.append(task2)
|
|
|
|
async def _sync_nostr_events():
|
|
global nostr_client
|
|
await asyncio.sleep(15) # Wait for NostrClient to connect
|
|
if not nostr_client:
|
|
logger.info("[EVENTS] No NostrClient, skipping Nostr sync")
|
|
return
|
|
try:
|
|
from .nostr_sync import wait_for_nostr_events
|
|
|
|
await wait_for_nostr_events(nostr_client)
|
|
except Exception as exc:
|
|
logger.error(f"[EVENTS] Nostr sync task failed: {exc}")
|
|
|
|
task3 = create_permanent_unique_task("ext_events_nostr_sync", _sync_nostr_events)
|
|
scheduled_tasks.append(task3)
|
|
|
|
|
|
__all__ = ["db", "events_ext", "events_start", "events_static_files", "events_stop"]
|