|
6 | 6 | //! |
7 | 7 | //! The primary way of addressing a node is by using the [`NodeAddr`]. |
8 | 8 |
|
9 | | -use std::{collections::BTreeSet, fmt, net::SocketAddr, ops::Deref, str::FromStr}; |
| 9 | +use std::{collections::BTreeSet, net::SocketAddr}; |
10 | 10 |
|
11 | | -use anyhow::Context; |
12 | 11 | use serde::{Deserialize, Serialize}; |
13 | | -use url::Url; |
14 | 12 |
|
15 | 13 | use crate::key::{NodeId, PublicKey}; |
| 14 | +pub use crate::relay_url::RelayUrl; |
16 | 15 |
|
17 | 16 | /// Network-level addressing information for an iroh-net node. |
18 | 17 | /// |
@@ -199,120 +198,3 @@ pub enum AddrInfoOptions { |
199 | 198 | /// Includes the Node ID and the direct addresses. |
200 | 199 | Addresses, |
201 | 200 | } |
202 | | - |
203 | | -/// A URL identifying a relay server. |
204 | | -/// |
205 | | -/// This is but a wrapper around [`Url`], with a few custom tweaks: |
206 | | -/// |
207 | | -/// - A relay URL is never a relative URL, so an implicit `.` is added at the end of the |
208 | | -/// domain name if missing. |
209 | | -/// |
210 | | -/// - [`fmt::Debug`] is implemented so it prints the URL rather than the URL struct fields. |
211 | | -/// Useful when logging e.g. `Option<RelayUrl>`. |
212 | | -/// |
213 | | -/// To create a [`RelayUrl`] use the `From<Url>` implementation. |
214 | | -#[derive( |
215 | | - Clone, derive_more::Display, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, |
216 | | -)] |
217 | | -pub struct RelayUrl(Url); |
218 | | - |
219 | | -impl From<Url> for RelayUrl { |
220 | | - fn from(mut url: Url) -> Self { |
221 | | - if let Some(domain) = url.domain() { |
222 | | - if !domain.ends_with('.') { |
223 | | - let domain = String::from(domain) + "."; |
224 | | - |
225 | | - // This can fail, though it is unlikely the resulting URL is usable as a |
226 | | - // relay URL, probably it has the wrong scheme or is not a base URL or the |
227 | | - // like. We don't do full URL validation however, so just silently leave |
228 | | - // this bad URL in place. Something will fail later. |
229 | | - url.set_host(Some(&domain)).ok(); |
230 | | - } |
231 | | - } |
232 | | - Self(url) |
233 | | - } |
234 | | -} |
235 | | - |
236 | | -/// Support for parsing strings directly. |
237 | | -/// |
238 | | -/// If you need more control over the error first create a [`Url`] and use [`RelayUrl::from`] |
239 | | -/// instead. |
240 | | -impl FromStr for RelayUrl { |
241 | | - type Err = anyhow::Error; |
242 | | - |
243 | | - fn from_str(s: &str) -> Result<Self, Self::Err> { |
244 | | - let inner = Url::from_str(s).context("invalid URL")?; |
245 | | - Ok(RelayUrl::from(inner)) |
246 | | - } |
247 | | -} |
248 | | - |
249 | | -impl From<RelayUrl> for Url { |
250 | | - fn from(value: RelayUrl) -> Self { |
251 | | - value.0 |
252 | | - } |
253 | | -} |
254 | | - |
255 | | -/// Dereferences to the wrapped [`Url`]. |
256 | | -/// |
257 | | -/// Note that [`DerefMut`] is not implemented on purpose, so this type has more flexibility |
258 | | -/// to change the inner later. |
259 | | -/// |
260 | | -/// [`DerefMut`]: std::ops::DerefMut |
261 | | -impl Deref for RelayUrl { |
262 | | - type Target = Url; |
263 | | - |
264 | | - fn deref(&self) -> &Self::Target { |
265 | | - &self.0 |
266 | | - } |
267 | | -} |
268 | | - |
269 | | -impl fmt::Debug for RelayUrl { |
270 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
271 | | - f.debug_tuple("RelayUrl") |
272 | | - .field(&DbgStr(self.0.as_str())) |
273 | | - .finish() |
274 | | - } |
275 | | -} |
276 | | - |
277 | | -/// Helper struct to format a &str without allocating a String. |
278 | | -/// |
279 | | -/// Maybe this is entirely unneeded and the compiler would be smart enough to never allocate |
280 | | -/// the String anyway. Who knows. Writing this was faster than checking the assembler |
281 | | -/// output. |
282 | | -struct DbgStr<'a>(&'a str); |
283 | | - |
284 | | -impl<'a> fmt::Debug for DbgStr<'a> { |
285 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
286 | | - write!(f, r#""{}""#, self.0) |
287 | | - } |
288 | | -} |
289 | | - |
290 | | -#[cfg(test)] |
291 | | -mod tests { |
292 | | - use super::*; |
293 | | - |
294 | | - #[test] |
295 | | - fn test_relay_url_debug_display() { |
296 | | - let url = RelayUrl::from(Url::parse("https://example.com").unwrap()); |
297 | | - |
298 | | - assert_eq!(format!("{url:?}"), r#"RelayUrl("https://example.com./")"#); |
299 | | - |
300 | | - assert_eq!(format!("{url}"), "https://example.com./"); |
301 | | - } |
302 | | - |
303 | | - #[test] |
304 | | - fn test_relay_url_absolute() { |
305 | | - let url = RelayUrl::from(Url::parse("https://example.com").unwrap()); |
306 | | - |
307 | | - assert_eq!(url.domain(), Some("example.com.")); |
308 | | - |
309 | | - let url1 = RelayUrl::from(Url::parse("https://example.com.").unwrap()); |
310 | | - assert_eq!(url, url1); |
311 | | - |
312 | | - let url2 = RelayUrl::from(Url::parse("https://example.com./").unwrap()); |
313 | | - assert_eq!(url, url2); |
314 | | - |
315 | | - let url3 = RelayUrl::from(Url::parse("https://example.com/").unwrap()); |
316 | | - assert_eq!(url, url3); |
317 | | - } |
318 | | -} |
0 commit comments