rename sunc_bootstrap_relay_url

This commit is contained in:
DanConwayDev
2025-12-05 12:03:52 +00:00
parent ef7ba7c59b
commit 339b0c02f2
9 changed files with 90 additions and 48 deletions
+37 -4
View File
@@ -99,13 +99,46 @@
# Options: error, warn, info, debug, trace
# RUST_LOG=info
# ============================================================================
# PROACTIVE SYNC (GRASP-02)
# ============================================================================
# Bootstrap relay URL for initial sync (optional)
# Additional relays are automatically discovered from repository announcements
# that list our service domain.
# CLI: --sync-bootstrap-relay-url <url>
# Default: (none - relay discovery from stored announcements only)
# NGIT_SYNC_BOOTSTRAP_RELAY_URL=wss://relay.example.com
# Maximum backoff time in seconds for sync relay reconnection
# CLI: --sync-max-backoff-secs <seconds>
# Default: 3600 (1 hour)
# NGIT_SYNC_MAX_BACKOFF_SECS=3600
# Delay in seconds before running startup catchup
# CLI: --sync-startup-delay-secs <seconds>
# Default: 30
# NGIT_SYNC_STARTUP_DELAY_SECS=30
# Delay in seconds before running reconnect catchup
# CLI: --sync-reconnect-delay-secs <seconds>
# Default: 10
# NGIT_SYNC_RECONNECT_DELAY_SECS=10
# Number of days to look back for reconnect catchup
# CLI: --sync-reconnect-lookback-days <days>
# Default: 3
# NGIT_SYNC_RECONNECT_LOOKBACK_DAYS=3
# Maximum startup jitter in milliseconds for sync connections
# Set to 0 to disable jitter (useful for testing)
# CLI: --sync-startup-jitter-ms <ms>
# Default: 10000 (10 seconds)
# NGIT_SYNC_STARTUP_JITTER_MS=10000
# ============================================================================
# FUTURE/PLANNED OPTIONS (not yet implemented)
# ============================================================================
# Proactive sync settings (GRASP-02)
# NGIT_PROACTIVE_SYNC_ENABLED=true
# NGIT_PROACTIVE_SYNC_INTERVAL_SECS=3600
# Archive mode (GRASP-05)
# NGIT_ARCHIVE_MODE=false
+5 -2
View File
@@ -758,7 +758,8 @@ The implementation closely follows the design document with the following comple
#### Phase 1: Basic Sync (commit b167f1b)
- [`SyncManager`](../../src/sync/manager.rs) - Main coordinator for proactive sync
- Single relay sync via `NGIT_SYNC_RELAY_URL` configuration
- Bootstrap relay sync via `NGIT_SYNC_BOOTSTRAP_RELAY_URL` configuration
- Dynamic relay discovery from repository announcements that list our service
- Event validation through existing [`Nip34WritePolicy`](../../src/nostr/builder.rs)
#### Phase 2: Three-Layer Filters (commit bf558b0)
@@ -844,12 +845,14 @@ All configuration via environment variables or CLI flags:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `NGIT_SYNC_RELAY_URL` | String | None | Primary sync relay URL |
| `NGIT_SYNC_BOOTSTRAP_RELAY_URL` | String | None | Bootstrap relay URL for initial sync |
| `NGIT_SYNC_MAX_BACKOFF_SECS` | u64 | 3600 | Max backoff delay (seconds) |
| `NGIT_SYNC_STARTUP_DELAY_SECS` | u64 | 30 | Catchup delay after startup |
| `NGIT_SYNC_RECONNECT_DELAY_SECS` | u64 | 10 | Catchup delay after reconnect |
| `NGIT_SYNC_RECONNECT_LOOKBACK_DAYS` | u64 | 3 | Days to look back on reconnect |
**Note:** Additional relays are automatically discovered from repository announcements (kind 30617) that list our service domain. The bootstrap relay provides an initial sync source but is not required - sync will discover relays from stored announcements.
### Module Structure (As Implemented)
```
+9 -8
View File
@@ -269,28 +269,29 @@ NGIT_DATABASE_BACKEND=lmdb
These options configure the proactive sync feature that synchronizes events from other relays.
#### `NGIT_SYNC_RELAY_URL`
#### `NGIT_SYNC_BOOTSTRAP_RELAY_URL`
**Description:** URL of the primary relay to sync events from
**Description:** URL of the bootstrap relay to initially sync events from
**Type:** String (WebSocket URL)
**Default:** None (sync disabled)
**Default:** None (relay discovery only)
**Required:** No
**Examples:**
```bash
# Sync from a public relay
NGIT_SYNC_RELAY_URL=wss://relay.example.com
NGIT_SYNC_BOOTSTRAP_RELAY_URL=wss://relay.example.com
# Sync from another GRASP relay
NGIT_SYNC_RELAY_URL=wss://git.nostr.dev
NGIT_SYNC_BOOTSTRAP_RELAY_URL=wss://git.nostr.dev
# Local testing
NGIT_SYNC_RELAY_URL=ws://127.0.0.1:8081
NGIT_SYNC_BOOTSTRAP_RELAY_URL=ws://127.0.0.1:8081
```
**Notes:**
- When set, enables proactive sync feature
- The relay will discover additional relays from repository announcements
- Bootstrap relay provides initial sync source on startup
- Additional relays are **automatically discovered** from repository announcements that list our service
- Even without a bootstrap relay, sync will discover relays from stored announcements
- Synced events go through the same validation as directly-submitted events
- Use WebSocket protocol (`ws://` or `wss://`)
+6 -4
View File
@@ -84,9 +84,10 @@ pub struct Config {
#[arg(long = "metrics-top-n-repos", env = "NGIT_METRICS_TOP_N_REPOS", default_value_t = 10)]
pub metrics_top_n_repos: usize,
/// URL of relay to sync kind 30617 events from (optional, enables proactive sync)
#[arg(long, env = "NGIT_SYNC_RELAY_URL")]
pub sync_relay_url: Option<String>,
/// URL of bootstrap relay to sync from on startup (optional)
/// Sync discovers additional relays from repository announcements that list our service
#[arg(long, env = "NGIT_SYNC_BOOTSTRAP_RELAY_URL")]
pub sync_bootstrap_relay_url: Option<String>,
/// Maximum backoff time in seconds for sync relay reconnection (default: 3600 = 1 hour)
#[arg(long, env = "NGIT_SYNC_MAX_BACKOFF_SECS", default_value_t = 3600)]
@@ -163,11 +164,12 @@ impl Config {
metrics_enabled: true,
metrics_connection_per_ip_abuse_threshold: 10,
metrics_top_n_repos: 10,
sync_relay_url: None,
sync_bootstrap_relay_url: None,
sync_max_backoff_secs: 3600,
sync_startup_delay_secs: 30,
sync_reconnect_delay_secs: 10,
sync_reconnect_lookback_days: 3,
sync_startup_jitter_ms: 10_000,
}
}
}
+4 -2
View File
@@ -105,11 +105,12 @@ mod tests {
metrics_enabled: true,
metrics_connection_per_ip_abuse_threshold: 10,
metrics_top_n_repos: 10,
sync_relay_url: None,
sync_bootstrap_relay_url: None,
sync_max_backoff_secs: 3600,
sync_startup_delay_secs: 30,
sync_reconnect_delay_secs: 10,
sync_reconnect_lookback_days: 3,
sync_startup_jitter_ms: 10_000,
};
let doc = RelayInformationDocument::from_config(&config);
@@ -144,11 +145,12 @@ mod tests {
metrics_enabled: true,
metrics_connection_per_ip_abuse_threshold: 10,
metrics_top_n_repos: 10,
sync_relay_url: None,
sync_bootstrap_relay_url: None,
sync_max_backoff_secs: 3600,
sync_startup_delay_secs: 30,
sync_reconnect_delay_secs: 10,
sync_reconnect_lookback_days: 3,
sync_startup_jitter_ms: 10_000,
};
let doc = RelayInformationDocument::from_config(&config);
+4 -4
View File
@@ -52,17 +52,17 @@ async fn main() -> Result<()> {
);
// Start SyncManager for proactive sync (Phase 2: multi-relay support, Phase 3: health tracking)
// Even without initial sync_relay_url, SyncManager can discover relays from stored announcements
// Even without bootstrap relay, SyncManager discovers relays from stored announcements
let sync_manager = SyncManager::new(
config.sync_relay_url.clone(),
config.sync_bootstrap_relay_url.clone(),
config.domain.clone(),
relay_with_db.database.clone(),
relay_with_db.write_policy.clone(),
&config,
);
if config.sync_relay_url.is_some() {
info!("Starting proactive sync from: {:?}", config.sync_relay_url);
if config.sync_bootstrap_relay_url.is_some() {
info!("Starting proactive sync with bootstrap relay: {:?}", config.sync_bootstrap_relay_url);
} else {
info!("Proactive sync enabled (will discover relays from stored announcements)");
}
+17 -16
View File
@@ -60,8 +60,9 @@ fn get_sync_source_addr(bind_address: &str) -> SocketAddr {
/// Coordinates proactive sync from configured and discovered relays
pub struct SyncManager {
/// Initial relay URL to sync from (from config)
initial_relay_url: Option<String>,
/// Bootstrap relay URL for initial sync (from config)
/// Additional relays are discovered from repository announcements that list our service
bootstrap_relay_url: Option<String>,
/// Our relay's domain (for filtering)
relay_domain: String,
/// Database for storing accepted events
@@ -82,20 +83,20 @@ impl SyncManager {
/// Create a new SyncManager
///
/// # Arguments
/// * `initial_relay_url` - Optional initial relay URL from config
/// * `bootstrap_relay_url` - Optional bootstrap relay URL from config
/// * `relay_domain` - Our relay's domain (used to exclude self from sync)
/// * `database` - Shared database for storing events and querying announcements
/// * `write_policy` - Write policy for validating synced events
/// * `config` - Configuration for health tracking settings
pub fn new(
initial_relay_url: Option<String>,
bootstrap_relay_url: Option<String>,
relay_domain: String,
database: SharedDatabase,
write_policy: Nip34WritePolicy,
config: &Config,
) -> Self {
Self {
initial_relay_url,
bootstrap_relay_url,
relay_domain,
database,
write_policy,
@@ -109,14 +110,14 @@ impl SyncManager {
/// Create a new SyncManager with metrics
///
/// # Arguments
/// * `initial_relay_url` - Optional initial relay URL from config
/// * `bootstrap_relay_url` - Optional bootstrap relay URL from config
/// * `relay_domain` - Our relay's domain (used to exclude self from sync)
/// * `database` - Shared database for storing events and querying announcements
/// * `write_policy` - Write policy for validating synced events
/// * `config` - Configuration for health tracking settings
/// * `metrics` - Sync metrics for Prometheus
pub fn with_metrics(
initial_relay_url: Option<String>,
bootstrap_relay_url: Option<String>,
relay_domain: String,
database: SharedDatabase,
write_policy: Nip34WritePolicy,
@@ -124,7 +125,7 @@ impl SyncManager {
metrics: SyncMetrics,
) -> Self {
Self {
initial_relay_url,
bootstrap_relay_url,
relay_domain,
database,
write_policy,
@@ -137,14 +138,14 @@ impl SyncManager {
/// Create a SyncManager with a single relay URL (Phase 1 compatibility)
pub fn with_single_relay(
sync_relay_url: String,
bootstrap_url: String,
database: SharedDatabase,
write_policy: Nip34WritePolicy,
) -> Self {
// Extract domain from URL for filtering
let relay_domain = extract_domain_from_url(&sync_relay_url).unwrap_or_default();
let relay_domain = extract_domain_from_url(&bootstrap_url).unwrap_or_default();
Self {
initial_relay_url: Some(sync_relay_url),
bootstrap_relay_url: Some(bootstrap_url),
relay_domain,
database,
write_policy,
@@ -176,9 +177,9 @@ impl SyncManager {
/// and processes incoming events. Runs indefinitely until cancelled.
pub async fn run(self) {
tracing::info!(
"Starting SyncManager (domain: {}, initial relay: {:?})",
"Starting SyncManager (domain: {}, bootstrap relay: {:?})",
self.relay_domain,
self.initial_relay_url
self.bootstrap_relay_url
);
// Create the filter service
@@ -196,13 +197,13 @@ impl SyncManager {
// Collect all relays to connect to
let mut relays_to_connect: Vec<String> = Vec::new();
// Start with initial relay if configured
if let Some(ref url) = self.initial_relay_url {
// Start with bootstrap relay if configured
if let Some(ref url) = self.bootstrap_relay_url {
if !self.is_own_relay(url) {
relays_to_connect.push(url.clone());
active_relays.insert(url.clone());
} else {
tracing::info!("Skipping initial relay (is our own relay): {}", url);
tracing::info!("Skipping bootstrap relay (is our own relay): {}", url);
}
}
+7 -7
View File
@@ -41,7 +41,7 @@ impl TestRelay {
Self::start_with_options(port, None).await
}
/// Start relay with sync from another relay
/// Start relay with sync from another relay (bootstrap relay)
///
/// # Example
///
@@ -57,12 +57,12 @@ impl TestRelay {
/// source.stop().await;
/// }
/// ```
pub async fn start_with_sync(sync_relay_url: &str) -> Self {
Self::start_with_options(Self::find_free_port(), Some(sync_relay_url.to_string())).await
pub async fn start_with_sync(bootstrap_relay_url: &str) -> Self {
Self::start_with_options(Self::find_free_port(), Some(bootstrap_relay_url.to_string())).await
}
/// Start relay with options
async fn start_with_options(port: u16, sync_relay_url: Option<String>) -> Self {
async fn start_with_options(port: u16, bootstrap_relay_url: Option<String>) -> Self {
let bind_address = format!("127.0.0.1:{}", port);
let url = format!("ws://127.0.0.1:{}", port);
@@ -97,9 +97,9 @@ impl TestRelay {
.stdout(Stdio::null())
.stderr(Stdio::null());
// Add sync relay URL if provided
if let Some(ref sync_url) = sync_relay_url {
cmd.env("NGIT_SYNC_RELAY_URL", sync_url);
// Add bootstrap relay URL if provided
if let Some(ref bootstrap_url) = bootstrap_relay_url {
cmd.env("NGIT_SYNC_BOOTSTRAP_RELAY_URL", bootstrap_url);
}
let process = cmd.spawn().expect("Failed to start relay process");
+1 -1
View File
@@ -170,7 +170,7 @@ async fn test_sync_configuration_applied() {
tokio::time::sleep(Duration::from_millis(300)).await;
// Both relays should be running
// The sync relay has NGIT_SYNC_RELAY_URL set (verified by relay starting)
// The sync relay has NGIT_SYNC_BOOTSTRAP_RELAY_URL set (verified by relay starting)
let client_source = Client::default();
client_source