From 74a4dc2533761ed095bafe6ee19874167d8efc3f Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 7 Sep 2025 06:54:56 -0400 Subject: [PATCH] v0.3.2 - Implement -p/--port CLI option for first-time startup port override - Add cli_options_t structure for extensible command line options - Implement port override in create_default_config_event() - Update main() with robust CLI parsing and validation - Add comprehensive help text documenting first-time only behavior - Ensure CLI options only affect initial configuration event creation - Maintain event-based configuration architecture for ongoing operation - Include comprehensive error handling and input validation - Add documentation in CLI_PORT_OVERRIDE_IMPLEMENTATION.md Tested: First-time startup uses CLI port, subsequent startups use database config --- CLI_PORT_OVERRIDE_IMPLEMENTATION.md | 145 ++++++++++++++++++ ...86cd8718a260a375890b5670b33e632f1d300b9.db | Bin 0 -> 114688 bytes relay.pid | 2 +- src/config.c | 28 +++- src/config.h | 8 +- src/default_config_event.h | 6 +- src/main.c | 38 ++++- 7 files changed, 216 insertions(+), 11 deletions(-) create mode 100644 CLI_PORT_OVERRIDE_IMPLEMENTATION.md create mode 100644 fd8000ad015bc2e5e606a67c586cd8718a260a375890b5670b33e632f1d300b9.db diff --git a/CLI_PORT_OVERRIDE_IMPLEMENTATION.md b/CLI_PORT_OVERRIDE_IMPLEMENTATION.md new file mode 100644 index 0000000..9fb76ca --- /dev/null +++ b/CLI_PORT_OVERRIDE_IMPLEMENTATION.md @@ -0,0 +1,145 @@ +# CLI Port Override Implementation + +## Overview + +This document describes the implementation of the `-p ` command line option for the C Nostr Relay, which allows overriding the default relay port during first-time startup only. + +## Design Principles + +1. **First-time startup only**: Command line options only affect the initial configuration event creation +2. **Event-based persistence**: After first startup, all configuration is managed through database events +3. **Proper encapsulation**: All configuration logic is contained within `config.c` +4. **Extensible design**: The CLI options structure can easily accommodate future command line options + +## Implementation Details + +### Files Modified + +#### `src/config.h` +- Added `cli_options_t` structure to encapsulate command line options +- Updated `first_time_startup_sequence()` function signature + +#### `src/config.c` +- Updated `first_time_startup_sequence()` to accept CLI options parameter +- Updated `create_default_config_event()` to accept CLI options parameter +- Implemented port override logic in DEFAULT_CONFIG_VALUES array processing + +#### `src/default_config_event.h` +- Updated function signature for `create_default_config_event()` +- Added proper header include for `cli_options_t` definition + +#### `src/main.c` +- Added command line parsing for `-p ` and `--port ` +- Updated help text to document the new option +- Added proper error handling for invalid port values +- Updated function call to pass CLI options to configuration system + +### CLI Options Structure + +```c +typedef struct { + int port_override; // -1 = not set, >0 = port value + // Future CLI options can be added here +} cli_options_t; +``` + +### Command Line Usage + +```bash +# First-time startup with port override +./c_relay_x86 -p 9090 +./c_relay_x86 --port 9090 + +# Show help (includes new option) +./c_relay_x86 --help + +# Show version +./c_relay_x86 --version +``` + +### Error Handling + +The implementation includes robust error handling for: +- Missing port argument: `./c_relay_x86 -p` +- Invalid port format: `./c_relay_x86 -p invalid_port` +- Out-of-range ports: `./c_relay_x86 -p 0` or `./c_relay_x86 -p 99999` + +## Behavior Verification + +### First-Time Startup +When no database exists: +1. Command line is parsed and `-p ` is processed +2. CLI options are passed to `first_time_startup_sequence()` +3. Port override is applied in `create_default_config_event()` +4. Configuration event is created with overridden port value +5. Relay starts on the specified port +6. Port setting is persisted in database for future startups + +### Subsequent Startups +When database already exists: +1. Command line is still parsed (for consistency) +2. Existing relay path is taken +3. Configuration is loaded from database events +4. CLI options are ignored +5. Relay starts on port from database configuration + +## Testing Results + +### Test 1: First-time startup with port override +```bash +./c_relay_x86 -p 9090 +``` +**Result**: ✅ Relay starts on port 9090, configuration stored in database + +### Test 2: Subsequent startup ignores CLI options +```bash +./c_relay_x86 -p 7777 +``` +**Result**: ✅ Relay starts on port 9090 (from database), ignores `-p 7777` + +### Test 3: Error handling +```bash +./c_relay_x86 -p invalid_port +./c_relay_x86 -p +``` +**Result**: ✅ Proper error messages and help text displayed + +### Test 4: Help text +```bash +./c_relay_x86 --help +``` +**Result**: ✅ Displays updated help with `-p, --port PORT` option + +## Database Verification + +The port setting is correctly stored in the database: +```sql +SELECT json_extract(tags, '$') FROM events WHERE kind = 33334; +``` +Shows the overridden port value in the configuration event tags. + +## Future Extensions + +The `cli_options_t` structure is designed to be easily extended: + +```c +typedef struct { + int port_override; // -1 = not set, >0 = port value + char* description_override; // Future: relay description override + int max_connections_override; // Future: connection limit override + // Add more options as needed +} cli_options_t; +``` + +## Key Design Benefits + +1. **Separation of Concerns**: Main function handles CLI parsing, config system handles application +2. **First-time Only**: Prevents confusion about configuration precedence +3. **Event-based Architecture**: Maintains consistency with the relay's event-based configuration system +4. **Extensible**: Easy to add new command line options in the future +5. **Robust**: Comprehensive error handling and validation +6. **Documented**: Clear help text explains behavior to users + +## Summary + +The `-p ` command line option implementation successfully provides a way to override the default relay port during first-time startup while maintaining the event-based configuration architecture for ongoing operation. The implementation is robust, well-tested, and ready for production use. \ No newline at end of file diff --git a/fd8000ad015bc2e5e606a67c586cd8718a260a375890b5670b33e632f1d300b9.db b/fd8000ad015bc2e5e606a67c586cd8718a260a375890b5670b33e632f1d300b9.db new file mode 100644 index 0000000000000000000000000000000000000000..889c24055a8bfac13c5b75edd57a934a3d64afe4 GIT binary patch literal 114688 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 BG(`Xa literal 0 HcmV?d00001 diff --git a/relay.pid b/relay.pid index eda1436..78d8b0e 100644 --- a/relay.pid +++ b/relay.pid @@ -1 +1 @@ -1177520 +1187428 diff --git a/src/config.c b/src/config.c index 4651982..7a14f84 100644 --- a/src/config.c +++ b/src/config.c @@ -443,7 +443,8 @@ int generate_random_private_key_bytes(unsigned char* privkey_bytes) { cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes, const char* relay_privkey_hex, - const char* relay_pubkey_hex) { + const char* relay_pubkey_hex, + const cli_options_t* cli_options) { if (!admin_privkey_bytes || !relay_privkey_hex || !relay_pubkey_hex) { log_error("Invalid parameters for creating default config event"); return NULL; @@ -475,11 +476,28 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes, cJSON_AddItemToArray(relay_privkey_tag, cJSON_CreateString(relay_privkey_hex)); cJSON_AddItemToArray(tags, relay_privkey_tag); - // Add all default configuration values + // Add all default configuration values with command line overrides for (size_t i = 0; i < DEFAULT_CONFIG_COUNT; i++) { cJSON* tag = cJSON_CreateArray(); cJSON_AddItemToArray(tag, cJSON_CreateString(DEFAULT_CONFIG_VALUES[i].key)); - cJSON_AddItemToArray(tag, cJSON_CreateString(DEFAULT_CONFIG_VALUES[i].value)); + + // Check for command line overrides + const char* value = DEFAULT_CONFIG_VALUES[i].value; + if (cli_options) { + // Override relay_port if specified on command line + if (cli_options->port_override > 0 && strcmp(DEFAULT_CONFIG_VALUES[i].key, "relay_port") == 0) { + char port_str[16]; + snprintf(port_str, sizeof(port_str), "%d", cli_options->port_override); + cJSON_AddItemToArray(tag, cJSON_CreateString(port_str)); + log_info("Using command line port override in configuration event"); + printf(" Port: %d (overriding default %s)\n", cli_options->port_override, DEFAULT_CONFIG_VALUES[i].value); + } else { + cJSON_AddItemToArray(tag, cJSON_CreateString(value)); + } + } else { + cJSON_AddItemToArray(tag, cJSON_CreateString(value)); + } + cJSON_AddItemToArray(tags, tag); } @@ -516,7 +534,7 @@ cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes, // IMPLEMENTED FUNCTIONS // ================================ -int first_time_startup_sequence(void) { +int first_time_startup_sequence(const cli_options_t* cli_options) { log_info("Starting first-time startup sequence..."); // 1. Generate admin keypair using /dev/urandom + nostr_core_lib @@ -566,7 +584,7 @@ int first_time_startup_sequence(void) { } // 5. Create initial configuration event using defaults - cJSON* config_event = create_default_config_event(admin_privkey_bytes, relay_privkey, relay_pubkey); + cJSON* config_event = create_default_config_event(admin_privkey_bytes, relay_privkey, relay_pubkey, cli_options); if (!config_event) { log_error("Failed to create default configuration event"); return -1; diff --git a/src/config.h b/src/config.h index ffa528b..c35373e 100644 --- a/src/config.h +++ b/src/config.h @@ -32,6 +32,12 @@ typedef struct { char config_file_path[512]; // Temporary for compatibility } config_manager_t; +// Command line options structure for first-time startup +typedef struct { + int port_override; // -1 = not set, >0 = port value + // Future CLI options can be added here +} cli_options_t; + // Global configuration manager extern config_manager_t g_config_manager; @@ -62,7 +68,7 @@ int get_config_bool(const char* key, int default_value); // First-time startup functions int is_first_time_startup(void); -int first_time_startup_sequence(void); +int first_time_startup_sequence(const cli_options_t* cli_options); int startup_existing_relay(const char* relay_pubkey); // Configuration application functions diff --git a/src/default_config_event.h b/src/default_config_event.h index 6ca9afd..995f61b 100644 --- a/src/default_config_event.h +++ b/src/default_config_event.h @@ -2,6 +2,7 @@ #define DEFAULT_CONFIG_EVENT_H #include +#include "config.h" // For cli_options_t definition /* * Default Configuration Event Template @@ -61,8 +62,9 @@ static const struct { #define DEFAULT_CONFIG_COUNT (sizeof(DEFAULT_CONFIG_VALUES) / sizeof(DEFAULT_CONFIG_VALUES[0])) // Function to create default configuration event -cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes, +cJSON* create_default_config_event(const unsigned char* admin_privkey_bytes, const char* relay_privkey_hex, - const char* relay_pubkey_hex); + const char* relay_pubkey_hex, + const cli_options_t* cli_options); #endif /* DEFAULT_CONFIG_EVENT_H */ \ No newline at end of file diff --git a/src/main.c b/src/main.c index d3b3e41..28d70cd 100644 --- a/src/main.c +++ b/src/main.c @@ -3132,14 +3132,19 @@ void print_usage(const char* program_name) { printf("Options:\n"); printf(" -h, --help Show this help message\n"); printf(" -v, --version Show version information\n"); + printf(" -p, --port PORT Override relay port (first-time startup only)\n"); printf("\n"); printf("Configuration:\n"); printf(" This relay uses event-based configuration stored in the database.\n"); printf(" On first startup, keys are automatically generated and printed once.\n"); + printf(" Command line options like --port only apply during first-time setup.\n"); + printf(" After initial setup, all configuration is managed via database events.\n"); printf(" Database file: .db (created automatically)\n"); printf("\n"); printf("Examples:\n"); printf(" %s # Start relay (auto-configure on first run)\n", program_name); + printf(" %s -p 8080 # First-time setup with port 8080\n", program_name); + printf(" %s --port 9000 # First-time setup with port 9000\n", program_name); printf(" %s --help # Show this help\n", program_name); printf(" %s --version # Show version info\n", program_name); printf("\n"); @@ -3154,7 +3159,12 @@ void print_version() { } int main(int argc, char* argv[]) { - // Parse minimal command line arguments (no configuration overrides) + // Initialize CLI options structure + cli_options_t cli_options = { + .port_override = -1 // -1 = not set + }; + + // Parse command line arguments for (int i = 1; i < argc; i++) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { print_usage(argv[0]); @@ -3162,6 +3172,30 @@ int main(int argc, char* argv[]) { } else if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) { print_version(); return 0; + } else if (strcmp(argv[i], "-p") == 0 || strcmp(argv[i], "--port") == 0) { + // Port override option + if (i + 1 >= argc) { + log_error("Port option requires a value. Use --help for usage information."); + print_usage(argv[0]); + return 1; + } + + // Parse port number + char* endptr; + long port = strtol(argv[i + 1], &endptr, 10); + + if (endptr == argv[i + 1] || *endptr != '\0' || port < 1 || port > 65535) { + log_error("Invalid port number. Port must be between 1 and 65535."); + print_usage(argv[0]); + return 1; + } + + cli_options.port_override = (int)port; + i++; // Skip the port argument + + char port_msg[128]; + snprintf(port_msg, sizeof(port_msg), "Port override specified: %d", cli_options.port_override); + log_info(port_msg); } else { log_error("Unknown argument. Use --help for usage information."); print_usage(argv[0]); @@ -3194,7 +3228,7 @@ int main(int argc, char* argv[]) { } // Run first-time startup sequence (generates keys, creates database, etc.) - if (first_time_startup_sequence() != 0) { + if (first_time_startup_sequence(&cli_options) != 0) { log_error("Failed to complete first-time startup sequence"); cleanup_configuration_system(); nostr_cleanup();