811 lines
34 KiB
HTML
811 lines
34 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>C-Relay-PG Admin</title>
|
|
<link rel="stylesheet" href="/api/index.css">
|
|
</head>
|
|
|
|
<body>
|
|
<!-- Side Navigation Menu -->
|
|
<nav class="side-nav" id="side-nav">
|
|
<ul class="nav-menu">
|
|
<li><button class="nav-item" data-page="statistics">Statistics</button></li>
|
|
<li><button class="nav-item" data-page="subscriptions">Subscriptions</button></li>
|
|
<li><button class="nav-item" data-page="configuration">Configuration</button></li>
|
|
<li><button class="nav-item" data-page="authorization">Authorization</button></li>
|
|
<li><button class="nav-item" data-page="ip-bans">IP BANS</button></li>
|
|
<li><button class="nav-item" data-page="relay-events">Relay Events</button></li>
|
|
<li><button class="nav-item" data-page="caching">Caching</button></li>
|
|
<li><button class="nav-item" data-page="dm">DM</button></li>
|
|
<li><button class="nav-item" data-page="database">Database Query</button></li>
|
|
</ul>
|
|
<div class="nav-footer">
|
|
<button class="nav-footer-btn" id="nav-dark-mode-btn">DARK MODE</button>
|
|
<button class="nav-footer-btn" id="nav-logout-btn">LOGOUT</button>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Side Navigation Overlay -->
|
|
<div class="side-nav-overlay" id="side-nav-overlay"></div>
|
|
|
|
<!-- Header with title and profile display -->
|
|
<div class="section">
|
|
|
|
<div class="header-content">
|
|
<div class="header-title clickable" id="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>
|
|
<div class="relay-info">
|
|
<div id="relay-name" class="relay-name">C-Relay-PG</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 -->
|
|
<!-- Dropdown menu removed - buttons moved to sidebar -->
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Login Modal Overlay -->
|
|
<div id="login-modal" class="login-modal-overlay" style="display: none;">
|
|
<div class="login-modal-content">
|
|
<div id="login-modal-container"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Access Denied Overlay (shown when non-admin user logs in) -->
|
|
<div id="access-denied-overlay" class="access-denied-overlay" style="display: none;">
|
|
<div class="access-denied-content">
|
|
<div class="access-denied-icon">⛔</div>
|
|
<h2>ACCESS DENIED</h2>
|
|
<p class="access-denied-message">This interface is restricted to the relay administrator.</p>
|
|
<p class="access-denied-submessage">The logged-in account does not have admin privileges.</p>
|
|
<button type="button" class="access-denied-logout-btn" onclick="logout()">LOGOUT</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- DATABASE STATISTICS Section -->
|
|
<!-- Subscribe to kind 24567 events to receive real-time monitoring data -->
|
|
<div class="section flex-section" id="databaseStatisticsSection" style="display: none;">
|
|
<div class="section-header">
|
|
DATABASE STATISTICS
|
|
</div>
|
|
|
|
<!-- Event Rate Graph Container -->
|
|
<div id="event-rate-chart"></div>
|
|
|
|
<!-- Database Overview Table -->
|
|
<div class="input-group">
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="stats-overview-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Metric</th>
|
|
<th>Value</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="stats-overview-table-body">
|
|
<tr>
|
|
<td>Database Size</td>
|
|
<td id="db-size">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Total Events</td>
|
|
<td id="total-events">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Process ID</td>
|
|
<td id="process-id">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>WebSocket Connections</td>
|
|
<td id="websocket-connections">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Active Subscriptions</td>
|
|
<td id="active-subscriptions">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Memory Usage</td>
|
|
<td id="memory-usage">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>CPU Usage</td>
|
|
<td id="cpu-usage">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>CPU Core</td>
|
|
<td id="cpu-core">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Oldest Event</td>
|
|
<td id="oldest-event">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Newest Event</td>
|
|
<td id="newest-event">-</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Event Kind Distribution Table -->
|
|
<div class="input-group">
|
|
<label>Event Kind Distribution:</label>
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="stats-kinds-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Event Kind</th>
|
|
<th>Count</th>
|
|
<th>Percentage</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="stats-kinds-table-body">
|
|
<tr>
|
|
<td colspan="3" style="text-align: center; font-style: italic;">No data loaded</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Time-based Statistics Table -->
|
|
<div class="input-group">
|
|
<label>Time-based Statistics:</label>
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="stats-time-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Period</th>
|
|
<th>Events</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="stats-time-table-body">
|
|
<tr>
|
|
<td>Last 24 Hours</td>
|
|
<td id="events-24h">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Last 7 Days</td>
|
|
<td id="events-7d">-</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Last 30 Days</td>
|
|
<td id="events-30d">-</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Top Pubkeys Table -->
|
|
<div class="input-group">
|
|
<label>Top Pubkeys by Event Count:</label>
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="stats-pubkeys-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Rank</th>
|
|
<th>Name</th>
|
|
<th>Pubkey</th>
|
|
<th>Event Count</th>
|
|
<th>Percentage</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="stats-pubkeys-table-body">
|
|
<tr>
|
|
<td colspan="5" style="text-align: center; font-style: italic;">No data loaded</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- SUBSCRIPTION DETAILS Section (Admin Only) -->
|
|
<div class="section flex-section" id="subscriptionDetailsSection" style="display: none;">
|
|
<div class="section-header">
|
|
ACTIVE SUBSCRIPTION DETAILS
|
|
</div>
|
|
|
|
<div class="input-group">
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="subscription-details-table">
|
|
<tbody id="subscription-details-table-body">
|
|
<tr>
|
|
<td colspan="4" style="text-align: center; font-style: italic;">No subscriptions active</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Testing Section -->
|
|
<div id="div_config" class="section flex-section" style="display: none;">
|
|
<div class="section-header">
|
|
RELAY CONFIGURATION
|
|
</div>
|
|
<div id="config-display" class="hidden">
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="config-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Parameter</th>
|
|
<th>Value</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="config-table-body">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<div class="inline-buttons">
|
|
<button type="button" id="fetch-config-btn">REFRESH</button>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Auth Rules Management - Moved after configuration -->
|
|
<!-- AUTH RULES MANAGEMENT SECTION -->
|
|
<div class="section flex-section" id="authRulesSection" style="display: none;">
|
|
<div class="section-header">
|
|
AUTH RULES MANAGEMENT
|
|
</div>
|
|
|
|
<!-- Auth Rules Table -->
|
|
<div id="authRulesTableContainer" style="display: none;">
|
|
<table class="config-table" id="authRulesTable">
|
|
<thead>
|
|
<tr>
|
|
<th>Rule Type</th>
|
|
<th>Pattern Type</th>
|
|
<th>Pattern Value</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="authRulesTableBody">
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Auth Rule Input Section -->
|
|
<div id="authRuleInputSections" style="display: block;">
|
|
<div class="input-group">
|
|
<label for="authRulePubkey">Public Key (npub or hex):</label>
|
|
<input type="text" id="authRulePubkey" placeholder="npub1... or 64-character hex pubkey">
|
|
</div>
|
|
<div id="whitelistWarning" class="warning-box" style="display: none;">
|
|
<strong>⚠️ WARNING:</strong> Adding whitelist rules changes relay behavior to whitelist-only
|
|
mode.
|
|
Only whitelisted users will be able to interact with the relay.
|
|
</div>
|
|
<div class="inline-buttons">
|
|
<button type="button" id="addWhitelistBtn" onclick="addWhitelistRule()">ADD TO
|
|
WHITELIST</button>
|
|
<button type="button" id="addBlacklistBtn" onclick="addBlacklistRule()">ADD TO
|
|
BLACKLIST</button>
|
|
<button type="button" id="refreshAuthRulesBtn">REFRESH</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- WEB OF TRUST SECTION -->
|
|
<div class="section flex-section" id="wotSection" style="display: none;">
|
|
<div class="section-header">
|
|
WEB OF TRUST
|
|
</div>
|
|
|
|
<!-- Kind 3 Status Indicator -->
|
|
<div id="wotKind3Status" class="wot-status-row">
|
|
<span>Admin Contact List (kind 3):</span>
|
|
<span id="wotKind3Indicator" class="wot-indicator wot-unknown">Checking...</span>
|
|
</div>
|
|
|
|
<!-- WoT Level Selector -->
|
|
<div class="wot-level-selector">
|
|
<label>WoT Level:</label>
|
|
<div class="inline-buttons">
|
|
<button type="button" id="wotLevel0Btn" class="wot-level-btn" onclick="setWotLevel(0)">
|
|
OFF
|
|
</button>
|
|
<button type="button" id="wotLevel1Btn" class="wot-level-btn" onclick="setWotLevel(1)">
|
|
WRITE ONLY
|
|
</button>
|
|
<button type="button" id="wotLevel2Btn" class="wot-level-btn" onclick="setWotLevel(2)">
|
|
FULL
|
|
</button>
|
|
</div>
|
|
<div class="wot-level-description" id="wotLevelDescription">
|
|
Level 0: Open relay — anyone can read and write
|
|
</div>
|
|
</div>
|
|
|
|
<!-- WoT Stats -->
|
|
<div class="wot-stats-row">
|
|
<span>Whitelisted Pubkeys:</span>
|
|
<span id="wotWhitelistCount">—</span>
|
|
</div>
|
|
|
|
<!-- Sync Button -->
|
|
<div class="inline-buttons">
|
|
<button type="button" id="wotSyncBtn" onclick="syncWot()">SYNC FROM KIND 3</button>
|
|
<button type="button" id="wotRefreshBtn" onclick="loadWotStatus()">REFRESH STATUS</button>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- NIP-17 DIRECT MESSAGES Section -->
|
|
<div class="section" id="nip17DMSection" style="display: none;">
|
|
<div class="section-header">
|
|
<h2>NIP-17 DIRECT MESSAGES</h2>
|
|
</div>
|
|
|
|
<!-- Outbox -->
|
|
<div>
|
|
<label for="dm-outbox">Send Message to Relay:</label>
|
|
<textarea id="dm-outbox" rows="4" placeholder="Enter your message to send to the relay..."></textarea>
|
|
</div>
|
|
|
|
<!-- Send Button -->
|
|
<div class="input-group">
|
|
<button type="button" id="send-dm-btn">SEND MESSAGE</button>
|
|
</div>
|
|
|
|
<!-- Inbox -->
|
|
<div class="input-group">
|
|
<label>Received Messages from Relay:</label>
|
|
<div id="dm-inbox" class="log-panel" style="height: 200px;">
|
|
<div class="log-entry">No messages received yet.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- IP BANS Section -->
|
|
<div class="section" id="ipBansSection" style="display: none;">
|
|
<div class="section-header">
|
|
IP BAN MANAGEMENT
|
|
</div>
|
|
|
|
<!-- Statistics Cards -->
|
|
<div class="input-group">
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="ip-bans-stats-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Total IPs Tracked</th>
|
|
<th>Currently Banned</th>
|
|
<th>Total Bans Issued</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td id="ip-bans-total">-</td>
|
|
<td id="ip-bans-active">-</td>
|
|
<td id="ip-bans-issued">-</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Ban Form -->
|
|
<div class="input-group">
|
|
<h3>Manually Ban IP Address</h3>
|
|
<div class="form-group">
|
|
<label for="ban-ip-input">IP Address:</label>
|
|
<input type="text" id="ban-ip-input" placeholder="192.168.1.100">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="ban-duration-select">Ban Duration:</label>
|
|
<select id="ban-duration-select">
|
|
<option value="3600">1 Hour</option>
|
|
<option value="86400" selected>24 Hours</option>
|
|
<option value="604800">7 Days</option>
|
|
<option value="2592000">30 Days</option>
|
|
<option value="31536000">1 Year</option>
|
|
<option value="999999999">Permanent</option>
|
|
</select>
|
|
</div>
|
|
<div class="inline-buttons">
|
|
<button type="button" id="add-ban-btn">BAN IP</button>
|
|
</div>
|
|
<div id="add-ban-status" class="status-message"></div>
|
|
</div>
|
|
|
|
<!-- Whitelist Management -->
|
|
<div class="input-group">
|
|
<h3>IP Whitelist (Never Banned)</h3>
|
|
<p style="font-size:13px;opacity:0.8;">IPs in this list are never idle-banned. Comma-separated.</p>
|
|
<div class="form-group">
|
|
<label for="whitelist-ip-input">Add IP to Whitelist:</label>
|
|
<input type="text" id="whitelist-ip-input" placeholder="103.81.231.220">
|
|
</div>
|
|
<div class="inline-buttons">
|
|
<button type="button" id="add-whitelist-btn">ADD TO WHITELIST</button>
|
|
</div>
|
|
<div id="whitelist-status" class="status-message"></div>
|
|
<div id="whitelist-current" style="margin-top:8px;font-size:13px;"></div>
|
|
</div>
|
|
|
|
<!-- Filter Controls -->
|
|
<div class="input-group">
|
|
<div class="inline-buttons">
|
|
<button type="button" id="ip-ban-filter-all" class="active">All IPs</button>
|
|
<button type="button" id="ip-ban-filter-banned">Currently Banned</button>
|
|
<button type="button" id="ip-ban-filter-expired">Expired</button>
|
|
<button type="button" id="refresh-ip-bans-btn">REFRESH</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- IP Bans List -->
|
|
<div class="input-group">
|
|
<label>Banned IP Addresses:</label>
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="ip-bans-table">
|
|
<thead>
|
|
<tr>
|
|
<th>IP Address</th>
|
|
<th>Status</th>
|
|
<th>Banned Until</th>
|
|
<th>Failures</th>
|
|
<th>Authed Successfully</th>
|
|
<th>Connection Attempts</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="ip-bans-tbody">
|
|
<tr>
|
|
<td colspan="7" style="text-align: center;">Click REFRESH to load IP bans</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- RELAY EVENTS Section -->
|
|
<div class="section" id="relayEventsSection" style="display: none;">
|
|
<div class="section-header">
|
|
RELAY EVENTS MANAGEMENT
|
|
</div>
|
|
|
|
<!-- Live Relay Event Feed -->
|
|
<div class="input-group">
|
|
<h3>Live Relay Event Feed (Normal Nostr Subscription)</h3>
|
|
<div class="config-table-container">
|
|
<table class="config-table" id="live-relay-events-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Time</th>
|
|
<th>Kind</th>
|
|
<th>Pubkey</th>
|
|
<th>ID</th>
|
|
<th>Content Preview</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="live-relay-events-table-body">
|
|
<tr>
|
|
<td colspan="5" style="text-align: center;">Waiting for live events...</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Kind 0: User Metadata -->
|
|
<div class="input-group">
|
|
<h3>Kind 0: User Metadata</h3>
|
|
<div class="form-group">
|
|
<label for="kind0-name">Name:</label>
|
|
<input type="text" id="kind0-name" placeholder="Relay Name">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="kind0-about">About:</label>
|
|
<textarea id="kind0-about" rows="3" placeholder="Relay Description"></textarea>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="kind0-picture">Picture URL:</label>
|
|
<input type="url" id="kind0-picture" placeholder="https://example.com/logo.png">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="kind0-banner">Banner URL:</label>
|
|
<input type="url" id="kind0-banner" placeholder="https://example.com/banner.png">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="kind0-nip05">NIP-05:</label>
|
|
<input type="text" id="kind0-nip05" placeholder="relay@example.com">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="kind0-website">Website:</label>
|
|
<input type="url" id="kind0-website" placeholder="https://example.com">
|
|
</div>
|
|
<div class="inline-buttons">
|
|
<button type="button" id="submit-kind0-btn">UPDATE METADATA</button>
|
|
</div>
|
|
<div id="kind0-status" class="status-message"></div>
|
|
</div>
|
|
|
|
<!-- Kind 10050: DM Relay List -->
|
|
<div class="input-group">
|
|
<h3>Kind 10050: DM Relay List</h3>
|
|
<div class="form-group">
|
|
<label for="kind10050-relays">Relay URLs (one per line):</label>
|
|
<textarea id="kind10050-relays" rows="4" placeholder="wss://relay1.com wss://relay2.com"></textarea>
|
|
</div>
|
|
<div class="inline-buttons">
|
|
<button type="button" id="submit-kind10050-btn">UPDATE DM RELAYS</button>
|
|
</div>
|
|
<div id="kind10050-status" class="status-message"></div>
|
|
</div>
|
|
|
|
<!-- Kind 10002: Relay List -->
|
|
<div class="input-group">
|
|
<h3>Kind 10002: Relay List</h3>
|
|
<div id="kind10002-relay-entries">
|
|
<!-- Dynamic relay entries will be added here -->
|
|
</div>
|
|
<div class="inline-buttons">
|
|
<button type="button" id="add-relay-entry-btn">ADD RELAY</button>
|
|
<button type="button" id="submit-kind10002-btn">UPDATE RELAYS</button>
|
|
</div>
|
|
<div id="kind10002-status" class="status-message"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- CACHING Section -->
|
|
<div class="section" id="cachingSection" style="display: none;">
|
|
<div class="section-header">CACHING</div>
|
|
|
|
<!-- Caching Service Status (read-only) -->
|
|
<div class="input-group">
|
|
<h3>Caching Service Status</h3>
|
|
<div id="caching-service-status" class="status-display">
|
|
<p>Service status will appear here after connecting.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Relay Inbox Status (read-only) -->
|
|
<div class="input-group">
|
|
<h3>Relay Inbox Status</h3>
|
|
<div id="caching-inbox-status" class="status-display">
|
|
<p>Inbox status will appear here after connecting.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Caching Configuration (editable) -->
|
|
<div class="input-group">
|
|
<h3>Caching Configuration</h3>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-enabled">Enable Caching:</label>
|
|
<select id="caching-enabled">
|
|
<option value="false">Disabled</option>
|
|
<option value="true">Enabled</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-inbox-enabled">Enable Inbox Consumer:</label>
|
|
<select id="caching-inbox-enabled">
|
|
<option value="false">Disabled</option>
|
|
<option value="true">Enabled</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-root-npubs">Root Npubs (one per line):</label>
|
|
<textarea id="caching-root-npubs" rows="4" placeholder="npub1...">npub13lm5wf8dvsdnc2894pkhch9uf8phvw9varrv8zf4sc885hhdmc8q6lx7ks</textarea>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-bootstrap-relays">Bootstrap Relays (one per line):</label>
|
|
<textarea id="caching-bootstrap-relays" rows="4" placeholder="wss://relay.damus.io">wss://relay.damus.io
|
|
wss://nos.lol
|
|
wss://relay.primal.net
|
|
wss://laantungir.net/relay</textarea>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-kinds">Kinds (comma-separated):</label>
|
|
<input type="text" id="caching-kinds" placeholder="1,3,6,10000,30023" value="0,1,3,6,10000,10002,30023">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-admin-kinds">Admin Kinds (comma-separated, * for all):</label>
|
|
<input type="text" id="caching-admin-kinds" placeholder="*">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-live-enabled">Live Subscriptions:</label>
|
|
<select id="caching-live-enabled">
|
|
<option value="true">Enabled</option>
|
|
<option value="false">Disabled</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-backfill-enabled">Backfill:</label>
|
|
<select id="caching-backfill-enabled">
|
|
<option value="true">Enabled</option>
|
|
<option value="false">Disabled</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-backfill-windows">Backfill Windows (seconds, comma-separated):</label>
|
|
<input type="text" id="caching-backfill-windows" placeholder="86400,604800,2592000,7776000,31536000">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-backfill-page-size">Backfill Page Size:</label>
|
|
<input type="number" id="caching-backfill-page-size" placeholder="50">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-backfill-tick-interval">Backfill Tick Interval (ms):</label>
|
|
<input type="number" id="caching-backfill-tick-interval" placeholder="5000">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-inbox-batch-size">Inbox Batch Size:</label>
|
|
<input type="number" id="caching-inbox-batch-size" placeholder="150">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-inbox-active-poll">Inbox Active Poll (ms):</label>
|
|
<input type="number" id="caching-inbox-active-poll" placeholder="200">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-inbox-idle-poll">Inbox Idle Poll (ms):</label>
|
|
<input type="number" id="caching-inbox-idle-poll" placeholder="5000">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-service-binary-path">Caching Service Binary Path:</label>
|
|
<input type="text" id="caching-service-binary-path" placeholder="./caching_relay" value="./caching_relay">
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="caching-service-pg-conn">Caching Service PG Connection:</label>
|
|
<input type="text" id="caching-service-pg-conn" placeholder="host=localhost port=5432 dbname=crelay user=crelay password=crelay" value="host=localhost port=5432 dbname=crelay user=crelay password=crelay">
|
|
</div>
|
|
|
|
<div class="inline-buttons">
|
|
<button type="button" id="caching-apply-btn">APPLY CONFIGURATION</button>
|
|
<button type="button" id="caching-reset-progress-btn">RESET BACKFILL PROGRESS</button>
|
|
</div>
|
|
<div id="caching-config-status" class="status-message"></div>
|
|
</div>
|
|
|
|
<div class="input-group">
|
|
<h3>Caching Service Control</h3>
|
|
<p>Start or stop the external caching service process. Set <code>caching_service_binary_path</code> and <code>caching_service_pg_conn</code> above and click APPLY CONFIGURATION before starting.</p>
|
|
<div class="inline-buttons">
|
|
<button type="button" id="caching-start-service-btn">START CACHING SERVICE</button>
|
|
<button type="button" id="caching-stop-service-btn">STOP CACHING SERVICE</button>
|
|
</div>
|
|
<div id="caching-service-control-status" class="status-message"></div>
|
|
</div>
|
|
|
|
<div class="input-group">
|
|
<h3>Followed Pubkeys</h3>
|
|
<p>Pubkeys being cached with their profile names, event counts, outbox relays, and backfill status.</p>
|
|
<div id="caching-follows-status" class="status-message"></div>
|
|
<table id="caching-follows-table" style="width: 100%; border-collapse: collapse; font-size: 13px;">
|
|
<thead>
|
|
<tr style="border-bottom: 2px solid var(--border-color, #444); text-align: left;">
|
|
<th style="padding: 6px 8px;">Name</th>
|
|
<th style="padding: 6px 8px;">npub</th>
|
|
<th style="padding: 6px 8px;">Root?</th>
|
|
<th style="padding: 6px 8px;">Events in DB</th>
|
|
<th style="padding: 6px 8px;">Backfill</th>
|
|
<th style="padding: 6px 8px; width: 40%;">Relays (status, events fetched)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="caching-follows-table-body">
|
|
<tr><td colspan="6" style="text-align: center; font-style: italic; padding: 12px;">Loading follows status...</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- SQL QUERY Section -->
|
|
<div class="section" id="sqlQuerySection" style="display: none;">
|
|
<div class="section-header">
|
|
<h2>SQL QUERY CONSOLE</h2>
|
|
</div>
|
|
|
|
<!-- Query Selector -->
|
|
<div class="input-group">
|
|
<label for="query-dropdown">Quick Queries & History:</label>
|
|
<select id="query-dropdown" onchange="loadSelectedQuery()">
|
|
<option value="">-- Select a query --</option>
|
|
<optgroup label="Common Queries">
|
|
<option value="recent_events">Recent Events</option>
|
|
<option value="event_stats">Event Statistics</option>
|
|
<option value="subscriptions">Active Subscriptions</option>
|
|
<option value="top_pubkeys">Top Pubkeys</option>
|
|
<option value="event_kinds">Event Kinds Distribution</option>
|
|
<option value="time_stats">Time-based Statistics</option>
|
|
</optgroup>
|
|
<optgroup label="IP Ban Queries">
|
|
<option value="banned_ips_summary">Banned IPs Summary</option>
|
|
<option value="banned_ips_list">All Banned IP Addresses</option>
|
|
</optgroup>
|
|
<optgroup label="Query History" id="history-group">
|
|
<!-- Dynamically populated from localStorage -->
|
|
</optgroup>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Query Editor -->
|
|
<div class="input-group">
|
|
<label for="sql-input">SQL Query:</label>
|
|
<textarea id="sql-input" rows="5" placeholder="SELECT * FROM events LIMIT 10"></textarea>
|
|
</div>
|
|
|
|
<!-- Query Actions -->
|
|
<div class="input-group">
|
|
<div class="inline-buttons">
|
|
<button type="button" id="execute-sql-btn">EXECUTE QUERY</button>
|
|
<button type="button" id="clear-sql-btn">CLEAR</button>
|
|
<button type="button" id="clear-history-btn">CLEAR HISTORY</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Query Results -->
|
|
<div class="input-group">
|
|
<label>Query Results:</label>
|
|
<div id="query-info" class="info-box"></div>
|
|
<div id="query-table" class="config-table-container"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Load the official nostr-tools bundle first -->
|
|
<!-- <script src="https://laantungir.net/nostr-login-lite/nostr.bundle.js"></script> -->
|
|
<script src="/api/nostr.bundle.js"></script>
|
|
|
|
<!-- Load NOSTR_LOGIN_LITE main library -->
|
|
<!-- <script src="https://laantungir.net/nostr-login-lite/nostr-lite.js"></script> -->
|
|
<script src="/api/nostr-lite.js"></script>
|
|
<!-- Load text_graph library -->
|
|
<script src="/api/text_graph.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
<script src="/api/index.js"></script>
|
|
</body>
|
|
|
|
</html> |