v2.1.18 - Fixed caching service integration: aligned caching_status response schema, fixed launcher to use -c config_path instead of --pg-conn, added caching service config fields to UI, replaced misleading not-implemented placeholder with accurate auth-failure messaging
This commit is contained in:
+16
-1
@@ -686,6 +686,21 @@ WEB OF TRUST
|
||||
<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="/absolute/path/to/caching_relay" value="/home/user/lt/caching_relay/caching_relay">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-service-config-path">Caching Service Config Path:</label>
|
||||
<input type="text" id="caching-service-config-path" placeholder="/absolute/path/to/caching_relay_config.jsonc" value="/home/user/lt/caching_relay/caching_relay_config.jsonc">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="caching-service-pg-conn">Caching Service PG Connection (future):</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>
|
||||
@@ -695,7 +710,7 @@ WEB OF TRUST
|
||||
|
||||
<div class="input-group">
|
||||
<h3>Caching Service Control</h3>
|
||||
<p>Start or stop the external caching service process. Requires <code>caching_service_binary_path</code> and <code>caching_service_pg_conn</code> to be set in Configuration.</p>
|
||||
<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>
|
||||
|
||||
+65
-18
@@ -6839,7 +6839,10 @@ const CACHING_CONFIG_FIELDS = [
|
||||
{ key: 'caching_backfill_tick_interval_ms',field: 'caching-backfill-tick-interval', type: 'integer' },
|
||||
{ key: 'caching_inbox_batch_size', field: 'caching-inbox-batch-size', type: 'integer' },
|
||||
{ key: 'caching_inbox_active_poll_ms', field: 'caching-inbox-active-poll', type: 'integer' },
|
||||
{ key: 'caching_inbox_idle_poll_ms', field: 'caching-inbox-idle-poll', type: 'integer' }
|
||||
{ key: 'caching_inbox_idle_poll_ms', field: 'caching-inbox-idle-poll', type: 'integer' },
|
||||
{ key: 'caching_service_binary_path', field: 'caching-service-binary-path', type: 'string' },
|
||||
{ key: 'caching_service_config_path', field: 'caching-service-config-path', type: 'string' },
|
||||
{ key: 'caching_service_pg_conn', field: 'caching-service-pg-conn', type: 'string' }
|
||||
];
|
||||
|
||||
// Helper: read a config value from currentConfig (which stores values in tags as [key, value])
|
||||
@@ -6882,24 +6885,39 @@ async function fetchCachingStatus() {
|
||||
});
|
||||
|
||||
// Attempt to fetch service/inbox status via the caching_status system command.
|
||||
// If the backend has not implemented it yet, show a graceful "unavailable" message.
|
||||
// Show a neutral "loading" placeholder; handleCachingStatusResponse() will
|
||||
// overwrite it when the response arrives. If the command fails (e.g. admin
|
||||
// auth rejection), the catch block surfaces the real error.
|
||||
const serviceStatusEl = document.getElementById('caching-service-status');
|
||||
const inboxStatusEl = document.getElementById('caching-inbox-status');
|
||||
|
||||
if (serviceStatusEl) {
|
||||
serviceStatusEl.innerHTML = '<p>Service status unavailable (caching_status command not implemented on relay).</p>';
|
||||
serviceStatusEl.innerHTML = '<p>Loading caching service status...</p>';
|
||||
}
|
||||
if (inboxStatusEl) {
|
||||
inboxStatusEl.innerHTML = '<p>Inbox status unavailable (caching_status command not implemented on relay).</p>';
|
||||
inboxStatusEl.innerHTML = '<p>Loading relay inbox status...</p>';
|
||||
}
|
||||
|
||||
// Best-effort: send caching_status system command. Response handling is added in
|
||||
// handleSystemCommandResponse() below; if unimplemented, the status blocks remain
|
||||
// at the "unavailable" message set above.
|
||||
// Best-effort: send caching_status system command. Response handling is in
|
||||
// handleSystemCommandResponse() -> handleCachingStatusResponse() below.
|
||||
try {
|
||||
await sendAdminCommand(['system_command', 'caching_status']);
|
||||
} catch (e) {
|
||||
console.log('caching_status command not available: ' + e.message);
|
||||
console.log('caching_status command failed: ' + e.message);
|
||||
const errMsg = escapeHtml(e.message || 'Unknown error');
|
||||
// Detect admin authorization failures and surface a clear message,
|
||||
// since the relay rejects the kind 23456 event before the command
|
||||
// handler ever runs.
|
||||
const isAuthError = /unauthorized admin event attempt|invalid admin pubkey|not admin/i.test(e.message || '');
|
||||
const authNote = isAuthError
|
||||
? ' <em>(Your browser pubkey is not registered as an admin on this relay. Load the admin private key in your Nostr extension.)</em>'
|
||||
: '';
|
||||
if (serviceStatusEl) {
|
||||
serviceStatusEl.innerHTML = `<p style="color:red">Failed to load service status: ${errMsg}${authNote}</p>`;
|
||||
}
|
||||
if (inboxStatusEl) {
|
||||
inboxStatusEl.innerHTML = `<p style="color:red">Failed to load inbox status: ${errMsg}${authNote}</p>`;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
@@ -7041,13 +7059,22 @@ function handleCachingStatusResponse(responseData) {
|
||||
|
||||
const data = responseData.data || responseData;
|
||||
|
||||
// Service status block
|
||||
// Helper: pick the first defined value from a list of candidate keys/paths.
|
||||
function pick(...vals) {
|
||||
for (const v of vals) {
|
||||
if (v !== undefined && v !== null) return v;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Service status block (external caching service process)
|
||||
if (serviceStatusEl) {
|
||||
const service = data.service || data.caching_service || {};
|
||||
const enabled = service.enabled !== undefined ? service.enabled : (data.enabled !== undefined ? data.enabled : null);
|
||||
const running = service.running !== undefined ? service.running : (data.running !== undefined ? data.running : null);
|
||||
const connectedRelays = service.connected_relays !== undefined ? service.connected_relays : (data.connected_relays !== undefined ? data.connected_relays : null);
|
||||
const eventsCached = service.events_cached !== undefined ? service.events_cached : (data.events_cached !== undefined ? data.events_cached : null);
|
||||
// Backward-compat: fall back to top-level flat fields if nested object absent.
|
||||
const enabled = pick(service.enabled, data.caching_enabled, data.enabled);
|
||||
const running = pick(service.running, data.running);
|
||||
const connectedRelays = pick(service.connected_relays, data.connected_relays);
|
||||
const eventsCached = pick(service.events_cached, data.events_cached);
|
||||
|
||||
let html = '<ul style="list-style:none;padding:0;margin:0;">';
|
||||
if (enabled !== null) html += `<li><strong>Enabled:</strong> ${escapeHtml(String(enabled))}</li>`;
|
||||
@@ -7058,19 +7085,39 @@ function handleCachingStatusResponse(responseData) {
|
||||
serviceStatusEl.innerHTML = html;
|
||||
}
|
||||
|
||||
// Inbox status block
|
||||
// Inbox status block (relay-owned inbox poller)
|
||||
if (inboxStatusEl) {
|
||||
const inbox = data.inbox || data.caching_inbox || {};
|
||||
const inboxEnabled = inbox.enabled !== undefined ? inbox.enabled : null;
|
||||
const inboxRunning = inbox.running !== undefined ? inbox.running : null;
|
||||
const queueDepth = inbox.queue_depth !== undefined ? inbox.queue_depth : null;
|
||||
const lastPoll = inbox.last_poll !== undefined ? inbox.last_poll : null;
|
||||
// Backward-compat: derive from flat top-level inbox_* fields if nested object absent.
|
||||
const inboxEnabled = pick(inbox.enabled, data.caching_inbox_enabled);
|
||||
const inboxRunning = pick(inbox.running);
|
||||
const queueDepth = pick(inbox.queue_depth,
|
||||
(data.inbox_pending_live !== undefined && data.inbox_pending_backfill !== undefined)
|
||||
? (Number(data.inbox_pending_live) + Number(data.inbox_pending_backfill))
|
||||
: undefined);
|
||||
const lastPoll = pick(inbox.last_poll);
|
||||
const totalDequeued = pick(inbox.total_dequeued, data.inbox_total_dequeued);
|
||||
const totalAccepted = pick(inbox.total_accepted, data.inbox_total_accepted);
|
||||
const totalRejected = pick(inbox.total_rejected, data.inbox_total_rejected);
|
||||
const totalDuplicates = pick(inbox.total_duplicates, data.inbox_total_duplicates);
|
||||
const lastBatchSize = pick(inbox.last_batch_size, data.inbox_last_batch_size);
|
||||
const pendingLive = pick(inbox.pending_live, data.inbox_pending_live);
|
||||
const pendingBackfill = pick(inbox.pending_backfill, data.inbox_pending_backfill);
|
||||
const oldestAge = pick(inbox.oldest_age_seconds, data.inbox_oldest_age_seconds);
|
||||
|
||||
let html = '<ul style="list-style:none;padding:0;margin:0;">';
|
||||
if (inboxEnabled !== null) html += `<li><strong>Inbox Enabled:</strong> ${escapeHtml(String(inboxEnabled))}</li>`;
|
||||
if (inboxRunning !== null) html += `<li><strong>Inbox Running:</strong> ${escapeHtml(String(inboxRunning))}</li>`;
|
||||
if (queueDepth !== null) html += `<li><strong>Queue Depth:</strong> ${escapeHtml(String(queueDepth))}</li>`;
|
||||
if (lastPoll !== null) html += `<li><strong>Last Poll:</strong> ${escapeHtml(String(lastPoll))}</li>`;
|
||||
if (totalDequeued !== null) html += `<li><strong>Total Dequeued:</strong> ${escapeHtml(String(totalDequeued))}</li>`;
|
||||
if (totalAccepted !== null) html += `<li><strong>Total Accepted:</strong> ${escapeHtml(String(totalAccepted))}</li>`;
|
||||
if (totalRejected !== null) html += `<li><strong>Total Rejected:</strong> ${escapeHtml(String(totalRejected))}</li>`;
|
||||
if (totalDuplicates !== null) html += `<li><strong>Total Duplicates:</strong> ${escapeHtml(String(totalDuplicates))}</li>`;
|
||||
if (lastBatchSize !== null) html += `<li><strong>Last Batch Size:</strong> ${escapeHtml(String(lastBatchSize))}</li>`;
|
||||
if (pendingLive !== null) html += `<li><strong>Pending (Live):</strong> ${escapeHtml(String(pendingLive))}</li>`;
|
||||
if (pendingBackfill !== null) html += `<li><strong>Pending (Backfill):</strong> ${escapeHtml(String(pendingBackfill))}</li>`;
|
||||
if (oldestAge !== null) html += `<li><strong>Oldest Pending Age:</strong> ${escapeHtml(String(oldestAge))}s</li>`;
|
||||
html += '</ul>';
|
||||
inboxStatusEl.innerHTML = html;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user