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 extension;
65pub mod hooks;
66pub mod server;
67pub mod snapshots;
68
69pub use crate::io::reactor::{ConnRole, TcpTransport, Transport};
70
71pub use self::builder::ServerBuilder;
72pub use self::error::EmbedError;
73pub use self::events::{
74 CloseReason, ConnId, ConnRoleTag, EventStream, PeerDownReason, PeerId, ServerEvent,
75};
76pub use self::extension::{CommandExtension, HsetOutcome};
77pub use self::hooks::{
78 BoxFuture, CryptoProvider, CryptoProviderError, Datastore, DatastoreError, DnsSeedsProvider,
79 FloridaSeedsProvider, LoggingMetricsSink, MemcacheDatastore, MemoryDatastore, MetricsError,
80 MetricsSink, Protocol, RedisDatastore, RustCryptoProvider, SeedsProvider, SimpleSeedsProvider,
81};
82pub use self::server::{Server, ServerHandle};
83pub use self::snapshots::{DatacenterSnapshot, PeerSnapshot, RackSnapshot, RingSnapshot};
84
85impl Server {
86 /// Convenience entry point.
87 ///
88 /// # Examples
89 ///
90 /// ```
91 /// use dynomite::embed::Server;
92 /// let _b = Server::builder("dyn_o_mite");
93 /// ```
94 #[must_use]
95 pub fn builder(pool_name: impl Into<String>) -> ServerBuilder {
96 ServerBuilder::new(pool_name)
97 }
98
99 /// One-shot "validate, build, and start" helper.
100 ///
101 /// Equivalent to calling `builder.build()?.start().await`. The
102 /// chained-call form remains available for embedders that
103 /// want to inspect the [`Server`] before spawning tasks; this
104 /// helper exists because most embedders only ever build then
105 /// immediately start.
106 ///
107 /// # Errors
108 ///
109 /// Returns the same [`EmbedError`] variants that
110 /// [`ServerBuilder::build`] and [`Server::start`] surface.
111 ///
112 /// # Examples
113 ///
114 /// ```no_run
115 /// use dynomite::embed::{Server, ServerBuilder};
116 /// use dynomite::conf::DataStore;
117 /// # tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap().block_on(async {
118 /// let builder = ServerBuilder::new("dyn_o_mite")
119 /// .listen("127.0.0.1:0".parse().unwrap())
120 /// .dyn_listen("127.0.0.1:0".parse().unwrap())
121 /// .data_store(DataStore::Redis)
122 /// .servers(vec![dynomite::conf::ConfServer::parse("127.0.0.1:6379:1").unwrap()])
123 /// .tokens_str("0");
124 /// let handle = Server::start_with(builder).await.unwrap();
125 /// handle.shutdown().await.unwrap();
126 /// # });
127 /// ```
128 pub async fn start_with(builder: ServerBuilder) -> Result<ServerHandle, EmbedError> {
129 builder.build()?.start().await
130 }
131}