v0.4.2 - Implement NIP-11 Relay Information Document with event-based configuration - make relay info dynamically configurable via admin API
This commit is contained in:
191
src/config.c
191
src/config.c
@@ -99,19 +99,25 @@ static char g_temp_relay_privkey[65] = {0};
|
||||
static int get_cache_timeout(void) {
|
||||
char *no_cache = getenv("GINX_NO_CACHE");
|
||||
char *cache_timeout = getenv("GINX_CACHE_TIMEOUT");
|
||||
|
||||
|
||||
if (no_cache && strcmp(no_cache, "1") == 0) {
|
||||
return 0; // No caching
|
||||
}
|
||||
|
||||
|
||||
if (cache_timeout) {
|
||||
int timeout = atoi(cache_timeout);
|
||||
return (timeout >= 0) ? timeout : 300; // Use provided value or default
|
||||
}
|
||||
|
||||
|
||||
return 300; // Default 5 minutes
|
||||
}
|
||||
|
||||
// Helper function to safely return dynamically allocated string from static buffer
|
||||
static char* safe_strdup_from_static(const char* static_str) {
|
||||
if (!static_str) return NULL;
|
||||
return strdup(static_str);
|
||||
}
|
||||
|
||||
// Force cache refresh - invalidates current cache
|
||||
void force_config_cache_refresh(void) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
@@ -396,58 +402,61 @@ const char* get_config_value(const char* key) {
|
||||
if (!key) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Special fast path for frequently accessed keys via unified cache
|
||||
if (strcmp(key, "admin_pubkey") == 0) {
|
||||
return get_admin_pubkey_cached();
|
||||
const char* cached_value = get_admin_pubkey_cached();
|
||||
return safe_strdup_from_static(cached_value);
|
||||
}
|
||||
if (strcmp(key, "relay_pubkey") == 0) {
|
||||
return get_relay_pubkey_cached();
|
||||
const char* cached_value = get_relay_pubkey_cached();
|
||||
return safe_strdup_from_static(cached_value);
|
||||
}
|
||||
|
||||
|
||||
// For other keys, try config table first
|
||||
const char* table_value = get_config_value_from_table(key);
|
||||
if (table_value) {
|
||||
return table_value;
|
||||
}
|
||||
|
||||
|
||||
// Fallback to legacy event-based config for backward compatibility
|
||||
// Use unified cache buffer instead of static buffer
|
||||
|
||||
|
||||
if (!g_current_config) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// Look for key in current configuration tags
|
||||
cJSON* tags = cJSON_GetObjectItem(g_current_config, "tags");
|
||||
if (!tags || !cJSON_IsArray(tags)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
|
||||
|
||||
cJSON* tag = NULL;
|
||||
cJSON_ArrayForEach(tag, tags) {
|
||||
if (cJSON_IsArray(tag) && cJSON_GetArraySize(tag) >= 2) {
|
||||
cJSON* tag_key = cJSON_GetArrayItem(tag, 0);
|
||||
cJSON* tag_value = cJSON_GetArrayItem(tag, 1);
|
||||
|
||||
|
||||
if (tag_key && tag_value &&
|
||||
cJSON_IsString(tag_key) && cJSON_IsString(tag_value)) {
|
||||
|
||||
|
||||
if (strcmp(cJSON_GetStringValue(tag_key), key) == 0) {
|
||||
strncpy(g_unified_cache.temp_buffer, cJSON_GetStringValue(tag_value),
|
||||
sizeof(g_unified_cache.temp_buffer) - 1);
|
||||
g_unified_cache.temp_buffer[sizeof(g_unified_cache.temp_buffer) - 1] = '\0';
|
||||
const char* result = safe_strdup_from_static(g_unified_cache.temp_buffer);
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
return g_unified_cache.temp_buffer;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -456,14 +465,18 @@ int get_config_int(const char* key, int default_value) {
|
||||
if (!str_value) {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
|
||||
char* endptr;
|
||||
long val = strtol(str_value, &endptr, 10);
|
||||
|
||||
|
||||
if (endptr == str_value || *endptr != '\0') {
|
||||
// Free the dynamically allocated string
|
||||
free((char*)str_value);
|
||||
return default_value;
|
||||
}
|
||||
|
||||
|
||||
// Free the dynamically allocated string
|
||||
free((char*)str_value);
|
||||
return (int)val;
|
||||
}
|
||||
|
||||
@@ -472,18 +485,23 @@ int get_config_bool(const char* key, int default_value) {
|
||||
if (!str_value) {
|
||||
return default_value;
|
||||
}
|
||||
|
||||
if (strcasecmp(str_value, "true") == 0 ||
|
||||
strcasecmp(str_value, "yes") == 0 ||
|
||||
|
||||
int result;
|
||||
if (strcasecmp(str_value, "true") == 0 ||
|
||||
strcasecmp(str_value, "yes") == 0 ||
|
||||
strcasecmp(str_value, "1") == 0) {
|
||||
return 1;
|
||||
} else if (strcasecmp(str_value, "false") == 0 ||
|
||||
strcasecmp(str_value, "no") == 0 ||
|
||||
result = 1;
|
||||
} else if (strcasecmp(str_value, "false") == 0 ||
|
||||
strcasecmp(str_value, "no") == 0 ||
|
||||
strcasecmp(str_value, "0") == 0) {
|
||||
return 0;
|
||||
result = 0;
|
||||
} else {
|
||||
result = default_value;
|
||||
}
|
||||
|
||||
return default_value;
|
||||
|
||||
// Free the dynamically allocated string
|
||||
free((char*)str_value);
|
||||
return result;
|
||||
}
|
||||
|
||||
// ================================
|
||||
@@ -1063,33 +1081,38 @@ int startup_existing_relay(const char* relay_pubkey) {
|
||||
log_error("Invalid relay pubkey for existing relay startup");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
log_info("Starting existing relay...");
|
||||
printf(" Relay pubkey: %s\n", relay_pubkey);
|
||||
|
||||
|
||||
// Store relay pubkey in unified cache
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_pubkey, relay_pubkey, sizeof(g_unified_cache.relay_pubkey) - 1);
|
||||
g_unified_cache.relay_pubkey[sizeof(g_unified_cache.relay_pubkey) - 1] = '\0';
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
|
||||
|
||||
// Set database path
|
||||
char* db_name = get_database_name_from_relay_pubkey(relay_pubkey);
|
||||
if (!db_name) {
|
||||
log_error("Failed to generate database name");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
strncpy(g_database_path, db_name, sizeof(g_database_path) - 1);
|
||||
g_database_path[sizeof(g_database_path) - 1] = '\0';
|
||||
free(db_name);
|
||||
|
||||
|
||||
// Ensure default configuration values are populated (for any missing keys)
|
||||
if (populate_default_config_values() != 0) {
|
||||
log_warning("Failed to populate default config values for existing relay - continuing");
|
||||
}
|
||||
|
||||
// Configuration will be migrated from events to table after database initialization
|
||||
log_info("Configuration migration will be performed after database is available");
|
||||
|
||||
|
||||
// Load configuration event from database (after database is initialized)
|
||||
// This will be done in apply_configuration_from_database()
|
||||
|
||||
|
||||
log_success("Existing relay startup prepared");
|
||||
return 0;
|
||||
}
|
||||
@@ -1814,31 +1837,90 @@ int handle_configuration_event(cJSON* event, char* error_message, size_t error_s
|
||||
// Get value from config table
|
||||
const char* get_config_value_from_table(const char* key) {
|
||||
if (!g_db || !key) return NULL;
|
||||
|
||||
|
||||
const char* sql = "SELECT value FROM config WHERE key = ?";
|
||||
|
||||
|
||||
sqlite3_stmt* stmt;
|
||||
int rc = sqlite3_prepare_v2(g_db, sql, -1, &stmt, NULL);
|
||||
if (rc != SQLITE_OK) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
sqlite3_bind_text(stmt, 1, key, -1, SQLITE_STATIC);
|
||||
|
||||
|
||||
const char* result = NULL;
|
||||
|
||||
|
||||
if (sqlite3_step(stmt) == SQLITE_ROW) {
|
||||
const char* value = (char*)sqlite3_column_text(stmt, 0);
|
||||
if (value) {
|
||||
// Use unified cache buffer with thread safety
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.temp_buffer, value, sizeof(g_unified_cache.temp_buffer) - 1);
|
||||
g_unified_cache.temp_buffer[sizeof(g_unified_cache.temp_buffer) - 1] = '\0';
|
||||
result = g_unified_cache.temp_buffer;
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
// For NIP-11 fields, store in cache buffers but return dynamically allocated strings for consistency
|
||||
if (strcmp(key, "relay_name") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.name, value, sizeof(g_unified_cache.relay_info.name) - 1);
|
||||
g_unified_cache.relay_info.name[sizeof(g_unified_cache.relay_info.name) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "relay_description") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.description, value, sizeof(g_unified_cache.relay_info.description) - 1);
|
||||
g_unified_cache.relay_info.description[sizeof(g_unified_cache.relay_info.description) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "relay_contact") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.contact, value, sizeof(g_unified_cache.relay_info.contact) - 1);
|
||||
g_unified_cache.relay_info.contact[sizeof(g_unified_cache.relay_info.contact) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "relay_software") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.software, value, sizeof(g_unified_cache.relay_info.software) - 1);
|
||||
g_unified_cache.relay_info.software[sizeof(g_unified_cache.relay_info.software) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "relay_version") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.version, value, sizeof(g_unified_cache.relay_info.version) - 1);
|
||||
g_unified_cache.relay_info.version[sizeof(g_unified_cache.relay_info.version) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "supported_nips") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.supported_nips_str, value, sizeof(g_unified_cache.relay_info.supported_nips_str) - 1);
|
||||
g_unified_cache.relay_info.supported_nips_str[sizeof(g_unified_cache.relay_info.supported_nips_str) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "language_tags") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.language_tags_str, value, sizeof(g_unified_cache.relay_info.language_tags_str) - 1);
|
||||
g_unified_cache.relay_info.language_tags_str[sizeof(g_unified_cache.relay_info.language_tags_str) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "relay_countries") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.relay_countries_str, value, sizeof(g_unified_cache.relay_info.relay_countries_str) - 1);
|
||||
g_unified_cache.relay_info.relay_countries_str[sizeof(g_unified_cache.relay_info.relay_countries_str) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "posting_policy") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.posting_policy, value, sizeof(g_unified_cache.relay_info.posting_policy) - 1);
|
||||
g_unified_cache.relay_info.posting_policy[sizeof(g_unified_cache.relay_info.posting_policy) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else if (strcmp(key, "payments_url") == 0) {
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
strncpy(g_unified_cache.relay_info.payments_url, value, sizeof(g_unified_cache.relay_info.payments_url) - 1);
|
||||
g_unified_cache.relay_info.payments_url[sizeof(g_unified_cache.relay_info.payments_url) - 1] = '\0';
|
||||
result = strdup(value); // Return dynamically allocated copy
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
} else {
|
||||
// For other keys, return a dynamically allocated string to prevent buffer reuse
|
||||
result = strdup(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sqlite3_finalize(stmt);
|
||||
return result;
|
||||
}
|
||||
@@ -3906,12 +3988,17 @@ const char* get_config_value_hybrid(const char* key) {
|
||||
if (is_config_table_ready()) {
|
||||
const char* table_value = get_config_value_from_table(key);
|
||||
if (table_value) {
|
||||
return table_value;
|
||||
return table_value; // Already dynamically allocated
|
||||
}
|
||||
}
|
||||
|
||||
// Fall back to event-based config
|
||||
return get_config_value(key);
|
||||
|
||||
// Fall back to event-based config, but ensure it's dynamically allocated
|
||||
const char* fallback_value = get_config_value(key);
|
||||
if (fallback_value) {
|
||||
return strdup(fallback_value); // Make a copy since fallback might be static
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if config table is ready
|
||||
|
||||
Reference in New Issue
Block a user