summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRadosław Kot <rdkt13@gmail.com>2021-06-26 15:32:44 +0200
committerRadosław Kot <rdkt13@gmail.com>2021-07-03 20:30:21 +0200
commitf4de34eefe95cead9527557abcfddc2648d30278 (patch)
tree3454d8f9a576e178ce8edb03e6357ddb442edc73
parentc708d44985805b31b60697643ca77fd64315330e (diff)
Add example implementation using async source
Signed-off-by: Matthias Beyer <mail@beyermatthias.de> Reviewed-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--Cargo.toml4
-rw-r--r--examples/async_source/main.rs75
2 files changed, 79 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 5d0db61..f72389f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -40,3 +40,7 @@ json5_rs = { version = "0.3", optional = true, package = "json5" }
serde_derive = "1.0.8"
float-cmp = "0.8"
chrono = { version = "0.4", features = ["serde"] }
+tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util", "time"]}
+warp = "0.3.1"
+futures = "0.3.15"
+reqwest = "0.11.3"
diff --git a/examples/async_source/main.rs b/examples/async_source/main.rs
new file mode 100644
index 0000000..979f829
--- /dev/null
+++ b/examples/async_source/main.rs
@@ -0,0 +1,75 @@
+use std::{collections::HashMap, error::Error};
+
+use config::{builder::AsyncState, AsyncSource, ConfigBuilder, ConfigError, FileFormat};
+
+use async_trait::async_trait;
+use futures::{select, FutureExt};
+use warp::Filter;
+
+// Example below presents sample configuration server and client.
+//
+// Server serves simple configuration on HTTP endpoint.
+// Client consumes it using custom HTTP AsyncSource built on top of reqwest.
+
+#[tokio::main]
+async fn main() -> Result<(), Box<dyn Error>> {
+ select! {
+ r = run_server().fuse() => r,
+ r = run_client().fuse() => r
+ }
+}
+
+async fn run_server() -> Result<(), Box<dyn Error>> {
+ let service = warp::path("configuration").map(|| r#"{ "value" : 123 }"#);
+
+ println!("Running server on localhost:5001");
+
+ warp::serve(service).bind(([127, 0, 0, 1], 5001)).await;
+
+ Ok(())
+}
+
+async fn run_client() -> Result<(), Box<dyn Error>> {
+ // Good enough for an example to allow server to start
+ tokio::time::sleep(tokio::time::Duration::from_secs(3)).await;
+
+ let config = ConfigBuilder::<AsyncState>::default()
+ .add_async_source(HttpSource {
+ uri: "http://localhost:5001/configuration".into(),
+ format: FileFormat::Json,
+ })
+ .build()
+ .await?;
+
+ println!("Config value is {}", config.get::<String>("value")?);
+
+ Ok(())
+}
+
+// Actual implementation of AsyncSource can be found below
+
+#[derive(Debug)]
+struct HttpSource {
+ uri: String,
+ format: FileFormat,
+}
+
+impl HttpSource {
+ async fn call(&self) -> Result<String, reqwest::Error> {
+ reqwest::get(&self.uri).await?.text().await
+ }
+}
+
+#[async_trait]
+impl AsyncSource for HttpSource {
+ async fn collect(&self) -> Result<HashMap<String, config::Value>, ConfigError> {
+ self.call()
+ .await
+ .map_err(|e| ConfigError::Foreign(Box::new(e)))
+ .and_then(|text| {
+ self.format
+ .parse(Some(&self.uri), &text)
+ .map_err(|e| ConfigError::Foreign(e))
+ })
+ }
+}