v0.1.1 - -release
This commit is contained in:
435
src/main.c
435
src/main.c
@@ -28,6 +28,13 @@
|
||||
#define SUBSCRIPTION_ID_MAX_LENGTH 64
|
||||
#define CLIENT_IP_MAX_LENGTH 64
|
||||
|
||||
// NIP-11 relay information configuration
|
||||
#define RELAY_NAME_MAX_LENGTH 128
|
||||
#define RELAY_DESCRIPTION_MAX_LENGTH 1024
|
||||
#define RELAY_URL_MAX_LENGTH 256
|
||||
#define RELAY_CONTACT_MAX_LENGTH 128
|
||||
#define RELAY_PUBKEY_MAX_LENGTH 65 // 64 hex chars + null terminator
|
||||
|
||||
// Color constants for logging
|
||||
#define RED "\033[31m"
|
||||
#define GREEN "\033[32m"
|
||||
@@ -41,6 +48,32 @@ static sqlite3* g_db = NULL;
|
||||
static int g_server_running = 1;
|
||||
static struct lws_context *ws_context = NULL;
|
||||
|
||||
// NIP-11 relay information structure
|
||||
struct relay_info {
|
||||
char name[RELAY_NAME_MAX_LENGTH];
|
||||
char description[RELAY_DESCRIPTION_MAX_LENGTH];
|
||||
char banner[RELAY_URL_MAX_LENGTH];
|
||||
char icon[RELAY_URL_MAX_LENGTH];
|
||||
char pubkey[RELAY_PUBKEY_MAX_LENGTH];
|
||||
char contact[RELAY_CONTACT_MAX_LENGTH];
|
||||
char software[RELAY_URL_MAX_LENGTH];
|
||||
char version[64];
|
||||
char privacy_policy[RELAY_URL_MAX_LENGTH];
|
||||
char terms_of_service[RELAY_URL_MAX_LENGTH];
|
||||
cJSON* supported_nips; // Array of supported NIP numbers
|
||||
cJSON* limitation; // Server limitations object
|
||||
cJSON* retention; // Event retention policies array
|
||||
cJSON* relay_countries; // Array of country codes
|
||||
cJSON* language_tags; // Array of language tags
|
||||
cJSON* tags; // Array of content tags
|
||||
char posting_policy[RELAY_URL_MAX_LENGTH];
|
||||
cJSON* fees; // Payment fee structure
|
||||
char payments_url[RELAY_URL_MAX_LENGTH];
|
||||
};
|
||||
|
||||
// Global relay information instance
|
||||
static struct relay_info g_relay_info = {0};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -151,6 +184,12 @@ int mark_event_as_deleted(const char* event_id, const char* deletion_event_id, c
|
||||
// Forward declaration for database functions
|
||||
int store_event(cJSON* event);
|
||||
|
||||
// Forward declarations for NIP-11 relay information handling
|
||||
void init_relay_info();
|
||||
void cleanup_relay_info();
|
||||
cJSON* generate_relay_info_json();
|
||||
int handle_nip11_http_request(struct lws* wsi, const char* accept_header);
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -922,8 +961,11 @@ int handle_deletion_request(cJSON* event, char* error_message, size_t error_size
|
||||
}
|
||||
|
||||
const char* requester_pubkey = cJSON_GetStringValue(pubkey_obj);
|
||||
// Extract deletion event ID and reason (for potential logging)
|
||||
const char* deletion_event_id = cJSON_GetStringValue(event_id_obj);
|
||||
const char* reason = content_obj ? cJSON_GetStringValue(content_obj) : "";
|
||||
(void)deletion_event_id; // Mark as intentionally unused for now
|
||||
(void)reason; // Mark as intentionally unused for now
|
||||
long deletion_timestamp = (long)cJSON_GetNumberValue(created_at_obj);
|
||||
|
||||
if (!cJSON_IsArray(tags_obj)) {
|
||||
@@ -1011,7 +1053,7 @@ int handle_deletion_request(cJSON* event, char* error_message, size_t error_size
|
||||
snprintf(debug_msg, sizeof(debug_msg), "Deletion request processed: %d events deleted", deleted_count);
|
||||
log_info(debug_msg);
|
||||
|
||||
snprintf(error_message, error_size, ""); // Success
|
||||
error_message[0] = '\0'; // Success - empty error message
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1176,6 +1218,352 @@ int mark_event_as_deleted(const char* event_id, const char* deletion_event_id, c
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NIP-11 RELAY INFORMATION DOCUMENT
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Initialize relay information with default values
|
||||
void init_relay_info() {
|
||||
// Set default relay information
|
||||
strncpy(g_relay_info.name, "C Nostr Relay", sizeof(g_relay_info.name) - 1);
|
||||
strncpy(g_relay_info.description, "A high-performance Nostr relay implemented in C with SQLite storage", sizeof(g_relay_info.description) - 1);
|
||||
strncpy(g_relay_info.software, "https://github.com/teknari/c-relay", sizeof(g_relay_info.software) - 1);
|
||||
strncpy(g_relay_info.version, "0.1.0", sizeof(g_relay_info.version) - 1);
|
||||
|
||||
// Initialize supported NIPs array
|
||||
g_relay_info.supported_nips = cJSON_CreateArray();
|
||||
if (g_relay_info.supported_nips) {
|
||||
cJSON_AddItemToArray(g_relay_info.supported_nips, cJSON_CreateNumber(1)); // NIP-01: Basic protocol
|
||||
cJSON_AddItemToArray(g_relay_info.supported_nips, cJSON_CreateNumber(9)); // NIP-09: Event deletion
|
||||
cJSON_AddItemToArray(g_relay_info.supported_nips, cJSON_CreateNumber(11)); // NIP-11: Relay information
|
||||
cJSON_AddItemToArray(g_relay_info.supported_nips, cJSON_CreateNumber(15)); // NIP-15: EOSE
|
||||
cJSON_AddItemToArray(g_relay_info.supported_nips, cJSON_CreateNumber(20)); // NIP-20: Command results
|
||||
}
|
||||
|
||||
// Initialize server limitations
|
||||
g_relay_info.limitation = cJSON_CreateObject();
|
||||
if (g_relay_info.limitation) {
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "max_message_length", 16384);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "max_subscriptions", MAX_SUBSCRIPTIONS_PER_CLIENT);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "max_limit", 5000);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "max_subid_length", SUBSCRIPTION_ID_MAX_LENGTH);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "max_event_tags", 100);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "max_content_length", 8196);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "min_pow_difficulty", 0);
|
||||
cJSON_AddBoolToObject(g_relay_info.limitation, "auth_required", cJSON_False);
|
||||
cJSON_AddBoolToObject(g_relay_info.limitation, "payment_required", cJSON_False);
|
||||
cJSON_AddBoolToObject(g_relay_info.limitation, "restricted_writes", cJSON_False);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "created_at_lower_limit", 0);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "created_at_upper_limit", 2147483647);
|
||||
cJSON_AddNumberToObject(g_relay_info.limitation, "default_limit", 500);
|
||||
}
|
||||
|
||||
// Initialize empty retention policies (can be configured later)
|
||||
g_relay_info.retention = cJSON_CreateArray();
|
||||
|
||||
// Initialize language tags - set to global for now
|
||||
g_relay_info.language_tags = cJSON_CreateArray();
|
||||
if (g_relay_info.language_tags) {
|
||||
cJSON_AddItemToArray(g_relay_info.language_tags, cJSON_CreateString("*"));
|
||||
}
|
||||
|
||||
// Initialize relay countries - set to global for now
|
||||
g_relay_info.relay_countries = cJSON_CreateArray();
|
||||
if (g_relay_info.relay_countries) {
|
||||
cJSON_AddItemToArray(g_relay_info.relay_countries, cJSON_CreateString("*"));
|
||||
}
|
||||
|
||||
// Initialize content tags as empty array
|
||||
g_relay_info.tags = cJSON_CreateArray();
|
||||
|
||||
// Initialize fees as empty object (no payment required by default)
|
||||
g_relay_info.fees = cJSON_CreateObject();
|
||||
|
||||
log_success("Relay information initialized with default values");
|
||||
}
|
||||
|
||||
// Clean up relay information JSON objects
|
||||
void cleanup_relay_info() {
|
||||
if (g_relay_info.supported_nips) {
|
||||
cJSON_Delete(g_relay_info.supported_nips);
|
||||
g_relay_info.supported_nips = NULL;
|
||||
}
|
||||
if (g_relay_info.limitation) {
|
||||
cJSON_Delete(g_relay_info.limitation);
|
||||
g_relay_info.limitation = NULL;
|
||||
}
|
||||
if (g_relay_info.retention) {
|
||||
cJSON_Delete(g_relay_info.retention);
|
||||
g_relay_info.retention = NULL;
|
||||
}
|
||||
if (g_relay_info.language_tags) {
|
||||
cJSON_Delete(g_relay_info.language_tags);
|
||||
g_relay_info.language_tags = NULL;
|
||||
}
|
||||
if (g_relay_info.relay_countries) {
|
||||
cJSON_Delete(g_relay_info.relay_countries);
|
||||
g_relay_info.relay_countries = NULL;
|
||||
}
|
||||
if (g_relay_info.tags) {
|
||||
cJSON_Delete(g_relay_info.tags);
|
||||
g_relay_info.tags = NULL;
|
||||
}
|
||||
if (g_relay_info.fees) {
|
||||
cJSON_Delete(g_relay_info.fees);
|
||||
g_relay_info.fees = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate NIP-11 compliant JSON document
|
||||
cJSON* generate_relay_info_json() {
|
||||
cJSON* info = cJSON_CreateObject();
|
||||
if (!info) {
|
||||
log_error("Failed to create relay info JSON object");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add basic relay information
|
||||
if (strlen(g_relay_info.name) > 0) {
|
||||
cJSON_AddStringToObject(info, "name", g_relay_info.name);
|
||||
}
|
||||
if (strlen(g_relay_info.description) > 0) {
|
||||
cJSON_AddStringToObject(info, "description", g_relay_info.description);
|
||||
}
|
||||
if (strlen(g_relay_info.banner) > 0) {
|
||||
cJSON_AddStringToObject(info, "banner", g_relay_info.banner);
|
||||
}
|
||||
if (strlen(g_relay_info.icon) > 0) {
|
||||
cJSON_AddStringToObject(info, "icon", g_relay_info.icon);
|
||||
}
|
||||
if (strlen(g_relay_info.pubkey) > 0) {
|
||||
cJSON_AddStringToObject(info, "pubkey", g_relay_info.pubkey);
|
||||
}
|
||||
if (strlen(g_relay_info.contact) > 0) {
|
||||
cJSON_AddStringToObject(info, "contact", g_relay_info.contact);
|
||||
}
|
||||
|
||||
// Add supported NIPs
|
||||
if (g_relay_info.supported_nips) {
|
||||
cJSON_AddItemToObject(info, "supported_nips", cJSON_Duplicate(g_relay_info.supported_nips, 1));
|
||||
}
|
||||
|
||||
// Add software information
|
||||
if (strlen(g_relay_info.software) > 0) {
|
||||
cJSON_AddStringToObject(info, "software", g_relay_info.software);
|
||||
}
|
||||
if (strlen(g_relay_info.version) > 0) {
|
||||
cJSON_AddStringToObject(info, "version", g_relay_info.version);
|
||||
}
|
||||
|
||||
// Add policies
|
||||
if (strlen(g_relay_info.privacy_policy) > 0) {
|
||||
cJSON_AddStringToObject(info, "privacy_policy", g_relay_info.privacy_policy);
|
||||
}
|
||||
if (strlen(g_relay_info.terms_of_service) > 0) {
|
||||
cJSON_AddStringToObject(info, "terms_of_service", g_relay_info.terms_of_service);
|
||||
}
|
||||
if (strlen(g_relay_info.posting_policy) > 0) {
|
||||
cJSON_AddStringToObject(info, "posting_policy", g_relay_info.posting_policy);
|
||||
}
|
||||
|
||||
// Add server limitations
|
||||
if (g_relay_info.limitation) {
|
||||
cJSON_AddItemToObject(info, "limitation", cJSON_Duplicate(g_relay_info.limitation, 1));
|
||||
}
|
||||
|
||||
// Add retention policies if configured
|
||||
if (g_relay_info.retention && cJSON_GetArraySize(g_relay_info.retention) > 0) {
|
||||
cJSON_AddItemToObject(info, "retention", cJSON_Duplicate(g_relay_info.retention, 1));
|
||||
}
|
||||
|
||||
// Add geographical and language information
|
||||
if (g_relay_info.relay_countries) {
|
||||
cJSON_AddItemToObject(info, "relay_countries", cJSON_Duplicate(g_relay_info.relay_countries, 1));
|
||||
}
|
||||
if (g_relay_info.language_tags) {
|
||||
cJSON_AddItemToObject(info, "language_tags", cJSON_Duplicate(g_relay_info.language_tags, 1));
|
||||
}
|
||||
if (g_relay_info.tags && cJSON_GetArraySize(g_relay_info.tags) > 0) {
|
||||
cJSON_AddItemToObject(info, "tags", cJSON_Duplicate(g_relay_info.tags, 1));
|
||||
}
|
||||
|
||||
// Add payment information if configured
|
||||
if (strlen(g_relay_info.payments_url) > 0) {
|
||||
cJSON_AddStringToObject(info, "payments_url", g_relay_info.payments_url);
|
||||
}
|
||||
if (g_relay_info.fees && cJSON_GetObjectItem(g_relay_info.fees, "admission")) {
|
||||
cJSON_AddItemToObject(info, "fees", cJSON_Duplicate(g_relay_info.fees, 1));
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// Handle NIP-11 HTTP request
|
||||
int handle_nip11_http_request(struct lws* wsi, const char* accept_header) {
|
||||
log_info("Handling NIP-11 relay information request");
|
||||
|
||||
// Check if client accepts application/nostr+json
|
||||
int accepts_nostr_json = 0;
|
||||
if (accept_header) {
|
||||
if (strstr(accept_header, "application/nostr+json") != NULL) {
|
||||
accepts_nostr_json = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!accepts_nostr_json) {
|
||||
log_warning("HTTP request without proper Accept header for NIP-11");
|
||||
// Return 406 Not Acceptable
|
||||
unsigned char buf[LWS_PRE + 256];
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
unsigned char *start = p;
|
||||
unsigned char *end = &buf[sizeof(buf) - 1];
|
||||
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char*)"text/plain", 10, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_content_length(wsi, 0, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_finalize_http_header(wsi, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
return -1; // Close connection
|
||||
}
|
||||
|
||||
// Generate relay information JSON
|
||||
cJSON* info_json = generate_relay_info_json();
|
||||
if (!info_json) {
|
||||
log_error("Failed to generate relay info JSON");
|
||||
unsigned char buf[LWS_PRE + 256];
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
unsigned char *start = p;
|
||||
unsigned char *end = &buf[sizeof(buf) - 1];
|
||||
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char*)"text/plain", 10, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_content_length(wsi, 0, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_finalize_http_header(wsi, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char* json_string = cJSON_Print(info_json);
|
||||
cJSON_Delete(info_json);
|
||||
|
||||
if (!json_string) {
|
||||
log_error("Failed to serialize relay info JSON");
|
||||
unsigned char buf[LWS_PRE + 256];
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
unsigned char *start = p;
|
||||
unsigned char *end = &buf[sizeof(buf) - 1];
|
||||
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_INTERNAL_SERVER_ERROR, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char*)"text/plain", 10, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_content_length(wsi, 0, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
if (lws_finalize_http_header(wsi, &p, end)) {
|
||||
return -1;
|
||||
}
|
||||
lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t json_len = strlen(json_string);
|
||||
|
||||
// Prepare HTTP response with CORS headers
|
||||
unsigned char buf[LWS_PRE + 1024];
|
||||
unsigned char *p = &buf[LWS_PRE];
|
||||
unsigned char *start = p;
|
||||
unsigned char *end = &buf[sizeof(buf) - 1];
|
||||
|
||||
// Add status
|
||||
if (lws_add_http_header_status(wsi, HTTP_STATUS_OK, &p, end)) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add content type
|
||||
if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
|
||||
(unsigned char*)"application/nostr+json", 22, &p, end)) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add content length
|
||||
if (lws_add_http_header_content_length(wsi, json_len, &p, end)) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add CORS headers as required by NIP-11
|
||||
if (lws_add_http_header_by_name(wsi, (unsigned char*)"access-control-allow-origin:",
|
||||
(unsigned char*)"*", 1, &p, end)) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_by_name(wsi, (unsigned char*)"access-control-allow-headers:",
|
||||
(unsigned char*)"content-type, accept", 20, &p, end)) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
if (lws_add_http_header_by_name(wsi, (unsigned char*)"access-control-allow-methods:",
|
||||
(unsigned char*)"GET, OPTIONS", 12, &p, end)) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Finalize headers
|
||||
if (lws_finalize_http_header(wsi, &p, end)) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write headers
|
||||
if (lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS) < 0) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write JSON body
|
||||
unsigned char *json_buf = malloc(LWS_PRE + json_len);
|
||||
if (!json_buf) {
|
||||
free(json_string);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(json_buf + LWS_PRE, json_string, json_len);
|
||||
if (lws_write(wsi, json_buf + LWS_PRE, json_len, LWS_WRITE_HTTP) < 0) {
|
||||
free(json_string);
|
||||
free(json_buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(json_buf);
|
||||
|
||||
free(json_string);
|
||||
log_success("NIP-11 relay information served successfully");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DATABASE FUNCTIONS
|
||||
@@ -1843,14 +2231,14 @@ int handle_event_message(cJSON* event, char* error_message, size_t error_size) {
|
||||
}
|
||||
} else if (event_type == EVENT_TYPE_EPHEMERAL) {
|
||||
// Ephemeral events should not be stored
|
||||
snprintf(error_message, error_size, ""); // Success but no storage
|
||||
error_message[0] = '\0'; // Success but no storage - empty error message
|
||||
return 0; // Accept but don't store
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5: Store event in database
|
||||
if (store_event(event) == 0) {
|
||||
snprintf(error_message, error_size, ""); // Success
|
||||
error_message[0] = '\0'; // Success - empty error message
|
||||
log_success("Event validated and stored successfully");
|
||||
return 0;
|
||||
}
|
||||
@@ -1873,6 +2261,43 @@ static int nostr_relay_callback(struct lws *wsi, enum lws_callback_reasons reaso
|
||||
struct per_session_data *pss = (struct per_session_data *)user;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
// Handle NIP-11 relay information requests (HTTP GET to root path)
|
||||
{
|
||||
char *requested_uri = (char *)in;
|
||||
log_info("HTTP request received");
|
||||
|
||||
// Check if this is a GET request to the root path
|
||||
if (strcmp(requested_uri, "/") == 0) {
|
||||
// Get Accept header
|
||||
char accept_header[256] = {0};
|
||||
int header_len = lws_hdr_copy(wsi, accept_header, sizeof(accept_header) - 1, WSI_TOKEN_HTTP_ACCEPT);
|
||||
|
||||
if (header_len > 0) {
|
||||
accept_header[header_len] = '\0';
|
||||
|
||||
// Handle NIP-11 request
|
||||
if (handle_nip11_http_request(wsi, accept_header) == 0) {
|
||||
return 0; // Successfully handled
|
||||
}
|
||||
} else {
|
||||
log_warning("HTTP request without Accept header");
|
||||
}
|
||||
|
||||
// Return 404 for other requests
|
||||
lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Return 404 for non-root paths
|
||||
lws_return_http_status(wsi, HTTP_STATUS_NOT_FOUND, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
case LWS_CALLBACK_HTTP_WRITEABLE:
|
||||
// HTTP response continuation if needed
|
||||
break;
|
||||
|
||||
case LWS_CALLBACK_ESTABLISHED:
|
||||
log_info("WebSocket connection established");
|
||||
memset(pss, 0, sizeof(*pss));
|
||||
@@ -2175,12 +2600,16 @@ int main(int argc, char* argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize NIP-11 relay information
|
||||
init_relay_info();
|
||||
|
||||
log_info("Starting relay server...");
|
||||
|
||||
// Start WebSocket Nostr relay server
|
||||
int result = start_websocket_relay();
|
||||
|
||||
// Cleanup
|
||||
cleanup_relay_info();
|
||||
nostr_cleanup();
|
||||
close_database();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user