Skip to main content

dynomite/embed/
mod.rs

1//! Public embedding API for the Dynomite engine.
2//!
3//! `dynomite::embed` is the surface an embedding program uses to
4//! construct, run, observe, and shut down a Dynomite engine
5//! in-process. The same surface drives the [`dynomited`] binary;
6//! the binary is a thin wrapper around this module rather than a
7//! parallel code path.
8//!
9//! # Two-tier API
10//!
11//! 1. [`Server::builder`] returns a [`ServerBuilder`] - a typed,
12//!    fluent, validated-at-`build` builder that mirrors every
13//!    YAML-visible [`crate::conf::ConfPool`] field plus typed
14//!    setters for hook traits with no YAML form.
15//! 2. [`Server::start`] returns immediately; the tokio runtime
16//!    owns the background work. The caller drives the running
17//!    server through a [`ServerHandle`].
18//!
19//! # Hooks
20//!
21//! Five public traits expose every cross-cutting concern an
22//! embedder may want to override:
23//!
24//! * [`hooks::Datastore`] - backing store (Redis / Memcache /
25//!   custom).
26//! * [`hooks::SeedsProvider`] - service discovery integration.
27//! * [`hooks::CryptoProvider`] - HSM / KMS integration.
28//! * [`hooks::MetricsSink`] - exporter integration.
29//! * [`crate::io::reactor::Transport`] - already exposed by
30//!   `io::reactor`; re-exported here as
31//!   [`Transport`](crate::embed::Transport) for discoverability.
32//!
33//! Every trait has at least one default implementation shipped
34//! in-crate, and the crate-root re-exports below mean a typical
35//! embedder writes
36//! `use dynomite::embed::{Server, ServerBuilder, ServerHandle};`
37//! without reaching into the submodules.
38//!
39//! # Examples
40//!
41//! ```no_run
42//! use dynomite::embed::{Server, ServerBuilder};
43//! use dynomite::conf::DataStore;
44//! # tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap().block_on(async {
45//! let server: Server = ServerBuilder::new("dyn_o_mite")
46//!     .listen("127.0.0.1:0".parse().unwrap())
47//!     .dyn_listen("127.0.0.1:0".parse().unwrap())
48//!     .data_store(DataStore::Redis)
49//!     .servers(vec![dynomite::conf::ConfServer::parse("127.0.0.1:6379:1").unwrap()])
50//!     .tokens_str("0")
51//!     .build()
52//!     .unwrap();
53//! let handle = server.start().await.unwrap();
54//! assert_eq!(handle.peers().len(), 1);
55//! handle.shutdown().await.unwrap();
56//! # });
57//! ```
58//!
59//! [`dynomited`]: ../../dynomited/index.html
60
61pub mod builder;
62pub mod error;
63pub mod events;
64pub mod hooks;
65pub mod server;
66pub mod snapshots;
67
68pub use crate::io::reactor::{ConnRole, TcpTransport, Transport};
69
70pub use self::builder::ServerBuilder;
71pub use self::error::EmbedError;
72pub use self::events::{
73    CloseReason, ConnId, ConnRoleTag, EventStream, PeerDownReason, PeerId, ServerEvent,
74};
75pub use self::hooks::{
76    BoxFuture, CryptoProvider, CryptoProviderError, Datastore, DatastoreError, DnsSeedsProvider,
77    FloridaSeedsProvider, LoggingMetricsSink, MemcacheDatastore, MemoryDatastore, MetricsError,
78    MetricsSink, Protocol, RedisDatastore, RustCryptoProvider, SeedsProvider, SimpleSeedsProvider,
79};
80pub use self::server::{Server, ServerHandle};
81pub use self::snapshots::{DatacenterSnapshot, PeerSnapshot, RackSnapshot, RingSnapshot};
82
83impl Server {
84    /// Convenience entry point.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use dynomite::embed::Server;
90    /// let _b = Server::builder("dyn_o_mite");
91    /// ```
92    #[must_use]
93    pub fn builder(pool_name: impl Into<String>) -> ServerBuilder {
94        ServerBuilder::new(pool_name)
95    }
96
97    /// One-shot "validate, build, and start" helper.
98    ///
99    /// Equivalent to calling `builder.build()?.start().await`. The
100    /// chained-call form remains available for embedders that
101    /// want to inspect the [`Server`] before spawning tasks; this
102    /// helper exists because most embedders only ever build then
103    /// immediately start.
104    ///
105    /// # Errors
106    ///
107    /// Returns the same [`EmbedError`] variants that
108    /// [`ServerBuilder::build`] and [`Server::start`] surface.
109    ///
110    /// # Examples
111    ///
112    /// ```no_run
113    /// use dynomite::embed::{Server, ServerBuilder};
114    /// use dynomite::conf::DataStore;
115    /// # tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap().block_on(async {
116    /// let builder = ServerBuilder::new("dyn_o_mite")
117    ///     .listen("127.0.0.1:0".parse().unwrap())
118    ///     .dyn_listen("127.0.0.1:0".parse().unwrap())
119    ///     .data_store(DataStore::Redis)
120    ///     .servers(vec![dynomite::conf::ConfServer::parse("127.0.0.1:6379:1").unwrap()])
121    ///     .tokens_str("0");
122    /// let handle = Server::start_with(builder).await.unwrap();
123    /// handle.shutdown().await.unwrap();
124    /// # });
125    /// ```
126    pub async fn start_with(builder: ServerBuilder) -> Result<ServerHandle, EmbedError> {
127        builder.build()?.start().await
128    }
129}