/* * Simple WebSocket Debug Tool for NIP-17 Testing * * Connects to a relay and sends a subscription request to see what responses we get. */ #define _GNU_SOURCE #define _POSIX_C_SOURCE 200809L #include "../nostr_core/nostr_core.h" #include "../nostr_websocket/nostr_websocket_tls.h" #include #include #include #include #include int main(int argc, char* argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s [event_id]\n", argv[0]); fprintf(stderr, "Example: websocket_debug wss://relay.laantungir.net 06cdf2cdd095ddb1ebe15d5b3c736b27a34de2683e847b871fe37d86ac998772\n"); return 1; } const char* relay_url = argv[1]; const char* event_id = (argc >= 3) ? argv[2] : NULL; printf("🔍 WebSocket Debug Tool\n"); printf("=======================\n"); printf("Relay: %s\n", relay_url); if (event_id) { printf("Looking for event: %s\n", event_id); } printf("\n"); // Initialize crypto if (nostr_init() != NOSTR_SUCCESS) { fprintf(stderr, "Failed to initialize crypto\n"); return 1; } // Connect to relay printf("🔌 Connecting to relay...\n"); nostr_ws_client_t* client = nostr_ws_connect(relay_url); if (!client) { fprintf(stderr, "Failed to connect to relay - nostr_ws_connect returned NULL\n"); return 1; } // Check initial state nostr_ws_state_t initial_state = nostr_ws_get_state(client); printf("Initial connection state: %d\n", (int)initial_state); // Wait for connection time_t start_time = time(NULL); while (time(NULL) - start_time < 10) { // 10 second timeout nostr_ws_state_t state = nostr_ws_get_state(client); if (state == NOSTR_WS_CONNECTED) { printf("✅ Connected!\n"); break; } else if (state == NOSTR_WS_ERROR) { fprintf(stderr, "❌ Connection failed\n"); nostr_ws_close(client); return 1; } usleep(100000); // 100ms } if (nostr_ws_get_state(client) != NOSTR_WS_CONNECTED) { fprintf(stderr, "❌ Connection timeout\n"); nostr_ws_close(client); return 1; } // Send subscription request printf("📡 Sending subscription request...\n"); // Create filter for kind 1059 events cJSON* filter = cJSON_CreateObject(); cJSON* kinds = cJSON_CreateArray(); cJSON_AddItemToArray(kinds, cJSON_CreateNumber(1059)); cJSON_AddItemToObject(filter, "kinds", kinds); // If we have a specific event ID, add it to the filter if (event_id) { cJSON* ids = cJSON_CreateArray(); cJSON_AddItemToArray(ids, cJSON_CreateString(event_id)); cJSON_AddItemToObject(filter, "ids", ids); } char* filter_json = cJSON_PrintUnformatted(filter); printf("Filter: %s\n", filter_json); // Send REQ message char subscription_id[32]; snprintf(subscription_id, sizeof(subscription_id), "debug_%ld", time(NULL)); if (nostr_relay_send_req(client, subscription_id, filter) < 0) { fprintf(stderr, "Failed to send subscription request\n"); cJSON_Delete(filter); free(filter_json); nostr_ws_close(client); return 1; } cJSON_Delete(filter); free(filter_json); printf("✅ Subscription sent (ID: %s)\n", subscription_id); printf("⏳ Listening for responses (30 seconds)...\n"); printf("Press Ctrl+C to stop\n\n"); // Listen for responses start_time = time(NULL); int message_count = 0; while (time(NULL) - start_time < 30) { // 30 second timeout char buffer[16384]; int len = nostr_ws_receive(client, buffer, sizeof(buffer) - 1, 1000); // 1 second timeout if (len > 0) { buffer[len] = '\0'; message_count++; printf("📨 Message %d:\n", message_count); printf("%s\n", buffer); // Parse the message char* msg_type = NULL; cJSON* parsed = NULL; if (nostr_parse_relay_message(buffer, &msg_type, &parsed) == 0) { if (msg_type && strcmp(msg_type, "EVENT") == 0) { printf(" → EVENT received\n"); if (cJSON_IsArray(parsed) && cJSON_GetArraySize(parsed) >= 3) { cJSON* event = cJSON_GetArrayItem(parsed, 2); if (event) { cJSON* kind_item = cJSON_GetObjectItem(event, "kind"); cJSON* id_item = cJSON_GetObjectItem(event, "id"); if (kind_item && cJSON_IsNumber(kind_item)) { printf(" → Kind: %d\n", (int)cJSON_GetNumberValue(kind_item)); } if (id_item && cJSON_IsString(id_item)) { printf(" → ID: %.12s...\n", cJSON_GetStringValue(id_item)); } } } } else if (msg_type && strcmp(msg_type, "EOSE") == 0) { printf(" → EOSE (End of Stored Events)\n"); } else if (msg_type && strcmp(msg_type, "NOTICE") == 0) { printf(" → NOTICE from relay\n"); if (cJSON_IsArray(parsed) && cJSON_GetArraySize(parsed) >= 2) { cJSON* notice_msg = cJSON_GetArrayItem(parsed, 1); if (notice_msg && cJSON_IsString(notice_msg)) { printf(" → Message: %s\n", cJSON_GetStringValue(notice_msg)); } } } else if (msg_type) { printf(" → %s\n", msg_type); } if (msg_type) free(msg_type); if (parsed) cJSON_Delete(parsed); } printf("\n"); } else if (len < 0) { printf("❌ Receive error\n"); break; } // Small delay to prevent busy waiting usleep(10000); // 10ms } printf("📊 Total messages received: %d\n", message_count); // Send CLOSE message printf("🔌 Closing subscription...\n"); nostr_relay_send_close(client, subscription_id); // Close connection nostr_ws_close(client); nostr_cleanup(); printf("✅ Done\n"); return 0; }