1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#![cfg_attr(not(debug_assertions), deny(unused_variables))]
#![cfg_attr(not(debug_assertions), deny(unused_imports))]
#![cfg_attr(not(debug_assertions), deny(dead_code))]
#![cfg_attr(not(debug_assertions), deny(unused_extern_crates))]
#![deny(unused_must_use)]
#![deny(unreachable_patterns)]
#![deny(unknown_lints)]
//! # Service framework
//!
//! This module contains the building blocks for async services.
//!
//! It consists of the following modules:
//!
//! ## `initializer`
//!
//! This module contains the [ServiceInitializer] trait. Service modules should implement this trait and pass
//! that implementation to the [StackBuilder].
//!
//! ## `stack`
//!
//! Contains the [StackBuilder] that is responsible for collecting and 'executing' the implementations of
//! [ServiceInitializer].
//!
//! ## `handles`
//!
//! A set of utilities used to collect and share handles between services. The [StackBuilder] is responsible for
//! initializing a [ServiceHandlesFuture] and making it available to [ServiceInitializer] implementations.
//!
//! Handles are simply a way to communicate with their corresponding service. Typically, a [SenderService] would
//! be used for this purpose but a handle can be implemented in any way the implementor sees fit.
//!
//! ## `reply_channel`
//!
//! This provides for query messages to be sent to services along with a "reply channel" for the service to send back
//! results. The `reply_channel::unbounded` function is used to create a sender/receiver pair. The sender
//! implements `tower_service::Service` and can be used to make requests of a applicable type. The receiver
//! implements `futures::Stream` and will provide a `RequestContext` object that contains a `oneshot` reply channel
//! that the service can use to reply back to the caller.
//!
//! ## Examples
//!
//! ### `reply_channel`
//!
//! ```edition2018
//! # use futures::executor::block_on;
//! # use futures::StreamExt;
//! # use futures::join;
//! use tari_service_framework::{reply_channel, tower::ServiceExt};
//!
//! block_on(async {
//!    let (mut sender, mut receiver) = reply_channel::unbounded();
//!
//!    let (result, _) = futures::join!(
//!         // Make the request and make progress on the resulting future
//!         sender.call_ready("upper"),
//!         // At the same time receive the request and reply
//!         async move {
//!           let req_context = receiver.next().await.unwrap();
//!           let msg = req_context.request().unwrap().clone();
//!           req_context.reply(msg.to_uppercase());
//!         }
//!     );
//!
//!    assert_eq!(result.unwrap(), "UPPER");
//! });
//! ```
//!
//! [ServiceInitializer]: ./initializer/trait.ServiceInitializer.html
//! [StackBuilder]: ./stack/struct.StackBuilder.html
//! [ServiceHandlesFuture]: ./handles/future/struct.ServiceHandlesFuture.html
//! [SenderService]: ./reply_channel/struct.SenderService.html

// Used to eliminate the need for boxing futures in many cases.
// Tracking issue: https://github.com/rust-lang/rust/issues/63063
#![feature(type_alias_impl_trait)]

mod context;
pub use context::{LazyService, ServiceHandles, ServiceInitializerContext};

mod initializer;
pub use initializer::{ServiceInitializationError, ServiceInitializer};

mod stack;
pub use stack::StackBuilder;

pub mod reply_channel;
pub mod tower;

mod utilities;
pub use utilities::RegisterHandle;

// Re-export
pub use tower_service::Service;