feat: improve error handling and reporting
This commit is contained in:
parent
dabc26f8a6
commit
f8d578e6aa
6 changed files with 101 additions and 42 deletions
|
|
@ -8,12 +8,18 @@ from pydantic import BaseModel, Field
|
||||||
from lnbits.helpers import urlsafe_short_hash
|
from lnbits.helpers import urlsafe_short_hash
|
||||||
|
|
||||||
|
|
||||||
|
class RelayStatus(BaseModel):
|
||||||
|
num_sent_events: Optional[int] = 0
|
||||||
|
num_received_events: Optional[int] = 0
|
||||||
|
error_counter: Optional[int] = 0
|
||||||
|
error_list: Optional[List] = []
|
||||||
|
|
||||||
class Relay(BaseModel):
|
class Relay(BaseModel):
|
||||||
id: Optional[str] = None
|
id: Optional[str] = None
|
||||||
url: Optional[str] = None
|
url: Optional[str] = None
|
||||||
connected: Optional[bool] = None
|
connected: Optional[bool] = None
|
||||||
connected_string: Optional[str] = None
|
connected_string: Optional[str] = None
|
||||||
status: Optional[str] = None
|
status: Optional[RelayStatus] = None
|
||||||
active: Optional[bool] = None
|
active: Optional[bool] = None
|
||||||
ping: Optional[int] = None
|
ping: Optional[int] = None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,20 @@ class ClientMessageType:
|
||||||
REQUEST = "REQ"
|
REQUEST = "REQ"
|
||||||
CLOSE = "CLOSE"
|
CLOSE = "CLOSE"
|
||||||
|
|
||||||
|
|
||||||
class RelayMessageType:
|
class RelayMessageType:
|
||||||
EVENT = "EVENT"
|
EVENT = "EVENT"
|
||||||
NOTICE = "NOTICE"
|
NOTICE = "NOTICE"
|
||||||
END_OF_STORED_EVENTS = "EOSE"
|
END_OF_STORED_EVENTS = "EOSE"
|
||||||
|
COMMAND_RESULT = "OK"
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_valid(type: str) -> bool:
|
def is_valid(type: str) -> bool:
|
||||||
if type == RelayMessageType.EVENT or type == RelayMessageType.NOTICE or type == RelayMessageType.END_OF_STORED_EVENTS:
|
if (
|
||||||
|
type == RelayMessageType.EVENT
|
||||||
|
or type == RelayMessageType.NOTICE
|
||||||
|
or type == RelayMessageType.END_OF_STORED_EVENTS
|
||||||
|
or type == RelayMessageType.COMMAND_RESULT
|
||||||
|
):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import json
|
||||||
import time
|
import time
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from threading import Lock
|
from threading import Lock
|
||||||
|
from typing import List
|
||||||
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from websocket import WebSocketApp
|
from websocket import WebSocketApp
|
||||||
|
|
@ -39,6 +40,7 @@ class Relay:
|
||||||
self.shutdown: bool = False
|
self.shutdown: bool = False
|
||||||
self.error_counter: int = 0
|
self.error_counter: int = 0
|
||||||
self.error_threshold: int = 100
|
self.error_threshold: int = 100
|
||||||
|
self.error_list: List[str] = []
|
||||||
self.num_received_events: int = 0
|
self.num_received_events: int = 0
|
||||||
self.num_sent_events: int = 0
|
self.num_sent_events: int = 0
|
||||||
self.num_subscriptions: int = 0
|
self.num_subscriptions: int = 0
|
||||||
|
|
@ -100,7 +102,7 @@ class Relay:
|
||||||
self.ws.send(message)
|
self.ws.send(message)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if self.shutdown:
|
if self.shutdown:
|
||||||
logger.warning(f"Closing queue worker for {self.url}")
|
logger.warning(f"Closing queue worker for '{self.url}'.")
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
@ -133,18 +135,14 @@ class Relay:
|
||||||
logger.warning(f"Connection to relay {self.url} closed. Status: '{status_code}'. Message: '{message}'.")
|
logger.warning(f"Connection to relay {self.url} closed. Status: '{status_code}'. Message: '{message}'.")
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _on_message(self, _, message: str):
|
def _on_message(self, _, message: str):
|
||||||
if self._is_valid_message(message):
|
if self._is_valid_message(message):
|
||||||
self.num_received_events += 1
|
self.num_received_events += 1
|
||||||
self.message_pool.add_message(message, self.url)
|
self.message_pool.add_message(message, self.url)
|
||||||
else:
|
|
||||||
logger.debug(f"Invalid relay message: '{message}'.")
|
|
||||||
|
|
||||||
def _on_error(self, _, error):
|
def _on_error(self, _, error):
|
||||||
logger.warning(f"Relay error: '{str(error)}'")
|
logger.warning(f"Relay error: '{str(error)}'")
|
||||||
|
self._append_error_message(str(error))
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.error_counter += 1
|
self.error_counter += 1
|
||||||
|
|
||||||
|
|
@ -161,33 +159,57 @@ class Relay:
|
||||||
|
|
||||||
message_json = json.loads(message)
|
message_json = json.loads(message)
|
||||||
message_type = message_json[0]
|
message_type = message_json[0]
|
||||||
|
|
||||||
if not RelayMessageType.is_valid(message_type):
|
if not RelayMessageType.is_valid(message_type):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if message_type == RelayMessageType.EVENT:
|
if message_type == RelayMessageType.EVENT:
|
||||||
if not len(message_json) == 3:
|
return self._is_valid_event_message(message_json)
|
||||||
return False
|
|
||||||
|
if message_type == RelayMessageType.COMMAND_RESULT:
|
||||||
subscription_id = message_json[1]
|
return self._is_valid_command_result_message(message, message_json)
|
||||||
with self.lock:
|
|
||||||
if subscription_id not in self.subscriptions:
|
|
||||||
return False
|
|
||||||
|
|
||||||
e = message_json[2]
|
|
||||||
event = Event(
|
|
||||||
e["content"],
|
|
||||||
e["pubkey"],
|
|
||||||
e["created_at"],
|
|
||||||
e["kind"],
|
|
||||||
e["tags"],
|
|
||||||
e["sig"],
|
|
||||||
)
|
|
||||||
if not event.verify():
|
|
||||||
return False
|
|
||||||
|
|
||||||
with self.lock:
|
|
||||||
subscription = self.subscriptions[subscription_id]
|
|
||||||
|
|
||||||
if subscription.filters and not subscription.filters.match(event):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def _is_valid_event_message(self, message_json):
|
||||||
|
if not len(message_json) == 3:
|
||||||
|
return False
|
||||||
|
|
||||||
|
subscription_id = message_json[1]
|
||||||
|
with self.lock:
|
||||||
|
if subscription_id not in self.subscriptions:
|
||||||
|
return False
|
||||||
|
|
||||||
|
e = message_json[2]
|
||||||
|
event = Event(
|
||||||
|
e["content"],
|
||||||
|
e["pubkey"],
|
||||||
|
e["created_at"],
|
||||||
|
e["kind"],
|
||||||
|
e["tags"],
|
||||||
|
e["sig"],
|
||||||
|
)
|
||||||
|
if not event.verify():
|
||||||
|
return False
|
||||||
|
|
||||||
|
with self.lock:
|
||||||
|
subscription = self.subscriptions[subscription_id]
|
||||||
|
|
||||||
|
if subscription.filters and not subscription.filters.match(event):
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _is_valid_command_result_message(self, message, message_json):
|
||||||
|
if not len(message_json) < 3:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if message_json[2] != True:
|
||||||
|
logger.warning(f"Relay '{self.url}' negative command result: '{message}'")
|
||||||
|
self._append_error_message(message)
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _append_error_message(self, message):
|
||||||
|
self.error_list = ([message] + self.error_list)[:20]
|
||||||
|
|
@ -102,4 +102,5 @@ class RelayManager:
|
||||||
|
|
||||||
self.remove_relay(relay.url)
|
self.remove_relay(relay.url)
|
||||||
new_relay = self.add_relay(relay.url)
|
new_relay = self.add_relay(relay.url)
|
||||||
new_relay.error_counter = relay.error_counter
|
new_relay.error_counter = relay.error_counter
|
||||||
|
new_relay.error_list = relay.error_list
|
||||||
|
|
@ -51,6 +51,18 @@
|
||||||
<q-tr :props="props">
|
<q-tr :props="props">
|
||||||
<q-td v-for="col in props.cols" :key="col.name" :props="props" auto-width>
|
<q-td v-for="col in props.cols" :key="col.name" :props="props" auto-width>
|
||||||
<div v-if="col.name == 'id'"></div>
|
<div v-if="col.name == 'id'"></div>
|
||||||
|
<div v-else-if="col.name == 'status'">
|
||||||
|
<div>
|
||||||
|
⬆️ <span v-text="col.value.sentEvents"></span>
|
||||||
|
⬇️ <span v-text="col.value.receveidEvents"></span>
|
||||||
|
⚠️ <span v-text="col.value.errorCount">
|
||||||
|
|
||||||
|
</span>
|
||||||
|
<q-tooltip>
|
||||||
|
<span v-for="e in col.value.errorList" v-text="e"></span><br>
|
||||||
|
</q-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<div v-if="col.value == true" style="background-color: green">
|
<div v-if="col.value == true" style="background-color: green">
|
||||||
{{ col.value }}
|
{{ col.value }}
|
||||||
|
|
@ -196,6 +208,13 @@
|
||||||
obj._data = _.clone(obj)
|
obj._data = _.clone(obj)
|
||||||
obj.theTime = obj.time * 60 - (Date.now() / 1000 - obj.timestamp)
|
obj.theTime = obj.time * 60 - (Date.now() / 1000 - obj.timestamp)
|
||||||
obj.time = obj.time + 'mins'
|
obj.time = obj.time + 'mins'
|
||||||
|
obj.status = {
|
||||||
|
sentEvents: obj.status.num_sent_events,
|
||||||
|
receveidEvents: obj.status.num_received_events,
|
||||||
|
errorCount: obj.status.error_counter,
|
||||||
|
errorList: obj.status.error_list
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
obj.ping = obj.ping + ' ms'
|
obj.ping = obj.ping + ' ms'
|
||||||
|
|
||||||
|
|
|
||||||
18
views_api.py
18
views_api.py
|
|
@ -24,19 +24,23 @@ all_routers: list[NostrRouter] = []
|
||||||
async def api_get_relays() -> RelayList:
|
async def api_get_relays() -> RelayList:
|
||||||
relays = RelayList(__root__=[])
|
relays = RelayList(__root__=[])
|
||||||
for url, r in nostr.client.relay_manager.relays.items():
|
for url, r in nostr.client.relay_manager.relays.items():
|
||||||
status_text = (
|
# status_text = (
|
||||||
f"⬆️ {r.num_sent_events} ⬇️ {r.num_received_events} ⚠️ {r.error_counter}"
|
# f"⬆️ {r.num_sent_events} ⬇️ {r.num_received_events} ⚠️ {r.error_counter}"
|
||||||
)
|
# )
|
||||||
connected_text = "🟢" if r.connected else "🔴"
|
# connected_text = "🟢" if r.connected else "🔴"
|
||||||
relay_id = urlsafe_short_hash()
|
relay_id = urlsafe_short_hash()
|
||||||
relays.__root__.append(
|
relays.__root__.append(
|
||||||
Relay(
|
Relay(
|
||||||
id=relay_id,
|
id=relay_id,
|
||||||
url=url,
|
url=url,
|
||||||
connected_string=connected_text,
|
connected=r.connected,
|
||||||
status=status_text,
|
status={
|
||||||
|
"num_sent_events": r.num_sent_events,
|
||||||
|
"num_received_events": r.num_received_events,
|
||||||
|
"error_counter": r.error_counter,
|
||||||
|
"error_list": r.error_list
|
||||||
|
},
|
||||||
ping=r.ping,
|
ping=r.ping,
|
||||||
connected=True,
|
|
||||||
active=True,
|
active=True,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue