Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80b15e16e2 |
18
README.md
18
README.md
@@ -116,6 +116,24 @@ All commands are sent as NIP-44 encrypted JSON arrays in the event content. The
|
||||
- `pow_min_difficulty`: Minimum proof-of-work difficulty
|
||||
- `nip40_expiration_enabled`: Enable event expiration (`true`/`false`)
|
||||
|
||||
### Dynamic Configuration Updates
|
||||
|
||||
C-Relay supports **dynamic configuration updates** without requiring a restart for most settings. Configuration parameters are categorized as either **dynamic** (can be updated immediately) or **restart-required** (require relay restart to take effect).
|
||||
|
||||
**Dynamic Configuration Parameters (No Restart Required):**
|
||||
- All relay information (NIP-11) settings: `relay_name`, `relay_description`, `relay_contact`, `relay_software`, `relay_version`, `supported_nips`, `language_tags`, `relay_countries`, `posting_policy`, `payments_url`
|
||||
- Authentication settings: `auth_enabled`, `nip42_auth_required`, `nip42_auth_required_kinds`, `nip42_challenge_timeout`
|
||||
- Subscription limits: `max_subscriptions_per_client`, `max_total_subscriptions`
|
||||
- Event validation limits: `max_event_tags`, `max_content_length`, `max_message_length`
|
||||
- Proof of Work settings: `pow_min_difficulty`, `pow_mode`
|
||||
- Event expiration settings: `nip40_expiration_enabled`, `nip40_expiration_strict`, `nip40_expiration_filter`, `nip40_expiration_grace_period`
|
||||
|
||||
**Restart-Required Configuration Parameters:**
|
||||
- Connection settings: `max_connections`, `relay_port`
|
||||
- Database and core system settings
|
||||
|
||||
When updating configuration, the admin API response will indicate whether a restart is required for each parameter. Dynamic updates take effect immediately and are reflected in NIP-11 relay information documents without restart.
|
||||
|
||||
### Response Format
|
||||
|
||||
All admin commands return **signed EVENT responses** via WebSocket following standard Nostr protocol. Responses use JSON content with structured data.
|
||||
|
||||
197
src/config.c
197
src/config.c
@@ -127,40 +127,119 @@ void force_config_cache_refresh(void) {
|
||||
log_info("Configuration cache forcibly invalidated");
|
||||
}
|
||||
|
||||
// Update specific cache value without full refresh
|
||||
int update_cache_value(const char* key, const char* value) {
|
||||
if (!key || !value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_unified_cache.cache_lock);
|
||||
|
||||
// Update specific cache fields
|
||||
if (strcmp(key, "admin_pubkey") == 0) {
|
||||
strncpy(g_unified_cache.admin_pubkey, value, sizeof(g_unified_cache.admin_pubkey) - 1);
|
||||
g_unified_cache.admin_pubkey[sizeof(g_unified_cache.admin_pubkey) - 1] = '\0';
|
||||
} else if (strcmp(key, "relay_pubkey") == 0) {
|
||||
strncpy(g_unified_cache.relay_pubkey, value, sizeof(g_unified_cache.relay_pubkey) - 1);
|
||||
g_unified_cache.relay_pubkey[sizeof(g_unified_cache.relay_pubkey) - 1] = '\0';
|
||||
} else if (strcmp(key, "auth_required") == 0) {
|
||||
g_unified_cache.auth_required = (strcmp(value, "true") == 0) ? 1 : 0;
|
||||
} else if (strcmp(key, "admin_enabled") == 0) {
|
||||
g_unified_cache.admin_enabled = (strcmp(value, "true") == 0) ? 1 : 0;
|
||||
} else if (strcmp(key, "max_file_size") == 0) {
|
||||
g_unified_cache.max_file_size = atol(value);
|
||||
} else if (strcmp(key, "nip42_mode") == 0) {
|
||||
if (strcmp(value, "disabled") == 0) {
|
||||
g_unified_cache.nip42_mode = 0;
|
||||
} else if (strcmp(value, "required") == 0) {
|
||||
g_unified_cache.nip42_mode = 2;
|
||||
} else {
|
||||
g_unified_cache.nip42_mode = 1; // Optional/enabled
|
||||
}
|
||||
} else if (strcmp(key, "nip42_challenge_timeout") == 0) {
|
||||
g_unified_cache.nip42_challenge_timeout = atoi(value);
|
||||
} else if (strcmp(key, "nip42_time_tolerance") == 0) {
|
||||
g_unified_cache.nip42_time_tolerance = atoi(value);
|
||||
} else {
|
||||
// For NIP-11 relay info fields, update the cache buffers
|
||||
if (strcmp(key, "relay_name") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "relay_description") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "relay_contact") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "relay_software") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "relay_version") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "supported_nips") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "language_tags") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "relay_countries") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "posting_policy") == 0) {
|
||||
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';
|
||||
} else if (strcmp(key, "payments_url") == 0) {
|
||||
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';
|
||||
}
|
||||
}
|
||||
|
||||
// Reset cache expiration to extend validity
|
||||
int cache_timeout = get_cache_timeout();
|
||||
g_unified_cache.cache_expires = time(NULL) + cache_timeout;
|
||||
|
||||
pthread_mutex_unlock(&g_unified_cache.cache_lock);
|
||||
|
||||
log_info("Updated specific cache value");
|
||||
printf(" Key: %s\n", key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Refresh unified cache from database
|
||||
static int refresh_unified_cache_from_table(void) {
|
||||
if (!g_db) {
|
||||
log_error("Database not available for cache refresh");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Clear cache
|
||||
memset(&g_unified_cache, 0, sizeof(g_unified_cache));
|
||||
g_unified_cache.cache_lock = (pthread_mutex_t)PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
// Load critical config values from table
|
||||
const char* admin_pubkey = get_config_value_from_table("admin_pubkey");
|
||||
if (admin_pubkey) {
|
||||
strncpy(g_unified_cache.admin_pubkey, admin_pubkey, sizeof(g_unified_cache.admin_pubkey) - 1);
|
||||
g_unified_cache.admin_pubkey[sizeof(g_unified_cache.admin_pubkey) - 1] = '\0';
|
||||
}
|
||||
|
||||
|
||||
const char* relay_pubkey = get_config_value_from_table("relay_pubkey");
|
||||
if (relay_pubkey) {
|
||||
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';
|
||||
}
|
||||
|
||||
|
||||
// Load auth-related config
|
||||
const char* auth_required = get_config_value_from_table("auth_required");
|
||||
g_unified_cache.auth_required = (auth_required && strcmp(auth_required, "true") == 0) ? 1 : 0;
|
||||
|
||||
|
||||
const char* admin_enabled = get_config_value_from_table("admin_enabled");
|
||||
g_unified_cache.admin_enabled = (admin_enabled && strcmp(admin_enabled, "true") == 0) ? 1 : 0;
|
||||
|
||||
|
||||
const char* max_file_size = get_config_value_from_table("max_file_size");
|
||||
g_unified_cache.max_file_size = max_file_size ? atol(max_file_size) : 104857600; // 100MB default
|
||||
|
||||
|
||||
const char* nip42_mode = get_config_value_from_table("nip42_mode");
|
||||
if (nip42_mode) {
|
||||
if (strcmp(nip42_mode, "disabled") == 0) {
|
||||
@@ -173,18 +252,18 @@ static int refresh_unified_cache_from_table(void) {
|
||||
} else {
|
||||
g_unified_cache.nip42_mode = 1; // Default to optional/enabled
|
||||
}
|
||||
|
||||
|
||||
const char* challenge_timeout = get_config_value_from_table("nip42_challenge_timeout");
|
||||
g_unified_cache.nip42_challenge_timeout = challenge_timeout ? atoi(challenge_timeout) : 600;
|
||||
|
||||
|
||||
const char* time_tolerance = get_config_value_from_table("nip42_time_tolerance");
|
||||
g_unified_cache.nip42_time_tolerance = time_tolerance ? atoi(time_tolerance) : 300;
|
||||
|
||||
|
||||
// Set cache expiration
|
||||
int cache_timeout = get_cache_timeout();
|
||||
g_unified_cache.cache_expires = time(NULL) + cache_timeout;
|
||||
g_unified_cache.cache_valid = 1;
|
||||
|
||||
|
||||
log_info("Unified configuration cache refreshed from database");
|
||||
return 0;
|
||||
}
|
||||
@@ -1980,12 +2059,12 @@ int update_config_in_table(const char* key, const char* value) {
|
||||
// Populate default config values
|
||||
int populate_default_config_values(void) {
|
||||
log_info("Populating default configuration values in table...");
|
||||
|
||||
|
||||
// Add all default configuration values to the table
|
||||
for (size_t i = 0; i < DEFAULT_CONFIG_COUNT; i++) {
|
||||
const char* key = DEFAULT_CONFIG_VALUES[i].key;
|
||||
const char* value = DEFAULT_CONFIG_VALUES[i].value;
|
||||
|
||||
|
||||
// Determine data type
|
||||
const char* data_type = "string";
|
||||
if (strcmp(key, "relay_port") == 0 ||
|
||||
@@ -2009,7 +2088,7 @@ int populate_default_config_values(void) {
|
||||
strcmp(key, "nip42_auth_required") == 0) {
|
||||
data_type = "boolean";
|
||||
}
|
||||
|
||||
|
||||
// Set category
|
||||
const char* category = "general";
|
||||
if (strstr(key, "relay_")) {
|
||||
@@ -2023,21 +2102,29 @@ int populate_default_config_values(void) {
|
||||
} else if (strstr(key, "max_")) {
|
||||
category = "limits";
|
||||
}
|
||||
|
||||
// Determine if requires restart
|
||||
|
||||
// Determine if requires restart (0 = dynamic, 1 = restart required)
|
||||
int requires_restart = 0;
|
||||
if (strcmp(key, "relay_port") == 0) {
|
||||
|
||||
// Restart required configs
|
||||
if (strcmp(key, "relay_port") == 0 ||
|
||||
strcmp(key, "max_connections") == 0 ||
|
||||
strcmp(key, "auth_enabled") == 0 ||
|
||||
strcmp(key, "nip42_auth_required") == 0 ||
|
||||
strcmp(key, "nip42_auth_required_kinds") == 0 ||
|
||||
strcmp(key, "nip42_challenge_timeout") == 0 ||
|
||||
strcmp(key, "database_path") == 0) {
|
||||
requires_restart = 1;
|
||||
}
|
||||
|
||||
|
||||
if (set_config_value_in_table(key, value, data_type, NULL, category, requires_restart) != 0) {
|
||||
char error_msg[256];
|
||||
snprintf(error_msg, sizeof(error_msg), "Failed to set default config: %s = %s", key, value);
|
||||
log_error(error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
log_success("Default configuration values populated");
|
||||
|
||||
log_success("Default configuration values populated with restart requirements");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3797,10 +3884,59 @@ int handle_config_update_unified(cJSON* event, char* error_message, size_t error
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if this config requires restart
|
||||
const char* requires_restart_sql = "SELECT requires_restart FROM config WHERE key = ?";
|
||||
sqlite3_stmt* restart_stmt;
|
||||
int requires_restart = 0;
|
||||
|
||||
if (sqlite3_prepare_v2(g_db, requires_restart_sql, -1, &restart_stmt, NULL) == SQLITE_OK) {
|
||||
sqlite3_bind_text(restart_stmt, 1, key, -1, SQLITE_STATIC);
|
||||
if (sqlite3_step(restart_stmt) == SQLITE_ROW) {
|
||||
requires_restart = sqlite3_column_int(restart_stmt, 0);
|
||||
}
|
||||
sqlite3_finalize(restart_stmt);
|
||||
}
|
||||
|
||||
// Update the configuration value in the table
|
||||
if (update_config_in_table(key, value) == 0) {
|
||||
updates_applied++;
|
||||
|
||||
|
||||
// For dynamic configs (requires_restart = 0), refresh cache immediately
|
||||
if (requires_restart == 0) {
|
||||
log_info("Dynamic config updated - refreshing cache");
|
||||
refresh_unified_cache_from_table();
|
||||
|
||||
// Apply selective re-initialization for specific dynamic configs
|
||||
log_info("Applying selective re-initialization for dynamic config changes");
|
||||
if (strcmp(key, "max_subscriptions_per_client") == 0 ||
|
||||
strcmp(key, "max_total_subscriptions") == 0) {
|
||||
log_info("Subscription limits changed - updating subscription manager");
|
||||
update_subscription_manager_config();
|
||||
// Also refresh NIP-11 relay info since max_subscriptions_per_client affects limitation field
|
||||
log_info("Subscription limits changed - reinitializing relay info for NIP-11");
|
||||
init_relay_info();
|
||||
} else if (strcmp(key, "pow_min_difficulty") == 0 ||
|
||||
strcmp(key, "pow_mode") == 0) {
|
||||
log_info("PoW configuration changed - reinitializing PoW system");
|
||||
init_pow_config();
|
||||
} else if (strcmp(key, "nip40_expiration_enabled") == 0 ||
|
||||
strcmp(key, "nip40_expiration_strict") == 0 ||
|
||||
strcmp(key, "nip40_expiration_filter") == 0 ||
|
||||
strcmp(key, "nip40_expiration_grace_period") == 0) {
|
||||
log_info("Expiration configuration changed - reinitializing expiration system");
|
||||
init_expiration_config();
|
||||
} else if (strcmp(key, "relay_description") == 0 ||
|
||||
strcmp(key, "relay_contact") == 0 ||
|
||||
strcmp(key, "relay_software") == 0 ||
|
||||
strcmp(key, "relay_version") == 0 ||
|
||||
strcmp(key, "max_message_length") == 0 ||
|
||||
strcmp(key, "max_event_tags") == 0 ||
|
||||
strcmp(key, "max_content_length") == 0) {
|
||||
log_info("Relay information changed - reinitializing relay info");
|
||||
init_relay_info();
|
||||
}
|
||||
}
|
||||
|
||||
// Add successful config to response array
|
||||
cJSON* success_config = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(success_config, "key", key);
|
||||
@@ -3808,15 +3944,16 @@ int handle_config_update_unified(cJSON* event, char* error_message, size_t error
|
||||
cJSON_AddStringToObject(success_config, "data_type", data_type);
|
||||
cJSON_AddStringToObject(success_config, "category", category);
|
||||
cJSON_AddStringToObject(success_config, "status", "updated");
|
||||
cJSON_AddBoolToObject(success_config, "requires_restart", requires_restart);
|
||||
cJSON_AddItemToArray(processed_configs, success_config);
|
||||
|
||||
|
||||
log_success("Config field updated successfully");
|
||||
printf(" Updated: %s = %s\n", key, value);
|
||||
printf(" Updated: %s = %s (restart: %s)\n", key, value, requires_restart ? "yes" : "no");
|
||||
} else {
|
||||
log_error("Failed to update config field in database");
|
||||
printf(" Failed to update: %s = %s\n", key, value);
|
||||
validation_errors++;
|
||||
|
||||
|
||||
// Add failed config to response array
|
||||
cJSON* failed_config = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(failed_config, "key", key);
|
||||
@@ -4162,9 +4299,17 @@ int populate_config_table_from_event(const cJSON* event) {
|
||||
category = "limits";
|
||||
}
|
||||
|
||||
// Determine if requires restart
|
||||
// Determine if requires restart (0 = dynamic, 1 = restart required)
|
||||
int requires_restart = 0;
|
||||
if (strcmp(key, "relay_port") == 0) {
|
||||
|
||||
// Restart required configs
|
||||
if (strcmp(key, "relay_port") == 0 ||
|
||||
strcmp(key, "max_connections") == 0 ||
|
||||
strcmp(key, "auth_enabled") == 0 ||
|
||||
strcmp(key, "nip42_auth_required") == 0 ||
|
||||
strcmp(key, "nip42_auth_required_kinds") == 0 ||
|
||||
strcmp(key, "nip42_challenge_timeout") == 0 ||
|
||||
strcmp(key, "database_path") == 0) {
|
||||
requires_restart = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
#define MAIN_H
|
||||
|
||||
// Version information (auto-updated by build_and_push.sh)
|
||||
#define VERSION "v0.4.2"
|
||||
#define VERSION "v0.4.3"
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 4
|
||||
#define VERSION_PATCH 2
|
||||
#define VERSION_PATCH 3
|
||||
|
||||
// Relay metadata (authoritative source for NIP-11 information)
|
||||
#define RELAY_NAME "C-Relay"
|
||||
|
||||
133
test_dynamic_config.sh
Executable file
133
test_dynamic_config.sh
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Test dynamic config updates without restart
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration from relay startup
|
||||
ADMIN_PRIVKEY="ddea442930976541e199a05248eb6cd92f2a65ba366a883a8f6880add9bdc9c9"
|
||||
RELAY_PUBKEY="1bd4a5e2e32401737f8c16cc0dfa89b93f25f395770a2896fe78c9fb61582dfc"
|
||||
RELAY_URL="ws://localhost:8888"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
log_info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_success() {
|
||||
echo -e "${GREEN}[SUCCESS]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if nak is available
|
||||
if ! command -v nak &> /dev/null; then
|
||||
log_error "nak command not found. Please install nak first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_info "Testing dynamic config updates without restart..."
|
||||
|
||||
# Test 1: Check current NIP-11 info
|
||||
log_info "Checking current NIP-11 relay info..."
|
||||
CURRENT_DESC=$(curl -s -H "Accept: application/nostr+json" http://localhost:8888 | jq -r '.description')
|
||||
log_info "Current description: $CURRENT_DESC"
|
||||
|
||||
# Test 2: Update relay description dynamically
|
||||
NEW_DESC="Dynamic Config Test - Updated at $(date)"
|
||||
log_info "Updating relay description to: $NEW_DESC"
|
||||
|
||||
COMMAND="[\"config_update\", [{\"key\": \"relay_description\", \"value\": \"$NEW_DESC\", \"data_type\": \"string\", \"category\": \"relay\"}]]"
|
||||
|
||||
# Encrypt the command
|
||||
ENCRYPTED_COMMAND=$(nak encrypt "$COMMAND" --sec "$ADMIN_PRIVKEY" --recipient-pubkey "$RELAY_PUBKEY")
|
||||
|
||||
if [ -z "$ENCRYPTED_COMMAND" ]; then
|
||||
log_error "Failed to encrypt config update command"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create admin event
|
||||
ADMIN_EVENT=$(nak event \
|
||||
--kind 23456 \
|
||||
--content "$ENCRYPTED_COMMAND" \
|
||||
--sec "$ADMIN_PRIVKEY" \
|
||||
--tag "p=$RELAY_PUBKEY")
|
||||
|
||||
# Send the admin command
|
||||
log_info "Sending config update command..."
|
||||
ADMIN_RESULT=$(echo "$ADMIN_EVENT" | nak event "$RELAY_URL")
|
||||
|
||||
if echo "$ADMIN_RESULT" | grep -q "error\|failed\|denied"; then
|
||||
log_error "Failed to send config update: $ADMIN_RESULT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log_success "Config update command sent successfully"
|
||||
|
||||
# Wait for processing
|
||||
sleep 3
|
||||
|
||||
# Test 3: Check if NIP-11 info updated without restart
|
||||
log_info "Checking if NIP-11 info was updated without restart..."
|
||||
UPDATED_DESC=$(curl -s -H "Accept: application/nostr+json" http://localhost:8888 | jq -r '.description')
|
||||
|
||||
if [ "$UPDATED_DESC" = "$NEW_DESC" ]; then
|
||||
log_success "SUCCESS: Relay description updated dynamically without restart!"
|
||||
log_success "Old: $CURRENT_DESC"
|
||||
log_success "New: $UPDATED_DESC"
|
||||
else
|
||||
log_error "FAILED: Relay description was not updated"
|
||||
log_error "Expected: $NEW_DESC"
|
||||
log_error "Got: $UPDATED_DESC"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Test 4: Test another dynamic config - max_subscriptions_per_client
|
||||
log_info "Testing another dynamic config: max_subscriptions_per_client"
|
||||
|
||||
# Get current value from database
|
||||
OLD_LIMIT=$(sqlite3 build/*.db "SELECT value FROM config WHERE key = 'max_subscriptions_per_client';" 2>/dev/null || echo "25")
|
||||
log_info "Current max_subscriptions_per_client: $OLD_LIMIT"
|
||||
|
||||
NEW_LIMIT=50
|
||||
|
||||
COMMAND2="[\"config_update\", [{\"key\": \"max_subscriptions_per_client\", \"value\": \"$NEW_LIMIT\", \"data_type\": \"integer\", \"category\": \"limits\"}]]"
|
||||
|
||||
ENCRYPTED_COMMAND2=$(nak encrypt "$COMMAND2" --sec "$ADMIN_PRIVKEY" --recipient-pubkey "$RELAY_PUBKEY")
|
||||
|
||||
ADMIN_EVENT2=$(nak event \
|
||||
--kind 23456 \
|
||||
--content "$ENCRYPTED_COMMAND2" \
|
||||
--sec "$ADMIN_PRIVKEY" \
|
||||
--tag "p=$RELAY_PUBKEY")
|
||||
|
||||
log_info "Updating max_subscriptions_per_client to $NEW_LIMIT..."
|
||||
ADMIN_RESULT2=$(echo "$ADMIN_EVENT2" | nak event "$RELAY_URL")
|
||||
|
||||
if echo "$ADMIN_RESULT2" | grep -q "error\|failed\|denied"; then
|
||||
log_error "Failed to send second config update: $ADMIN_RESULT2"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
sleep 3
|
||||
|
||||
# Check updated value from database
|
||||
UPDATED_LIMIT=$(sqlite3 build/*.db "SELECT value FROM config WHERE key = 'max_subscriptions_per_client';" 2>/dev/null || echo "25")
|
||||
|
||||
if [ "$UPDATED_LIMIT" = "$NEW_LIMIT" ]; then
|
||||
log_success "SUCCESS: max_subscriptions_per_client updated dynamically!"
|
||||
log_success "Old: $OLD_LIMIT, New: $UPDATED_LIMIT"
|
||||
else
|
||||
log_error "FAILED: max_subscriptions_per_client was not updated"
|
||||
log_error "Expected: $NEW_LIMIT, Got: $UPDATED_LIMIT"
|
||||
fi
|
||||
|
||||
log_success "Dynamic config update testing completed successfully!"
|
||||
Reference in New Issue
Block a user