mirror of
https://github.com/coracle-social/coracle.git
synced 2024-09-28 16:00:52 +00:00
Show relay status based on stats not current connection status
This commit is contained in:
parent
756c2abb30
commit
9d09eeb38c
@ -88,8 +88,7 @@ If you like Coracle and want to support its development, you can donate sats via
|
||||
- [ ] Initial user load doesn't have any relays, cache user or wait for people db to be loaded
|
||||
- [ ] Shorten height of chat headers
|
||||
- [ ] Custom views should combine pubkeys, relays, and topics
|
||||
- [ ] Show relay status based on stats not current connection status
|
||||
- Add a dot below the relay's color code on feeds?
|
||||
- [ ] Are write relays the only ones that matter? User read relays only matter for global feed, or where there's no relay hints available. But if relays are navigable, this is unnecessary.
|
||||
|
||||
# Changelog
|
||||
|
||||
@ -101,6 +100,7 @@ If you like Coracle and want to support its development, you can donate sats via
|
||||
- [x] Reduce how many relays replies are published to
|
||||
- [x] Re-work thread layout
|
||||
- [x] Color code relays
|
||||
- [x] Show relay status based on stats not current connection status
|
||||
|
||||
## 0.2.11
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
|
||||
import {find, is, identity, nthArg, pluck} from 'ramda'
|
||||
import {onMount} from "svelte"
|
||||
import {createMap} from 'hurdak/lib/hurdak'
|
||||
import {createMap, first} from 'hurdak/lib/hurdak'
|
||||
import {writable, get} from "svelte/store"
|
||||
import {fly, fade} from "svelte/transition"
|
||||
import {cubicInOut} from "svelte/easing"
|
||||
@ -113,12 +113,12 @@
|
||||
log(
|
||||
'Connection stats',
|
||||
pool.getConnections()
|
||||
.map(({nostr: {url}, stats: s}) => `${url} ${s.timer / s.count}`)
|
||||
.map(c => `${c.nostr.url} ${c.getQuality().join(' ')}`)
|
||||
)
|
||||
|
||||
// Alert the user to any heinously slow connections
|
||||
slowConnections = pool.getConnections()
|
||||
.filter(({nostr: {url}, stats: s}) => relayUrls.includes(url) && s.timer / s.count > 3000)
|
||||
.filter(c => relayUrls.includes(c.nostr.url) && first(c.getQuality()) < 0.3)
|
||||
}
|
||||
|
||||
const retrieveRelayMeta = async () => {
|
||||
|
@ -10,6 +10,14 @@ import database from 'src/agent/database'
|
||||
|
||||
const connections = []
|
||||
|
||||
const CONNECTION_STATUS = {
|
||||
NEW: 'new',
|
||||
ERROR: 'error',
|
||||
PENDING: 'pending',
|
||||
CLOSED: 'closed',
|
||||
READY: 'ready',
|
||||
}
|
||||
|
||||
class Connection {
|
||||
promise: Promise<void>
|
||||
nostr: Relay
|
||||
@ -21,34 +29,36 @@ class Connection {
|
||||
this.nostr = relayInit(url)
|
||||
this.status = 'new'
|
||||
this.stats = {
|
||||
count: 0,
|
||||
timer: 0,
|
||||
timeouts: 0,
|
||||
activeCount: 0,
|
||||
subCount: 0,
|
||||
eoseCount: 0,
|
||||
eoseTimer: 0,
|
||||
eventsCount: 0,
|
||||
activeSubsCount: 0,
|
||||
}
|
||||
|
||||
connections.push(this)
|
||||
}
|
||||
async connect() {
|
||||
const shouldConnect = (
|
||||
this.status === 'new'
|
||||
this.status === CONNECTION_STATUS.NEW
|
||||
|| (
|
||||
this.status === 'error'
|
||||
this.status === CONNECTION_STATUS.ERROR
|
||||
&& Date.now() - this.lastConnectionAttempt > 60_000
|
||||
)
|
||||
)
|
||||
|
||||
if (shouldConnect) {
|
||||
this.status = 'pending'
|
||||
this.status = CONNECTION_STATUS.PENDING
|
||||
this.promise = this.nostr.connect()
|
||||
}
|
||||
|
||||
if (this.status === 'pending') {
|
||||
if (this.status === CONNECTION_STATUS.PENDING) {
|
||||
try {
|
||||
await this.promise
|
||||
this.status = 'ready'
|
||||
this.status = CONNECTION_STATUS.READY
|
||||
} catch (e) {
|
||||
this.status = 'error'
|
||||
this.status = CONNECTION_STATUS.ERROR
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,7 +67,7 @@ class Connection {
|
||||
return this
|
||||
}
|
||||
async disconnect() {
|
||||
this.status = 'closed'
|
||||
this.status = CONNECTION_STATUS.CLOSED
|
||||
|
||||
try {
|
||||
await this.nostr.close()
|
||||
@ -65,6 +75,39 @@ class Connection {
|
||||
// For some reason bugsnag is saying this.nostr is undefined, even if we check it
|
||||
}
|
||||
}
|
||||
getQuality() {
|
||||
if (this.status === CONNECTION_STATUS.ERROR) {
|
||||
return [0, "Failed to connect"]
|
||||
}
|
||||
|
||||
const {timeouts, subCount, eoseTimer, eoseCount} = this.stats
|
||||
const timeoutRate = subCount > 10 ? timeouts / subCount : null
|
||||
const eoseQuality = eoseCount > 10 ? Math.max(1, 500 / (eoseTimer / eoseCount)) : null
|
||||
|
||||
if (timeoutRate && timeoutRate > 0.5) {
|
||||
return [1 - timeoutRate, "Slow connection"]
|
||||
}
|
||||
|
||||
if (eoseQuality && eoseQuality < 0.7) {
|
||||
return [eoseQuality, "Slow connection"]
|
||||
}
|
||||
|
||||
if (eoseQuality) {
|
||||
return [eoseQuality, "Connected"]
|
||||
}
|
||||
|
||||
if ([CONNECTION_STATUS.NEW, CONNECTION_STATUS.PENDING].includes(this.status)) {
|
||||
return [0.5, "Trying to connect"]
|
||||
}
|
||||
|
||||
if (this.status === CONNECTION_STATUS.CLOSED) {
|
||||
return [0.5, "Disconnected"]
|
||||
}
|
||||
|
||||
if (this.status === CONNECTION_STATUS.READY) {
|
||||
return [1, "Connected"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const getConnections = () => connections
|
||||
@ -145,6 +188,7 @@ const subscribe = async (relays, filters, {onEvent, onEose}: Record<string, (e:
|
||||
if (!seen.has(e.id)) {
|
||||
seen.add(e.id)
|
||||
|
||||
conn.stats.eventsCount += 1
|
||||
e.seen_on = conn.nostr.url
|
||||
|
||||
onEvent(e as MyEvent)
|
||||
@ -160,15 +204,16 @@ const subscribe = async (relays, filters, {onEvent, onEose}: Record<string, (e:
|
||||
if (!eose.has(conn.nostr.url)) {
|
||||
eose.add(conn.nostr.url)
|
||||
|
||||
conn.stats.count += 1
|
||||
conn.stats.timer += Date.now() - now
|
||||
conn.stats.eoseCount += 1
|
||||
conn.stats.eoseTimer += Date.now() - now
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
conn.stats.activeCount += 1
|
||||
conn.stats.subsCount += 1
|
||||
conn.stats.activeSubsCount += 1
|
||||
|
||||
if (conn.stats.activeCount > 10) {
|
||||
if (conn.stats.activeSubsCount > 10) {
|
||||
warn(`Relay ${conn.nostr.url} has >10 active subscriptions`)
|
||||
}
|
||||
|
||||
@ -187,7 +232,7 @@ const subscribe = async (relays, filters, {onEvent, onEose}: Record<string, (e:
|
||||
sub.unsub()
|
||||
}
|
||||
|
||||
sub.conn.stats.activeCount -= 1
|
||||
sub.conn.stats.activeSubsCount -= 1
|
||||
}
|
||||
})
|
||||
},
|
||||
@ -217,6 +262,14 @@ const subscribeUntilEose = async (
|
||||
const timedOutRelays = without(Array.from(eose), relays)
|
||||
|
||||
log(`Timing out ${timedOutRelays.length} relays after ${timeout}ms`, timedOutRelays)
|
||||
|
||||
timedOutRelays.forEach(url => {
|
||||
const conn = findConnection(url)
|
||||
|
||||
if (conn) {
|
||||
conn.stats.timeouts += 1
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (isComplete || isTimeout) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
import {last, find, propEq} from 'ramda'
|
||||
import {onMount} from 'svelte'
|
||||
import {poll, stringToColor} from "src/util/misc"
|
||||
import {switcher} from 'hurdak/lib/hurdak'
|
||||
import {between} from 'hurdak/lib/hurdak'
|
||||
import {fly} from 'svelte/transition'
|
||||
import Toggle from "src/partials/Toggle.svelte"
|
||||
import {user} from "src/agent/helpers"
|
||||
@ -14,22 +14,25 @@
|
||||
export let theme = 'dark'
|
||||
export let showControls = false
|
||||
|
||||
let status = null
|
||||
let quality = null
|
||||
let message = null
|
||||
let showStatus = false
|
||||
let joined = false
|
||||
|
||||
$: joined = find(propEq('url', relay.url), $user?.relays || [])
|
||||
|
||||
onMount(() => {
|
||||
return poll(300, async () => {
|
||||
const conn = find(propEq('url', relay.url), pool.getConnections())
|
||||
return poll(10_000, async () => {
|
||||
const conn = await pool.findConnection(relay.url)
|
||||
|
||||
if (conn) {
|
||||
const slow = conn.status === 'ready' && conn.stats.timer / conn.stats.count > 1000
|
||||
|
||||
// Be more strict here than with alerts
|
||||
status = slow ? 'slow' : conn.status
|
||||
[quality, message] = conn.getQuality()
|
||||
} else {
|
||||
quality = null
|
||||
message = "Not connected"
|
||||
}
|
||||
|
||||
console.log(quality, message)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@ -45,28 +48,20 @@
|
||||
<div class="flex gap-2 items-center text-xl">
|
||||
<i class={relay.url.startsWith('wss') ? "fa fa-lock" : "fa fa-unlock"} />
|
||||
<span>{last(relay.url.split('://'))}</span>
|
||||
{#if joined}
|
||||
<span
|
||||
on:mouseout={() => {showStatus = false}}
|
||||
on:mouseover={() => {showStatus = true}}
|
||||
class="w-2 h-2 rounded-full bg-medium cursor-pointer"
|
||||
class:bg-danger={['pending', 'error'].includes(status)}
|
||||
class:bg-warning={status === 'slow'}
|
||||
class:bg-success={status === 'ready'}>
|
||||
class:bg-danger={quality <= 0.3}
|
||||
class:bg-warning={between(0.3, 0.7, quality)}
|
||||
class:bg-success={quality > 0.7}>
|
||||
</span>
|
||||
<p
|
||||
class="text-light text-sm transition-all hidden sm:block"
|
||||
class:opacity-0={!showStatus}
|
||||
class:opacity-1={showStatus}>
|
||||
{switcher(status, {
|
||||
error: 'Not connected',
|
||||
pending: 'Trying to connect',
|
||||
slow: 'Slow connection',
|
||||
ready: 'Connected',
|
||||
default: 'Waiting to reconnect',
|
||||
})}
|
||||
{message}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
{#if joined}
|
||||
<button class="flex gap-3 items-center text-light" on:click={() => removeRelay(relay.url)}>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {flatten, reverse} from 'ramda'
|
||||
import {flatten} from 'ramda'
|
||||
import {fly} from 'svelte/transition'
|
||||
import {logs} from 'src/util/logger.js'
|
||||
import {formatTimestamp} from 'src/util/misc'
|
||||
@ -7,7 +7,7 @@
|
||||
</script>
|
||||
|
||||
<Content>
|
||||
{#each reverse(flatten($logs)) as {created_at, message}}
|
||||
{#each flatten($logs) as {created_at, message}}
|
||||
<div in:fly={{y: 20}} class="text-sm flex flex-col gap-2">
|
||||
<div class="text-light underline">{formatTimestamp(created_at/1000)}</div>
|
||||
<pre>{message.map(m => JSON.stringify(m, null, 2)).join(' ')}</pre>
|
||||
|
@ -1,23 +1,20 @@
|
||||
<script>
|
||||
import {pluck, objOf, fromPairs} from 'ramda'
|
||||
import {pluck, objOf} from 'ramda'
|
||||
import {noop, createMap} from 'hurdak/lib/hurdak'
|
||||
import {onMount} from 'svelte'
|
||||
import {get} from 'svelte/store'
|
||||
import {fly} from 'svelte/transition'
|
||||
import {fuzzy, poll} from "src/util/misc"
|
||||
import {fuzzy} from "src/util/misc"
|
||||
import Input from "src/partials/Input.svelte"
|
||||
import Anchor from "src/partials/Anchor.svelte"
|
||||
import Content from "src/partials/Content.svelte"
|
||||
import RelayCard from "src/partials/RelayCard.svelte"
|
||||
import {user} from "src/agent/helpers"
|
||||
import database from 'src/agent/database'
|
||||
import pool from 'src/agent/pool'
|
||||
import {modal, settings} from "src/app"
|
||||
import defaults from "src/agent/defaults"
|
||||
|
||||
let q = ""
|
||||
let search
|
||||
let status = {}
|
||||
let relays = []
|
||||
|
||||
fetch(get(settings).dufflepudUrl + '/relay')
|
||||
@ -32,32 +29,13 @@
|
||||
const knownRelays = database.watch('relays', relays => relays.all())
|
||||
|
||||
$: {
|
||||
const joined = pluck('url', $user?.relays || [])
|
||||
const data = ($knownRelays || []).filter(r => !joined.includes(r.url))
|
||||
relays = $user?.relays || []
|
||||
|
||||
const joined = new Set(pluck('url', relays))
|
||||
const data = ($knownRelays || []).filter(r => !joined.has(r.url))
|
||||
|
||||
search = fuzzy(data, {keys: ["name", "description", "url"]})
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
return poll(1000, async () => {
|
||||
relays = ($user?.relays || [])
|
||||
.map(relay => ({...database.relays.get(relay.url), ...relay}))
|
||||
|
||||
// Attempt to connect so we can show status
|
||||
relays.forEach(relay => pool.connect(relay.url))
|
||||
|
||||
status = fromPairs(
|
||||
pool.getConnections().map(({url, status, stats}) => {
|
||||
// Be more strict here than with alerts
|
||||
if (status === 'ready' && stats.timer / stats.count > 1000) {
|
||||
status = 'slow'
|
||||
}
|
||||
|
||||
return [url, status]
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<Content>
|
||||
|
@ -3,7 +3,7 @@ import {writable} from 'svelte/store'
|
||||
export const logs = writable([])
|
||||
|
||||
const logAndAppend = (level, ...message) => {
|
||||
logs.update($logs => $logs.concat({created_at: Date.now(), message}))
|
||||
logs.update($logs => $logs.concat({created_at: Date.now(), message}).slice(-100))
|
||||
console[level](...message)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user