Skip to content

Commit 3e374cf

Browse files
committed
feat: support for accessing HTTP services internal state
1 parent 1a5dcbe commit 3e374cf

File tree

5 files changed

+75
-41
lines changed

5 files changed

+75
-41
lines changed

examples/services/http/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ axum = "0.7.7"
88
mikros = { path = "../../../" }
99
tokio = { version = "1.41.1", features = ["full"] }
1010
tonic = "0.12.3"
11+
futures = "0.3.31"

examples/services/http/src/main.rs

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,55 @@
1+
use std::any::Any;
12
use std::sync::Arc;
23

34
use axum::extract::State;
45
use axum::routing::get;
6+
use mikros::FutureMutex;
57
use mikros::http::{ServiceInternalState, ServiceState};
68
use mikros::service::builder::ServiceBuilder;
7-
use mikros::FutureMutex;
9+
//use mikros::FutureMutex;
810

911
#[derive(Clone, Default)]
10-
pub struct AppState;
11-
impl ServiceInternalState for AppState {}
12+
pub struct AppState {
13+
value: i32,
14+
}
15+
16+
impl AppState {
17+
pub fn increase(&mut self) {
18+
self.value += 1;
19+
}
20+
}
21+
22+
impl ServiceInternalState for AppState {
23+
fn clone_box(&self) -> Box<dyn ServiceInternalState> {
24+
Box::new(self.clone())
25+
}
26+
27+
fn as_any(&self) -> &dyn Any {
28+
self
29+
}
30+
}
1231

1332
// Handler method for the first endpoint
1433
//async fn handler_one(ctx: Option<State<Arc<Context>>>) -> String {
15-
async fn handler_one(State(state): State<Arc<ServiceState>>) -> String {
34+
async fn handler_one(State(state): State<Arc<FutureMutex<ServiceState>>>) -> String {
1635
println!("Handler One");
17-
let context = state.context();
36+
let context = state.lock().await.context();
1837
context.logger().info("just a log message");
1938

2039
format!("Handler One")
2140
}
2241

2342
// Handler method for the second endpoint
24-
async fn handler_two(State(_state): State<Arc<ServiceState>>) -> String {
43+
async fn handler_two(State(state): State<Arc<FutureMutex<ServiceState>>>) -> String {
2544
println!("Handler Two");
45+
46+
if let Some(app_state) = state.lock().await.state::<AppState>().await {
47+
println!("App State current value: {}", app_state.value);
48+
app_state.increase();
49+
let mut x = app_state.clone_box();
50+
x.in
51+
}
52+
2653
format!("Handler Two")
2754
}
2855

@@ -34,7 +61,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
3461

3562
let state = AppState::default();
3663
let svc = ServiceBuilder::default()
37-
.http_with_state(api, Arc::new(FutureMutex::new(state)))
64+
.http_with_state(api, Box::new(state))
65+
// .http_with_state(api, Arc::new(FutureMutex::new(state)))
3866
// .http(api)
3967
.build();
4068

src/http/mod.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,48 @@
1+
use std::any::Any;
12
use std::sync::Arc;
23

34
use futures::lock::Mutex;
45

56
use crate::service::context::Context;
67

7-
pub trait ServiceInternalState: Send + 'static {}
8-
98
#[derive(Clone)]
109
pub struct ServiceState {
1110
context: Arc<Context>,
12-
state: Option<Box<Arc<Mutex<dyn ServiceInternalState>>>>
11+
state: Arc<Mutex<Option<Box<dyn ServiceInternalState>>>>
1312
}
1413

1514
impl ServiceState {
16-
pub(crate) fn new(context: &Context) -> ServiceState {
15+
pub(crate) fn new(context: &Context) -> Self {
1716
Self {
1817
context: Arc::new(context.clone()),
19-
state: None
18+
state: Arc::new(Mutex::new(None)),
2019
}
2120
}
2221

23-
pub(crate) fn new_with_state(context: &Context, state: &Box<Arc<Mutex<dyn ServiceInternalState>>>) -> ServiceState {
22+
pub(crate) fn new_with_state(context: &Context, state: Box<dyn ServiceInternalState>) -> Self {
2423
Self {
2524
context: Arc::new(context.clone()),
26-
state: Some(state.clone())
25+
state: Arc::new(Mutex::new(Some(state))),
2726
}
2827
}
2928

3029
pub fn context(&self) -> Arc<Context> {
3130
self.context.clone()
3231
}
3332

34-
pub fn state(&self) -> Option<Box<Arc<Mutex<dyn ServiceInternalState>>>> {
35-
self.state.clone()
33+
pub async fn state<T: Clone + 'static>(&self) -> Option<Arc<T>> {
34+
let state = self.state.lock().await;
35+
state.as_ref()?.as_any().downcast_ref::<T>().map(|t|Arc::new(t.clone()))
3636
}
37-
}
37+
}
38+
39+
pub trait ServiceInternalState: Send + Sync + 'static {
40+
fn clone_box(&self) -> Box<dyn ServiceInternalState>;
41+
fn as_any(&self) -> &dyn Any;
42+
}
43+
44+
impl Clone for Box<dyn ServiceInternalState> {
45+
fn clone(&self) -> Self {
46+
self.clone_box()
47+
}
48+
}

src/service/builder.rs

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,34 +88,30 @@ impl ServiceBuilder {
8888

8989
/// Initializes the HTTP service type with the required structure
9090
/// implementing the service endpoint handlers.
91-
pub fn http(mut self, router: Router<Arc<ServiceState>>) -> Self {
91+
pub fn http(mut self, router: Router<Arc<Mutex<ServiceState>>>) -> Self {
9292
self.servers.insert(definition::ServiceKind::Http.to_string(), Box::new(Http::new(router)));
9393
self
9494
}
9595

9696
/// Initializes the HTTP service type with the required structure
9797
/// implementing the service endpoint handlers and another with
9898
/// implementing the Lifecycle API.
99-
pub fn http_with_lifecycle<L>(mut self, router: Router<Arc<ServiceState>>, lifecycle: Arc<Mutex<L>>) -> Self
99+
pub fn http_with_lifecycle<L>(mut self, router: Router<Arc<Mutex<ServiceState>>>, lifecycle: Arc<Mutex<L>>) -> Self
100100
where
101101
L: Lifecycle + 'static
102102
{
103103
self.servers.insert(definition::ServiceKind::Http.to_string(), Box::new(Http::new_with_lifecycle(router, lifecycle)));
104104
self
105105
}
106106

107-
pub fn http_with_state<S>(mut self, router: Router<Arc<ServiceState>>, state: Arc<Mutex<S>>) -> Self
108-
where
109-
S: ServiceInternalState + 'static,
110-
{
107+
pub fn http_with_state(mut self, router: Router<Arc<Mutex<ServiceState>>>, state: Box<dyn ServiceInternalState>) -> Self {
111108
self.servers.insert(definition::ServiceKind::Http.to_string(), Box::new(Http::new_with_state(router, state)));
112109
self
113110
}
114111

115-
pub fn http_with_lifecycle_and_state<L, S>(mut self, router: Router<Arc<ServiceState>>, lifecycle: Arc<Mutex<L>>, state: Arc<Mutex<S>>) -> Self
112+
pub fn http_with_lifecycle_and_state<L>(mut self, router: Router<Arc<Mutex<ServiceState>>>, lifecycle: Arc<Mutex<L>>, state: Box<dyn ServiceInternalState>) -> Self
116113
where
117114
L: Lifecycle + 'static,
118-
S: ServiceInternalState + 'static,
119115
{
120116
self.servers.insert(definition::ServiceKind::Http.to_string(), Box::new(Http::new_with_lifecycle_and_state(router, lifecycle, state)));
121117
self

src/service/http/mod.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::collections::HashMap;
2+
use std::ops::Deref;
23
use std::sync::Arc;
34

45
use axum::Router;
@@ -15,22 +16,22 @@ use crate::service::lifecycle::Lifecycle;
1516
#[derive(Clone)]
1617
pub(crate) struct Http {
1718
port: i32,
18-
router: Router<Arc<ServiceState>>,
19+
router: Router<Arc<Mutex<ServiceState>>>,
1920
lifecycle: Option<Box<Arc<Mutex<dyn Lifecycle>>>>,
20-
internal_state: Option<Box<Arc<Mutex<dyn ServiceInternalState>>>>
21+
internal_state: Arc<Mutex<Option<Box<dyn ServiceInternalState>>>>
2122
}
2223

2324
impl Http {
24-
pub fn new(router: Router<Arc<ServiceState>>) -> Self {
25+
pub fn new(router: Router<Arc<Mutex<ServiceState>>>) -> Self {
2526
Self {
2627
port: 0,
2728
router,
2829
lifecycle: None,
29-
internal_state: None
30+
internal_state: Arc::new(Mutex::new(None))
3031
}
3132
}
3233

33-
pub fn new_with_lifecycle<L>(router: Router<Arc<ServiceState>>, lifecycle: Arc<Mutex<L>>) -> Self
34+
pub fn new_with_lifecycle<L>(router: Router<Arc<Mutex<ServiceState>>>, lifecycle: Arc<Mutex<L>>) -> Self
3435
where
3536
L: Lifecycle + 'static,
3637
{
@@ -39,23 +40,19 @@ impl Http {
3940
s
4041
}
4142

42-
pub fn new_with_state<S>(router: Router<Arc<ServiceState>>, state: Arc<Mutex<S>>) -> Self
43-
where
44-
S: ServiceInternalState + 'static,
45-
{
43+
pub fn new_with_state(router: Router<Arc<Mutex<ServiceState>>>, state: Box<dyn ServiceInternalState>) -> Self {
4644
let mut s = Self::new(router);
47-
s.internal_state = Some(Box::new(state));
45+
s.internal_state = Arc::new(Mutex::new(Some(state)));
4846
s
4947
}
5048

51-
pub fn new_with_lifecycle_and_state<L, S>(router: Router<Arc<ServiceState>>, lifecycle: Arc<Mutex<L>>, state: Arc<Mutex<S>>) -> Self
49+
pub fn new_with_lifecycle_and_state<L>(router: Router<Arc<Mutex<ServiceState>>>, lifecycle: Arc<Mutex<L>>, state: Box<dyn ServiceInternalState>) -> Self
5250
where
5351
L: Lifecycle + 'static,
54-
S: ServiceInternalState + 'static
5552
{
5653
let mut s = Self::new(router);
5754
s.lifecycle = Some(Box::new(lifecycle));
58-
s.internal_state = Some(Box::new(state));
55+
s.internal_state = Arc::new(Mutex::new(Some(state)));
5956
s
6057
}
6158
}
@@ -111,12 +108,13 @@ impl plugin::service::Service for Http {
111108
shutdown_rx.changed().await.ok();
112109
};
113110

114-
let state = match &self.internal_state {
111+
let internal_state = self.internal_state.clone();
112+
let state = match internal_state.lock().await.deref() {
115113
None => ServiceState::new(ctx),
116-
Some(st) => ServiceState::new_with_state(ctx, st)
114+
Some(state) => ServiceState::new_with_state(ctx, state.clone_box())
117115
};
118116

119-
let app = Router::new().merge(self.router.clone()).with_state(Arc::new(state));
117+
let app = Router::new().merge(self.router.clone()).with_state(Arc::new(Mutex::new(state)));
120118

121119
match TcpListener::bind(addr).await {
122120
Ok(incoming) => {

0 commit comments

Comments
 (0)