5.1 KiB
Implementation Plan: Republish Kind 1 Status Events to External Relays
Overview
The main relay (c_relay_pg) already does all the work via
generate_and_post_status_event():
- Generates stats text
- Gets the relay private key
- Creates and signs a kind 1 event
- Stores it in the
eventstable - Broadcasts to local WebSocket clients
The caching service just needs to detect new kind 1 events by the relay's pubkey and republish them to upstream relays. No key management, no stats generation, no event signing — just a simple poll-and-republish.
Architecture
flowchart TB
subgraph MainRelay[c_relay_pg - already done]
Gen[generate_and_post_status_event]
Store[Store kind 1 event in events table]
LocalBC[Broadcast to local clients]
Gen --> Store --> LocalBC
end
subgraph CachingService[caching_relay - new]
Poll[Poll events table for new kind 1\nby relay pubkey]
Republish[Republish to upstream relays\nvia nostr_relay_pool_publish_async]
Poll --> Republish
end
subgraph PostgreSQL
Events[events table]
Config[config table\nrelay_pubkey]
end
subgraph UpstreamRelays
R1[Relay 1]
R2[Relay 2]
R3[Relay N]
end
Store --> Events
Config --> Poll
Events --> Poll
Republish --> R1
Republish --> R2
Republish --> R3
Implementation Steps
Step 1: Add pg_inbox_get_latest_status_event() to pg_inbox
Files: caching/src/pg_inbox.h,
caching/src/pg_inbox.c
A function that queries the events table for the most recent kind 1 event
by the relay's pubkey. The relay pubkey is read from the config table
(same as the main relay does at src/api.c:899).
/* Get the latest kind 1 status event by the relay pubkey.
* Reads relay_pubkey from config, then queries events table.
* On success: fills out_event_json with a malloc'd string (caller frees)
* and out_event_id with the 64-char hex id. Returns 0 on success,
* -1 on error, 1 if no status event found. */
int pg_inbox_get_latest_status_event(char **out_event_json,
char *out_event_id, int id_len);
SQL:
SELECT e.event_json, e.id
FROM events e
WHERE e.pubkey = $1 AND e.kind = 1
ORDER BY e.created_at DESC
LIMIT 1
Step 2: Add status republish tick to main loop
File: caching/src/main.c
Add a periodic task in the main loop that:
- Checks if
kind_1_status_posts_hoursconfig is enabled (viapg_inbox_get_config_value()) - Polls for the latest kind 1 event by the relay pubkey
- If the event ID is different from the last one we republished:
- Parses the event JSON with
cJSON_Parse() - Gets the list of connected upstream relay URLs
- Calls
nostr_relay_pool_publish_async(upstream, urls, count, event, callback, NULL) - Records the event ID as "last republished"
- Parses the event JSON with
- Runs on a reasonable poll interval (e.g., every 60 seconds) — the actual
publish frequency is controlled by the main relay's
kind_1_status_posts_hoursconfig, which determines how often new kind 1 events appear in the database
A time_t last_status_check = 0 and char last_republished_id[65] = {0}
track state.
The publish callback is a simple logging function (same pattern as
sink_publish_cb()).
Event ownership: nostr_relay_pool_publish_async() takes a cJSON* event.
We need to verify whether the pool takes ownership or we need to keep it
alive. The safest approach: pass the parsed event and free it in the callback,
or make a copy. We'll check the nostr_core_lib implementation during coding.
Step 3: Build the caching service
cd caching && make
Step 4: Build and start the test relay on port 8888
./make_and_restart_relay.sh
Production on port 7777 (database crelay_prod) is untouched.
Step 5: Enable status publishing in the test database
PGPASSWORD=crelay psql -h localhost -U crelay -d crelay -c \
"INSERT INTO config (key, value, type, description, category, editable) \
VALUES ('kind_1_status_posts_hours', '1', 'int', \
'Hours between kind 1 status posts', 'relay', 1) \
ON CONFLICT (key) DO UPDATE SET value='1';"
Step 6: Run the caching service and verify
./build/caching_relay -p "host=127.0.0.1 dbname=crelay user=crelay password=crelay" -d 4
Check caching_relay.log for republish log messages.
Step 7: Verify published events
# Get relay pubkey
PGPASSWORD=crelay psql -h localhost -U crelay -d crelay -c \
"SELECT value FROM config WHERE key='relay_pubkey';"
# Query an upstream relay
nak req -k 1 -a <relay_pubkey> wss://relay.damus.io
Files to Modify
| File | Change |
|---|---|
caching/src/pg_inbox.h |
Add pg_inbox_get_latest_status_event() declaration |
caching/src/pg_inbox.c |
Implement pg_inbox_get_latest_status_event() |
caching/src/main.c |
Add status republish tick + publish callback |