Skip to content

Commit

Permalink
track subscriptions notices and display them
Browse files Browse the repository at this point in the history
  • Loading branch information
ticruz38 committed Dec 3, 2024
1 parent 5ccb27c commit 220c623
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 69 deletions.
12 changes: 7 additions & 5 deletions src/app/views/PublishesConnections.svelte
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
<script lang="ts">
import {relaysByUrl} from "@welshman/app"
import {addToMapKey, ctx} from "@welshman/lib"
import {throttled} from "@welshman/store"
import {displayRelayUrl} from "@welshman/util"
import {quantify} from "hurdak"
import {onMount} from "svelte"
import {writable, type Writable} from "svelte/store"
import AltColor from "src/partials/AltColor.svelte"
import SelectButton from "src/partials/SelectButton.svelte"
import {ConnectionType} from "src/engine"
Expand All @@ -13,8 +15,8 @@
export let activeTab: string
let selectedOptions: string[] = []
let connectionsStatus: Map<string, Set<string>> = new Map()
const connectionsStatus: Writable<Map<string, Set<string>>> = throttled(1000, writable(new Map()))
const options = [
ConnectionType.Connected,
ConnectionType.Logging,
Expand All @@ -26,7 +28,7 @@
]
$: connections = Array.from(ctx.net.pool.data.keys()).filter(url =>
selectedOptions.length ? selectedOptions.some(s => connectionsStatus.get(s)?.has(url)) : true,
selectedOptions.length ? selectedOptions.some(s => $connectionsStatus.get(s)?.has(url)) : true,
)
onMount(() => {
Expand All @@ -36,7 +38,7 @@
for (const [url, cxn] of ctx.net.pool.data.entries()) {
addToMapKey(newConnectionStatus, getConnectionStatus(cxn), url)
}
connectionsStatus = newConnectionStatus
$connectionsStatus = newConnectionStatus
}, 800)
return () => {
Expand All @@ -47,7 +49,7 @@

<SelectButton {options} bind:value={selectedOptions} multiple class="text-left">
<div class="flex items-center gap-2" slot="item" let:option>
{connectionsStatus.get(option)?.size || 0}
{$connectionsStatus.get(option)?.size || 0}
{option}
</div>
</SelectButton>
Expand Down Expand Up @@ -86,7 +88,7 @@
</div>
</div>
<div class="flex w-full items-center justify-end gap-2 text-sm">
{#each options.filter(o => connectionsStatus.get(o)?.has(url)) as opt}
{#each options.filter(o => $connectionsStatus.get(o)?.has(url)) as opt}
<div class="flex items-center gap-2">
<span>{opt}</span>
<div
Expand Down
117 changes: 55 additions & 62 deletions src/app/views/PublishesNotices.svelte
Original file line number Diff line number Diff line change
@@ -1,34 +1,18 @@
<script lang="ts">
import {formatTimestamp, thunks, type Thunk, type ThunkStatus} from "@welshman/app"
import {ctx, identity, uniq} from "@welshman/lib"
import {PublishStatus, ConnectionEvent, type Connection} from "@welshman/net"
import cx from "classnames"
import {PublishStatus, type Connection} from "@welshman/net"
import {get} from "svelte/store"
import {fly} from "svelte/transition"
import SearchSelect from "src/partials/SearchSelect.svelte"
import AltColor from "src/partials/AltColor.svelte"
import {fuzzy} from "src/util/misc"
import {router} from "src/app/util"
import {now} from "@welshman/signer"
import {onDestroy} from "svelte"
import {subscriptionNotices, type SubscriptionNotice} from "src/engine"
export let selected: string[] = []
type SubNotice = {received_at: number; notice: string}
const subNotices: SubNotice[] = []
const noticeListener = (notice: string) => {
subNotices.push({received_at: now(), notice})
}
$: selected
.map(url => ctx.net.pool.data.get(url))
.filter(Boolean)
.forEach(cxn => {
cxn.off(ConnectionEvent.Notice, noticeListener)
cxn.on(ConnectionEvent.Notice, noticeListener)
})
$: subNotices = selected.flatMap(s => $subscriptionNotices.get(s)?.map(n => ({...n, url: s})))
const searchConnections = fuzzy(Array.from(ctx.net.pool.data.keys()))
Expand All @@ -52,25 +36,31 @@
return {message: status.message || "Aborted", color: "text-accent"}
}
}
// for subscription notices
function colorFromVerb(verb: string) {
switch (verb) {
case "OK":
return "text-success"
case "EOSE":
return "text-neutral-100"
case "NOTICE":
return "text-accent"
case "CLOSED":
return "text-danger"
case "NEG-MSG":
return "text-accent"
}
}
$: pubNotices = getPubNotices(
selected.map(url => ctx.net.pool.data.get(url)).filter(Boolean),
) as Thunk[]
$: notices = ([...pubNotices, ...subNotices] as (Thunk & SubNotice)[]).sort((a, b) => {
const aDate = a?.event ? a?.event.created_at : a?.received_at
const bDate = b?.event ? b?.event.created_at : b?.received_at
return bDate - aDate
})
onDestroy(() => {
selected
.map(url => ctx.net.pool.data.get(url))
.filter(Boolean)
.forEach(cxn => {
cxn.off(ConnectionEvent.Notice, noticeListener)
})
})
$: notices = ([...pubNotices, ...subNotices] as (Thunk & (SubscriptionNotice & {url: string}))[])
.sort((a, b) => {
return a.created_at - b.created_at
})
.filter(Boolean)
</script>

<SearchSelect
Expand All @@ -84,43 +74,46 @@
</div>
</SearchSelect>

{#if !notices.length && selected.length}
{#if !selected.length}
<div transition:fly|local={{y: 20}}>
<AltColor background class="rounded-md p-6 shadow">
<div class="place text-center text-neutral-100">No relay selected.</div>
</AltColor>
</div>
{:else if !notices.length && selected.length}
<div transition:fly|local={{y: 20}}>
<AltColor background class="rounded-md p-6 shadow">
<div class="place text-center text-neutral-100">No notices found for selected relays.</div>
</AltColor>
</div>
{:else}
{#each notices as notice}
{#if notice.event}
<AltColor
background
class="rounded-md p-6 shadow"
on:click={() => router.at("notes").of(notice.event.id).open()}>
<div class="flex items-center gap-2">
<span class="text-neutral-400">{formatTimestamp(notice.event.created_at)}</span>
<span>[Kind {notice.event.kind}]</span>
{#each uniq(Object.entries(get(notice.status)).filter( ([k, v]) => selected.includes(k), )) as [url, status]}
<AltColor background class="rounded-md p-2">
{#each notices as notice (JSON.stringify(notice))}
<div>
{#if notice.event}
{#each uniq(Object.entries(get(notice.status)).filter( ([k, v]) => selected.includes(k), )) as [url, status] (url)}
{@const {message, color} = messageAndColorFromStatus(get(notice.status)[url])}
<div class="flex items-center justify-between gap-2">
to <strong>{url}:</strong>
<div class={cx(color, "flex items-center gap-1")}>
<span class="">{message}</span>
</div>
<div
class="flex gap-2 p-2"
on:click={() => router.at("notes").of(notice.event.id).open()}>
<span class="shrink-0 text-neutral-400"
>{formatTimestamp(notice.event.created_at)}</span>
<strong class={color}>to {url}:</strong>
<span class="shrink-0">[Kind {notice.event.kind}]</span>
<span class="">{message}</span>
</div>
{/each}
</div>
</AltColor>
{:else}
<AltColor background class="rounded-md p-6 shadow">
<div class="flex items-center gap-2">
<span class="text-neutral-400">{formatTimestamp(notice.received_at)}</span>
<span>[Notice]</span>
<div class="flex items-center gap-1">
<span class="text-neutral-100">{notice.notice}</span>
{:else}
<div class="flex flex-wrap items-center gap-2 overflow-hidden p-2">
<span class="shrink-0 text-neutral-400">{formatTimestamp(notice.created_at)}</span>
<strong class={colorFromVerb(notice.notice[0])}>from {notice.url}</strong>
<span class="shrink-0">[{notice.notice[0]}]</span>
{#each notice.notice.slice(1).filter(n => typeof n == "string") as item}
<span class="text-neutral-300">{item}</span>
{/each}
</div>
</div>
</AltColor>
{/if}
{/each}
{/if}
</div>
{/each}
</AltColor>
{/if}
27 changes: 25 additions & 2 deletions src/engine/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,16 @@ import {
uniq,
uniqBy,
} from "@welshman/lib"
import type {PublishRequest, Target} from "@welshman/net"
import {Executor, AuthMode, Local, Multi, Relays, SubscriptionEvent} from "@welshman/net"
import type {Connection, PublishRequest, Target} from "@welshman/net"
import {
Executor,
AuthMode,
Local,
Multi,
Relays,
SubscriptionEvent,
ConnectionEvent,
} from "@welshman/net"
import {Nip01Signer, Nip59} from "@welshman/signer"
import {deriveEvents, deriveEventsMapped, throttled, withGetter} from "@welshman/store"
import type {EventTemplate, PublishedList, SignedEvent, TrustedEvent} from "@welshman/util"
Expand Down Expand Up @@ -1023,6 +1031,10 @@ const migrateEvents = (events: TrustedEvent[]) => {
)
}

export type SubscriptionNotice = {created_at: number; notice: string[]}

export const subscriptionNotices = writable<Map<string, SubscriptionNotice[]>>(new Map())

// Avoid initializing multiple times on hot reload
if (!db) {
const initialRelays = [
Expand Down Expand Up @@ -1052,6 +1064,17 @@ if (!db) {
ctx.app.dufflepudUrl = getSetting("dufflepud_url")
})

ctx.net.pool.on("init", (connection: Connection) => {
// if (!connection.url.includes("snort")) return
connection.on(ConnectionEvent.Receive, function (cxn, [verb, ...args]) {
if (verb == "EVENT") return
subscriptionNotices.update($notices => {
pushToMapKey($notices, connection.url, {created_at: now(), notice: [verb, ...args]})
return $notices
})
})
})

ready = initStorage("coracle", 2, {
relays: {keyPath: "url", store: throttled(1000, relays)},
handles: {keyPath: "nip05", store: throttled(1000, handles)},
Expand Down

0 comments on commit 220c623

Please sign in to comment.