fix: improve nostrclient status detection and display

- Call nostrclient /relays API directly from frontend for accurate status
- Show correct error messages from API response (body.detail)
- Add orange warning state for no relays configured
- Show relay count when connected (X of Y connected)
- Simplify status logic: 200 = green, no relays = orange, error = red

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Ben Weeks 2025-12-22 12:49:33 +00:00
parent 9911a03575
commit d2755d7232
4 changed files with 118 additions and 60 deletions

View file

@ -18,21 +18,18 @@ window.app = Vue.createApp({
}, },
wsConnection: null, wsConnection: null,
nostrStatus: { nostrStatus: {
nostrclient_available: false, connected: false,
nostrclient_relays: [], error: null,
nostrclient_error: null, relays_connected: 0,
nostrmarket_running: false, relays_total: 0
websocket_connected: false
} }
} }
}, },
computed: { computed: {
nostrStatusColor: function () { nostrStatusColor: function () {
if (!this.nostrStatus.nostrclient_available) { if (this.nostrStatus.connected) {
return 'red'
} else if (this.nostrStatus.websocket_connected) {
return 'green' return 'green'
} else if (this.nostrStatus.nostrmarket_running) { } else if (this.nostrStatus.warning) {
return 'orange' return 'orange'
} }
return 'red' return 'red'
@ -218,31 +215,61 @@ window.app = Vue.createApp({
}) })
} }
}, },
checkNostrStatus: async function () { checkNostrStatus: async function (showNotification = false) {
try { try {
const {data} = await LNbits.api.request( const response = await fetch('/nostrclient/api/v1/relays')
'GET', const body = await response.json()
'/nostrmarket/api/v1/status', console.log('Nostrclient /relays:', response.status, body)
this.g.user.wallets[0].inkey
) if (response.status === 200) {
this.nostrStatus = data const relaysConnected = body.filter(r => r.connected).length
if (!data.nostrclient_available) { if (body.length === 0) {
this.nostrStatus = {
connected: false,
error: 'No relays configured in Nostr Client',
relays_connected: 0,
relays_total: 0,
warning: true
}
} else {
this.nostrStatus = {
connected: true,
error: null,
relays_connected: relaysConnected,
relays_total: body.length
}
}
} else {
this.nostrStatus = {
connected: false,
error: body.detail,
relays_connected: 0,
relays_total: 0
}
}
if (showNotification) {
this.$q.notify({ this.$q.notify({
timeout: 5000, timeout: 3000,
type: 'warning', type: this.nostrStatus.connected ? 'positive' : 'warning',
message: 'Nostrclient extension not available', message: this.nostrStatus.connected ? 'Connected' : 'Disconnected',
caption: caption: this.nostrStatus.error || undefined
data.nostrclient_error ||
'Please install and configure the nostrclient extension'
}) })
} }
} catch (error) { } catch (error) {
console.error('Failed to check nostr status:', error)
this.nostrStatus = { this.nostrStatus = {
nostrclient_available: false, connected: false,
nostrclient_relays: [], error: error.message,
nostrclient_error: 'Failed to check status', relays_connected: 0,
nostrmarket_running: false, relays_total: 0
websocket_connected: false }
if (showNotification) {
this.$q.notify({
timeout: 5000,
type: 'negative',
message: this.nostrStatus.error
})
} }
} }
}, },
@ -253,13 +280,18 @@ window.app = Vue.createApp({
) )
.onOk(async () => { .onOk(async () => {
try { try {
this.$q.notify({
timeout: 2000,
type: 'info',
message: 'Reconnecting...'
})
await LNbits.api.request( await LNbits.api.request(
'PUT', 'PUT',
'/nostrmarket/api/v1/restart', '/nostrmarket/api/v1/restart',
this.g.user.wallets[0].adminkey this.g.user.wallets[0].adminkey
) )
// Check status after restart // Check status after restart (give time for websocket to reconnect)
setTimeout(() => this.checkNostrStatus(), 2000) setTimeout(() => this.checkNostrStatus(true), 3000)
} catch (error) { } catch (error) {
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
} }

View file

@ -1,6 +1,6 @@
<q-card> <q-card>
<q-card-section> <q-card-section>
<p class="text-body1"> <p>
Create, edit and publish products to your Nostr relays. Customers can Create, edit and publish products to your Nostr relays. Customers can
browse your stalls and pay with Lightning. browse your stalls and pay with Lightning.
</p> </p>

View file

@ -170,7 +170,7 @@
</q-item-label> </q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item clickable v-close-popup @click="checkNostrStatus"> <q-item clickable v-close-popup @click="checkNostrStatus(true)">
<q-item-section avatar> <q-item-section avatar>
<q-icon name="wifi_find" color="primary"></q-icon> <q-icon name="wifi_find" color="primary"></q-icon>
</q-item-section> </q-item-section>
@ -185,27 +185,29 @@
<q-item> <q-item>
<q-item-section> <q-item-section>
<q-item-label caption> <q-item-label caption>
<strong>Nostrclient:</strong> <strong>Status:</strong>
<q-badge <q-badge
:color="nostrStatus.nostrclient_available ? 'green' : 'red'" :color="nostrStatus.connected ? 'green' : 'red'"
class="q-ml-xs" class="q-ml-xs"
v-text="nostrStatus.nostrclient_available ? 'Available' : 'Not Available'" v-text="nostrStatus.connected ? 'Connected' : 'Disconnected'"
></q-badge>
<br />
<strong>Relays:</strong>
<span v-text="(nostrStatus.nostrclient_relays || []).length"></span> configured<br />
<strong>WebSocket:</strong>
<q-badge
:color="nostrStatus.websocket_connected ? 'green' : 'orange'"
class="q-ml-xs"
v-text="nostrStatus.websocket_connected ? 'Connected' : 'Disconnected'"
></q-badge> ></q-badge>
</q-item-label> </q-item-label>
<q-item-label <q-item-label
v-if="nostrStatus.nostrclient_error" v-if="nostrStatus.relays_total > 0"
caption
class="q-mt-xs"
>
<strong>Relays:</strong>&nbsp;
<span v-text="nostrStatus.relays_connected"></span>
of
<span v-text="nostrStatus.relays_total"></span>
connected
</q-item-label>
<q-item-label
v-if="nostrStatus.error"
caption caption
class="text-negative q-mt-xs" class="text-negative q-mt-xs"
v-text="nostrStatus.nostrclient_error" v-text="nostrStatus.error"
></q-item-label> ></q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>

View file

@ -1113,31 +1113,55 @@ async def api_get_nostr_status(
) -> dict: ) -> dict:
"""Get the status of the nostrclient extension.""" """Get the status of the nostrclient extension."""
nostrclient_available = False nostrclient_available = False
nostrclient_relays = [] relays = []
nostrclient_error = None error = None
try: try:
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.get( url = f"http://127.0.0.1:{settings.port}/nostrclient/api/v1/relays"
f"http://localhost:{settings.port}/nostrclient/api/v1/relays", logger.info(f"Calling nostrclient API: {url}")
timeout=5.0, response = await client.get(url, timeout=5.0)
logger.info(
f"Nostrclient response: status={response.status_code}, "
f"body={response.text[:500]}"
) )
if response.status_code == 200: if response.status_code == 200:
nostrclient_available = True nostrclient_available = True
nostrclient_relays = response.json() relays = response.json()
else:
# Any non-200 response means we can't verify nostrclient is working
try:
error = response.json().get("detail", f"HTTP {response.status_code}")
except Exception:
error = f"HTTP {response.status_code}"
except httpx.ConnectError: except httpx.ConnectError:
nostrclient_error = "Cannot connect to nostrclient extension" error = "Cannot connect to nostrclient extension"
except httpx.TimeoutException: except httpx.TimeoutException:
nostrclient_error = "Timeout connecting to nostrclient" error = "Timeout connecting to nostrclient"
except Exception as ex: except Exception as ex:
nostrclient_error = str(ex) error = str(ex)
# Only show connected if no errors and websocket is connected
connected = (
nostrclient_available
and nostr_client.is_websocket_connected
and error is None
)
# If nostrclient exists but websocket not connected, explain why
if nostrclient_available and not nostr_client.is_websocket_connected and not error:
error = "Websocket not connected"
# Count connected relays
relays_connected = sum(1 for r in relays if r.get("connected", False))
relays_total = len(relays)
return { return {
"nostrclient_available": nostrclient_available, "connected": connected,
"nostrclient_relays": nostrclient_relays, "error": error,
"nostrclient_error": nostrclient_error, "relays_connected": relays_connected,
"nostrmarket_running": nostr_client.running, "relays_total": relays_total,
"websocket_connected": nostr_client.is_websocket_connected,
} }