Adding async publish to relay pool

This commit is contained in:
2025-10-09 09:19:11 -04:00
parent c0784fc890
commit 45fb6d061d
12 changed files with 929 additions and 1626 deletions

Binary file not shown.

View File

@@ -8,6 +8,7 @@
*/
#define _POSIX_C_SOURCE 200809L
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -109,7 +110,7 @@ void* poll_thread_func(void* arg) {
// Print menu
void print_menu() {
printf("\n=== NOSTR Relay Pool Test Menu ===\n");
printf("1. Start Pool (wss://relay.laantungir.net)\n");
printf("1. Start Pool (ws://localhost:7555)\n");
printf("2. Stop Pool\n");
printf("3. Add relay to pool\n");
printf("4. Remove relay from pool\n");
@@ -117,7 +118,8 @@ void print_menu() {
printf("6. Remove subscription\n");
printf("7. Show pool status\n");
printf("8. Test reconnection (simulate disconnect)\n");
printf("9. Exit\n");
printf("9. Publish Event\n");
printf("0. Exit\n");
printf("Choice: ");
}
@@ -405,11 +407,24 @@ void show_pool_status() {
printf("├── %s: %s\n", relay_urls[i], status_str);
// Show connection and publish error details
const char* conn_error = nostr_relay_pool_get_relay_last_connection_error(pool, relay_urls[i]);
const char* pub_error = nostr_relay_pool_get_relay_last_publish_error(pool, relay_urls[i]);
if (conn_error) {
printf("│ ├── Connection error: %s\n", conn_error);
}
if (pub_error) {
printf("│ ├── Last publish error: %s\n", pub_error);
}
const nostr_relay_stats_t* stats = nostr_relay_pool_get_relay_stats(pool, relay_urls[i]);
if (stats) {
printf("│ ├── Events received: %d\n", stats->events_received);
printf("│ ├── Connection attempts: %d\n", stats->connection_attempts);
printf("│ ├── Connection failures: %d\n", stats->connection_failures);
printf("│ ├── Events published: %d (OK: %d, Failed: %d)\n",
stats->events_published, stats->events_published_ok, stats->events_published_failed);
printf("│ ├── Ping latency: %.2f ms\n", stats->ping_latency_current);
printf("│ └── Query latency: %.2f ms\n", stats->query_latency_avg);
}
@@ -422,6 +437,148 @@ void show_pool_status() {
printf("\n");
}
// Async publish callback context
typedef struct {
int total_relays;
int responses_received;
int success_count;
time_t start_time;
} async_publish_context_t;
// Async publish callback - called for each relay response
void async_publish_callback(const char* relay_url, const char* event_id,
int success, const char* message, void* user_data) {
async_publish_context_t* ctx = (async_publish_context_t*)user_data;
ctx->responses_received++;
if (success) {
ctx->success_count++;
}
// Calculate elapsed time
time_t now = time(NULL);
double elapsed = difftime(now, ctx->start_time);
// Log to file with real-time feedback
char timestamp[26];
ctime_r(&now, timestamp);
timestamp[24] = '\0';
if (success) {
printf("✅ %s: Published successfully (%.1fs)\n", relay_url, elapsed);
dprintf(log_fd, "[%s] ✅ ASYNC: %s published successfully (%.1fs)\n",
timestamp, relay_url, elapsed);
} else {
printf("❌ %s: Failed - %s (%.1fs)\n", relay_url, message ? message : "unknown error", elapsed);
dprintf(log_fd, "[%s] ❌ ASYNC: %s failed - %s (%.1fs)\n",
timestamp, relay_url, message ? message : "unknown error", elapsed);
}
// Show progress
printf(" Progress: %d/%d responses received\n", ctx->responses_received, ctx->total_relays);
if (ctx->responses_received >= ctx->total_relays) {
printf("\n🎉 All relays responded! Final result: %d/%d successful\n",
ctx->success_count, ctx->total_relays);
dprintf(log_fd, "[%s] 🎉 ASYNC: All relays responded - %d/%d successful\n\n",
timestamp, ctx->success_count, ctx->total_relays);
}
}
// Publish test event with async callbacks
void publish_event() {
if (!pool) {
printf("❌ Pool not started\n");
return;
}
printf("\n--- Publish Test Event ---\n");
// Generate random keypair
unsigned char private_key[32], public_key[32];
if (nostr_generate_keypair(private_key, public_key) != NOSTR_SUCCESS) {
printf("❌ Failed to generate keypair\n");
return;
}
// Get current timestamp
time_t now = time(NULL);
// Format content with date/time
char content[256];
struct tm* tm_info = localtime(&now);
strftime(content, sizeof(content), "Test post at %Y-%m-%d %H:%M:%S", tm_info);
// Create kind 1 event
cJSON* event = nostr_create_and_sign_event(1, content, NULL, private_key, now);
if (!event) {
printf("❌ Failed to create event\n");
return;
}
// Get relay URLs from pool
char** relay_urls = NULL;
nostr_pool_relay_status_t* statuses = NULL;
int relay_count = nostr_relay_pool_list_relays(pool, &relay_urls, &statuses);
if (relay_count <= 0) {
printf("❌ No relays in pool\n");
cJSON_Delete(event);
return;
}
printf("📤 Publishing event to %d relay(s)...\n", relay_count);
printf("Watch for real-time responses below:\n\n");
// Setup callback context
async_publish_context_t ctx = {0};
ctx.total_relays = relay_count;
ctx.start_time = time(NULL);
// Log the event
char* event_json = cJSON_Print(event);
char timestamp[26];
ctime_r(&now, timestamp);
timestamp[24] = '\0';
dprintf(log_fd, "[%s] 📤 Publishing test event\n", timestamp);
dprintf(log_fd, "Event: %s\n\n", event_json);
free(event_json);
// Publish using async function
int sent_count = nostr_relay_pool_publish_async(pool, (const char**)relay_urls,
relay_count, event,
async_publish_callback, &ctx);
if (sent_count > 0) {
printf("📡 Event sent to %d/%d relays, waiting for responses...\n\n",
sent_count, relay_count);
// Wait for all responses or timeout (10 seconds)
time_t wait_start = time(NULL);
while (ctx.responses_received < ctx.total_relays &&
(time(NULL) - wait_start) < 10) {
// Let the polling thread process messages
usleep(100000); // 100ms
}
if (ctx.responses_received < ctx.total_relays) {
printf("\n⏰ Timeout reached - %d/%d relays responded\n",
ctx.responses_received, ctx.total_relays);
}
} else {
printf("❌ Failed to send event to any relays\n");
}
// Cleanup
for (int i = 0; i < relay_count; i++) {
free(relay_urls[i]);
}
free(relay_urls);
free(statuses);
cJSON_Delete(event);
}
int main() {
// Setup logging to file
log_fd = open("pool.log", O_WRONLY | O_CREAT | O_TRUNC, 0644);
@@ -489,14 +646,14 @@ int main() {
break;
}
if (nostr_relay_pool_add_relay(pool, "wss://relay.laantungir.net") != NOSTR_SUCCESS) {
if (nostr_relay_pool_add_relay(pool, "ws://localhost:7555") != NOSTR_SUCCESS) {
printf("❌ Failed to add default relay\n");
nostr_relay_pool_destroy(pool);
pool = NULL;
break;
}
printf("✅ Pool started with wss://relay.laantungir.net\n");
printf("✅ Pool started with ws://localhost:7555\n");
now = time(NULL);
ctime_r(&now, timestamp);
@@ -544,13 +701,49 @@ int main() {
if (url && strlen(url) > 0) {
if (nostr_relay_pool_add_relay(pool, url) == NOSTR_SUCCESS) {
printf("✅ Relay added: %s\n", url);
printf("⏳ Attempting to connect...\n");
// Give it a moment to attempt connection
sleep(2);
// Check connection status and show any errors
nostr_pool_relay_status_t status = nostr_relay_pool_get_relay_status(pool, url);
const char* error_msg = nostr_relay_pool_get_relay_last_connection_error(pool, url);
switch (status) {
case NOSTR_POOL_RELAY_CONNECTED:
printf("🟢 Successfully connected to %s\n", url);
break;
case NOSTR_POOL_RELAY_CONNECTING:
printf("🟡 Still connecting to %s...\n", url);
break;
case NOSTR_POOL_RELAY_DISCONNECTED:
printf("⚪ Disconnected from %s\n", url);
if (error_msg) {
printf(" Last error: %s\n", error_msg);
}
break;
case NOSTR_POOL_RELAY_ERROR:
printf("🔴 Connection error for %s\n", url);
if (error_msg) {
printf(" Error details: %s\n", error_msg);
}
break;
default:
printf("❓ Unknown status for %s\n", url);
break;
}
now = time(NULL);
ctime_r(&now, timestamp);
timestamp[24] = '\0';
dprintf(log_fd, "[%s] Relay added: %s\n\n", timestamp, url);
dprintf(log_fd, "[%s] Relay added: %s (status: %d)\n", timestamp, url, status);
if (error_msg) {
dprintf(log_fd, " Connection error: %s\n", error_msg);
}
dprintf(log_fd, "\n");
} else {
printf("❌ Failed to add relay\n");
printf("❌ Failed to add relay to pool\n");
}
}
free(url);
@@ -655,7 +848,11 @@ int main() {
break;
}
case '9': // Exit
case '9': // Publish Event
publish_event();
break;
case '0': // Exit
running = 0;
break;