2025-03-09 11:15:28 -04:00
|
|
|
// lib/db/services/RelayService.ts
|
|
|
|
import { SQLiteDatabase } from 'expo-sqlite';
|
|
|
|
import { NDKCommon, NDKRelayCommon, safeAddRelay, safeRemoveRelay } from '@/types/ndk-common';
|
|
|
|
|
|
|
|
// Status constants to match NDK implementations
|
|
|
|
const NDK_RELAY_STATUS = {
|
|
|
|
CONNECTING: 0,
|
|
|
|
CONNECTED: 1,
|
|
|
|
DISCONNECTING: 2,
|
|
|
|
DISCONNECTED: 3,
|
|
|
|
RECONNECTING: 4,
|
|
|
|
AUTH_REQUIRED: 5
|
|
|
|
};
|
|
|
|
|
|
|
|
// Default relays to use when none are configured
|
|
|
|
export const DEFAULT_RELAYS = [
|
|
|
|
'wss://relay.damus.io',
|
|
|
|
'wss://relay.nostr.band',
|
|
|
|
'wss://nos.lol',
|
|
|
|
'wss://relay.snort.social',
|
|
|
|
'wss://relay.current.fyi'
|
|
|
|
];
|
|
|
|
|
|
|
|
export interface RelayConfig {
|
|
|
|
url: string;
|
|
|
|
read: boolean;
|
|
|
|
write: boolean;
|
|
|
|
priority?: number;
|
|
|
|
created_at: number;
|
|
|
|
updated_at: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface RelayWithStatus extends RelayConfig {
|
|
|
|
status: 'connected' | 'connecting' | 'disconnected' | 'error';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Service for managing Nostr relays
|
|
|
|
*/
|
|
|
|
export class RelayService {
|
|
|
|
private db: SQLiteDatabase;
|
|
|
|
private ndk: NDKCommon | null = null;
|
2025-03-09 12:48:24 -04:00
|
|
|
private debug: boolean = false;
|
2025-03-09 11:15:28 -04:00
|
|
|
|
|
|
|
constructor(db: SQLiteDatabase) {
|
|
|
|
this.db = db;
|
|
|
|
}
|
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
enableDebug() {
|
|
|
|
this.debug = true;
|
|
|
|
console.log('[RelayService] Debug mode enabled');
|
|
|
|
}
|
|
|
|
|
|
|
|
private logDebug(message: string, ...args: any[]) {
|
|
|
|
if (this.debug) {
|
|
|
|
console.log(`[RelayService Debug] ${message}`, ...args);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-09 11:15:28 -04:00
|
|
|
/**
|
|
|
|
* Set NDK instance for relay operations
|
|
|
|
*/
|
|
|
|
setNDK(ndk: NDKCommon) {
|
|
|
|
this.ndk = ndk;
|
|
|
|
console.log('[RelayService] NDK instance set');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all relays from database
|
|
|
|
*/
|
|
|
|
async getAllRelays(): Promise<RelayConfig[]> {
|
|
|
|
try {
|
|
|
|
const relays = await this.db.getAllAsync<RelayConfig>(
|
|
|
|
'SELECT url, read, write, priority, created_at, updated_at FROM relays ORDER BY priority DESC, created_at DESC'
|
|
|
|
);
|
|
|
|
|
|
|
|
console.log(`[RelayService] Found ${relays.length} relays in database`);
|
|
|
|
|
|
|
|
return relays.map(relay => ({
|
|
|
|
...relay,
|
|
|
|
read: Boolean(relay.read),
|
|
|
|
write: Boolean(relay.write)
|
|
|
|
}));
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error getting relays:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get all relays with their current connection status
|
|
|
|
*/
|
|
|
|
async getAllRelaysWithStatus(): Promise<RelayWithStatus[]> {
|
|
|
|
try {
|
|
|
|
const relays = await this.getAllRelays();
|
|
|
|
|
|
|
|
if (!this.ndk) {
|
|
|
|
console.warn('[RelayService] NDK not initialized, returning relays with disconnected status');
|
|
|
|
return relays.map(relay => ({
|
|
|
|
...relay,
|
|
|
|
status: 'disconnected'
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
// Log the relays in the NDK pool for debugging
|
|
|
|
console.log('[RelayService] Checking status for relays. Current NDK pool:');
|
|
|
|
this.ndk.pool.relays.forEach((ndkRelay, url) => {
|
|
|
|
console.log(` - ${url}: status=${ndkRelay.status}`);
|
|
|
|
});
|
|
|
|
|
2025-03-09 11:15:28 -04:00
|
|
|
return relays.map(relay => {
|
2025-03-09 12:48:24 -04:00
|
|
|
const status = this.getRelayStatus(relay);
|
|
|
|
console.log(`[RelayService] Status for relay ${relay.url}: ${status}`);
|
2025-03-09 11:15:28 -04:00
|
|
|
|
|
|
|
return {
|
|
|
|
...relay,
|
|
|
|
status
|
|
|
|
};
|
|
|
|
});
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error getting relays with status:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
private normalizeRelayUrl(url: string): string {
|
|
|
|
// Remove trailing slash if present
|
|
|
|
return url.replace(/\/$/, '');
|
|
|
|
}
|
|
|
|
|
2025-03-09 11:15:28 -04:00
|
|
|
/**
|
|
|
|
* Add a new relay to the database
|
|
|
|
*/
|
|
|
|
async addRelay(url: string, read = true, write = true, priority?: number): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
// Normalize the URL
|
2025-03-09 12:48:24 -04:00
|
|
|
url = this.normalizeRelayUrl(url.trim());
|
2025-03-09 11:15:28 -04:00
|
|
|
|
|
|
|
// Validate URL format
|
|
|
|
if (!url.startsWith('wss://')) {
|
|
|
|
throw new Error('Relay URL must start with wss://');
|
|
|
|
}
|
|
|
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
|
|
// Check if relay already exists
|
|
|
|
const existingRelay = await this.db.getFirstAsync<{ url: string }>(
|
|
|
|
'SELECT url FROM relays WHERE url = ?',
|
|
|
|
[url]
|
|
|
|
);
|
|
|
|
|
|
|
|
if (existingRelay) {
|
|
|
|
console.log(`[RelayService] Relay ${url} already exists, updating instead`);
|
|
|
|
return this.updateRelay(url, { read, write, priority });
|
|
|
|
}
|
|
|
|
|
|
|
|
// If no priority specified, make it higher than the current highest
|
|
|
|
if (priority === undefined) {
|
|
|
|
const highestPriority = await this.db.getFirstAsync<{ priority: number }>(
|
|
|
|
'SELECT MAX(priority) as priority FROM relays'
|
|
|
|
);
|
|
|
|
|
|
|
|
priority = ((highestPriority?.priority || 0) + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[RelayService] Adding relay ${url} with read=${read}, write=${write}, priority=${priority}`);
|
|
|
|
|
|
|
|
// Add the relay
|
|
|
|
await this.db.runAsync(
|
|
|
|
'INSERT INTO relays (url, read, write, priority, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
|
|
|
|
[url, read ? 1 : 0, write ? 1 : 0, priority, now, now]
|
|
|
|
);
|
|
|
|
|
|
|
|
console.log(`[RelayService] Successfully added relay ${url}`);
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error adding relay:', error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Update an existing relay
|
|
|
|
*/
|
|
|
|
async updateRelay(url: string, changes: Partial<RelayConfig>): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
|
|
// Check if relay exists
|
|
|
|
const existingRelay = await this.db.getFirstAsync<{ url: string }>(
|
|
|
|
'SELECT url FROM relays WHERE url = ?',
|
|
|
|
[url]
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!existingRelay) {
|
|
|
|
console.log(`[RelayService] Relay ${url} does not exist, adding instead`);
|
|
|
|
const read = changes.read !== undefined ? changes.read : true;
|
|
|
|
const write = changes.write !== undefined ? changes.write : true;
|
|
|
|
return this.addRelay(url, read, write, changes.priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Prepare update fields
|
|
|
|
const updates: string[] = [];
|
|
|
|
const params: any[] = [];
|
|
|
|
|
|
|
|
if (changes.read !== undefined) {
|
|
|
|
updates.push('read = ?');
|
|
|
|
params.push(changes.read ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changes.write !== undefined) {
|
|
|
|
updates.push('write = ?');
|
|
|
|
params.push(changes.write ? 1 : 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changes.priority !== undefined) {
|
|
|
|
updates.push('priority = ?');
|
|
|
|
params.push(changes.priority);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always update the updated_at timestamp
|
|
|
|
updates.push('updated_at = ?');
|
|
|
|
params.push(now);
|
|
|
|
|
|
|
|
// Add the URL to the parameters
|
|
|
|
params.push(url);
|
|
|
|
|
|
|
|
console.log(`[RelayService] Updating relay ${url} with changes:`,
|
|
|
|
Object.entries(changes)
|
|
|
|
.filter(([key]) => ['read', 'write', 'priority'].includes(key))
|
|
|
|
.map(([key, value]) => `${key}=${value}`)
|
|
|
|
.join(', ')
|
|
|
|
);
|
|
|
|
|
|
|
|
// Execute update
|
|
|
|
if (updates.length > 0) {
|
|
|
|
await this.db.runAsync(
|
|
|
|
`UPDATE relays SET ${updates.join(', ')} WHERE url = ?`,
|
|
|
|
params
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[RelayService] Successfully updated relay ${url}`);
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error updating relay:', error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Remove a relay from the database
|
|
|
|
*/
|
|
|
|
async removeRelay(url: string): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
console.log(`[RelayService] Removing relay ${url}`);
|
|
|
|
await this.db.runAsync('DELETE FROM relays WHERE url = ?', [url]);
|
|
|
|
console.log(`[RelayService] Successfully removed relay ${url}`);
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error removing relay:', error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get relays that are enabled for reading, writing, or both
|
|
|
|
*/
|
|
|
|
async getEnabledRelays(): Promise<string[]> {
|
|
|
|
try {
|
|
|
|
const relays = await this.db.getAllAsync<{ url: string }>(
|
|
|
|
'SELECT url FROM relays WHERE read = 1 OR write = 1 ORDER BY priority DESC, created_at DESC'
|
|
|
|
);
|
|
|
|
|
|
|
|
console.log(`[RelayService] Found ${relays.length} enabled relays`);
|
|
|
|
return relays.map(relay => relay.url);
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error getting enabled relays:', error);
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Apply relay configuration to NDK
|
|
|
|
* This implementation uses the safeAddRelay and safeRemoveRelay utilities
|
|
|
|
*/
|
|
|
|
async applyRelayConfig(ndk?: NDKCommon): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
// Use provided NDK or the stored one
|
|
|
|
const ndkInstance = ndk || this.ndk;
|
|
|
|
|
|
|
|
if (!ndkInstance) {
|
|
|
|
throw new Error('NDK not initialized');
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get all relay configurations
|
|
|
|
const relayConfigs = await this.getAllRelays();
|
|
|
|
|
|
|
|
if (relayConfigs.length === 0) {
|
|
|
|
console.warn('[RelayService] No relays found, using defaults');
|
|
|
|
await this.resetToDefaults();
|
|
|
|
return this.applyRelayConfig(ndkInstance); // Recursive call after reset
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[RelayService] Applying configuration for ${relayConfigs.length} relays`);
|
|
|
|
|
|
|
|
// Get the current relay URLs
|
|
|
|
const currentRelayUrls: string[] = [];
|
|
|
|
try {
|
|
|
|
ndkInstance.pool.relays.forEach((_, url) => currentRelayUrls.push(url));
|
|
|
|
console.log(`[RelayService] NDK currently has ${currentRelayUrls.length} relays`);
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error getting current relay URLs:', error);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disconnect from relays that are not in the config or have changed permissions
|
|
|
|
for (const url of currentRelayUrls) {
|
|
|
|
// Get config for this URL if it exists
|
|
|
|
const config = relayConfigs.find(r => r.url === url);
|
|
|
|
|
|
|
|
// If the relay doesn't exist in our config or the read/write status changed,
|
|
|
|
// we should remove it and possibly add it back with new settings
|
|
|
|
if (!config || (!config.read && !config.write)) {
|
|
|
|
console.log(`[RelayService] Removing relay ${url} from NDK pool`);
|
|
|
|
safeRemoveRelay(ndkInstance, url);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add or reconfigure relays
|
|
|
|
for (const relay of relayConfigs) {
|
|
|
|
if (relay.read || relay.write) {
|
|
|
|
try {
|
|
|
|
let ndkRelay = ndkInstance.pool.getRelay(relay.url);
|
|
|
|
|
|
|
|
if (ndkRelay) {
|
|
|
|
// Update relay's read/write config if needed
|
|
|
|
try {
|
|
|
|
const needsUpdate = (ndkRelay.read !== relay.read) ||
|
|
|
|
(ndkRelay.write !== relay.write);
|
|
|
|
|
|
|
|
if (needsUpdate) {
|
|
|
|
console.log(`[RelayService] Updating relay ${relay.url} settings: read=${relay.read}, write=${relay.write}`);
|
|
|
|
// Set properties directly
|
|
|
|
ndkRelay.read = relay.read;
|
|
|
|
ndkRelay.write = relay.write;
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
// If we can't set properties directly, remove and re-add the relay
|
|
|
|
console.log(`[RelayService] Recreating relay ${relay.url} due to error:`, error);
|
|
|
|
safeRemoveRelay(ndkInstance, relay.url);
|
|
|
|
ndkRelay = safeAddRelay(ndkInstance, relay.url, {
|
|
|
|
read: relay.read,
|
|
|
|
write: relay.write
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Add new relay
|
|
|
|
console.log(`[RelayService] Adding new relay ${relay.url} to NDK pool`);
|
|
|
|
ndkRelay = safeAddRelay(ndkInstance, relay.url, {
|
|
|
|
read: relay.read,
|
|
|
|
write: relay.write
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// Connect the relay if it was added successfully
|
|
|
|
if (ndkRelay && typeof ndkRelay.connect === 'function') {
|
|
|
|
console.log(`[RelayService] Connecting to relay ${relay.url}`);
|
|
|
|
ndkRelay.connect().catch((error: any) => {
|
|
|
|
console.error(`[RelayService] Error connecting to relay ${relay.url}:`, error);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (innerError) {
|
|
|
|
console.error(`[RelayService] Error adding/updating relay ${relay.url}:`, innerError);
|
|
|
|
// Continue with other relays even if one fails
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log('[RelayService] Successfully applied relay configuration');
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error applying relay configuration:', error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Import relays from user metadata (kind:3 events)
|
|
|
|
*/
|
|
|
|
async importFromUserMetadata(pubkey: string, ndk: any): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
if (!ndk) {
|
|
|
|
throw new Error('NDK not initialized');
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[RelayService] Importing relays from metadata for user ${pubkey.slice(0, 8)}...`);
|
|
|
|
|
|
|
|
// Fetch kind:3 event for user's relay list
|
|
|
|
const filter = { kinds: [3], authors: [pubkey] };
|
|
|
|
const events = await ndk.fetchEvents(filter);
|
|
|
|
|
|
|
|
if (!events || events.size === 0) {
|
|
|
|
console.log('[RelayService] No relay list found in user metadata');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find the most recent event
|
|
|
|
let latestEvent: any = null;
|
|
|
|
let latestCreatedAt = 0;
|
|
|
|
|
|
|
|
for (const event of events) {
|
|
|
|
if (event.created_at && event.created_at > latestCreatedAt) {
|
|
|
|
latestEvent = event;
|
|
|
|
latestCreatedAt = event.created_at;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!latestEvent) {
|
|
|
|
console.log('[RelayService] No valid relay list found in user metadata');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[RelayService] Found relay list in event created at ${new Date(latestCreatedAt * 1000).toISOString()}`);
|
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
// Safely log event details without circular references
|
|
|
|
try {
|
|
|
|
console.log('[RelayService] Event ID:', latestEvent.id);
|
|
|
|
console.log('[RelayService] Event Kind:', latestEvent.kind);
|
|
|
|
console.log('[RelayService] Event Created At:', latestEvent.created_at);
|
|
|
|
console.log('[RelayService] Event Tags Count:', latestEvent.tags ? latestEvent.tags.length : 0);
|
|
|
|
|
|
|
|
// Safely log the tags
|
|
|
|
if (latestEvent.tags && Array.isArray(latestEvent.tags)) {
|
|
|
|
console.log('[RelayService] Tags:');
|
|
|
|
latestEvent.tags.forEach((tag: any[], index: number) => {
|
|
|
|
console.log(` Tag ${index}:`, JSON.stringify(tag));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.log('[RelayService] Error logging event details:', error);
|
|
|
|
}
|
|
|
|
|
2025-03-09 11:15:28 -04:00
|
|
|
// Get highest current priority
|
|
|
|
const highestPriority = await this.db.getFirstAsync<{ priority: number }>(
|
|
|
|
'SELECT MAX(priority) as priority FROM relays'
|
|
|
|
);
|
|
|
|
|
|
|
|
let maxPriority = (highestPriority?.priority || 0);
|
|
|
|
let importCount = 0;
|
|
|
|
let updatedCount = 0;
|
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
// Check if any relay tags exist
|
|
|
|
let relayTagsFound = false;
|
|
|
|
|
2025-03-09 11:15:28 -04:00
|
|
|
// Process each relay in the event
|
2025-03-09 12:48:24 -04:00
|
|
|
if (latestEvent.tags && Array.isArray(latestEvent.tags)) {
|
|
|
|
for (const tag of latestEvent.tags) {
|
2025-03-09 11:15:28 -04:00
|
|
|
try {
|
2025-03-09 12:48:24 -04:00
|
|
|
console.log(`[RelayService] Processing tag: ${JSON.stringify(tag)}`);
|
|
|
|
|
|
|
|
// More flexible tag detection - handle 'r', 'R', or 'relay' tag types
|
|
|
|
if ((tag[0] === 'r' || tag[0] === 'R' || tag[0] === 'relay') && tag.length > 1 && tag[1]) {
|
|
|
|
relayTagsFound = true;
|
|
|
|
console.log(`[RelayService] Found relay tag: ${tag[1]}`);
|
|
|
|
|
|
|
|
const url = tag[1];
|
|
|
|
|
|
|
|
// Ensure URL is properly formatted
|
|
|
|
if (!url.startsWith('wss://') && !url.startsWith('ws://')) {
|
|
|
|
console.log(`[RelayService] Skipping invalid relay URL: ${url}`);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for read/write specification in the tag
|
|
|
|
let read = true;
|
|
|
|
let write = true;
|
|
|
|
|
|
|
|
if (tag.length > 2) {
|
|
|
|
// Handle various common formatting patterns
|
|
|
|
const readWriteSpec = tag[2]?.toLowerCase();
|
|
|
|
if (readWriteSpec === 'write') {
|
|
|
|
read = false;
|
|
|
|
write = true;
|
|
|
|
console.log(`[RelayService] Relay ${url} configured as write-only`);
|
|
|
|
} else if (readWriteSpec === 'read') {
|
|
|
|
read = true;
|
|
|
|
write = false;
|
|
|
|
console.log(`[RelayService] Relay ${url} configured as read-only`);
|
|
|
|
} else {
|
|
|
|
console.log(`[RelayService] Unrecognized read/write spec: ${readWriteSpec}, using default (read+write)`);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Check if the relay already exists
|
|
|
|
const existingRelay = await this.db.getFirstAsync<{ url: string }>(
|
|
|
|
'SELECT url FROM relays WHERE url = ?',
|
|
|
|
[url]
|
|
|
|
);
|
|
|
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
|
|
if (existingRelay) {
|
|
|
|
// Update existing relay
|
|
|
|
await this.db.runAsync(
|
|
|
|
'UPDATE relays SET read = ?, write = ?, updated_at = ? WHERE url = ?',
|
|
|
|
[read ? 1 : 0, write ? 1 : 0, now, url]
|
|
|
|
);
|
|
|
|
updatedCount++;
|
|
|
|
console.log(`[RelayService] Updated existing relay: ${url} (read=${read}, write=${write})`);
|
|
|
|
} else {
|
|
|
|
// Add new relay with incremented priority
|
|
|
|
maxPriority++;
|
|
|
|
await this.db.runAsync(
|
|
|
|
'INSERT INTO relays (url, read, write, priority, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
|
|
|
|
[url, read ? 1 : 0, write ? 1 : 0, maxPriority, now, now]
|
|
|
|
);
|
|
|
|
importCount++;
|
|
|
|
console.log(`[RelayService] Added new relay: ${url} (read=${read}, write=${write}, priority=${maxPriority})`);
|
|
|
|
}
|
|
|
|
} catch (innerError) {
|
|
|
|
console.error(`[RelayService] Error importing relay ${url}:`, innerError);
|
|
|
|
// Continue with other relays
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (tagError) {
|
|
|
|
console.log('[RelayService] Error processing tag:', tagError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for relays in content (some clients store them there)
|
|
|
|
if (!relayTagsFound) {
|
|
|
|
console.log('[RelayService] No relay tags found in event tags, checking content...');
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Only try to parse the content if it's a string
|
|
|
|
if (typeof latestEvent.content === 'string') {
|
|
|
|
const contentObj = JSON.parse(latestEvent.content);
|
2025-03-09 11:15:28 -04:00
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
// Only log specific properties to avoid circular references
|
|
|
|
console.log('[RelayService] Content has relays property:', contentObj.hasOwnProperty('relays'));
|
2025-03-09 11:15:28 -04:00
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
// Some clients store relays in content as an object
|
|
|
|
if (contentObj.relays && typeof contentObj.relays === 'object') {
|
|
|
|
console.log('[RelayService] Found relay URLs in content:', Object.keys(contentObj.relays));
|
|
|
|
|
|
|
|
// Process relays from content object
|
|
|
|
for (const [url, permissions] of Object.entries(contentObj.relays)) {
|
|
|
|
try {
|
|
|
|
if (typeof url === 'string' && (url.startsWith('wss://') || url.startsWith('ws://'))) {
|
|
|
|
relayTagsFound = true;
|
|
|
|
|
|
|
|
let read = true;
|
|
|
|
let write = true;
|
|
|
|
|
|
|
|
// Handle different formats of permissions
|
|
|
|
if (typeof permissions === 'object' && permissions !== null) {
|
|
|
|
// Format: { "wss://relay.example.com": { "read": true, "write": false } }
|
|
|
|
if ('read' in permissions) read = Boolean((permissions as any).read);
|
|
|
|
if ('write' in permissions) write = Boolean((permissions as any).write);
|
|
|
|
} else if (typeof permissions === 'string') {
|
|
|
|
// Format: { "wss://relay.example.com": "read" }
|
|
|
|
read = (permissions as string).includes('read');
|
|
|
|
write = (permissions as string).includes('write');
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[RelayService] Found relay in content: ${url} (read=${read}, write=${write})`);
|
|
|
|
|
|
|
|
// Then add or update the relay just like above...
|
|
|
|
try {
|
|
|
|
const existingRelay = await this.db.getFirstAsync<{ url: string }>(
|
|
|
|
'SELECT url FROM relays WHERE url = ?',
|
|
|
|
[url]
|
|
|
|
);
|
|
|
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
|
|
if (existingRelay) {
|
|
|
|
await this.db.runAsync(
|
|
|
|
'UPDATE relays SET read = ?, write = ?, updated_at = ? WHERE url = ?',
|
|
|
|
[read ? 1 : 0, write ? 1 : 0, now, url]
|
|
|
|
);
|
|
|
|
updatedCount++;
|
|
|
|
console.log(`[RelayService] Updated existing relay from content: ${url} (read=${read}, write=${write})`);
|
|
|
|
} else {
|
|
|
|
maxPriority++;
|
|
|
|
await this.db.runAsync(
|
|
|
|
'INSERT INTO relays (url, read, write, priority, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
|
|
|
|
[url, read ? 1 : 0, write ? 1 : 0, maxPriority, now, now]
|
|
|
|
);
|
|
|
|
importCount++;
|
|
|
|
console.log(`[RelayService] Added new relay from content: ${url} (read=${read}, write=${write}, priority=${maxPriority})`);
|
|
|
|
}
|
|
|
|
} catch (innerError) {
|
|
|
|
console.error(`[RelayService] Error importing relay ${url} from content:`, innerError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (relayError) {
|
|
|
|
console.log('[RelayService] Error processing relay from content:', relayError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
console.log('[RelayService] Content is not a string:', typeof latestEvent.content);
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
// Convert the unknown error to a string safely
|
|
|
|
const errorMessage = e instanceof Error ? e.message : String(e);
|
|
|
|
console.log('[RelayService] Content is not JSON or does not contain relay information:', errorMessage);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check the raw event string that might be available
|
|
|
|
if (!relayTagsFound && latestEvent.rawEvent && typeof latestEvent.rawEvent === 'string') {
|
|
|
|
console.log('[RelayService] Checking raw event string for relay information');
|
|
|
|
try {
|
|
|
|
const rawEventObj = JSON.parse(latestEvent.rawEvent);
|
|
|
|
if (rawEventObj.tags && Array.isArray(rawEventObj.tags)) {
|
|
|
|
console.log(`[RelayService] Raw event has ${rawEventObj.tags.length} tags`);
|
|
|
|
|
|
|
|
for (const tag of rawEventObj.tags) {
|
|
|
|
try {
|
|
|
|
if ((tag[0] === 'r' || tag[0] === 'R') && tag.length > 1 && tag[1]) {
|
|
|
|
relayTagsFound = true;
|
|
|
|
const url = tag[1];
|
|
|
|
|
|
|
|
console.log(`[RelayService] Found relay in raw event: ${url}`);
|
|
|
|
|
|
|
|
// Process like above...
|
|
|
|
if (url.startsWith('wss://') || url.startsWith('ws://')) {
|
|
|
|
let read = true;
|
|
|
|
let write = true;
|
|
|
|
|
|
|
|
if (tag.length > 2) {
|
|
|
|
const readWriteSpec = tag[2]?.toLowerCase();
|
|
|
|
if (readWriteSpec === 'write') {
|
|
|
|
read = false;
|
|
|
|
write = true;
|
|
|
|
} else if (readWriteSpec === 'read') {
|
|
|
|
read = true;
|
|
|
|
write = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const existingRelay = await this.db.getFirstAsync<{ url: string }>(
|
|
|
|
'SELECT url FROM relays WHERE url = ?',
|
|
|
|
[url]
|
|
|
|
);
|
|
|
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
|
|
if (existingRelay) {
|
|
|
|
await this.db.runAsync(
|
|
|
|
'UPDATE relays SET read = ?, write = ?, updated_at = ? WHERE url = ?',
|
|
|
|
[read ? 1 : 0, write ? 1 : 0, now, url]
|
|
|
|
);
|
|
|
|
updatedCount++;
|
|
|
|
} else {
|
|
|
|
maxPriority++;
|
|
|
|
await this.db.runAsync(
|
|
|
|
'INSERT INTO relays (url, read, write, priority, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
|
|
|
|
[url, read ? 1 : 0, write ? 1 : 0, maxPriority, now, now]
|
|
|
|
);
|
|
|
|
importCount++;
|
|
|
|
}
|
|
|
|
} catch (innerError) {
|
|
|
|
console.error(`[RelayService] Error importing relay ${url} from raw event:`, innerError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (tagError) {
|
|
|
|
console.log('[RelayService] Error processing tag from raw event:', tagError);
|
|
|
|
}
|
2025-03-09 11:15:28 -04:00
|
|
|
}
|
|
|
|
}
|
2025-03-09 12:48:24 -04:00
|
|
|
} catch (rawError) {
|
|
|
|
// Convert the unknown error to a string safely
|
|
|
|
const errorMessage = rawError instanceof Error ? rawError.message : String(rawError);
|
|
|
|
console.log('[RelayService] Error parsing raw event:', errorMessage);
|
2025-03-09 11:15:28 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
// Try to access user cached relays
|
|
|
|
if (!relayTagsFound && ndk && ndk.pool && ndk.pool.relays) {
|
|
|
|
console.log('[RelayService] Checking for relays in the user NDK pool');
|
|
|
|
|
|
|
|
try {
|
|
|
|
// Try to access the user's connected relays
|
|
|
|
const userRelays = Array.from(ndk.pool.relays.keys());
|
|
|
|
if (userRelays.length > 0) {
|
|
|
|
console.log(`[RelayService] Found ${userRelays.length} relays in user's NDK pool:`, userRelays);
|
|
|
|
|
|
|
|
// Import these relays
|
|
|
|
for (const url of userRelays) {
|
|
|
|
if (typeof url === 'string' && (url.startsWith('wss://') || url.startsWith('ws://'))) {
|
|
|
|
try {
|
|
|
|
const existingRelay = await this.db.getFirstAsync<{ url: string }>(
|
|
|
|
'SELECT url FROM relays WHERE url = ?',
|
|
|
|
[url]
|
|
|
|
);
|
|
|
|
|
|
|
|
const now = Date.now();
|
|
|
|
|
|
|
|
if (existingRelay) {
|
|
|
|
// We'll only update the timestamp, not the permissions
|
|
|
|
await this.db.runAsync(
|
|
|
|
'UPDATE relays SET updated_at = ? WHERE url = ?',
|
|
|
|
[now, url]
|
|
|
|
);
|
|
|
|
updatedCount++;
|
|
|
|
console.log(`[RelayService] Updated existing relay from NDK pool: ${url}`);
|
|
|
|
} else {
|
|
|
|
maxPriority++;
|
|
|
|
await this.db.runAsync(
|
|
|
|
'INSERT INTO relays (url, read, write, priority, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
|
|
|
|
[url, 1, 1, maxPriority, now, now]
|
|
|
|
);
|
|
|
|
importCount++;
|
|
|
|
console.log(`[RelayService] Added new relay from NDK pool: ${url}`);
|
|
|
|
}
|
|
|
|
} catch (innerError) {
|
|
|
|
console.error(`[RelayService] Error importing relay ${url} from NDK pool:`, innerError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set flag to true because we found relays
|
|
|
|
relayTagsFound = userRelays.length > 0;
|
|
|
|
}
|
|
|
|
} catch (poolError) {
|
|
|
|
console.log('[RelayService] Error accessing NDK pool relays:', poolError);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!relayTagsFound) {
|
|
|
|
console.log('[RelayService] No relay information found in any format');
|
|
|
|
}
|
|
|
|
|
2025-03-09 11:15:28 -04:00
|
|
|
console.log(`[RelayService] Imported ${importCount} new relays, updated ${updatedCount} existing relays`);
|
|
|
|
return importCount > 0 || updatedCount > 0;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error importing relays from metadata:', error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reset relays to default set
|
|
|
|
*/
|
|
|
|
async resetToDefaults(): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
console.log('[RelayService] Resetting relays to defaults');
|
|
|
|
|
|
|
|
// Clear existing relays
|
|
|
|
await this.db.runAsync('DELETE FROM relays');
|
|
|
|
|
|
|
|
// Add default relays
|
|
|
|
const now = Date.now();
|
2025-03-09 12:48:24 -04:00
|
|
|
let addedCount = 0;
|
2025-03-09 11:15:28 -04:00
|
|
|
|
|
|
|
for (let i = 0; i < DEFAULT_RELAYS.length; i++) {
|
|
|
|
const url = DEFAULT_RELAYS[i];
|
|
|
|
const priority = DEFAULT_RELAYS.length - i; // Higher priority for first relays
|
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
try {
|
|
|
|
await this.db.runAsync(
|
|
|
|
'INSERT INTO relays (url, read, write, priority, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)',
|
|
|
|
[url, 1, 1, priority, now, now]
|
|
|
|
);
|
|
|
|
addedCount++;
|
|
|
|
} catch (innerError) {
|
|
|
|
console.error(`[RelayService] Error adding default relay ${url}:`, innerError);
|
|
|
|
}
|
2025-03-09 11:15:28 -04:00
|
|
|
}
|
|
|
|
|
2025-03-09 12:48:24 -04:00
|
|
|
console.log(`[RelayService] Successfully reset to ${addedCount} default relays`);
|
|
|
|
return addedCount > 0;
|
2025-03-09 11:15:28 -04:00
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error resetting relays to defaults:', error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a kind:3 event with the user's relay preferences
|
|
|
|
*/
|
|
|
|
async publishRelayList(ndk?: any): Promise<boolean> {
|
|
|
|
try {
|
|
|
|
// Use provided NDK or the stored one
|
|
|
|
const ndkInstance = ndk || this.ndk;
|
|
|
|
|
|
|
|
if (!ndkInstance || !ndkInstance.signer) {
|
|
|
|
throw new Error('NDK not initialized or not signed in');
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log('[RelayService] Publishing relay list to Nostr');
|
|
|
|
|
|
|
|
// Get all relays
|
|
|
|
const relays = await this.getAllRelays();
|
|
|
|
|
|
|
|
if (relays.length === 0) {
|
|
|
|
console.warn('[RelayService] No relays to publish');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create event using any NDK version
|
|
|
|
const NDKEvent = ndkInstance.constructor.name === 'NDK' ?
|
|
|
|
ndkInstance.constructor.NDKEvent :
|
|
|
|
require('@nostr-dev-kit/ndk-mobile').NDKEvent;
|
|
|
|
|
|
|
|
const event = new NDKEvent(ndkInstance);
|
|
|
|
event.kind = 3;
|
|
|
|
|
|
|
|
// Add relay tags
|
|
|
|
for (const relay of relays) {
|
|
|
|
// Skip disabled relays
|
|
|
|
if (!relay.read && !relay.write) continue;
|
|
|
|
|
|
|
|
if (relay.read && relay.write) {
|
|
|
|
// Full access
|
|
|
|
event.tags.push(['r', relay.url]);
|
|
|
|
} else if (relay.read) {
|
|
|
|
// Read-only
|
|
|
|
event.tags.push(['r', relay.url, 'read']);
|
|
|
|
} else if (relay.write) {
|
|
|
|
// Write-only
|
|
|
|
event.tags.push(['r', relay.url, 'write']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(`[RelayService] Publishing kind:3 event with ${event.tags.length} relay tags`);
|
|
|
|
|
|
|
|
// Sign and publish
|
|
|
|
await event.sign();
|
|
|
|
await event.publish();
|
|
|
|
|
|
|
|
console.log('[RelayService] Successfully published relay list');
|
|
|
|
return true;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error publishing relay list:', error);
|
|
|
|
throw error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize relays from database or defaults
|
|
|
|
* If no relays in database, add defaults
|
|
|
|
*/
|
|
|
|
async initializeRelays(): Promise<string[]> {
|
|
|
|
try {
|
|
|
|
console.log('[RelayService] Initializing relays');
|
|
|
|
|
|
|
|
// First verify the relays table exists and has the correct structure
|
|
|
|
await this.checkAndDebugRelays();
|
|
|
|
|
|
|
|
// Check if there are any relays in the database
|
|
|
|
const count = await this.db.getFirstAsync<{ count: number }>(
|
|
|
|
'SELECT COUNT(*) as count FROM relays'
|
|
|
|
);
|
|
|
|
|
|
|
|
// If no relays, add defaults
|
|
|
|
if (!count || count.count === 0) {
|
|
|
|
console.log('[RelayService] No relays found in database, adding defaults');
|
|
|
|
await this.resetToDefaults();
|
|
|
|
} else {
|
|
|
|
console.log(`[RelayService] Found ${count.count} relays in database`);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return enabled relays
|
|
|
|
const enabledRelays = await this.getEnabledRelays();
|
|
|
|
console.log(`[RelayService] Returning ${enabledRelays.length} enabled relays`);
|
|
|
|
return enabledRelays;
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error initializing relays:', error);
|
|
|
|
console.log('[RelayService] Falling back to default relays');
|
|
|
|
// Return defaults on error
|
|
|
|
return DEFAULT_RELAYS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper to convert NDK relay status to our status format
|
|
|
|
*/
|
|
|
|
private getRelayStatus(relay: any): 'connected' | 'connecting' | 'disconnected' | 'error' {
|
2025-03-09 12:48:24 -04:00
|
|
|
try {
|
|
|
|
// Check if the relay has a trailing slash in the URL
|
|
|
|
const urlWithoutSlash = relay.url ? relay.url.replace(/\/$/, '') : '';
|
|
|
|
const urlWithSlash = urlWithoutSlash + '/';
|
|
|
|
|
|
|
|
// Try to get the relay from NDK pool - check both with and without trailing slash
|
|
|
|
const ndkRelay = this.ndk?.pool.getRelay(urlWithoutSlash) ||
|
|
|
|
this.ndk?.pool.getRelay(urlWithSlash);
|
|
|
|
|
|
|
|
if (ndkRelay) {
|
|
|
|
console.log(`[RelayService] Detailed relay status for ${relay.url}: status=${ndkRelay.status}, connected=${!!ndkRelay.connected}`);
|
|
|
|
|
|
|
|
// The most reliable way to check connection status is to check the 'connected' property
|
|
|
|
if (ndkRelay.connected) {
|
|
|
|
return 'connected';
|
|
|
|
}
|
|
|
|
|
|
|
|
// NDK relay status: 0=connecting, 1=connected, 2=disconnecting, 3=disconnected, 4=reconnecting, 5=auth_required
|
|
|
|
if (ndkRelay.status === 1) {
|
2025-03-09 11:15:28 -04:00
|
|
|
return 'connected';
|
2025-03-09 12:48:24 -04:00
|
|
|
} else if (ndkRelay.status === 0 || ndkRelay.status === 4) { // CONNECTING or RECONNECTING
|
2025-03-09 11:15:28 -04:00
|
|
|
return 'connecting';
|
2025-03-09 12:48:24 -04:00
|
|
|
} else if (ndkRelay.status === 5) { // AUTH_REQUIRED - This is actually a connected state!
|
|
|
|
return 'connected'; // This is the key fix
|
2025-03-09 11:15:28 -04:00
|
|
|
} else {
|
|
|
|
return 'disconnected';
|
|
|
|
}
|
|
|
|
}
|
2025-03-09 12:48:24 -04:00
|
|
|
|
|
|
|
// If we can't find the relay in the NDK pool
|
|
|
|
return 'disconnected';
|
|
|
|
} catch (error) {
|
|
|
|
console.error(`[RelayService] Error getting relay status:`, error);
|
|
|
|
return 'disconnected';
|
2025-03-09 11:15:28 -04:00
|
|
|
}
|
2025-03-09 12:48:24 -04:00
|
|
|
}
|
2025-03-09 11:15:28 -04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Check and debug relays table and content
|
|
|
|
*/
|
|
|
|
private async checkAndDebugRelays(): Promise<void> {
|
|
|
|
try {
|
|
|
|
console.log('[RelayService] Checking database for relays...');
|
|
|
|
|
|
|
|
// Check if table exists
|
|
|
|
const tableExists = await this.db.getFirstAsync<{ count: number }>(
|
|
|
|
`SELECT count(*) as count FROM sqlite_master
|
|
|
|
WHERE type='table' AND name='relays'`
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!tableExists || tableExists.count === 0) {
|
|
|
|
console.error('[RelayService] Relays table does not exist!');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log('[RelayService] Relays table exists');
|
|
|
|
|
|
|
|
// Check relay count
|
|
|
|
const count = await this.db.getFirstAsync<{ count: number }>(
|
|
|
|
'SELECT COUNT(*) as count FROM relays'
|
|
|
|
);
|
|
|
|
|
|
|
|
console.log(`[RelayService] Found ${count?.count || 0} relays in database`);
|
|
|
|
|
|
|
|
if (count && count.count > 0) {
|
|
|
|
// Get sample relays
|
|
|
|
const sampleRelays = await this.db.getAllAsync<RelayConfig>(
|
|
|
|
'SELECT url, read, write, priority FROM relays LIMIT 5'
|
|
|
|
);
|
|
|
|
|
|
|
|
console.log('[RelayService] Sample relays:', sampleRelays);
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error checking relays:', error);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Import user's relay preferences on login
|
|
|
|
*/
|
|
|
|
async importUserRelaysOnLogin(user: any, ndk: any): Promise<void> {
|
|
|
|
console.log('[RelayService] Checking for user relay preferences...');
|
|
|
|
if (!user || !user.pubkey) return;
|
|
|
|
|
|
|
|
try {
|
|
|
|
// First check if we already have relays in the database
|
|
|
|
const existingCount = await this.db.getFirstAsync<{ count: number }>(
|
|
|
|
'SELECT COUNT(*) as count FROM relays'
|
|
|
|
);
|
|
|
|
|
|
|
|
// If we have relays and they're not just the defaults, skip import
|
2025-03-09 12:48:24 -04:00
|
|
|
if (existingCount && existingCount.count !== undefined && existingCount.count > 0) {
|
|
|
|
console.log(`[RelayService] Found ${existingCount.count} existing relays, checking if we need to import more`);
|
|
|
|
} else {
|
|
|
|
console.log('[RelayService] No existing relays found, will attempt to import');
|
2025-03-09 11:15:28 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
console.log('[RelayService] Attempting to import user relay preferences');
|
|
|
|
|
|
|
|
// Try to import from metadata
|
|
|
|
const success = await this.importFromUserMetadata(user.pubkey, ndk);
|
|
|
|
|
|
|
|
if (success) {
|
|
|
|
console.log('[RelayService] Successfully imported user relay preferences');
|
|
|
|
// Apply the imported configuration immediately
|
|
|
|
await this.applyRelayConfig(ndk);
|
|
|
|
} else {
|
2025-03-09 12:48:24 -04:00
|
|
|
console.log('[RelayService] No relay preferences found, resetting to defaults');
|
|
|
|
await this.resetToDefaults();
|
|
|
|
await this.applyRelayConfig(ndk);
|
2025-03-09 11:15:28 -04:00
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error('[RelayService] Error importing user relays:', error);
|
2025-03-09 12:48:24 -04:00
|
|
|
// On error, reset to defaults
|
|
|
|
try {
|
|
|
|
console.log('[RelayService] Error occurred, resetting to defaults');
|
|
|
|
await this.resetToDefaults();
|
|
|
|
await this.applyRelayConfig(ndk);
|
|
|
|
} catch (resetError) {
|
|
|
|
console.error('[RelayService] Error resetting to defaults:', resetError);
|
|
|
|
}
|
2025-03-09 11:15:28 -04:00
|
|
|
}
|
2025-03-09 12:48:24 -04:00
|
|
|
}}
|