v0.7.24 - Fix admin API subscription issues: NIP-17 historical events and relay pubkey timing
This commit is contained in:
242
api/index.js
242
api/index.js
@@ -22,6 +22,7 @@ let currentConfig = null;
|
||||
// Global subscription state
|
||||
let relayPool = null;
|
||||
let subscriptionId = null;
|
||||
let isSubscribed = false; // Flag to prevent multiple simultaneous subscriptions
|
||||
// Relay connection state
|
||||
let relayInfo = null;
|
||||
let isRelayConnected = false;
|
||||
@@ -353,6 +354,9 @@ async function setupAutomaticRelayConnection(showSections = false) {
|
||||
// Mark as connected
|
||||
isRelayConnected = true;
|
||||
|
||||
// Update relay info in header
|
||||
updateRelayInfoInHeader();
|
||||
|
||||
// Only show admin sections if explicitly requested
|
||||
if (showSections) {
|
||||
updateAdminSectionsVisibility();
|
||||
@@ -747,6 +751,8 @@ async function logout() {
|
||||
}
|
||||
relayPool = null;
|
||||
subscriptionId = null;
|
||||
// Reset subscription flag
|
||||
isSubscribed = false;
|
||||
}
|
||||
|
||||
await nlLite.logout();
|
||||
@@ -758,6 +764,8 @@ async function logout() {
|
||||
// Reset relay connection state
|
||||
isRelayConnected = false;
|
||||
relayPubkey = null;
|
||||
// Reset subscription flag
|
||||
isSubscribed = false;
|
||||
|
||||
// Reset UI - hide profile and show login modal
|
||||
hideProfileFromHeader();
|
||||
@@ -798,6 +806,12 @@ async function subscribeToConfiguration() {
|
||||
try {
|
||||
console.log('=== STARTING SIMPLEPOOL CONFIGURATION SUBSCRIPTION ===');
|
||||
|
||||
// Prevent multiple simultaneous subscription attempts
|
||||
if (isSubscribed) {
|
||||
console.log('Subscription already established, skipping duplicate subscription attempt');
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isLoggedIn) {
|
||||
console.log('WARNING: Not logged in, but proceeding with subscription test');
|
||||
}
|
||||
@@ -810,16 +824,14 @@ async function subscribeToConfiguration() {
|
||||
|
||||
console.log(`Connecting to relay via SimplePool: ${url}`);
|
||||
|
||||
// Clean up existing pool
|
||||
if (relayPool) {
|
||||
console.log('Closing existing pool connection');
|
||||
relayPool.close([url]);
|
||||
relayPool = null;
|
||||
subscriptionId = null;
|
||||
// Reuse existing pool if available, otherwise create new one
|
||||
if (!relayPool) {
|
||||
console.log('Creating new SimplePool instance');
|
||||
relayPool = new window.NostrTools.SimplePool();
|
||||
} else {
|
||||
console.log('Reusing existing SimplePool instance');
|
||||
}
|
||||
|
||||
// Create new SimplePool instance
|
||||
relayPool = new window.NostrTools.SimplePool();
|
||||
subscriptionId = generateSubId();
|
||||
|
||||
console.log(`Generated subscription ID: ${subscriptionId}`);
|
||||
@@ -838,6 +850,7 @@ async function subscribeToConfiguration() {
|
||||
"#p": [userPubkey], // Only DMs directed to this user
|
||||
limit: 50
|
||||
}, {
|
||||
since: Math.floor(Date.now() / 1000), // Start from current time
|
||||
kinds: [1059], // NIP-17 GiftWrap events
|
||||
"#p": [userPubkey], // Only GiftWrap events addressed to this user
|
||||
limit: 50
|
||||
@@ -940,6 +953,9 @@ async function subscribeToConfiguration() {
|
||||
// Store subscription for cleanup
|
||||
relayPool.currentSubscription = subscription;
|
||||
|
||||
// Mark as subscribed to prevent duplicate attempts
|
||||
isSubscribed = true;
|
||||
|
||||
console.log('SimplePool subscription established');
|
||||
return true;
|
||||
|
||||
@@ -1101,6 +1117,9 @@ function handleConfigQueryResponse(responseData) {
|
||||
// Display the configuration using the original display function
|
||||
displayConfiguration(syntheticEvent);
|
||||
|
||||
// Update relay info in header with config data
|
||||
updateStoredRelayInfo(responseData);
|
||||
|
||||
log(`Configuration loaded: ${responseData.total_results} parameters`, 'INFO');
|
||||
} else {
|
||||
console.log('No configuration data received');
|
||||
@@ -1335,14 +1354,16 @@ async function fetchConfiguration() {
|
||||
throw new Error('Must be connected to relay to fetch configuration. Please use the Relay Connection section first.');
|
||||
}
|
||||
|
||||
// First establish subscription to receive responses
|
||||
// First establish subscription to receive responses (only if not already subscribed)
|
||||
const subscriptionResult = await subscribeToConfiguration();
|
||||
if (!subscriptionResult) {
|
||||
throw new Error('Failed to establish admin response subscription');
|
||||
}
|
||||
|
||||
// Wait a moment for subscription to be established
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
// Wait a moment for subscription to be established (only if we just created it)
|
||||
if (!isSubscribed) {
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
}
|
||||
|
||||
// Send config query command if logged in
|
||||
if (isLoggedIn && userPubkey && relayPool) {
|
||||
@@ -1698,6 +1719,43 @@ if (logoutBtn) {
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize dark mode button handler
|
||||
const darkModeBtn = document.getElementById('dark-mode-btn');
|
||||
if (darkModeBtn) {
|
||||
darkModeBtn.addEventListener('click', function(e) {
|
||||
e.stopPropagation(); // Prevent profile area click
|
||||
toggleDarkMode();
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize relay pubkey container click handler for clipboard copy
|
||||
const relayPubkeyContainer = document.getElementById('relay-pubkey-container');
|
||||
if (relayPubkeyContainer) {
|
||||
relayPubkeyContainer.addEventListener('click', async function() {
|
||||
const relayPubkeyElement = document.getElementById('relay-pubkey');
|
||||
if (relayPubkeyElement && relayPubkeyElement.textContent !== 'Loading...') {
|
||||
try {
|
||||
// Get the full npub (remove line breaks for clipboard)
|
||||
const fullNpub = relayPubkeyElement.textContent.replace(/\n/g, '');
|
||||
|
||||
await navigator.clipboard.writeText(fullNpub);
|
||||
|
||||
// Add copied class for visual feedback
|
||||
relayPubkeyContainer.classList.add('copied');
|
||||
|
||||
// Remove the class after animation completes
|
||||
setTimeout(() => {
|
||||
relayPubkeyContainer.classList.remove('copied');
|
||||
}, 500);
|
||||
|
||||
log('Relay npub copied to clipboard', 'INFO');
|
||||
} catch (error) {
|
||||
log('Failed to copy relay npub to clipboard', 'ERROR');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Event handlers
|
||||
fetchConfigBtn.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
@@ -3181,16 +3239,90 @@ function addMessageToInbox(direction, message, timestamp, pubkey = null) {
|
||||
}
|
||||
}
|
||||
|
||||
// Update relay info in header
|
||||
function updateRelayInfoInHeader() {
|
||||
const relayNameElement = document.getElementById('relay-name');
|
||||
const relayPubkeyElement = document.getElementById('relay-pubkey');
|
||||
const relayDescriptionElement = document.getElementById('relay-description');
|
||||
|
||||
if (!relayNameElement || !relayPubkeyElement || !relayDescriptionElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get relay info from NIP-11 data or use defaults
|
||||
const relayInfo = getRelayInfo();
|
||||
const relayName = relayInfo.name || 'C-Relay';
|
||||
const relayDescription = relayInfo.description || 'Nostr Relay';
|
||||
|
||||
// Convert relay pubkey to npub
|
||||
let relayNpub = 'Loading...';
|
||||
if (relayPubkey) {
|
||||
try {
|
||||
relayNpub = window.NostrTools.nip19.npubEncode(relayPubkey);
|
||||
} catch (error) {
|
||||
console.log('Failed to encode relay pubkey to npub:', error.message);
|
||||
relayNpub = relayPubkey.substring(0, 16) + '...';
|
||||
}
|
||||
}
|
||||
|
||||
// Format npub into 3 lines of 21 characters each
|
||||
let formattedNpub = relayNpub;
|
||||
if (relayNpub.length === 63) {
|
||||
formattedNpub = relayNpub.substring(0, 21) + '\n' +
|
||||
relayNpub.substring(21, 42) + '\n' +
|
||||
relayNpub.substring(42, 63);
|
||||
}
|
||||
|
||||
relayNameElement.textContent = relayName;
|
||||
relayPubkeyElement.textContent = formattedNpub;
|
||||
relayDescriptionElement.textContent = relayDescription;
|
||||
}
|
||||
|
||||
// Global variable to store relay info from NIP-11 or config
|
||||
let relayInfoData = null;
|
||||
|
||||
// Helper function to get relay info from stored data
|
||||
function getRelayInfo() {
|
||||
// Return stored relay info if available, otherwise defaults
|
||||
if (relayInfoData) {
|
||||
return relayInfoData;
|
||||
}
|
||||
|
||||
// Default values
|
||||
return {
|
||||
name: 'C-Relay',
|
||||
description: 'Nostr Relay',
|
||||
pubkey: relayPubkey
|
||||
};
|
||||
}
|
||||
|
||||
// Update stored relay info when config is loaded
|
||||
function updateStoredRelayInfo(configData) {
|
||||
if (configData && configData.data) {
|
||||
// Extract relay info from config data
|
||||
const relayName = configData.data.find(item => item.key === 'relay_name')?.value || 'C-Relay';
|
||||
const relayDescription = configData.data.find(item => item.key === 'relay_description')?.value || 'Nostr Relay';
|
||||
|
||||
relayInfoData = {
|
||||
name: relayName,
|
||||
description: relayDescription,
|
||||
pubkey: relayPubkey
|
||||
};
|
||||
|
||||
// Update header immediately
|
||||
updateRelayInfoInHeader();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to get relay pubkey
|
||||
function getRelayPubkey() {
|
||||
// Use the dynamically fetched relay pubkey if available
|
||||
if (relayPubkey && isRelayConnected) {
|
||||
if (relayPubkey) {
|
||||
return relayPubkey;
|
||||
}
|
||||
|
||||
// Fallback to hardcoded value for testing/development
|
||||
log('Warning: Using hardcoded relay pubkey. Please connect to relay first.', 'WARNING');
|
||||
return '4f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa';
|
||||
// No fallback - throw error if relay pubkey not available
|
||||
throw new Error('Relay pubkey not available. Please connect to relay first.');
|
||||
}
|
||||
|
||||
// Enhanced SimplePool message handler to capture test responses
|
||||
@@ -3695,10 +3827,53 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
|
||||
|
||||
// Dark mode functionality
|
||||
function toggleDarkMode() {
|
||||
const body = document.body;
|
||||
const isDarkMode = body.classList.contains('dark-mode');
|
||||
|
||||
if (isDarkMode) {
|
||||
body.classList.remove('dark-mode');
|
||||
localStorage.setItem('darkMode', 'false');
|
||||
updateDarkModeButton(false);
|
||||
log('Switched to light mode', 'INFO');
|
||||
} else {
|
||||
body.classList.add('dark-mode');
|
||||
localStorage.setItem('darkMode', 'true');
|
||||
updateDarkModeButton(true);
|
||||
log('Switched to dark mode', 'INFO');
|
||||
}
|
||||
}
|
||||
|
||||
function updateDarkModeButton(isDarkMode) {
|
||||
const darkModeBtn = document.getElementById('dark-mode-btn');
|
||||
if (darkModeBtn) {
|
||||
darkModeBtn.textContent = isDarkMode ? 'LIGHT MODE' : 'DARK MODE';
|
||||
}
|
||||
}
|
||||
|
||||
function initializeDarkMode() {
|
||||
const savedDarkMode = localStorage.getItem('darkMode');
|
||||
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||
const shouldBeDark = savedDarkMode === 'true' || (savedDarkMode === null && prefersDark);
|
||||
|
||||
if (shouldBeDark) {
|
||||
document.body.classList.add('dark-mode');
|
||||
updateDarkModeButton(true);
|
||||
} else {
|
||||
updateDarkModeButton(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the app
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
console.log('C-Relay Admin API interface loaded');
|
||||
|
||||
// Initialize dark mode
|
||||
initializeDarkMode();
|
||||
|
||||
// Start RELAY letter animation
|
||||
startRelayAnimation();
|
||||
|
||||
// Ensure admin sections are hidden by default on page load
|
||||
updateAdminSectionsVisibility();
|
||||
@@ -3708,4 +3883,39 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
// Enhance SimplePool for testing after initialization
|
||||
setTimeout(enhancePoolForTesting, 2000);
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
|
||||
// RELAY letter animation function
|
||||
function startRelayAnimation() {
|
||||
const letters = document.querySelectorAll('.relay-letter');
|
||||
let currentIndex = 0;
|
||||
|
||||
function animateLetter() {
|
||||
// Remove underline from all letters first
|
||||
letters.forEach(letter => letter.classList.remove('underlined'));
|
||||
|
||||
// Add underline to current letter
|
||||
if (letters[currentIndex]) {
|
||||
letters[currentIndex].classList.add('underlined');
|
||||
}
|
||||
|
||||
// Move to next letter
|
||||
currentIndex++;
|
||||
|
||||
// If we've gone through all letters, remove all underlines and wait 4000ms then restart
|
||||
if (currentIndex > letters.length) {
|
||||
// Remove all underlines before the pause
|
||||
letters.forEach(letter => letter.classList.remove('underlined'));
|
||||
setTimeout(() => {
|
||||
currentIndex = 0;
|
||||
animateLetter();
|
||||
}, 4000);
|
||||
} else {
|
||||
// Otherwise, continue to next letter after 200ms
|
||||
setTimeout(animateLetter, 100);
|
||||
}
|
||||
}
|
||||
|
||||
// Start the animation
|
||||
animateLetter();
|
||||
}
|
||||
Reference in New Issue
Block a user