pub struct CanopyClient { /* private fields */ }Expand description
HTTP client with auth configured for talking to a canopy server.
Tries two auth paths in order of preference:
- Tailscale: if the canopy tailnet endpoint is reachable, plain HTTPS works (auth is implicit via tailscale identity).
- mTLS: a fresh self-signed cert from the device key, short-lived
([
CERT_VALIDITY_DAYS]); for long-running daemons,Self::renewshould tick onCERT_RENEW_AFTERto swap in a fresh cert before expiry.
Self::refresh re-probes tailscale and swaps modes on reload.
Implementations§
Source§impl CanopyClient
impl CanopyClient
Sourcepub async fn new(
tamanu_version: impl Into<String>,
device_key_pem: Option<&str>,
make_builder: impl Fn() -> ClientBuilder + Send + Sync + 'static,
) -> Result<Option<Self>>
pub async fn new( tamanu_version: impl Into<String>, device_key_pem: Option<&str>, make_builder: impl Fn() -> ClientBuilder + Send + Sync + 'static, ) -> Result<Option<Self>>
Build a canopy client, preferring tailscale and falling back to mTLS.
Probes the tailscale canopy endpoint first; if reachable, uses it.
Otherwise, if a device key PEM is provided, builds an mTLS client.
Returns Ok(None) if neither path is available.
tamanu_version is the version of the Tamanu install this client
speaks for; sent on every request via the X-Version header.
make_builder supplies the base reqwest::ClientBuilder — see
ClientBuilderFactory. Use client_builder for a sensible default.
Sourcepub async fn is_tailscale(&self) -> bool
pub async fn is_tailscale(&self) -> bool
Returns true if the client is currently using the tailscale path.
Sourcepub async fn refresh(&self) -> Result<()>
pub async fn refresh(&self) -> Result<()>
Re-probe tailscale and swap modes if the picture has changed.
Intended to be called when the daemon receives a reload signal.
Sourcepub async fn renew(&self) -> Result<()>
pub async fn renew(&self) -> Result<()>
Rebuild the underlying HTTP client with a fresh certificate.
No-op in tailscale mode (no cert to rotate). In mTLS mode, atomically replaces the live client; in-flight requests continue with the old client until they complete.
Sourcepub async fn post_status(
&self,
base_url: &Url,
server_id: &str,
payload: &Value,
) -> Result<()>
pub async fn post_status( &self, base_url: &Url, server_id: &str, payload: &Value, ) -> Result<()>
POST a status snapshot to the canopy server.
In tailscale mode, base_url is ignored and a {TAILSCALE_URL}/public/status/{server_id}
URL is used. In mTLS mode, posts to {base_url}/status/{server_id}.
The payload is free-form JSON; the canopy /status contract reserves the
top-level healthy: bool and health: [] keys. The body is gzip-encoded
with Content-Encoding: gzip.
Sourcepub async fn get(
&self,
base_url: &Url,
tailscale_path: &str,
mtls_path: &str,
) -> Result<Response>
pub async fn get( &self, base_url: &Url, tailscale_path: &str, mtls_path: &str, ) -> Result<Response>
GET a path on the canopy server, routed via tailscale when available.
In tailscale mode, the request goes to {TAILSCALE_URL}{tailscale_path}
(typically /public/..., the only mount that accepts tagged-device
tailscale callers). In mTLS mode, the request goes to {base_url}{mtls_path}.
Returns the raw response — the caller is responsible for status checks and body parsing so they can choose how to fall back if the response isn’t usable.
Sourcepub async fn post_event(
&self,
base_url: &Url,
event: NewEvent<'_>,
) -> Result<()>
pub async fn post_event( &self, base_url: &Url, event: NewEvent<'_>, ) -> Result<()>
POST an event to the canopy server.
In tailscale mode, base_url is ignored and TAILSCALE_URL is used.
In mTLS mode, posts to {base_url}/events.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for CanopyClient
impl !RefUnwindSafe for CanopyClient
impl Send for CanopyClient
impl Sync for CanopyClient
impl Unpin for CanopyClient
impl UnsafeUnpin for CanopyClient
impl !UnwindSafe for CanopyClient
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more