Skip to main content

soma_api/
state.rs

1use std::sync::{
2    atomic::{AtomicU64, Ordering},
3    Arc,
4};
5
6use soma_application::{ExecutionContext, SomaApplication};
7use soma_domain::{AuthorizationMode, Principal, RequestId, ScopeSet, Surface};
8
9#[cfg(test)]
10#[path = "state_tests.rs"]
11mod tests;
12
13#[derive(Clone)]
14pub struct ApiState {
15    application: Arc<SomaApplication>,
16    authorization_mode: AuthorizationMode,
17    server_name: Arc<str>,
18}
19
20impl ApiState {
21    pub fn new(
22        application: Arc<SomaApplication>,
23        authorization_mode: AuthorizationMode,
24        server_name: impl Into<Arc<str>>,
25    ) -> Self {
26        Self {
27            application,
28            authorization_mode,
29            server_name: server_name.into(),
30        }
31    }
32
33    pub fn application(&self) -> &SomaApplication {
34        self.application.as_ref()
35    }
36
37    pub fn server_name(&self) -> &str {
38        &self.server_name
39    }
40
41    pub fn execution_context(&self, subject: Option<&str>, scopes: &[String]) -> ExecutionContext {
42        ExecutionContext {
43            principal: subject
44                .map(|subject| Principal::new(subject, ScopeSet::new(scopes.iter().cloned()))),
45            authorization_mode: self.authorization_mode,
46            surface: Surface::Rest,
47            trace: None,
48            destructive_confirmation: Default::default(),
49            response_limit: None,
50            request_id: next_request_id(),
51        }
52    }
53}
54
55fn next_request_id() -> RequestId {
56    static REQUEST_SEQUENCE: AtomicU64 = AtomicU64::new(1);
57    let sequence = REQUEST_SEQUENCE.fetch_add(1, Ordering::Relaxed);
58    RequestId::new(format!("rest-{}-{sequence}", std::process::id()))
59        .expect("generated REST request ids are valid")
60}