pub struct Firestore { /* private fields */ }Expand description
A document in Firestore, as a configuration source.
Not Clone: it holds the session that caches an access token, and two
clones fetching tokens separately would double the traffic.
Implementations§
Source§impl Firestore
impl Firestore
Sourcepub fn new(project: impl Into<String>, path: impl Into<Keys>) -> Self
pub fn new(project: impl Into<String>, path: impl Into<Keys>) -> Self
The document at path in project’s default database.
path is collection-then-document — config/db, or
environments/prod/config/db for a nested one — or a Keys, for the
several-documents form.
The document is wrapped under the section key the configuration type
uses, "db" by default; change it with with_key.
Several documents all land under that one key and merge, later winning.
Sourcepub fn with_key(self, key: impl Into<String>) -> Self
pub fn with_key(self, key: impl Into<String>) -> Self
The section key to wrap the document under.
Must match the key the config type’s builder(..) was given.
Sourcepub fn with_database(self, database: impl Into<String>) -> Self
pub fn with_database(self, database: impl Into<String>) -> Self
A database other than (default).
Sourcepub fn with_auth(self, auth: Auth) -> Self
pub fn with_auth(self, auth: Auth) -> Self
How to obtain an access token.
Defaults to Auth::Emulator, which sends none — right for the
emulator and wrong for anything else, so a real deployment always names
one.
Sourcepub fn with_endpoint(self, endpoint: impl Into<String>) -> Self
pub fn with_endpoint(self, endpoint: impl Into<String>) -> Self
A different API endpoint.
What the Firestore emulator needs: FIRESTORE_EMULATOR_HOST is
127.0.0.1:8080, and this takes http://127.0.0.1:8080.
Sourcepub fn with_timeout(self, timeout: Duration) -> Self
pub fn with_timeout(self, timeout: Duration) -> Self
How long a single fetch may take before it is given up on. Ten seconds by default.
The deadline for one fetch attempt, excluding retries the
underlying client performs — the same sentence every store in this
family answers to. ureq performs none of its own, so here the
deadline is the whole story.
It covers fetching a token from the metadata server too: that request goes through the same client, and a token fetch that hangs stalls the read behind it.
Sourcepub fn with_agent(self, agent: Agent) -> Self
pub fn with_agent(self, agent: Agent) -> Self
Uses an HTTP client the program already has.
The escape hatch, and it stays one: with_tls covers
a private CA and a client certificate, and everything else — a proxy, a
connection pool, an option this crate has never heard of — still lives
here. Setting both is refused rather than resolved; see
with_tls.
Sourcepub fn with_tls(self, tls: TlsConfig) -> Self
pub fn with_tls(self, tls: TlsConfig) -> Self
A private certificate authority, a client certificate, or both.
The same three settings, spelled the same way, in all seven store
crates — and spelled as data, so nothing here names a ureq type:
let firestore = Firestore::new("my-project", "config/db")
.with_endpoint("https://firestore.internal")
.with_tls(TlsConfig::new().with_ca_certificate_file("/etc/ssl/private-ca.pem"));Firestore expresses all of it: a CA from a file or from bytes, and a client certificate from either. A CA replaces the platform trust store rather than adding to it, so a deployment that needs both puts both in the file.
Against Google’s own endpoint this is rarely what you want — their
certificates chain to a public authority the platform already trusts.
It is for the deployments that do not go there directly: an enterprise
TLS-inspecting proxy, or an emulator behind
with_endpoint with a certificate of its own.
There is no way to turn verification off; TlsConfig’s own
documentation argues that one.
Nothing is read here. The files are opened when the first request builds the client, so a missing CA is an error naming the path.
§With with_agent
Setting both is refused, at the first request, naming both calls. An agent already carries a complete TLS configuration, so “apply this too” has no meaning that is not a guess — and the guess that loses silently discards a CA.
Sourcepub fn reporting_to(self, sink: RemoteSink) -> Self
pub fn reporting_to(self, sink: RemoteSink) -> Self
Reports the watch loop’s failed attempts to sink.
A watch loop is the half of a store dynamic-config cannot otherwise
see. RemoteSink::apply records a delivery, so a working watch keeps
RemoteStatus current — but a loop whose poll is failing, whose
document was deleted or whose access token was refused delivers
nothing, and without this says nothing: dynamic_config_remote_up
would report the last delivery rather than the last attempt, and a
project that stopped answering an hour ago would look healthy until
something called refresh_remote.
let sink = DbConfig::remote_sink();
Firestore::new("my-project", "config/db")
.with_auth(Auth::metadata_server())
.reporting_to(sink)
.watch(&watching, Duration::from_secs(30), move |document| sink.apply(document))One sink serves both halves, and it is taken once, where the loop is
wired: a sink is Copy, and the generation it captures there is what
fences a loop winding down after its source was replaced from charging
its failures to the replacement.
A failure to report a failure never reaches the loop — reporting is
infallible and silent — and what it moves is deliberately narrow: the
failure streak and the last failure, never the fetch clock. So
dynamic_config_remote_last_fetch_seconds keeps ageing while
dynamic_config_remote_up goes to zero, which is the pair that says
both the store is not answering and how stale what it last said has
become.
A fetch needs none of this: a fetch records
itself, through the Remote that performed it.
Sourcepub fn watch<F>(
&self,
watching: &Watching,
interval: Duration,
on_change: F,
) -> Result<(), Error>
pub fn watch<F>( &self, watching: &Watching, interval: Duration, on_change: F, ) -> Result<(), Error>
Calls on_change when the document’s update time moves, checking every
interval.
Firestore can push — the real-time API is a gRPC stream — and this
deliberately does not use it: that would put a gRPC stack in a crate
whose whole point is a plain HTTP read. Polling reads one small document
and compares updateTime, which for a configuration document checked
every thirty seconds is a rounding error against a project’s quota.
The current value is not delivered at startup, for the same reason a file watcher does not report an edit when it starts.
A failed check does not end the watch. stop is noticed within a
quarter second whatever interval is. Surviving a failure quietly is
not the same as hiding it: reporting_to hands
each failed attempt to a RemoteSink, so a loop that has been
failing for an hour stops reporting the store as healthy.
§Errors
If the document comes back without an updateTime — there is then
nothing to compare, so every tick would find “no change” and the watch
would silently never fire. Or if on_change returns an error, which
ends the watch. Transport failures do not surface here; they are
retried.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Firestore
impl !RefUnwindSafe for Firestore
impl !UnwindSafe for Firestore
impl Send for Firestore
impl Sync for Firestore
impl Unpin for Firestore
impl UnsafeUnpin for Firestore
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> Paint for Twhere
T: ?Sized,
impl<T> Paint for Twhere
T: ?Sized,
Source§fn fg(&self, value: Color) -> Painted<&T>
fn fg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the foreground set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like red() and
green(), which have the same functionality but are
pithier.
§Example
Set foreground color to white using fg():
use yansi::{Paint, Color};
painted.fg(Color::White);Set foreground color to white using white().
use yansi::Paint;
painted.white();Source§fn bright_black(&self) -> Painted<&T>
fn bright_black(&self) -> Painted<&T>
Source§fn bright_red(&self) -> Painted<&T>
fn bright_red(&self) -> Painted<&T>
Source§fn bright_green(&self) -> Painted<&T>
fn bright_green(&self) -> Painted<&T>
Source§fn bright_yellow(&self) -> Painted<&T>
fn bright_yellow(&self) -> Painted<&T>
Source§fn bright_blue(&self) -> Painted<&T>
fn bright_blue(&self) -> Painted<&T>
Source§fn bright_magenta(&self) -> Painted<&T>
fn bright_magenta(&self) -> Painted<&T>
Source§fn bright_cyan(&self) -> Painted<&T>
fn bright_cyan(&self) -> Painted<&T>
Source§fn bright_white(&self) -> Painted<&T>
fn bright_white(&self) -> Painted<&T>
Source§fn bg(&self, value: Color) -> Painted<&T>
fn bg(&self, value: Color) -> Painted<&T>
Returns a styled value derived from self with the background set to
value.
This method should be used rarely. Instead, prefer to use color-specific
builder methods like on_red() and
on_green(), which have the same functionality but
are pithier.
§Example
Set background color to red using fg():
use yansi::{Paint, Color};
painted.bg(Color::Red);Set background color to red using on_red().
use yansi::Paint;
painted.on_red();Source§fn on_primary(&self) -> Painted<&T>
fn on_primary(&self) -> Painted<&T>
Source§fn on_magenta(&self) -> Painted<&T>
fn on_magenta(&self) -> Painted<&T>
Source§fn on_bright_black(&self) -> Painted<&T>
fn on_bright_black(&self) -> Painted<&T>
Source§fn on_bright_red(&self) -> Painted<&T>
fn on_bright_red(&self) -> Painted<&T>
Source§fn on_bright_green(&self) -> Painted<&T>
fn on_bright_green(&self) -> Painted<&T>
Source§fn on_bright_yellow(&self) -> Painted<&T>
fn on_bright_yellow(&self) -> Painted<&T>
Source§fn on_bright_blue(&self) -> Painted<&T>
fn on_bright_blue(&self) -> Painted<&T>
Source§fn on_bright_magenta(&self) -> Painted<&T>
fn on_bright_magenta(&self) -> Painted<&T>
Source§fn on_bright_cyan(&self) -> Painted<&T>
fn on_bright_cyan(&self) -> Painted<&T>
Source§fn on_bright_white(&self) -> Painted<&T>
fn on_bright_white(&self) -> Painted<&T>
Source§fn attr(&self, value: Attribute) -> Painted<&T>
fn attr(&self, value: Attribute) -> Painted<&T>
Enables the styling Attribute value.
This method should be used rarely. Instead, prefer to use
attribute-specific builder methods like bold() and
underline(), which have the same functionality
but are pithier.
§Example
Make text bold using attr():
use yansi::{Paint, Attribute};
painted.attr(Attribute::Bold);Make text bold using using bold().
use yansi::Paint;
painted.bold();Source§fn rapid_blink(&self) -> Painted<&T>
fn rapid_blink(&self) -> Painted<&T>
Source§fn quirk(&self, value: Quirk) -> Painted<&T>
fn quirk(&self, value: Quirk) -> Painted<&T>
Enables the yansi Quirk value.
This method should be used rarely. Instead, prefer to use quirk-specific
builder methods like mask() and
wrap(), which have the same functionality but are
pithier.
§Example
Enable wrapping using .quirk():
use yansi::{Paint, Quirk};
painted.quirk(Quirk::Wrap);Enable wrapping using wrap().
use yansi::Paint;
painted.wrap();Source§fn clear(&self) -> Painted<&T>
👎Deprecated since 1.0.1: renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
fn clear(&self) -> Painted<&T>
renamed to resetting() due to conflicts with Vec::clear().
The clear() method will be removed in a future release.
Source§fn whenever(&self, value: Condition) -> Painted<&T>
fn whenever(&self, value: Condition) -> Painted<&T>
Conditionally enable styling based on whether the Condition value
applies. Replaces any previous condition.
See the crate level docs for more details.
§Example
Enable styling painted only when both stdout and stderr are TTYs:
use yansi::{Paint, Condition};
painted.red().on_yellow().whenever(Condition::STDOUTERR_ARE_TTY);