use miette::Result;
use reqwest::Url;
use crate::{CanopyClient, ReqwestTransport};
pub async fn connect(
device_key_pem: Option<&str>,
make_builder: impl Fn() -> reqwest::ClientBuilder + Send + Sync + 'static,
) -> Result<Option<CanopyClient>> {
connect_to(
crate::DEFAULT_CANOPY_URL
.parse()
.expect("default canopy URL is valid"),
crate::TAILSCALE_URL
.parse()
.expect("default tailscale URL is valid"),
device_key_pem,
make_builder,
)
.await
}
pub async fn connect_to(
base_url: Url,
tailscale_url: Url,
device_key_pem: Option<&str>,
make_builder: impl Fn() -> reqwest::ClientBuilder + Send + Sync + 'static,
) -> Result<Option<CanopyClient>> {
Ok(
ReqwestTransport::new(base_url, tailscale_url, device_key_pem, make_builder)
.await?
.map(CanopyClient::new),
)
}
#[cfg(test)]
mod tests {
use crate::{
DEFAULT_CANOPY_URL,
test_support::{closed_url, serve_once},
};
use super::*;
#[tokio::test]
async fn connect_to_builds_on_the_default_transport() {
let (tailnet, _server) = serve_once("HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\n[]");
let client = connect_to(
DEFAULT_CANOPY_URL.parse().unwrap(),
tailnet.parse().unwrap(),
None,
reqwest::Client::builder,
)
.await
.expect("keyless build should not error")
.expect("a reachable tailnet is an auth path in its own right");
assert!(client.transport().is_tailscale().await);
client
.transport()
.renew()
.await
.expect("renew should be a no-op");
}
#[tokio::test]
async fn connect_to_yields_no_client_without_an_auth_path() {
let client = connect_to(
DEFAULT_CANOPY_URL.parse().unwrap(),
closed_url().parse().unwrap(),
None,
reqwest::Client::builder,
)
.await
.expect("keyless build should not error");
assert!(client.is_none());
}
}