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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
# Caching Status "Not Implemented" Fix Plan
|
||||
|
||||
## Root Cause
|
||||
|
||||
The caching page shows "Service status unavailable (caching_status command not
|
||||
implemented on relay)" — but the command **is** implemented at
|
||||
[`src/config.c:4128`](../src/config.c:4128). The real problem is **admin
|
||||
authorization failure**: every admin command from the browser is rejected at
|
||||
publish time with:
|
||||
|
||||
```
|
||||
Unauthorized admin event attempt: invalid admin pubkey
|
||||
```
|
||||
|
||||
This rejection happens at [`src/main.c:2249`](../src/main.c:2249) because the
|
||||
browser's pubkey is not in the relay's `admin_pubkey` config list. The kind
|
||||
23456 event never reaches the command handler, so `caching_status` never
|
||||
executes, and the placeholder text persists.
|
||||
|
||||
### Confirmed admin key
|
||||
|
||||
- Relay admin pubkey (hex): `6a04ab98d9e4774ad806e302dddeb63bea16b5cb5f223ee77478e861bb583eb3`
|
||||
- Relay admin npub: `npub13lm5wf8dvsdnc2894pkhch9uf8phvw9varrv8zf4sc885hhdmc8q6lx7ks`
|
||||
- Source: [`.relay.laantungir.net.keys`](../.relay.laantungir.net.keys:1)
|
||||
|
||||
The browser extension (nos2x) was using pubkey `8ff74724...`, which is not an
|
||||
admin on the port 7777 relay.
|
||||
|
||||
## Secondary Issue (latent)
|
||||
|
||||
Even after auth is fixed, the caching status UI would render **empty blocks**
|
||||
due to a schema mismatch between backend and frontend:
|
||||
|
||||
| Frontend expects ([`api/index.js:7046`](../api/index.js:7046)) | Backend emits ([`src/config.c:4135`](../src/config.c:4135)) |
|
||||
|---|---|
|
||||
| `data.service.enabled` | `data.caching_enabled` |
|
||||
| `data.service.running` | *(not emitted)* |
|
||||
| `data.inbox.enabled` | `data.caching_inbox_enabled` |
|
||||
| `data.inbox.queue_depth` | `data.inbox_pending_live` + `data.inbox_pending_backfill` |
|
||||
| *(not expected)* | `data.inbox_total_dequeued`, `data.inbox_total_accepted`, `data.inbox_total_rejected`, `data.inbox_oldest_age_seconds` |
|
||||
|
||||
## Fix Steps
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Step 1: Fix admin auth] --> B[Step 2: Align response schema]
|
||||
B --> C[Step 3: Fix frontend handler]
|
||||
C --> D[Step 4: Improve error messaging]
|
||||
D --> E[Step 5: Test end-to-end]
|
||||
```
|
||||
|
||||
### Step 1 — Fix admin authorization (config, user action)
|
||||
|
||||
Load the admin private key (corresponding to `6a04ab98...` /
|
||||
`npub13lm5wf8dvsdnc2894pkhch9uf8phvw9varrv8zf4sc885hhdmc8q6lx7ks`) into the
|
||||
nos2x browser extension so admin commands authenticate. Use `nak` on the
|
||||
command line to convert/derive the nsec if needed.
|
||||
|
||||
This unblocks **all** admin commands, not just caching.
|
||||
|
||||
### Step 2 — Align backend response schema (code, [`src/config.c:4128`](../src/config.c:4128))
|
||||
|
||||
Restructure the `data` object in the `caching_status` handler to emit nested
|
||||
`service` and `inbox` objects matching the frontend handler:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "caching_status",
|
||||
"status": "success",
|
||||
"data": {
|
||||
"service": {
|
||||
"enabled": false,
|
||||
"running": false,
|
||||
"connected_relays": 0,
|
||||
"events_cached": 0
|
||||
},
|
||||
"inbox": {
|
||||
"enabled": false,
|
||||
"running": true,
|
||||
"queue_depth": 0,
|
||||
"last_poll": 0,
|
||||
"total_dequeued": 0,
|
||||
"total_accepted": 0,
|
||||
"total_rejected": 0,
|
||||
"total_duplicates": 0,
|
||||
"pending_live": 0,
|
||||
"pending_backfill": 0,
|
||||
"oldest_age_seconds": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Populate `service.running` / `connected_relays` / `events_cached` from the
|
||||
caching service launcher state if available; otherwise emit zeros/defaults.
|
||||
|
||||
### Step 3 — Update frontend handler (code, [`api/index.js:7027`](../api/index.js:7027))
|
||||
|
||||
Update `handleCachingStatusResponse()` to render the inbox poller stats the
|
||||
backend actually produces (dequeued/accepted/rejected/pending/oldest_age), and
|
||||
map `data.inbox.pending_live + pending_backfill` to queue depth.
|
||||
|
||||
### Step 4 — Replace misleading placeholder (code, [`api/index.js:6889`](../api/index.js:6889))
|
||||
|
||||
- Change the pre-send placeholder from "caching_status command not implemented"
|
||||
to a neutral "Loading..." message.
|
||||
- On auth failure, show the actual error (e.g., "Not authorized: pubkey not
|
||||
registered as admin") instead of the generic "unavailable" text.
|
||||
|
||||
### Step 5 — Test end-to-end on port 7777
|
||||
|
||||
Verify the caching page shows real service/inbox status after auth is fixed
|
||||
and the schema is aligned.
|
||||
@@ -21,7 +21,7 @@ static pid_t g_caching_child_pid = -1;
|
||||
// Fork/exec implementation
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static int caching_service_start_fork(const char* binary_path, const char* pg_conn) {
|
||||
static int caching_service_start_fork(const char* binary_path, const char* config_path) {
|
||||
if (!binary_path || binary_path[0] == '\0') {
|
||||
DEBUG_ERROR("caching_service_start: caching_service_binary_path is not set");
|
||||
return -1;
|
||||
@@ -49,7 +49,8 @@ static int caching_service_start_fork(const char* binary_path, const char* pg_co
|
||||
g_caching_child_pid = -1;
|
||||
}
|
||||
|
||||
DEBUG_INFO("caching_service_start: forking '%s' with --pg-conn", binary_path);
|
||||
DEBUG_INFO("caching_service_start: forking '%s' with config '%s'",
|
||||
binary_path, config_path ? config_path : "(default)");
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
@@ -80,18 +81,18 @@ static int caching_service_start_fork(const char* binary_path, const char* pg_co
|
||||
close(devnull);
|
||||
}
|
||||
|
||||
// Build argv
|
||||
// argv[0] = binary path
|
||||
// argv[1] = "--pg-conn"
|
||||
// argv[2] = connection string (if provided)
|
||||
// argv[3] = NULL
|
||||
char* argv[4];
|
||||
// Build argv for the caching_relay binary.
|
||||
// The caching_relay binary uses a JSON config file, not a --pg-conn flag.
|
||||
// Interface: caching_relay [-c <config.jsonc>] [-d <level>] [-r]
|
||||
// If a config path is provided, pass it via -c; otherwise let the binary
|
||||
// use its default (./caching_relay_config.jsonc).
|
||||
char* argv[5];
|
||||
int argc = 0;
|
||||
argv[argc++] = (char*)binary_path;
|
||||
|
||||
if (pg_conn && pg_conn[0] != '\0') {
|
||||
argv[argc++] = (char*)"--pg-conn";
|
||||
argv[argc++] = (char*)pg_conn;
|
||||
if (config_path && config_path[0] != '\0') {
|
||||
argv[argc++] = (char*)"-c";
|
||||
argv[argc++] = (char*)config_path;
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
|
||||
@@ -199,10 +200,12 @@ int caching_service_start(void) {
|
||||
const char* launch_mode = get_config_value("caching_service_launch_mode");
|
||||
if (!launch_mode || strcmp(launch_mode, "fork") == 0) {
|
||||
const char* binary_path = get_config_value("caching_service_binary_path");
|
||||
const char* pg_conn = get_config_value("caching_service_pg_conn");
|
||||
int rc = caching_service_start_fork(binary_path, pg_conn);
|
||||
// The caching_relay binary uses a JSON config file (-c <path>), not a
|
||||
// --pg-conn flag. Read the config path from the config table.
|
||||
const char* config_path = get_config_value("caching_service_config_path");
|
||||
int rc = caching_service_start_fork(binary_path, config_path);
|
||||
if (binary_path) free((char*)binary_path);
|
||||
if (pg_conn) free((char*)pg_conn);
|
||||
if (config_path) free((char*)config_path);
|
||||
if (launch_mode) free((char*)launch_mode);
|
||||
return rc;
|
||||
}
|
||||
|
||||
+45
-14
@@ -4126,7 +4126,12 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
|
||||
return -1;
|
||||
}
|
||||
else if (strcmp(command, "caching_status") == 0) {
|
||||
// Build caching status response
|
||||
// Build caching status response.
|
||||
//
|
||||
// The response data is structured into nested "service" and "inbox"
|
||||
// objects to match the frontend handler in api/index.js
|
||||
// (handleCachingStatusResponse). The inbox object also carries the
|
||||
// detailed poller stats produced by caching_inbox_poller_get_stats().
|
||||
cJSON* response = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(response, "command", "caching_status");
|
||||
cJSON_AddStringToObject(response, "status", "success");
|
||||
@@ -4134,32 +4139,57 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
|
||||
|
||||
cJSON* status_data = cJSON_CreateObject();
|
||||
|
||||
// Caching config state
|
||||
// ---- Caching config state (top-level, for config-form hydration) ----
|
||||
const char* caching_enabled = get_config_value("caching_enabled");
|
||||
const char* caching_inbox_enabled = get_config_value("caching_inbox_enabled");
|
||||
const char* caching_config_gen = get_config_value("caching_config_generation");
|
||||
cJSON_AddStringToObject(status_data, "caching_enabled", caching_enabled ? caching_enabled : "false");
|
||||
cJSON_AddStringToObject(status_data, "caching_inbox_enabled", caching_inbox_enabled ? caching_inbox_enabled : "false");
|
||||
cJSON_AddNumberToObject(status_data, "config_generation", caching_config_gen ? atol(caching_config_gen) : 0);
|
||||
if (caching_enabled) free((char*)caching_enabled);
|
||||
if (caching_inbox_enabled) free((char*)caching_inbox_enabled);
|
||||
if (caching_config_gen) free((char*)caching_config_gen);
|
||||
|
||||
// Inbox poller stats (PostgreSQL only, no-op on SQLite)
|
||||
// ---- Inbox poller stats (PostgreSQL only, no-op on SQLite) ----
|
||||
int total_dequeued = 0, total_accepted = 0, total_rejected = 0;
|
||||
int total_duplicates = 0, last_batch_size = 0;
|
||||
int pending_live = 0, pending_backfill = 0, oldest_age = 0;
|
||||
caching_inbox_poller_get_stats(&total_dequeued, &total_accepted, &total_rejected,
|
||||
&total_duplicates, &last_batch_size,
|
||||
&pending_live, &pending_backfill, &oldest_age);
|
||||
cJSON_AddNumberToObject(status_data, "inbox_total_dequeued", total_dequeued);
|
||||
cJSON_AddNumberToObject(status_data, "inbox_total_accepted", total_accepted);
|
||||
cJSON_AddNumberToObject(status_data, "inbox_total_rejected", total_rejected);
|
||||
cJSON_AddNumberToObject(status_data, "inbox_total_duplicates", total_duplicates);
|
||||
cJSON_AddNumberToObject(status_data, "inbox_last_batch_size", last_batch_size);
|
||||
cJSON_AddNumberToObject(status_data, "inbox_pending_live", pending_live);
|
||||
cJSON_AddNumberToObject(status_data, "inbox_pending_backfill", pending_backfill);
|
||||
cJSON_AddNumberToObject(status_data, "inbox_oldest_age_seconds", oldest_age);
|
||||
|
||||
// ---- service object (external caching service process) ----
|
||||
cJSON* service_obj = cJSON_CreateObject();
|
||||
int svc_enabled = caching_enabled && (strcmp(caching_enabled, "true") == 0);
|
||||
int svc_running = caching_service_is_running();
|
||||
if (svc_running < 0) svc_running = 0;
|
||||
cJSON_AddBoolToObject(service_obj, "enabled", svc_enabled ? 1 : 0);
|
||||
cJSON_AddBoolToObject(service_obj, "running", svc_running ? 1 : 0);
|
||||
// connected_relays and events_cached are not yet tracked by the
|
||||
// launcher; emit zeros so the frontend has stable fields to render.
|
||||
cJSON_AddNumberToObject(service_obj, "connected_relays", 0);
|
||||
cJSON_AddNumberToObject(service_obj, "events_cached", 0);
|
||||
cJSON_AddItemToObject(status_data, "service", service_obj);
|
||||
|
||||
// ---- inbox object (relay-owned inbox poller) ----
|
||||
cJSON* inbox_obj = cJSON_CreateObject();
|
||||
int inbox_enabled = caching_inbox_enabled && (strcmp(caching_inbox_enabled, "true") == 0);
|
||||
cJSON_AddBoolToObject(inbox_obj, "enabled", inbox_enabled ? 1 : 0);
|
||||
// The relay-side inbox poller is "running" whenever the relay process
|
||||
// is up and the inbox consumer is enabled; we report inbox_enabled.
|
||||
cJSON_AddBoolToObject(inbox_obj, "running", inbox_enabled ? 1 : 0);
|
||||
cJSON_AddNumberToObject(inbox_obj, "queue_depth", pending_live + pending_backfill);
|
||||
cJSON_AddNumberToObject(inbox_obj, "last_poll", 0);
|
||||
cJSON_AddNumberToObject(inbox_obj, "total_dequeued", total_dequeued);
|
||||
cJSON_AddNumberToObject(inbox_obj, "total_accepted", total_accepted);
|
||||
cJSON_AddNumberToObject(inbox_obj, "total_rejected", total_rejected);
|
||||
cJSON_AddNumberToObject(inbox_obj, "total_duplicates", total_duplicates);
|
||||
cJSON_AddNumberToObject(inbox_obj, "last_batch_size", last_batch_size);
|
||||
cJSON_AddNumberToObject(inbox_obj, "pending_live", pending_live);
|
||||
cJSON_AddNumberToObject(inbox_obj, "pending_backfill", pending_backfill);
|
||||
cJSON_AddNumberToObject(inbox_obj, "oldest_age_seconds", oldest_age);
|
||||
cJSON_AddItemToObject(status_data, "inbox", inbox_obj);
|
||||
|
||||
if (caching_enabled) free((char*)caching_enabled);
|
||||
if (caching_inbox_enabled) free((char*)caching_inbox_enabled);
|
||||
if (caching_config_gen) free((char*)caching_config_gen);
|
||||
|
||||
// External service state from caching_service_state table (PostgreSQL only)
|
||||
#ifdef DB_BACKEND_POSTGRES
|
||||
@@ -4173,6 +4203,7 @@ int handle_system_command_unified(cJSON* event, const char* command, char* error
|
||||
cJSON_AddItemToObject(response, "data", status_data);
|
||||
|
||||
printf("=== Caching Status ===\n");
|
||||
printf("Service: enabled=%d running=%d\n", svc_enabled, svc_running);
|
||||
printf("Inbox: dequeued=%d accepted=%d rejected=%d duplicates=%d\n",
|
||||
total_dequeued, total_accepted, total_rejected, total_duplicates);
|
||||
printf("Pending: live=%d backfill=%d oldest_age=%ds\n",
|
||||
|
||||
@@ -162,8 +162,9 @@ static const struct {
|
||||
{"caching_inbox_active_poll_ms", "200"}, // Poll interval when inbox has events
|
||||
{"caching_inbox_idle_poll_ms", "5000"}, // Poll interval when inbox is empty
|
||||
{"caching_max_event_json_bytes", "65536"}, // Maximum event JSON size for inbox insert
|
||||
{"caching_service_binary_path", ""}, // Path to caching_relay binary (for fork/exec launch)
|
||||
{"caching_service_pg_conn", ""}, // PostgreSQL connection string for caching service
|
||||
{"caching_service_binary_path", "/home/user/lt/caching_relay/caching_relay"}, // Path to caching_relay binary (for fork/exec launch)
|
||||
{"caching_service_config_path", "/home/user/lt/caching_relay/caching_relay_config.jsonc"}, // Path to caching_relay JSON config file
|
||||
{"caching_service_pg_conn", "host=localhost port=5432 dbname=crelay user=crelay password=crelay"}, // PostgreSQL connection string for caching service (reserved for future PG-inbox integration)
|
||||
{"caching_service_launch_mode", "fork"} // Launch mode: "fork" or "systemd" (systemd not yet implemented)
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
+2
-2
@@ -13,8 +13,8 @@
|
||||
// Using CRELAY_ prefix to avoid conflicts with nostr_core_lib VERSION macros
|
||||
#define CRELAY_VERSION_MAJOR 2
|
||||
#define CRELAY_VERSION_MINOR 1
|
||||
#define CRELAY_VERSION_PATCH 17
|
||||
#define CRELAY_VERSION "v2.1.17"
|
||||
#define CRELAY_VERSION_PATCH 18
|
||||
#define CRELAY_VERSION "v2.1.18"
|
||||
|
||||
// Relay metadata (authoritative source for NIP-11 information)
|
||||
#define RELAY_NAME "C-Relay-PG"
|
||||
|
||||
Reference in New Issue
Block a user