Wire the Nostr layer through the nostrclient extension's relay manager
in-process (spirekeeper pattern), replacing the sketch stubs:
- _sign_and_publish: sign as operator (resolve_signer), optional NIP-44
encrypt, publish via nostr_client.relay_manager.publish_message. Soft-
fails (logs, returns None) if no operator onboarded, nostrclient absent,
or signer can't encrypt — never crashes the booking flow.
- publish_listing (30402) + publish_block_calendar (31923): public, work
today (sign_event only).
- publish_reservation (30078): NIP-44 encrypted to guest; soft-fails on a
LocalSigner until a bunker/server-signing signer lands (lnbits#18).
- subscribe_inbound: permanent task answering kind:22000 availability
queries with kind:22001 (plaintext — availability is public info), the
client-agnostic availability path parallel to the RPC.
events.py: drop the _plaintext scaffolding (service.py encrypts content in
place) and a broken {operator_pubkey} calendar tag.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019VUQCfdqiLSsFS2jcGnaFD
106 lines
3.5 KiB
Python
106 lines
3.5 KiB
Python
import asyncio
|
|
|
|
from fastapi import APIRouter
|
|
|
|
from .crud import db
|
|
from .tasks import expire_holds_loop, wait_for_paid_invoices
|
|
from .views import chatelet_generic_router
|
|
from .views_api import chatelet_api_router
|
|
|
|
chatelet_static_files = [
|
|
{
|
|
"path": "/chatelet/static",
|
|
"name": "chatelet_static",
|
|
}
|
|
]
|
|
|
|
chatelet_ext: APIRouter = APIRouter(prefix="/chatelet", tags=["chatelet"])
|
|
chatelet_ext.include_router(chatelet_generic_router)
|
|
chatelet_ext.include_router(chatelet_api_router)
|
|
|
|
scheduled_tasks: list[asyncio.Task] = []
|
|
|
|
|
|
def chatelet_stop():
|
|
for task in scheduled_tasks:
|
|
task.cancel()
|
|
|
|
|
|
def chatelet_start():
|
|
from lnbits.tasks import create_permanent_unique_task
|
|
|
|
scheduled_tasks.append(
|
|
create_permanent_unique_task("chatelet_invoices", wait_for_paid_invoices)
|
|
)
|
|
scheduled_tasks.append(
|
|
create_permanent_unique_task("chatelet_hold_expiry", expire_holds_loop)
|
|
)
|
|
|
|
# Inbound Nostr: answer kind:22000 availability queries over relays via
|
|
# nostrclient (client-agnostic availability path). Self-backs-off if
|
|
# nostrclient isn't installed.
|
|
from .nostr.service import subscribe_inbound
|
|
|
|
scheduled_tasks.append(
|
|
create_permanent_unique_task("chatelet_availability_sub", subscribe_inbound)
|
|
)
|
|
|
|
# Expose the booking flow over the core LNbits nostr transport (kind-21000
|
|
# RPC) so an HTTP-allergic client can drive Chatelet over relays. Also wire
|
|
# the booking-owner resolver so the operator can stream booking
|
|
# settlements via subscribe_payments({tag:"chatelet", link_id:<booking_id>}).
|
|
# No-op if the core transport module isn't present in this LNbits build.
|
|
try:
|
|
from lnbits.core.services.nostr_transport.dispatcher import (
|
|
AUTH_ACCOUNT,
|
|
AUTH_NONE,
|
|
AUTH_WALLET,
|
|
register_rpc,
|
|
)
|
|
from lnbits.core.services.nostr_transport.subscriptions import (
|
|
register_link_owner_resolver,
|
|
)
|
|
except ImportError:
|
|
return
|
|
|
|
from .transport_rpcs import (
|
|
handle_availability,
|
|
handle_block_create,
|
|
handle_booking_get,
|
|
handle_booking_request,
|
|
handle_room_create,
|
|
handle_room_get,
|
|
handle_room_list,
|
|
handle_room_list_mine,
|
|
handle_room_publish,
|
|
handle_room_update,
|
|
resolve_chatelet_owner,
|
|
)
|
|
|
|
# operator (wallet-scoped)
|
|
register_rpc("chatelet_room_create", handle_room_create, AUTH_WALLET)
|
|
register_rpc("chatelet_room_update", handle_room_update, AUTH_WALLET)
|
|
register_rpc("chatelet_room_publish", handle_room_publish, AUTH_WALLET)
|
|
register_rpc("chatelet_block_create", handle_block_create, AUTH_WALLET)
|
|
register_rpc("chatelet_room_list_mine", handle_room_list_mine, AUTH_ACCOUNT)
|
|
# public (discovery + guest booking)
|
|
register_rpc("chatelet_room_list", handle_room_list, AUTH_NONE)
|
|
register_rpc("chatelet_room_get", handle_room_get, AUTH_NONE)
|
|
register_rpc("chatelet_availability", handle_availability, AUTH_NONE)
|
|
register_rpc("chatelet_booking_request", handle_booking_request, AUTH_NONE)
|
|
register_rpc("chatelet_booking_get", handle_booking_get, AUTH_NONE)
|
|
|
|
# tasks.py stamps extra["booking_id"] on settlement (see on_invoice_paid),
|
|
# so override the default link_extra_key ("link") to match.
|
|
register_link_owner_resolver(
|
|
"chatelet", resolve_chatelet_owner, link_extra_key="booking_id"
|
|
)
|
|
|
|
|
|
__all__ = [
|
|
"db",
|
|
"chatelet_ext",
|
|
"chatelet_start",
|
|
"chatelet_static_files",
|
|
"chatelet_stop",
|
|
]
|