pub enum ServiceAddress {
FrontDoor {
domain: String,
health_path: Option<String>,
},
Node {
node_id: String,
alpn: String,
},
}Expand description
Where a service answers, and therefore what a liveness probe asks (R926-F1).
§Why this replaced a bare domain: String
domain used to be required, and two of this camp’s services have no
honest value for it. yah-cloud is publish-only and carries
unset.yah-cloud.invalid — RFC 2606’s reserved TLD, chosen precisely
because the field demanded a string and there was none (the R546-S2
decision, recorded in that file’s own header). The push relay is worse
than awkward: it has no HTTP surface at all. It binds an iroh endpoint,
serves ALPN yah/push-relay/1, and is addressed by hex NodeId over
QUIC — so a .invalid domain there would not merely look wrong, it
would leave the service permanently unprobeable, which is the exact
hole R926 exists to close.
The alternative was a second health mechanism beside health_path.
This repo is below v1.0.0 and its standing rule is to change the one
mechanism rather than grow a parallel one, so addressing became a sum
type: a service declares exactly one way to be reached, and the prober
switches on it. A service cannot accidentally declare both, and the
enum is what makes that unrepresentable rather than merely validated.
§TOML
[address]
kind = "front-door"
domain = "cloud.mesh.yah.dev"
health_path = "/key?v=138"[address]
kind = "node"
node_id = "8f2c…" # 64 hex chars
alpn = "yah/push-relay/1"Tagged rather than untagged: an operator edits this file by hand, and serde’s untagged errors name none of the variants it tried.
Variants§
FrontDoor
An HTTPS front door on a public or mesh domain. What all ten services registered in this camp today are.
Fields
health_path: Option<String>Path the probe requests, relative to domain. None means
/.
/ is the right question for a service whose root serves a
site, and the wrong one for an API. An account/RPC origin that
versions its surface answers only under its prefix and 404s
everything else on purpose — so probing the root reported a
broken cell for a service that was behaving exactly as
designed, which is the failure mode the probe exists to remove
rather than add to. Naming the path here makes the probe ask a
question the service has agreed to answer.
Service-scoped rather than per-component or per-mirror: one domain has one front door and therefore one canonical liveness URL, and that URL is a property of the service’s own router — it does not vary by environment, so repeating it per mirror would only let the copies drift.
Must be absolute (leading /); the loader refuses anything
else rather than silently joining it onto the origin.
Node
An iroh endpoint: a stable NodeId speaking one ALPN. Probed by
dialling that ALPN and expecting an answer.
There is no path and no port because there is no URL — QUIC
multiplexes on the ALPN, and the NodeId is the address. A
service reached this way is unreachable from a browser tab, so the
Services grid links nothing and renders the node id instead.
Implementations§
Source§impl ServiceAddress
impl ServiceAddress
Sourcepub fn front_door(domain: impl Into<String>) -> Self
pub fn front_door(domain: impl Into<String>) -> Self
Shorthand for the common case.
Sourcepub fn front_door_at(
domain: impl Into<String>,
health_path: impl Into<String>,
) -> Self
pub fn front_door_at( domain: impl Into<String>, health_path: impl Into<String>, ) -> Self
A front door with a declared probe path.
pub fn node(node_id: impl Into<String>, alpn: impl Into<String>) -> Self
Sourcepub fn domain(&self) -> Option<&str>
pub fn domain(&self) -> Option<&str>
The domain, for the callers that genuinely need one (DNS, zone
selection, a public URL). None for a node-addressed service —
and those callers must say so rather than substitute a
placeholder, which is how unset.yah-cloud.invalid happened.
pub fn health_path(&self) -> Option<&str>
Trait Implementations§
Source§impl Clone for ServiceAddress
impl Clone for ServiceAddress
Source§impl Debug for ServiceAddress
impl Debug for ServiceAddress
Source§impl<'de> Deserialize<'de> for ServiceAddress
impl<'de> Deserialize<'de> for ServiceAddress
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for ServiceAddress
Source§impl PartialEq for ServiceAddress
impl PartialEq for ServiceAddress
Source§impl Serialize for ServiceAddress
impl Serialize for ServiceAddress
impl StructuralPartialEq for ServiceAddress
Auto Trait Implementations§
impl Freeze for ServiceAddress
impl RefUnwindSafe for ServiceAddress
impl Send for ServiceAddress
impl Sync for ServiceAddress
impl Unpin for ServiceAddress
impl UnsafeUnpin for ServiceAddress
impl UnwindSafe for ServiceAddress
Blanket Implementations§
impl<T> Allocation for T
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<K, Q> Equivalent<Q> for K
impl<K, Q> Equivalent<Q> for K
Source§fn equivalent(&self, key: &Q) -> bool
fn equivalent(&self, key: &Q) -> bool
key and return true if they are equal.impl<T> ErasedDestructor for Twhere
T: 'static,
impl<T> Fruit for T
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
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