Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c38aaebf3 | ||
|
|
18b0ac44bf | ||
|
|
b6749eff2f |
@@ -1,6 +1,8 @@
|
||||
# Alpine-based MUSL static binary builder for C-Relay
|
||||
# Produces truly portable binaries with zero runtime dependencies
|
||||
|
||||
ARG DEBUG_BUILD=false
|
||||
|
||||
FROM alpine:3.19 AS builder
|
||||
|
||||
# Install build dependencies
|
||||
@@ -98,9 +100,19 @@ RUN cd nostr_core_lib && \
|
||||
COPY src/ /build/src/
|
||||
COPY Makefile /build/Makefile
|
||||
|
||||
# Build c-relay with full static linking and debug symbols (only rebuilds when src/ changes)
|
||||
# Build c-relay with full static linking (only rebuilds when src/ changes)
|
||||
# Disable fortification to avoid __*_chk symbols that don't exist in MUSL
|
||||
RUN gcc -static -g -O0 -DDEBUG -Wall -Wextra -std=c99 \
|
||||
# Use conditional compilation flags based on DEBUG_BUILD argument
|
||||
RUN if [ "$DEBUG_BUILD" = "true" ]; then \
|
||||
CFLAGS="-g -O0 -DDEBUG"; \
|
||||
STRIP_CMD=""; \
|
||||
echo "Building with DEBUG symbols enabled"; \
|
||||
else \
|
||||
CFLAGS="-O2"; \
|
||||
STRIP_CMD="strip /build/c_relay_static"; \
|
||||
echo "Building optimized production binary"; \
|
||||
fi && \
|
||||
gcc -static $CFLAGS -Wall -Wextra -std=c99 \
|
||||
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 \
|
||||
-I. -Ic_utils_lib/src -Inostr_core_lib -Inostr_core_lib/nostr_core \
|
||||
-Inostr_core_lib/cjson -Inostr_core_lib/nostr_websocket \
|
||||
@@ -111,10 +123,8 @@ RUN gcc -static -g -O0 -DDEBUG -Wall -Wextra -std=c99 \
|
||||
c_utils_lib/libc_utils.a \
|
||||
nostr_core_lib/libnostr_core_x64.a \
|
||||
-lwebsockets -lssl -lcrypto -lsqlite3 -lsecp256k1 \
|
||||
-lcurl -lz -lpthread -lm -ldl
|
||||
|
||||
# DO NOT strip - we need debug symbols for debugging
|
||||
# RUN strip /build/c_relay_static
|
||||
-lcurl -lz -lpthread -lm -ldl && \
|
||||
eval "$STRIP_CMD"
|
||||
|
||||
# Verify it's truly static
|
||||
RUN echo "=== Binary Information ===" && \
|
||||
|
||||
143
api/index.css
143
api/index.css
@@ -22,6 +22,23 @@
|
||||
--tab-border-opacity-logged-in: 0.1;
|
||||
}
|
||||
|
||||
/* Dark Mode Overrides */
|
||||
body.dark-mode {
|
||||
--primary-color: #ffffff;
|
||||
--secondary-color: #000000;
|
||||
--accent-color: #ff0000;
|
||||
--muted-color: #222222;
|
||||
--border-color: var(--muted-color);
|
||||
|
||||
|
||||
--tab-bg-logged-out: #000000;
|
||||
--tab-color-logged-out: #ffffff;
|
||||
--tab-border-logged-out: #ffffff;
|
||||
--tab-bg-logged-in: #000000;
|
||||
--tab-color-logged-in: #ffffff;
|
||||
--tab-border-logged-in: #00ffff;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -41,10 +58,8 @@ body {
|
||||
/* Header Styles */
|
||||
.main-header {
|
||||
background-color: var(--secondary-color);
|
||||
border-bottom: var(--border-width) solid var(--border-color);
|
||||
|
||||
padding: 15px 20px;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
@@ -67,6 +82,86 @@ body {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.relay-info {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.relay-name {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.relay-pubkey-container {
|
||||
border: 1px solid transparent;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 4px;
|
||||
margin-top: 4px;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s ease;
|
||||
background-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.relay-pubkey-container:hover {
|
||||
border-color: var(--border-color);
|
||||
}
|
||||
|
||||
.relay-pubkey-container.copied {
|
||||
border-color: var(--accent-color);
|
||||
animation: flash-accent 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
.relay-pubkey {
|
||||
font-size: 8px;
|
||||
color: var(--primary-color);
|
||||
font-family: "Courier New", Courier, monospace;
|
||||
line-height: 1.2;
|
||||
white-space: pre-line;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@keyframes flash-accent {
|
||||
0% { border-color: var(--accent-color); }
|
||||
50% { border-color: var(--accent-color); }
|
||||
100% { border-color: transparent; }
|
||||
}
|
||||
|
||||
.relay-description {
|
||||
font-size: 10px;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
margin: 0;
|
||||
font-size: 24px;
|
||||
font-weight: bolder;
|
||||
color: var(--primary-color);
|
||||
border: none;
|
||||
padding: 0;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.relay-letter {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
transition: all 0.05s ease;
|
||||
}
|
||||
|
||||
.relay-letter.underlined::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background-color: var(--accent-color);
|
||||
}
|
||||
|
||||
.header-user-name {
|
||||
display: block;
|
||||
font-weight: 500;
|
||||
@@ -78,6 +173,7 @@ body {
|
||||
|
||||
.profile-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
@@ -87,6 +183,14 @@ body {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.admin-label {
|
||||
font-size: 10px;
|
||||
color: var(--primary-color);
|
||||
font-weight: normal;
|
||||
margin-bottom: 4px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.profile-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -129,13 +233,13 @@ body {
|
||||
|
||||
.logout-btn {
|
||||
width: 100%;
|
||||
padding: 10px 15px;
|
||||
padding: 5px 10px;
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--primary-color);
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-size: 10px;
|
||||
font-family: var(--font-family);
|
||||
border-radius: var(--border-radius);
|
||||
transition: background-color 0.2s ease;
|
||||
@@ -255,10 +359,10 @@ button:active {
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
background-color: #ccc;
|
||||
color: var(--muted-color);
|
||||
background-color: var(--muted-color);
|
||||
color: var(--primary-color);
|
||||
cursor: not-allowed;
|
||||
border-color: #ccc;
|
||||
border-color: var(--muted-color);
|
||||
}
|
||||
|
||||
/* Flash animation for refresh button */
|
||||
@@ -269,7 +373,7 @@ button:disabled {
|
||||
}
|
||||
|
||||
.flash-red {
|
||||
animation: flash-red 0.5s ease-in-out;
|
||||
animation: flash-red 1s ease-in-out;
|
||||
}
|
||||
|
||||
/* Flash animation for updated statistics values */
|
||||
@@ -280,7 +384,7 @@ button:disabled {
|
||||
}
|
||||
|
||||
.flash-value {
|
||||
animation: flash-value 0.5s ease-in-out;
|
||||
animation: flash-value 1s ease-in-out;
|
||||
}
|
||||
|
||||
/* Npub links styling */
|
||||
@@ -346,6 +450,10 @@ button:disabled {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.config-table tbody tr:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.config-table-container {
|
||||
overflow-x: auto;
|
||||
max-width: 100%;
|
||||
@@ -353,12 +461,13 @@ button:disabled {
|
||||
|
||||
.config-table th {
|
||||
font-weight: bold;
|
||||
height: 40px; /* Double the default height */
|
||||
line-height: 40px; /* Center text vertically */
|
||||
height: 24px; /* Base height for tbody rows */
|
||||
line-height: 24px; /* Center text vertically */
|
||||
}
|
||||
|
||||
.config-table tr:hover {
|
||||
background-color: var(--muted-color);
|
||||
.config-table td {
|
||||
height: 16px; /* 50% taller than tbody rows would be */
|
||||
line-height: 16px; /* Center text vertically */
|
||||
}
|
||||
|
||||
/* Inline config value inputs - remove borders and padding to fit seamlessly in table cells */
|
||||
@@ -696,12 +805,6 @@ button:disabled {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
|
||||
.flex-section {
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
body {
|
||||
padding: 10px;
|
||||
|
||||
@@ -10,21 +10,38 @@
|
||||
|
||||
<body>
|
||||
<!-- Header with title and profile display -->
|
||||
<header class="main-header">
|
||||
<div class="header-content">
|
||||
<div class="header-title">RELAY</div>
|
||||
<div class="profile-area" id="profile-area" style="display: none;">
|
||||
<div class="profile-container">
|
||||
<img id="header-user-image" class="header-user-image" alt="Profile" style="display: none;">
|
||||
<span id="header-user-name" class="header-user-name">Loading...</span>
|
||||
<div class="section">
|
||||
|
||||
<div class="header-content">
|
||||
<div class="header-title">
|
||||
<span class="relay-letter" data-letter="R">R</span>
|
||||
<span class="relay-letter" data-letter="E">E</span>
|
||||
<span class="relay-letter" data-letter="L">L</span>
|
||||
<span class="relay-letter" data-letter="A">A</span>
|
||||
<span class="relay-letter" data-letter="Y">Y</span>
|
||||
</div>
|
||||
<!-- Logout dropdown -->
|
||||
<div class="logout-dropdown" id="logout-dropdown" style="display: none;">
|
||||
<button type="button" id="logout-btn" class="logout-btn">LOGOUT</button>
|
||||
<div class="relay-info">
|
||||
<div id="relay-name" class="relay-name">C-Relay</div>
|
||||
<div id="relay-description" class="relay-description">Loading...</div>
|
||||
<div id="relay-pubkey-container" class="relay-pubkey-container">
|
||||
<div id="relay-pubkey" class="relay-pubkey">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="profile-area" id="profile-area" style="display: none;">
|
||||
<div class="admin-label">admin</div>
|
||||
<div class="profile-container">
|
||||
<img id="header-user-image" class="header-user-image" alt="Profile" style="display: none;">
|
||||
<span id="header-user-name" class="header-user-name">Loading...</span>
|
||||
</div>
|
||||
<!-- Logout dropdown -->
|
||||
<div class="logout-dropdown" id="logout-dropdown" style="display: none;">
|
||||
<button type="button" id="dark-mode-btn" class="logout-btn">🌙 DARK MODE</button>
|
||||
<button type="button" id="logout-btn" class="logout-btn">LOGOUT</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Login Modal Overlay -->
|
||||
<div id="login-modal" class="login-modal-overlay" style="display: none;">
|
||||
@@ -43,36 +60,30 @@
|
||||
|
||||
<!-- Database Overview Table -->
|
||||
<div class="input-group">
|
||||
<label>Database Overview:</label>
|
||||
<div class="config-table-container">
|
||||
<table class="config-table" id="stats-overview-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Metric</th>
|
||||
<th>Value</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="stats-overview-table-body">
|
||||
<tr>
|
||||
<td>Database Size</td>
|
||||
<td id="db-size">-</td>
|
||||
<td>Current database file size</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Events</td>
|
||||
<td id="total-events">-</td>
|
||||
<td>Total number of events stored</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Oldest Event</td>
|
||||
<td id="oldest-event">-</td>
|
||||
<td>Timestamp of oldest event</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Newest Event</td>
|
||||
<td id="newest-event">-</td>
|
||||
<td>Timestamp of newest event</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -109,24 +120,20 @@
|
||||
<tr>
|
||||
<th>Period</th>
|
||||
<th>Events</th>
|
||||
<th>Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="stats-time-table-body">
|
||||
<tr>
|
||||
<td>Last 24 Hours</td>
|
||||
<td id="events-24h">-</td>
|
||||
<td>Events in the last day</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last 7 Days</td>
|
||||
<td id="events-7d">-</td>
|
||||
<td>Events in the last week</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last 30 Days</td>
|
||||
<td id="events-30d">-</td>
|
||||
<td>Events in the last month</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -9,11 +9,21 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
BUILD_DIR="$SCRIPT_DIR/build"
|
||||
DOCKERFILE="$SCRIPT_DIR/Dockerfile.alpine-musl"
|
||||
|
||||
echo "=========================================="
|
||||
echo "C-Relay MUSL Static Binary Builder"
|
||||
echo "=========================================="
|
||||
# Parse command line arguments
|
||||
DEBUG_BUILD=false
|
||||
if [[ "$1" == "--debug" ]]; then
|
||||
DEBUG_BUILD=true
|
||||
echo "=========================================="
|
||||
echo "C-Relay MUSL Static Binary Builder (DEBUG MODE)"
|
||||
echo "=========================================="
|
||||
else
|
||||
echo "=========================================="
|
||||
echo "C-Relay MUSL Static Binary Builder (PRODUCTION MODE)"
|
||||
echo "=========================================="
|
||||
fi
|
||||
echo "Project directory: $SCRIPT_DIR"
|
||||
echo "Build directory: $BUILD_DIR"
|
||||
echo "Debug build: $DEBUG_BUILD"
|
||||
echo ""
|
||||
|
||||
# Create build directory
|
||||
@@ -83,6 +93,7 @@ echo ""
|
||||
|
||||
$DOCKER_CMD build \
|
||||
--platform "$PLATFORM" \
|
||||
--build-arg DEBUG_BUILD=$DEBUG_BUILD \
|
||||
-f "$DOCKERFILE" \
|
||||
-t c-relay-musl-builder:latest \
|
||||
--progress=plain \
|
||||
@@ -105,6 +116,7 @@ echo "=========================================="
|
||||
# Build the builder stage to extract the binary
|
||||
$DOCKER_CMD build \
|
||||
--platform "$PLATFORM" \
|
||||
--build-arg DEBUG_BUILD=$DEBUG_BUILD \
|
||||
--target builder \
|
||||
-f "$DOCKERFILE" \
|
||||
-t c-relay-static-builder-stage:latest \
|
||||
@@ -179,11 +191,16 @@ echo "=========================================="
|
||||
echo "Binary: $BUILD_DIR/$OUTPUT_NAME"
|
||||
echo "Size: $(du -h "$BUILD_DIR/$OUTPUT_NAME" | cut -f1)"
|
||||
echo "Platform: $PLATFORM"
|
||||
if [ "$DEBUG_BUILD" = true ]; then
|
||||
echo "Build Type: DEBUG (with symbols, no optimization)"
|
||||
else
|
||||
echo "Build Type: PRODUCTION (optimized, stripped)"
|
||||
fi
|
||||
if [ "$TRULY_STATIC" = true ]; then
|
||||
echo "Type: Fully static binary (Alpine MUSL-based)"
|
||||
echo "Linkage: Fully static binary (Alpine MUSL-based)"
|
||||
echo "Portability: Works on ANY Linux distribution"
|
||||
else
|
||||
echo "Type: Static binary (may have minimal dependencies)"
|
||||
echo "Linkage: Static binary (may have minimal dependencies)"
|
||||
fi
|
||||
echo ""
|
||||
echo "✓ Build complete!"
|
||||
|
||||
38
notes.txt
38
notes.txt
@@ -39,6 +39,40 @@ Even simpler: Use this one-liner
|
||||
cd /usr/local/bin/c_relay
|
||||
sudo -u c-relay ./c_relay --debug-level=5 & sleep 2 && sudo gdb -p $(pgrep c_relay)
|
||||
|
||||
Once gdb attaches, type continue and wait for the crash. This way the relay starts normally and gdb just monitors it.
|
||||
|
||||
Which approach would you like to try?
|
||||
|
||||
How to View the Logs
|
||||
Check systemd journal:
|
||||
# View all c-relay logs
|
||||
sudo journalctl -u c-relay
|
||||
|
||||
# View recent logs (last 50 lines)
|
||||
sudo journalctl -u c-relay -n 50
|
||||
|
||||
# Follow logs in real-time
|
||||
sudo journalctl -u c-relay -f
|
||||
|
||||
# View logs since last boot
|
||||
sudo journalctl -u c-relay -b
|
||||
|
||||
Check if service is running:
|
||||
|
||||
|
||||
|
||||
To immediately trim the syslog file size:
|
||||
|
||||
Safe Syslog Truncation
|
||||
Stop syslog service first:
|
||||
sudo systemctl stop rsyslog
|
||||
|
||||
Truncate the syslog file:
|
||||
sudo truncate -s 0 /var/log/syslog
|
||||
|
||||
Restart syslog service:
|
||||
sudo systemctl start rsyslog
|
||||
sudo systemctl status rsyslog
|
||||
|
||||
|
||||
sudo -u c-relay ./c_relay --debug-level=5 -r 85d0b37e2ae822966dcadd06b2dc9368cde73865f90ea4d44f8b57d47ef0820a -a 1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139
|
||||
|
||||
./c_relay_static_x86_64 -p 7889 --debug-level=5 -r 85d0b37e2ae822966dcadd06b2dc9368cde73865f90ea4d44f8b57d47ef0820a -a 1ec454734dcbf6fe54901ce25c0c7c6bca5edd89443416761fadc321d38df139
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user