upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-01-08 12:02:59 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-01-08 12:14:27 +0000
commit0356740d11c9fb6524060e6755ab0c2186096724 (patch)
treedb7ca39d1cb6b078d40fde14d3a84cfbf443eaab
parent64eaf4407028d3727fe8854a9a8fb97a8660af95 (diff)
fix: sync-bootstrap-relay-url scheme optional
-rw-r--r--README.md2
-rw-r--r--docs/reference/configuration.md55
-rw-r--r--src/config.rs2
-rw-r--r--src/sync/relay_connection.rs101
4 files changed, 148 insertions, 12 deletions
diff --git a/README.md b/README.md
index 7e516eb..b8bff09 100644
--- a/README.md
+++ b/README.md
@@ -321,7 +321,7 @@ NGIT_OWNER_NPUB=npub1... ngit-grasp --domain relay.example.com
321 321
322**Sync Notes:** 322**Sync Notes:**
323 323
324- **Bootstrap relay**: Optional starting point for relay discovery. System automatically discovers additional relays from repository announcements. 324- **Bootstrap relay**: Optional starting point for relay discovery. System automatically discovers additional relays from repository announcements. URL scheme is optional - if not provided, `wss://` is assumed (e.g., `git.shakespeare.diy` → `wss://git.shakespeare.diy`).
325- **Backoff settings**: Controls exponential backoff for failed connections (`base * 2^(failures-1)`, capped at max). 325- **Backoff settings**: Controls exponential backoff for failed connections (`base * 2^(failures-1)`, capped at max).
326- **Negentropy**: Can be disabled for testing REQ+EOSE fallback behavior. 326- **Negentropy**: Can be disabled for testing REQ+EOSE fallback behavior.
327- **Batch window**: Self-subscriber batches events for this duration before triggering sync filters. 327- **Batch window**: Self-subscriber batches events for this duration before triggering sync filters.
diff --git a/docs/reference/configuration.md b/docs/reference/configuration.md
index 204fbd1..ece14af 100644
--- a/docs/reference/configuration.md
+++ b/docs/reference/configuration.md
@@ -29,6 +29,7 @@ Configuration is loaded at startup and validated before the server starts.
29**Required:** No 29**Required:** No
30 30
31**Examples:** 31**Examples:**
32
32```bash 33```bash
33# Localhost only (development) 34# Localhost only (development)
34NGIT_BIND_ADDRESS=127.0.0.1:8080 35NGIT_BIND_ADDRESS=127.0.0.1:8080
@@ -44,6 +45,7 @@ NGIT_BIND_ADDRESS=127.0.0.1:3000
44``` 45```
45 46
46**Notes:** 47**Notes:**
48
47- Use `127.0.0.1` for local development 49- Use `127.0.0.1` for local development
48- Use `0.0.0.0` for production (behind reverse proxy) 50- Use `0.0.0.0` for production (behind reverse proxy)
49- Ensure firewall rules allow the port 51- Ensure firewall rules allow the port
@@ -58,6 +60,7 @@ NGIT_BIND_ADDRESS=127.0.0.1:3000
58**Required:** Yes 60**Required:** Yes
59 61
60**Examples:** 62**Examples:**
63
61```bash 64```bash
62NGIT_DOMAIN=gitnostr.com 65NGIT_DOMAIN=gitnostr.com
63NGIT_DOMAIN=git.example.org 66NGIT_DOMAIN=git.example.org
@@ -65,12 +68,14 @@ NGIT_DOMAIN=localhost:8080 # Development only
65``` 68```
66 69
67**Used for:** 70**Used for:**
71
68- NIP-11 relay information document 72- NIP-11 relay information document
69- Generating repository URLs 73- Generating repository URLs
70- CORS configuration 74- CORS configuration
71- Webhook URLs (future) 75- Webhook URLs (future)
72 76
73**Notes:** 77**Notes:**
78
74- Must be accessible from the internet for production 79- Must be accessible from the internet for production
75- Include port if non-standard (e.g., `localhost:8080`) 80- Include port if non-standard (e.g., `localhost:8080`)
76- Used in repository clone URLs: `https://{NGIT_DOMAIN}/{npub}/{repo}.git` 81- Used in repository clone URLs: `https://{NGIT_DOMAIN}/{npub}/{repo}.git`
@@ -87,16 +92,19 @@ NGIT_DOMAIN=localhost:8080 # Development only
87**Required:** Yes 92**Required:** Yes
88 93
89**Examples:** 94**Examples:**
95
90```bash 96```bash
91NGIT_OWNER_NPUB=npub1alice... 97NGIT_OWNER_NPUB=npub1alice...
92``` 98```
93 99
94**Used for:** 100**Used for:**
101
95- NIP-11 relay information document 102- NIP-11 relay information document
96- Contact information 103- Contact information
97- Administrative operations (future) 104- Administrative operations (future)
98 105
99**Notes:** 106**Notes:**
107
100- Must be valid npub format (starts with `npub1`) 108- Must be valid npub format (starts with `npub1`)
101- Can be generated with Nostr tools 109- Can be generated with Nostr tools
102- Publicly visible in relay metadata 110- Publicly visible in relay metadata
@@ -111,12 +119,14 @@ NGIT_OWNER_NPUB=npub1alice...
111**Required:** No 119**Required:** No
112 120
113**Examples:** 121**Examples:**
122
114```bash 123```bash
115NGIT_RELAY_NAME="GitNostr Community Relay" 124NGIT_RELAY_NAME="GitNostr Community Relay"
116NGIT_RELAY_NAME="Alice's GRASP Server" 125NGIT_RELAY_NAME="Alice's GRASP Server"
117``` 126```
118 127
119**Used for:** 128**Used for:**
129
120- NIP-11 relay information document 130- NIP-11 relay information document
121- Client display 131- Client display
122- Relay discovery 132- Relay discovery
@@ -131,12 +141,14 @@ NGIT_RELAY_NAME="Alice's GRASP Server"
131**Required:** No 141**Required:** No
132 142
133**Examples:** 143**Examples:**
144
134```bash 145```bash
135NGIT_RELAY_DESCRIPTION="Public GRASP relay for open source projects" 146NGIT_RELAY_DESCRIPTION="Public GRASP relay for open source projects"
136NGIT_RELAY_DESCRIPTION="Private relay for ACME Corp repositories" 147NGIT_RELAY_DESCRIPTION="Private relay for ACME Corp repositories"
137``` 148```
138 149
139**Used for:** 150**Used for:**
151
140- NIP-11 relay information document 152- NIP-11 relay information document
141- User information 153- User information
142- Relay selection 154- Relay selection
@@ -153,6 +165,7 @@ NGIT_RELAY_DESCRIPTION="Private relay for ACME Corp repositories"
153**Required:** No 165**Required:** No
154 166
155**Examples:** 167**Examples:**
168
156```bash 169```bash
157# Relative path (development) 170# Relative path (development)
158NGIT_GIT_DATA_PATH=./data/git 171NGIT_GIT_DATA_PATH=./data/git
@@ -165,6 +178,7 @@ NGIT_GIT_DATA_PATH=/mnt/storage/git-repos
165``` 178```
166 179
167**Storage structure:** 180**Storage structure:**
181
168``` 182```
169{NGIT_GIT_DATA_PATH}/ 183{NGIT_GIT_DATA_PATH}/
170 ├── {npub1}/ 184 ├── {npub1}/
@@ -178,6 +192,7 @@ NGIT_GIT_DATA_PATH=/mnt/storage/git-repos
178``` 192```
179 193
180**Notes:** 194**Notes:**
195
181- Directory must be writable by ngit-grasp process 196- Directory must be writable by ngit-grasp process
182- Ensure sufficient disk space 197- Ensure sufficient disk space
183- Consider backup strategy 198- Consider backup strategy
@@ -193,6 +208,7 @@ NGIT_GIT_DATA_PATH=/mnt/storage/git-repos
193**Required:** No 208**Required:** No
194 209
195**Examples:** 210**Examples:**
211
196```bash 212```bash
197# Relative path (development) 213# Relative path (development)
198NGIT_RELAY_DATA_PATH=./data/relay 214NGIT_RELAY_DATA_PATH=./data/relay
@@ -205,6 +221,7 @@ NGIT_RELAY_DATA_PATH=/mnt/ssd/relay-data
205``` 221```
206 222
207**Storage structure:** 223**Storage structure:**
224
208``` 225```
209{NGIT_RELAY_DATA_PATH}/ 226{NGIT_RELAY_DATA_PATH}/
210 ├── events/ 227 ├── events/
@@ -217,6 +234,7 @@ NGIT_RELAY_DATA_PATH=/mnt/ssd/relay-data
217``` 234```
218 235
219**Notes:** 236**Notes:**
237
220- Directory must be writable 238- Directory must be writable
221- Consider SSD for better query performance 239- Consider SSD for better query performance
222- Size grows with event count 240- Size grows with event count
@@ -232,11 +250,13 @@ NGIT_RELAY_DATA_PATH=/mnt/ssd/relay-data
232**Required:** No 250**Required:** No
233 251
234**Valid Values:** 252**Valid Values:**
253
235- `memory` - In-memory database (default, fastest, no persistence) 254- `memory` - In-memory database (default, fastest, no persistence)
236- `nostrdb` - NostrDB backend (persistent, optimized for Nostr) [Not yet implemented] 255- `nostrdb` - NostrDB backend (persistent, optimized for Nostr) [Not yet implemented]
237- `lmdb` - LMDB backend (persistent, general purpose) [Not yet implemented] 256- `lmdb` - LMDB backend (persistent, general purpose) [Not yet implemented]
238 257
239**Examples:** 258**Examples:**
259
240```bash 260```bash
241# Development (default, no persistence) 261# Development (default, no persistence)
242NGIT_DATABASE_BACKEND=memory 262NGIT_DATABASE_BACKEND=memory
@@ -250,13 +270,14 @@ NGIT_DATABASE_BACKEND=lmdb
250 270
251**Comparison:** 271**Comparison:**
252 272
253| Backend | Persistence | Performance | Use Case | 273| Backend | Persistence | Performance | Use Case |
254|---------|-------------|-------------|----------| 274| ------- | ----------- | ----------- | ---------------------------- |
255| memory | No | Fastest | Development, testing | 275| memory | No | Fastest | Development, testing |
256| nostrdb | Yes | High | Production (Nostr-optimized) | 276| nostrdb | Yes | High | Production (Nostr-optimized) |
257| lmdb | Yes | High | Production (general purpose) | 277| lmdb | Yes | High | Production (general purpose) |
258 278
259**Notes:** 279**Notes:**
280
260- `memory` backend loses all data on restart 281- `memory` backend loses all data on restart
261- NostrDB and LMDB backends will use `NGIT_RELAY_DATA_PATH` for storage 282- NostrDB and LMDB backends will use `NGIT_RELAY_DATA_PATH` for storage
262- NostrDB and LMDB are planned features, not yet available 283- NostrDB and LMDB are planned features, not yet available
@@ -277,6 +298,7 @@ These options configure the proactive sync feature that synchronizes events from
277**Required:** No 298**Required:** No
278 299
279**Examples:** 300**Examples:**
301
280```bash 302```bash
281# Sync from a public relay 303# Sync from a public relay
282NGIT_SYNC_BOOTSTRAP_RELAY_URL=wss://relay.example.com 304NGIT_SYNC_BOOTSTRAP_RELAY_URL=wss://relay.example.com
@@ -289,11 +311,12 @@ NGIT_SYNC_BOOTSTRAP_RELAY_URL=ws://127.0.0.1:8081
289``` 311```
290 312
291**Notes:** 313**Notes:**
314
292- Bootstrap relay provides initial sync source on startup 315- Bootstrap relay provides initial sync source on startup
293- Additional relays are **automatically discovered** from repository announcements that list our service 316- Additional relays are **automatically discovered** from repository announcements that list our service
294- Even without a bootstrap relay, sync will discover relays from stored announcements 317- Even without a bootstrap relay, sync will discover relays from stored announcements
295- Synced events go through the same validation as directly-submitted events 318- Synced events go through the same validation as directly-submitted events
296- Use WebSocket protocol (`ws://` or `wss://`) 319- Use WebSocket protocol (`ws://` or `wss://`) or defaults to wss://
297 320
298--- 321---
299 322
@@ -305,6 +328,7 @@ NGIT_SYNC_BOOTSTRAP_RELAY_URL=ws://127.0.0.1:8081
305**Required:** No 328**Required:** No
306 329
307**Examples:** 330**Examples:**
331
308```bash 332```bash
309# Default: 1 hour max backoff 333# Default: 1 hour max backoff
310NGIT_SYNC_MAX_BACKOFF_SECS=3600 334NGIT_SYNC_MAX_BACKOFF_SECS=3600
@@ -317,6 +341,7 @@ NGIT_SYNC_MAX_BACKOFF_SECS=7200
317``` 341```
318 342
319**Notes:** 343**Notes:**
344
320- Backoff starts at 5 seconds and doubles on each failure 345- Backoff starts at 5 seconds and doubles on each failure
321- Capped at this maximum value 346- Capped at this maximum value
322- After 24 hours of failures, relay is marked "dead" and retried daily 347- After 24 hours of failures, relay is marked "dead" and retried daily
@@ -332,6 +357,7 @@ NGIT_SYNC_MAX_BACKOFF_SECS=7200
332**Required:** No 357**Required:** No
333 358
334**Examples:** 359**Examples:**
360
335```bash 361```bash
336# Default: 30 second delay 362# Default: 30 second delay
337NGIT_SYNC_STARTUP_DELAY_SECS=30 363NGIT_SYNC_STARTUP_DELAY_SECS=30
@@ -344,6 +370,7 @@ NGIT_SYNC_STARTUP_DELAY_SECS=60
344``` 370```
345 371
346**Notes:** 372**Notes:**
373
347- Allows connections to stabilize before catchup 374- Allows connections to stabilize before catchup
348- Reduces load on remote relays at startup 375- Reduces load on remote relays at startup
349- Set to 0 for immediate catchup (not recommended) 376- Set to 0 for immediate catchup (not recommended)
@@ -358,6 +385,7 @@ NGIT_SYNC_STARTUP_DELAY_SECS=60
358**Required:** No 385**Required:** No
359 386
360**Examples:** 387**Examples:**
388
361```bash 389```bash
362# Default: 10 second delay 390# Default: 10 second delay
363NGIT_SYNC_RECONNECT_DELAY_SECS=10 391NGIT_SYNC_RECONNECT_DELAY_SECS=10
@@ -370,6 +398,7 @@ NGIT_SYNC_RECONNECT_DELAY_SECS=30
370``` 398```
371 399
372**Notes:** 400**Notes:**
401
373- Prevents rate limiting from remote relays 402- Prevents rate limiting from remote relays
374- Applied after each successful reconnection 403- Applied after each successful reconnection
375- Only catches up on recent events (see lookback days) 404- Only catches up on recent events (see lookback days)
@@ -384,6 +413,7 @@ NGIT_SYNC_RECONNECT_DELAY_SECS=30
384**Required:** No 413**Required:** No
385 414
386**Examples:** 415**Examples:**
416
387```bash 417```bash
388# Default: 3 days lookback 418# Default: 3 days lookback
389NGIT_SYNC_RECONNECT_LOOKBACK_DAYS=3 419NGIT_SYNC_RECONNECT_LOOKBACK_DAYS=3
@@ -396,6 +426,7 @@ NGIT_SYNC_RECONNECT_LOOKBACK_DAYS=7
396``` 426```
397 427
398**Notes:** 428**Notes:**
429
399- Limits catchup queries to recent events only 430- Limits catchup queries to recent events only
400- Reduces load compared to full historical sync 431- Reduces load compared to full historical sync
401- Balance between completeness and performance 432- Balance between completeness and performance
@@ -413,6 +444,7 @@ NGIT_SYNC_RECONNECT_LOOKBACK_DAYS=7
413**Required:** No 444**Required:** No
414 445
415**Examples:** 446**Examples:**
447
416```bash 448```bash
417# Simple levels 449# Simple levels
418RUST_LOG=error # Errors only 450RUST_LOG=error # Errors only
@@ -429,6 +461,7 @@ RUST_LOG=debug,hyper=info,tokio=warn
429``` 461```
430 462
431**Log levels (most to least verbose):** 463**Log levels (most to least verbose):**
464
4321. `trace` - Very detailed, performance impact 4651. `trace` - Very detailed, performance impact
4332. `debug` - Detailed debugging information 4662. `debug` - Detailed debugging information
4343. `info` - General information (default) 4673. `info` - General information (default)
@@ -436,6 +469,7 @@ RUST_LOG=debug,hyper=info,tokio=warn
4365. `error` - Errors only 4695. `error` - Errors only
437 470
438**Production recommendation:** 471**Production recommendation:**
472
439```bash 473```bash
440RUST_LOG=info,ngit_grasp=debug 474RUST_LOG=info,ngit_grasp=debug
441``` 475```
@@ -452,6 +486,7 @@ RUST_LOG=info,ngit_grasp=debug
452**Status:** 🔜 Planned 486**Status:** 🔜 Planned
453 487
454**Examples:** 488**Examples:**
489
455```bash 490```bash
456NGIT_AUTH_REQUIRED=true # Require auth 491NGIT_AUTH_REQUIRED=true # Require auth
457NGIT_AUTH_REQUIRED=false # Public relay 492NGIT_AUTH_REQUIRED=false # Public relay
@@ -467,6 +502,7 @@ NGIT_AUTH_REQUIRED=false # Public relay
467**Status:** 🔜 Planned 502**Status:** 🔜 Planned
468 503
469**Examples:** 504**Examples:**
505
470```bash 506```bash
471NGIT_RATE_LIMIT_ENABLED=true 507NGIT_RATE_LIMIT_ENABLED=true
472NGIT_RATE_LIMIT_ENABLED=false 508NGIT_RATE_LIMIT_ENABLED=false
@@ -491,6 +527,7 @@ RUST_LOG=debug
491``` 527```
492 528
493**Notes:** 529**Notes:**
530
494- Never commit `.env` to version control 531- Never commit `.env` to version control
495- Use `.env.example` as a template 532- Use `.env.example` as a template
496- Environment variables override `.env` values 533- Environment variables override `.env` values
@@ -510,6 +547,7 @@ Error: Invalid configuration
510``` 547```
511 548
512**Validation checks:** 549**Validation checks:**
550
513- Required fields are present 551- Required fields are present
514- Values have correct format 552- Values have correct format
515- Paths are accessible and writable 553- Paths are accessible and writable
@@ -533,6 +571,7 @@ RUST_LOG=info,ngit_grasp=debug
533``` 571```
534 572
535**Additional production considerations:** 573**Additional production considerations:**
574
536- Use reverse proxy (nginx, Caddy) for HTTPS 575- Use reverse proxy (nginx, Caddy) for HTTPS
537- Set up log rotation 576- Set up log rotation
538- Configure monitoring 577- Configure monitoring
@@ -573,6 +612,7 @@ RUST_LOG=debug
573``` 612```
574 613
575**Testing notes:** 614**Testing notes:**
615
576- Use temporary directories 616- Use temporary directories
577- Use non-standard ports 617- Use non-standard ports
578- Clean up after tests 618- Clean up after tests
@@ -590,6 +630,7 @@ When multiple configuration sources exist:
5904. **Default values** (lowest priority) 6304. **Default values** (lowest priority)
591 631
592**Example:** 632**Example:**
633
593```bash 634```bash
594# .env file 635# .env file
595NGIT_BIND_ADDRESS=127.0.0.1:8080 636NGIT_BIND_ADDRESS=127.0.0.1:8080
@@ -610,4 +651,4 @@ NGIT_BIND_ADDRESS=0.0.0.0:3000 cargo run
610 651
611--- 652---
612 653
613*Part of the [ngit-grasp reference documentation](./)* 654_Part of the [ngit-grasp reference documentation](./)_
diff --git a/src/config.rs b/src/config.rs
index 7834a3f..94035e4 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -94,6 +94,8 @@ pub struct Config {
94 94
95 /// URL of bootstrap relay to sync from on startup (optional) 95 /// URL of bootstrap relay to sync from on startup (optional)
96 /// Sync discovers additional relays from repository announcements that list our service 96 /// Sync discovers additional relays from repository announcements that list our service
97 /// If no scheme is provided (wss:// or ws://), wss:// is assumed
98 /// Examples: "relay.example.com" -> "wss://relay.example.com", "wss://relay.example.com" -> unchanged
97 #[arg(long, env = "NGIT_SYNC_BOOTSTRAP_RELAY_URL")] 99 #[arg(long, env = "NGIT_SYNC_BOOTSTRAP_RELAY_URL")]
98 pub sync_bootstrap_relay_url: Option<String>, 100 pub sync_bootstrap_relay_url: Option<String>,
99 101
diff --git a/src/sync/relay_connection.rs b/src/sync/relay_connection.rs
index bd9ab80..21d864d 100644
--- a/src/sync/relay_connection.rs
+++ b/src/sync/relay_connection.rs
@@ -79,14 +79,38 @@ pub struct RelayConnection {
79} 79}
80 80
81impl RelayConnection { 81impl RelayConnection {
82 /// Normalize a relay URL to include a scheme (wss:// or ws://)
83 ///
84 /// If the URL already has a scheme, it's returned as-is.
85 /// If no scheme is provided, wss:// is assumed (secure by default).
86 ///
87 /// # Arguments
88 /// * `url` - The relay URL (with or without scheme)
89 ///
90 /// # Returns
91 /// The normalized URL with scheme
92 ///
93 /// # Examples
94 /// - `"relay.example.com"` -> `"wss://relay.example.com"`
95 /// - `"wss://relay.example.com"` -> `"wss://relay.example.com"`
96 /// - `"ws://relay.example.com"` -> `"ws://relay.example.com"`
97 fn normalize_url(url: &str) -> String {
98 if url.starts_with("wss://") || url.starts_with("ws://") {
99 url.to_string()
100 } else {
101 format!("wss://{}", url)
102 }
103 }
104
82 /// Create a new relay connection (not yet connected) 105 /// Create a new relay connection (not yet connected)
83 /// 106 ///
84 /// # Arguments 107 /// # Arguments
85 /// * `url` - The relay URL to connect to (e.g., "wss://relay.example.com") 108 /// * `url` - The relay URL to connect to (with or without scheme, e.g., "relay.example.com" or "wss://relay.example.com")
86 pub fn new(url: String) -> Self { 109 pub fn new(url: String) -> Self {
110 let normalized_url = Self::normalize_url(&url);
87 let client = Client::default(); 111 let client = Client::default();
88 Self { 112 Self {
89 url, 113 url: normalized_url,
90 client, 114 client,
91 database: None, 115 database: None,
92 nip77_warning_logged: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), 116 nip77_warning_logged: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
@@ -96,12 +120,13 @@ impl RelayConnection {
96 /// Create a new relay connection with database for negentropy sync 120 /// Create a new relay connection with database for negentropy sync
97 /// 121 ///
98 /// # Arguments 122 /// # Arguments
99 /// * `url` - The relay URL to connect to (e.g., "wss://relay.example.com") 123 /// * `url` - The relay URL to connect to (with or without scheme, e.g., "relay.example.com" or "wss://relay.example.com")
100 /// * `database` - Shared database for local event comparison during negentropy sync 124 /// * `database` - Shared database for local event comparison during negentropy sync
101 pub fn new_with_database(url: String, database: SharedDatabase) -> Self { 125 pub fn new_with_database(url: String, database: SharedDatabase) -> Self {
126 let normalized_url = Self::normalize_url(&url);
102 let client = Client::default(); 127 let client = Client::default();
103 Self { 128 Self {
104 url, 129 url: normalized_url,
105 client, 130 client,
106 database: Some(database), 131 database: Some(database),
107 nip77_warning_logged: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)), 132 nip77_warning_logged: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
@@ -491,3 +516,71 @@ impl RelayConnection {
491 self.database.is_some() 516 self.database.is_some()
492 } 517 }
493} 518}
519
520#[cfg(test)]
521mod tests {
522 use super::*;
523
524 #[test]
525 fn test_normalize_url_with_wss_scheme() {
526 let url = "wss://relay.example.com";
527 assert_eq!(RelayConnection::normalize_url(url), "wss://relay.example.com");
528 }
529
530 #[test]
531 fn test_normalize_url_with_ws_scheme() {
532 let url = "ws://relay.example.com";
533 assert_eq!(RelayConnection::normalize_url(url), "ws://relay.example.com");
534 }
535
536 #[test]
537 fn test_normalize_url_without_scheme() {
538 let url = "relay.example.com";
539 assert_eq!(RelayConnection::normalize_url(url), "wss://relay.example.com");
540 }
541
542 #[test]
543 fn test_normalize_url_without_scheme_with_port() {
544 let url = "relay.example.com:8080";
545 assert_eq!(RelayConnection::normalize_url(url), "wss://relay.example.com:8080");
546 }
547
548 #[test]
549 fn test_normalize_url_with_path() {
550 let url = "relay.example.com/nostr";
551 assert_eq!(RelayConnection::normalize_url(url), "wss://relay.example.com/nostr");
552 }
553
554 #[test]
555 fn test_new_normalizes_url() {
556 let conn = RelayConnection::new("relay.example.com".to_string());
557 assert_eq!(conn.url(), "wss://relay.example.com");
558 }
559
560 #[test]
561 fn test_new_preserves_wss_scheme() {
562 let conn = RelayConnection::new("wss://relay.example.com".to_string());
563 assert_eq!(conn.url(), "wss://relay.example.com");
564 }
565
566 #[test]
567 fn test_new_preserves_ws_scheme() {
568 let conn = RelayConnection::new("ws://relay.example.com".to_string());
569 assert_eq!(conn.url(), "ws://relay.example.com");
570 }
571
572 #[test]
573 fn test_new_with_database_normalizes_url() {
574 // This test just verifies the URL normalization works
575 // We can't easily test with_database without a real database
576 let conn = RelayConnection::new("git.shakespeare.diy".to_string());
577 assert_eq!(conn.url(), "wss://git.shakespeare.diy");
578 }
579
580 #[test]
581 fn test_normalize_url_real_world_example() {
582 // Test the exact case from the bug report
583 let url = "git.shakespeare.diy";
584 assert_eq!(RelayConnection::normalize_url(url), "wss://git.shakespeare.diy");
585 }
586}