21 releases

0.9.2 Oct 26, 2021
0.9.1 Jul 18, 2021
0.9.0 Apr 3, 2021
0.8.1 Jan 10, 2021
0.2.0 Oct 15, 2018

#1 in #spirit


Used in 2 crates

Apache-2.0 OR MIT

410KB
5.5K SLoC

Spirit-tokio

Travis Build Status

Several helpers to easily integrate tokio with configuration managed by the spirit system.

See the docs and the examples.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.


lib.rs:

Support for tokio inside spirit

This provides configuration of the tokio runtime and installer of futures.

It also provides few configuration Fragments for configuring network primitives.

Note that this enables several features of tokio.

Features

  • rt-from-cfg: Allows creating runtime from configuration. Enables the Tokio::FromCfg variant and Config. Enabled by default.
  • cfg-help: Support for generating help for the configuration options.
  • net: Network primitive configuration Fragments in the [net] module.
  • stream: Implementations of tokio_stream::Stream on several types.
  • futures: Support for converting between futures's and our Either.
  • either: Support for converting between our Either and the one from the either crate.

Examples

use std::future::Future;
use std::pin::Pin;
use std::time::Duration;

use err_context::AnyError;
use serde::{Deserialize, Serialize};
use spirit::{Empty, Pipeline, Spirit};
use spirit::prelude::*;
use spirit::fragment::driver::CacheEq;
use spirit_tokio::{FutureInstaller, Tokio};
use spirit_tokio::runtime::Config as TokioCfg;
use structdoc::StructDoc;

#[derive(Clone, Debug, Deserialize, PartialEq, Serialize, StructDoc)]
#[serde(default)]
struct MsgCfg {
    /// A message to print now and then.
    msg: String,
    /// Time between printing the message.
    interval: Duration,
}

impl MsgCfg {
    async fn run(self) {
        loop {
            println!("{}", self.msg);
            tokio::time::sleep(self.interval).await;
        }
    }
}

impl Default for MsgCfg {
    fn default() -> Self {
        MsgCfg {
            msg: "Hello".to_owned(),
            interval: Duration::from_secs(1),
        }
    }
}

spirit::simple_fragment! {
    impl Fragment for MsgCfg {
        type Driver = CacheEq<MsgCfg>;
        type Resource = Pin<Box<dyn Future<Output = ()> + Send>>;
        type Installer = FutureInstaller;
        fn create(&self, _: &'static str) -> Result<Self::Resource, AnyError> {
            let fut = self.clone().run();
            Ok(Box::pin(fut))
        }
    }
}

/// An application.
#[derive(Default, Deserialize, Serialize, StructDoc)]
struct AppConfig {
    #[serde(flatten)]
    msg: MsgCfg,

    /// Configuration of the asynchronous tokio runtime.
    #[serde(default)]
    threadpool: TokioCfg,
}

impl AppConfig {
    fn threadpool(&self) -> TokioCfg {
        self.threadpool.clone()
    }

    fn msg(&self) -> &MsgCfg {
        &self.msg
    }
}

fn main() {
    Spirit::<Empty, AppConfig>::new()
        // Makes sure we have a runtime configured from the config.
        // If we don't do this, the pipeline below would insert a default Tokio runtime to make
        // it work. If you want to customize the runtime (like here), make sure to insert it
        // before any pipelines requiring it (otherwise you get the default one from them).
        .with_singleton(Tokio::from_cfg(AppConfig::threadpool))
        // Will install and possibly cancel and replace the future if the config changes.
        .with(Pipeline::new("Msg").extract_cfg(AppConfig::msg))
        // Just an empty body here.
        .run(|spirit| {
            // Usually, one would terminate by CTRL+C, but we terminate from here to make sure
            // the example finishes.
            spirit.terminate();
            Ok(())
        })
}

An alternative approach can be seen at handlers::ToFutureUnconfigured.

Dependencies

~6–17MB
~192K SLoC