8.1 KiB
Plan: Publish Kind 1 Status Events to External Relays
Config Reuse
The config key kind_1_status_posts_hours already exists in the shared config table (used by the main relay at src/api.c:975). The caching service will read the same key — no new config needed. Setting it in the admin panel controls both:
- Main relay: generates and stores the kind 1 event locally
- Caching service: publishes it to external upstream relays
Phase 1: PHP Report Endpoint (admin/api/kind_1_report.php)
A new PHP endpoint at /relay/admin/api/kind_1_report.php that returns a markdown-formatted relay status report. This serves as:
- The content template for the kind 1 event
- A preview page you can visit in the browser to see what will be published
Report Structure (Markdown)
# Relay Name v0.x.x
## Event Rate (Last Hour)
[ASCII chart — same as the 1H chart from chart.php]
## Database Overview
- Total Events: X
- Database Size: X MB
- Oldest Event: date
- Newest Event: date
## Event Kinds (Top 10)
| Kind | Count | % |
|------|-------|---|
| 1 | X | X% |
| 7 | X | X% |
| ... | ... | ... |
## Time-Based Statistics
| Period | Events |
|----------|--------|
| 24 Hours | X |
| 7 Days | X |
| 30 Days | X |
## Top Pubkeys
| # | Name | Pubkey | Events | % |
|---|------|--------|--------|---|
| 1 | ... | ... | X | X%|
| 2 | ... | ... | X | X%|
Implementation
The PHP file will:
- Query PostgreSQL for all stats (same queries as
admin/api/stats.php) - Call the existing chart endpoint to get the 1H ASCII chart
- Format everything as markdown
- Return
Content-Type: text/plain; charset=utf-8
Nginx Config
Add a location block so the endpoint is accessible:
location ^~ /relay/admin/api/kind_1_report.php {
alias /opt/c-relay-pg/admin/api/kind_1_report.php;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_index kind_1_report.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
Phase 2: Caching Service Publishing
2a. pg_inbox_get_relay_private_key() (new function in pg_inbox.c)
Reads the relay's private key from the relay_seckey table. Returns a malloc'd hex string.
2b. Status publish tick (new function in main.c)
A periodic task in the main loop that:
- Reads
kind_1_status_posts_hoursfrom the config table - If enabled and time to publish:
- Fetches the relay private key from
relay_seckey - Fetches the report text by calling the PHP endpoint via HTTP (or generates it directly via SQL)
- Creates and signs a kind 1 event using
nostr_create_and_sign_event() - Publishes to all connected upstream relays via
nostr_relay_pool_publish_async()
- Fetches the relay private key from
Files to Modify
| File | Change |
|---|---|
admin/api/kind_1_report.php |
New — PHP endpoint returning markdown report |
caching/src/pg_inbox.h |
Add pg_inbox_get_relay_private_key() declaration |
caching/src/pg_inbox.c |
Implement pg_inbox_get_relay_private_key() |
caching/src/main.c |
Add periodic status publish tick |
| nginx config | Add location for kind_1_report.php |
Current State
The main relay (c_relay_pg) already has a generate_and_post_status_event() function that:
- Generates relay statistics text via
generate_stats_text() - Signs it as a kind 1 event with the relay's private key (from
relay_seckeytable) - Stores it locally and broadcasts to connected clients
But it never publishes to external relays — the main relay has no WebSocket client capability.
The caching service (caching_relay) has a full WebSocket relay pool (nostr_relay_pool_t) that can connect to external relays and publish events. It already connects to 26 upstream relays.
Architecture
┌─────────────────────┐ ┌──────────────────────────────┐
│ PHP Stats Endpoint │────▶│ PostgreSQL (stats data) │
│ /relay/api/stats/ │ │ │
└─────────────────────┘ └──────────┬───────────────────┘
│ reads every N hours
▼
┌──────────────────────────────────────────────────────────┐
│ caching_relay (main loop) │
│ │
│ 1. Read relay private key from relay_seckey table │
│ 2. Generate stats text (SQL queries via pg_inbox) │
│ 3. Create + sign kind 1 event │
│ 4. Publish to ALL connected upstream relays │
│ (via nostr_relay_pool_publish_async) │
└──────────────────────────────────────────────────────────┘
Changes Required
1. PHP Stats Text Endpoint (new file: admin/api/stats_text.php)
A public (or admin-authenticated) PHP endpoint that queries PostgreSQL directly and returns the stats text. This is useful for:
- Manual preview of what the relay publishes
- The caching service could fetch it via HTTP (but we'll use direct SQL instead)
2. Caching Service: pg_inbox_generate_stats_text() (new function in pg_inbox.c)
A C function that queries PostgreSQL to generate the same stats text that the main relay's generate_stats_text() produces. It queries:
SELECT COUNT(*) FROM events— total eventsSELECT COUNT(*) FROM events WHERE created_at > ...— time-based statsSELECT kind, COUNT(*) FROM events GROUP BY kind— kind distributionSELECT pubkey, COUNT(*) FROM events GROUP BY pubkey ORDER BY COUNT(*) DESC LIMIT 10— top pubkeysSELECT pg_database_size('crelay')— database size
3. Caching Service: pg_inbox_get_relay_private_key() (new function in pg_inbox.c)
Reads the relay's private key from the relay_seckey table so the caching service can sign events as the relay.
4. Caching Service: Status publish tick (new function in main.c)
A periodic task in the main loop that:
- Checks if it's time to publish (configurable interval, e.g., every 6 hours)
- Reads the relay private key from PostgreSQL
- Generates stats text via SQL queries
- Creates and signs a kind 1 event using
nostr_create_and_sign_event() - Publishes to all connected upstream relays via
nostr_relay_pool_publish_async()
5. Config: status_publish_hours (new config key)
Controls how often the status event is published. Stored in the config table. Default 0 = disabled.
Files to Modify
| File | Change |
|---|---|
admin/api/stats_text.php |
New — PHP endpoint returning stats text |
caching/src/pg_inbox.h |
Add declarations for pg_inbox_generate_stats_text() and pg_inbox_get_relay_private_key() |
caching/src/pg_inbox.c |
Implement both functions |
caching/src/main.c |
Add periodic status publish tick in main loop |
caching/src/pg_config.c |
Add status_publish_hours to config loading |
Data Flow
Every N hours (config: status_publish_hours):
1. main.c checks if time to publish
2. Calls pg_inbox_generate_stats_text() → returns malloc'd string
3. Calls pg_inbox_get_relay_private_key() → returns hex key
4. Creates cJSON event: kind=1, content=stats_text, tags=[]
5. Signs with nostr_create_and_sign_event(1, content, tags, privkey, now)
6. Publishes via nostr_relay_pool_publish_async() to all upstream relays
7. Free resources
Dependencies
- The caching service already links
nostr_core_libwhich providesnostr_create_and_sign_event()andnostr_relay_pool_publish_async() - The caching service already has a PostgreSQL connection via
pg_inbox - No new libraries needed