Skip to content

Commit 3405341

Browse files
committed
fixes
1 parent 3bee031 commit 3405341

File tree

8 files changed

+92
-77
lines changed

8 files changed

+92
-77
lines changed

__init__.py

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
import asyncio
2-
from typing import List
32

43
from fastapi import APIRouter
5-
from lnbits.db import Database
6-
from lnbits.helpers import template_renderer
7-
from lnbits.tasks import create_permanent_unique_task
84
from loguru import logger
95

10-
from .nostr.client.client import NostrClient
11-
from .router import NostrRouter
12-
13-
db = Database("ext_nostrclient")
6+
from .crud import db
7+
from .nostr_client import all_routers, nostr_client
8+
from .tasks import check_relays, init_relays, subscribe_events
9+
from .views import nostrclient_generic_router
10+
from .views_api import nostrclient_api_router
1411

1512
nostrclient_static_files = [
1613
{
@@ -20,23 +17,11 @@
2017
]
2118

2219
nostrclient_ext: APIRouter = APIRouter(prefix="/nostrclient", tags=["nostrclient"])
23-
24-
nostr_client: NostrClient = NostrClient()
25-
26-
# we keep this in
27-
all_routers: list[NostrRouter] = []
20+
nostrclient_ext.include_router(nostrclient_generic_router)
21+
nostrclient_ext.include_router(nostrclient_api_router)
2822
scheduled_tasks: list[asyncio.Task] = []
2923

3024

31-
def nostr_renderer():
32-
return template_renderer(["nostrclient/templates"])
33-
34-
35-
from .tasks import check_relays, init_relays, subscribe_events # noqa
36-
from .views import * # noqa
37-
from .views_api import * # noqa
38-
39-
4025
async def nostrclient_stop():
4126
for task in scheduled_tasks:
4227
try:
@@ -55,9 +40,20 @@ async def nostrclient_stop():
5540

5641

5742
def nostrclient_start():
43+
from lnbits.tasks import create_permanent_unique_task
44+
5845
task1 = create_permanent_unique_task("ext_nostrclient_init_relays", init_relays)
5946
task2 = create_permanent_unique_task(
6047
"ext_nostrclient_subscrive_events", subscribe_events
6148
)
6249
task3 = create_permanent_unique_task("ext_nostrclient_check_relays", check_relays)
6350
scheduled_tasks.extend([task1, task2, task3])
51+
52+
53+
__all__ = [
54+
"db",
55+
"nostrclient_ext",
56+
"nostrclient_static_files",
57+
"nostrclient_stop",
58+
"nostrclient_start",
59+
]

crud.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import json
2-
from typing import List, Optional
2+
from typing import Optional
3+
4+
from lnbits.db import Database
35

4-
from . import db
56
from .models import Config, Relay
67

8+
db = Database("ext_nostrclient")
9+
710

8-
async def get_relays() -> List[Relay]:
11+
async def get_relays() -> list[Relay]:
912
rows = await db.fetchall("SELECT * FROM nostrclient.relays")
1013
return [Relay.from_row(r) for r in rows]
1114

nostr_client.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .nostr.client.client import NostrClient
2+
from .router import NostrRouter
3+
4+
nostr_client: NostrClient = NostrClient()
5+
all_routers: list[NostrRouter] = []

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ build-backend = "poetry.core.masonry.api"
2222

2323
[tool.mypy]
2424
exclude = "(nostr/*)"
25+
2526
[[tool.mypy.overrides]]
2627
module = [
28+
"nostr.*",
2729
"lnbits.*",
2830
"lnurl.*",
2931
"loguru.*",
@@ -32,7 +34,9 @@ module = [
3234
"pyqrcode.*",
3335
"shortuuid.*",
3436
"httpx.*",
37+
"secp256k1.*",
3538
]
39+
follow_imports = "skip"
3640
ignore_missing_imports = "True"
3741

3842
[tool.pytest.ini_options]

router.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111

1212

1313
class NostrRouter:
14-
received_subscription_events: dict[str, List[EventMessage]] = {}
15-
received_subscription_notices: list[NoticeMessage] = []
16-
received_subscription_eosenotices: dict[str, EndOfStoredEventsMessage] = {}
14+
received_subscription_events: dict[str, List[EventMessage]]
15+
received_subscription_notices: list[NoticeMessage]
16+
received_subscription_eosenotices: dict[str, EndOfStoredEventsMessage]
1717

1818
def __init__(self, websocket: WebSocket):
1919
self.connected: bool = True
@@ -154,7 +154,10 @@ def _handle_client_close(self, subscription_id):
154154
self.original_subscription_ids.pop(subscription_id_rewritten)
155155
nostr_client.relay_manager.close_subscription(subscription_id_rewritten)
156156
logger.info(
157-
f"Unsubscribe from '{subscription_id_rewritten}'. Original id: '{subscription_id}.'"
157+
f"""
158+
Unsubscribe from '{subscription_id_rewritten}'.
159+
Original id: '{subscription_id}.'
160+
"""
158161
)
159162
else:
160163
logger.info(f"Failed to unsubscribe from '{subscription_id}.'")

tasks.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ async def init_relays():
1313
# get relays from db
1414
relays = await get_relays()
1515
# set relays and connect to them
16-
valid_relays = list(set([r.url for r in relays if r.url]))
16+
valid_relays = [r.url for r in relays if r.url]
1717

1818
nostr_client.reconnect(valid_relays)
1919

@@ -29,34 +29,32 @@ async def check_relays():
2929

3030

3131
async def subscribe_events():
32-
while not any([r.connected for r in nostr_client.relay_manager.relays.values()]):
32+
while not [r.connected for r in nostr_client.relay_manager.relays.values()]:
3333
await asyncio.sleep(2)
3434

35-
def callback_events(eventMessage: EventMessage):
36-
sub_id = eventMessage.subscription_id
35+
def callback_events(event_message: EventMessage):
36+
sub_id = event_message.subscription_id
3737
if sub_id not in NostrRouter.received_subscription_events:
38-
NostrRouter.received_subscription_events[sub_id] = [eventMessage]
38+
NostrRouter.received_subscription_events[sub_id] = [event_message]
3939
return
4040

4141
# do not add duplicate events (by event id)
42-
ids = set(
43-
[e.event_id for e in NostrRouter.received_subscription_events[sub_id]]
44-
)
45-
if eventMessage.event_id in ids:
42+
ids = [e.event_id for e in NostrRouter.received_subscription_events[sub_id]]
43+
if event_message.event_id in ids:
4644
return
4745

48-
NostrRouter.received_subscription_events[sub_id].append(eventMessage)
46+
NostrRouter.received_subscription_events[sub_id].append(event_message)
4947

50-
def callback_notices(noticeMessage: NoticeMessage):
51-
if noticeMessage not in NostrRouter.received_subscription_notices:
52-
NostrRouter.received_subscription_notices.append(noticeMessage)
48+
def callback_notices(notice_message: NoticeMessage):
49+
if notice_message not in NostrRouter.received_subscription_notices:
50+
NostrRouter.received_subscription_notices.append(notice_message)
5351

54-
def callback_eose_notices(eventMessage: EndOfStoredEventsMessage):
55-
sub_id = eventMessage.subscription_id
52+
def callback_eose_notices(event_message: EndOfStoredEventsMessage):
53+
sub_id = event_message.subscription_id
5654
if sub_id in NostrRouter.received_subscription_eosenotices:
5755
return
5856

59-
NostrRouter.received_subscription_eosenotices[sub_id] = eventMessage
57+
NostrRouter.received_subscription_eosenotices[sub_id] = event_message
6058

6159
def wrap_async_subscribe():
6260
asyncio.run(

views.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1-
from fastapi import Depends, Request
1+
from fastapi import APIRouter, Depends, Request
2+
from fastapi.responses import HTMLResponse
23
from fastapi.templating import Jinja2Templates
34
from lnbits.core.models import User
45
from lnbits.decorators import check_admin
5-
from starlette.responses import HTMLResponse
6-
7-
from . import nostr_renderer, nostrclient_ext
6+
from lnbits.helpers import template_renderer
87

98
templates = Jinja2Templates(directory="templates")
109

10+
nostrclient_generic_router = APIRouter()
11+
12+
13+
def nostr_renderer():
14+
return template_renderer(["nostrclient/templates"])
15+
1116

12-
@nostrclient_ext.get("/", response_class=HTMLResponse)
17+
@nostrclient_generic_router.get("/", response_class=HTMLResponse)
1318
async def index(request: Request, user: User = Depends(check_admin)):
1419
return nostr_renderer().TemplateResponse(
1520
"nostrclient/index.html", {"request": request, "user": user.dict()}

views_api.py

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
import asyncio
22
from http import HTTPStatus
3-
from typing import List
43

5-
from fastapi import Depends, WebSocket
4+
from fastapi import APIRouter, Depends, HTTPException, WebSocket
65
from lnbits.decorators import check_admin
76
from lnbits.helpers import decrypt_internal_message, urlsafe_short_hash
87
from loguru import logger
9-
from starlette.exceptions import HTTPException
108

11-
from . import all_routers, nostr_client, nostrclient_ext
129
from .crud import (
1310
add_relay,
1411
create_config,
@@ -18,13 +15,16 @@
1815
update_config,
1916
)
2017
from .helpers import normalize_public_key
21-
from .models import Config, Relay, TestMessage, TestMessageResponse
18+
from .models import Config, Relay, RelayStatus, TestMessage, TestMessageResponse
2219
from .nostr.key import EncryptedDirectMessage, PrivateKey
20+
from .nostr_client import all_routers, nostr_client
2321
from .router import NostrRouter
2422

23+
nostrclient_api_router = APIRouter()
2524

26-
@nostrclient_ext.get("/api/v1/relays", dependencies=[Depends(check_admin)])
27-
async def api_get_relays() -> List[Relay]:
25+
26+
@nostrclient_api_router.get("/api/v1/relays", dependencies=[Depends(check_admin)])
27+
async def api_get_relays() -> list[Relay]:
2828
relays = []
2929
for url, r in nostr_client.relay_manager.relays.items():
3030
relay_id = urlsafe_short_hash()
@@ -33,24 +33,24 @@ async def api_get_relays() -> List[Relay]:
3333
id=relay_id,
3434
url=url,
3535
connected=r.connected,
36-
status={
37-
"num_sent_events": r.num_sent_events,
38-
"num_received_events": r.num_received_events,
39-
"error_counter": r.error_counter,
40-
"error_list": r.error_list,
41-
"notice_list": r.notice_list,
42-
},
36+
status=RelayStatus(
37+
num_sent_events=r.num_sent_events,
38+
num_received_events=r.num_received_events,
39+
error_counter=r.error_counter,
40+
error_list=r.error_list,
41+
notice_list=r.notice_list,
42+
),
4343
ping=r.ping,
4444
active=True,
4545
)
4646
)
4747
return relays
4848

4949

50-
@nostrclient_ext.post(
50+
@nostrclient_api_router.post(
5151
"/api/v1/relay", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)]
5252
)
53-
async def api_add_relay(relay: Relay) -> List[Relay]:
53+
async def api_add_relay(relay: Relay) -> list[Relay]:
5454
if not relay.url:
5555
raise HTTPException(
5656
status_code=HTTPStatus.BAD_REQUEST, detail="Relay url not provided."
@@ -68,7 +68,7 @@ async def api_add_relay(relay: Relay) -> List[Relay]:
6868
return await get_relays()
6969

7070

71-
@nostrclient_ext.delete(
71+
@nostrclient_api_router.delete(
7272
"/api/v1/relay", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)]
7373
)
7474
async def api_delete_relay(relay: Relay) -> None:
@@ -81,7 +81,7 @@ async def api_delete_relay(relay: Relay) -> None:
8181
await delete_relay(relay)
8282

8383

84-
@nostrclient_ext.put(
84+
@nostrclient_api_router.put(
8585
"/api/v1/relay/test", status_code=HTTPStatus.OK, dependencies=[Depends(check_admin)]
8686
)
8787
async def api_test_endpoint(data: TestMessage) -> TestMessageResponse:
@@ -105,33 +105,34 @@ async def api_test_endpoint(data: TestMessage) -> TestMessageResponse:
105105
raise HTTPException(
106106
status_code=HTTPStatus.BAD_REQUEST,
107107
detail=str(ex),
108-
)
108+
) from ex
109109
except Exception as ex:
110110
logger.warning(ex)
111111
raise HTTPException(
112112
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
113113
detail="Cannot generate test event",
114-
)
114+
) from ex
115115

116116

117-
@nostrclient_ext.websocket("/api/v1/{id}")
118-
async def ws_relay(id: str, websocket: WebSocket) -> None:
117+
@nostrclient_api_router.websocket("/api/v1/{id}")
118+
async def ws_relay(ws_id: str, websocket: WebSocket) -> None:
119119
"""Relay multiplexer: one client (per endpoint) <-> multiple relays"""
120120

121121
logger.info("New websocket connection at: '/api/v1/relay'")
122122
try:
123123
config = await get_config()
124+
assert config, "Failed to get config"
124125

125126
if not config.private_ws and not config.public_ws:
126127
raise ValueError("Websocket connections not accepted.")
127128

128-
if id == "relay":
129+
if ws_id == "relay":
129130
if not config.public_ws:
130131
raise ValueError("Public websocket connections not accepted.")
131132
else:
132133
if not config.private_ws:
133134
raise ValueError("Private websocket connections not accepted.")
134-
if decrypt_internal_message(id) != "relay":
135+
if decrypt_internal_message(ws_id) != "relay":
135136
raise ValueError("Invalid websocket endpoint.")
136137

137138
await websocket.accept()
@@ -160,10 +161,10 @@ async def ws_relay(id: str, websocket: WebSocket) -> None:
160161
raise HTTPException(
161162
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
162163
detail="Cannot accept websocket connection",
163-
)
164+
) from ex
164165

165166

166-
@nostrclient_ext.get("/api/v1/config", dependencies=[Depends(check_admin)])
167+
@nostrclient_api_router.get("/api/v1/config", dependencies=[Depends(check_admin)])
167168
async def api_get_config() -> Config:
168169
config = await get_config()
169170
if not config:
@@ -172,7 +173,7 @@ async def api_get_config() -> Config:
172173
return config
173174

174175

175-
@nostrclient_ext.put("/api/v1/config", dependencies=[Depends(check_admin)])
176+
@nostrclient_api_router.put("/api/v1/config", dependencies=[Depends(check_admin)])
176177
async def api_update_config(data: Config):
177178
config = await update_config(data)
178179
assert config

0 commit comments

Comments
 (0)