orca/models/
read.rs
1use crate::model::{self, ActorModel, Transition, TransitionAction, TransitionResult};
2
3use crate::error::Error;
4use crate::run::EventRecord;
5use crate::state::*;
6use kanidm_client::KanidmClient;
7
8use async_trait::async_trait;
9use rand::Rng;
10use rand_chacha::ChaCha8Rng;
11
12use std::time::Duration;
13
14enum State {
15 Unauthenticated,
16 Authenticated,
17}
18
19pub struct ActorReader {
20 state: State,
21 randomised_backoff_time: Duration,
22}
23
24impl ActorReader {
25 pub fn new(mut cha_rng: ChaCha8Rng, warmup_time_ms: u64) -> Self {
26 let max_backoff_time_in_ms = warmup_time_ms - 1000;
27 let randomised_backoff_time =
28 Duration::from_millis(cha_rng.random_range(0..max_backoff_time_in_ms));
29 ActorReader {
30 state: State::Unauthenticated,
31 randomised_backoff_time,
32 }
33 }
34}
35
36#[async_trait]
37impl ActorModel for ActorReader {
38 async fn transition(
39 &mut self,
40 client: &KanidmClient,
41 person: &Person,
42 ) -> Result<Vec<EventRecord>, Error> {
43 let transition = self.next_transition();
44
45 if let Some(delay) = transition.delay {
46 tokio::time::sleep(delay).await;
47 }
48
49 let (result, event) = match transition.action {
51 TransitionAction::Login => model::login(client, person).await,
52 TransitionAction::Logout => model::logout(client, person).await,
53 TransitionAction::PrivilegeReauth
54 | TransitionAction::WriteAttributePersonMail
55 | TransitionAction::ReadSelfAccount
56 | TransitionAction::WriteSelfPassword => return Err(Error::InvalidState),
57 TransitionAction::ReadSelfMemberOf => {
58 model::person_get_self_memberof(client, person).await
59 }
60 }?;
61
62 self.next_state(transition.action, result);
63
64 Ok(event)
65 }
66}
67
68impl ActorReader {
69 fn next_transition(&mut self) -> Transition {
70 match self.state {
71 State::Unauthenticated => Transition {
72 delay: Some(self.randomised_backoff_time),
73 action: TransitionAction::Login,
74 },
75 State::Authenticated => Transition {
76 delay: Some(Duration::from_secs(1)),
77 action: TransitionAction::ReadSelfMemberOf,
78 },
79 }
80 }
81
82 fn next_state(&mut self, action: TransitionAction, result: TransitionResult) {
83 match (&self.state, action, result) {
86 (State::Unauthenticated, TransitionAction::Login, TransitionResult::Ok) => {
87 self.state = State::Authenticated;
88 }
89 (State::Authenticated, TransitionAction::ReadSelfMemberOf, TransitionResult::Ok) => {
90 self.state = State::Authenticated;
91 }
92 #[allow(clippy::unreachable)]
93 (_, _, TransitionResult::Ok) => unreachable!(),
94
95 (_, _, TransitionResult::Error) => {
96 self.state = State::Unauthenticated {};
97 }
98 }
99 }
100}