5 changed files with 478 additions and 27 deletions
@ -0,0 +1,162 @@
@@ -0,0 +1,162 @@
|
||||
<script lang="ts"> |
||||
import { Button, Alert } from 'flowbite-svelte'; |
||||
import { ndkInstance, ndkSignedIn, testRelayConnection, checkWebSocketSupport, checkEnvironmentForWebSocketDowngrade } from '$lib/ndk'; |
||||
import { standardRelays, anonymousRelays } from '$lib/consts'; |
||||
import { onMount } from 'svelte'; |
||||
import { feedType } from '$lib/stores'; |
||||
import { inboxRelays, outboxRelays } from '$lib/ndk'; |
||||
import { FeedType } from '$lib/consts'; |
||||
|
||||
interface RelayStatus { |
||||
url: string; |
||||
connected: boolean; |
||||
requiresAuth: boolean; |
||||
error?: string; |
||||
testing: boolean; |
||||
} |
||||
|
||||
let relayStatuses = $state<RelayStatus[]>([]); |
||||
let testing = $state(false); |
||||
|
||||
async function runRelayTests() { |
||||
testing = true; |
||||
const ndk = $ndkInstance; |
||||
if (!ndk) { |
||||
testing = false; |
||||
return; |
||||
} |
||||
|
||||
let relaysToTest: string[] = []; |
||||
|
||||
if ($feedType === FeedType.UserRelays && $ndkSignedIn) { |
||||
// Use user's relays (inbox + outbox), deduplicated |
||||
const userRelays = new Set([ |
||||
...$inboxRelays, |
||||
...$outboxRelays |
||||
]); |
||||
relaysToTest = Array.from(userRelays); |
||||
} else { |
||||
// Use default relays (standard + anonymous), deduplicated |
||||
relaysToTest = Array.from(new Set([ |
||||
...standardRelays, |
||||
...anonymousRelays |
||||
])); |
||||
} |
||||
|
||||
console.log('[RelayStatus] Relays to test:', relaysToTest); |
||||
|
||||
relayStatuses = relaysToTest.map(url => ({ |
||||
url, |
||||
connected: false, |
||||
requiresAuth: false, |
||||
testing: true |
||||
})); |
||||
|
||||
const results = await Promise.allSettled( |
||||
relaysToTest.map(async (url) => { |
||||
console.log('[RelayStatus] Testing relay:', url); |
||||
try { |
||||
return await testRelayConnection(url, ndk); |
||||
} catch (error) { |
||||
return { |
||||
connected: false, |
||||
requiresAuth: false, |
||||
error: error instanceof Error ? error.message : 'Unknown error' |
||||
}; |
||||
} |
||||
}) |
||||
); |
||||
|
||||
relayStatuses = relayStatuses.map((status, index) => { |
||||
const result = results[index]; |
||||
if (result.status === 'fulfilled') { |
||||
return { |
||||
...status, |
||||
...result.value, |
||||
testing: false |
||||
}; |
||||
} else { |
||||
return { |
||||
...status, |
||||
connected: false, |
||||
requiresAuth: false, |
||||
error: 'Test failed', |
||||
testing: false |
||||
}; |
||||
} |
||||
}); |
||||
|
||||
testing = false; |
||||
} |
||||
|
||||
$effect(() => { |
||||
// Re-run relay tests when feed type, login state, or relay lists change |
||||
void runRelayTests(); |
||||
}); |
||||
|
||||
onMount(() => { |
||||
checkWebSocketSupport(); |
||||
checkEnvironmentForWebSocketDowngrade(); |
||||
}); |
||||
|
||||
function getStatusColor(status: RelayStatus): string { |
||||
if (status.testing) return 'text-yellow-600'; |
||||
if (status.connected) return 'text-green-600'; |
||||
if (status.requiresAuth && !$ndkSignedIn) return 'text-orange-600'; |
||||
return 'text-red-600'; |
||||
} |
||||
|
||||
function getStatusText(status: RelayStatus): string { |
||||
if (status.testing) return 'Testing...'; |
||||
if (status.connected) return 'Connected'; |
||||
if (status.requiresAuth && !$ndkSignedIn) return 'Requires Authentication'; |
||||
if (status.error) return `Error: ${status.error}`; |
||||
return 'Failed to Connect'; |
||||
} |
||||
</script> |
||||
|
||||
<div class="space-y-4"> |
||||
<div class="flex items-center justify-between"> |
||||
<h3 class="text-lg font-medium">Relay Connection Status</h3> |
||||
<Button |
||||
size="sm" |
||||
onclick={runRelayTests} |
||||
disabled={testing} |
||||
> |
||||
{testing ? 'Testing...' : 'Refresh'} |
||||
</Button> |
||||
</div> |
||||
|
||||
{#if !$ndkSignedIn} |
||||
<Alert color="yellow"> |
||||
<span class="font-medium">Anonymous Mode</span> |
||||
<p class="mt-1 text-sm"> |
||||
You are not signed in. Some relays require authentication and may not be accessible. |
||||
Sign in to access all relays. |
||||
</p> |
||||
</Alert> |
||||
{/if} |
||||
|
||||
<div class="space-y-2"> |
||||
{#each relayStatuses as status} |
||||
<div class="flex items-center justify-between p-3 border rounded-lg"> |
||||
<div class="flex-1"> |
||||
<div class="font-medium">{status.url}</div> |
||||
<div class="text-sm {getStatusColor(status)}"> |
||||
{getStatusText(status)} |
||||
</div> |
||||
</div> |
||||
<div class="w-3 h-3 rounded-full {getStatusColor(status).replace('text-', 'bg-')}"></div> |
||||
</div> |
||||
{/each} |
||||
</div> |
||||
|
||||
{#if relayStatuses.some(s => s.requiresAuth && !$ndkSignedIn)} |
||||
<Alert color="orange"> |
||||
<span class="font-medium">Authentication Required</span> |
||||
<p class="mt-1 text-sm"> |
||||
Some relays require authentication. Sign in to access these relays. |
||||
</p> |
||||
</Alert> |
||||
{/if} |
||||
</div> |
||||
Loading…
Reference in new issue