shiny_common/
context.rs

1use crate::clock::{Clock, StaticClock, SystemClock};
2use crate::error::{ErrorTrace, ServiceError};
3use chrono::{DateTime, Utc};
4use std::borrow::Cow;
5use std::panic::Location;
6use serde::{Serialize};
7use thiserror::Error;
8use tokio_util::sync::CancellationToken;
9use shiny_configuration::Configuration;
10use shiny_configuration::value::serializer::{SerializerError, ValueSerializer};
11use crate::dyn_configuration::DynConfigurationKey;
12use crate::pointer_utils::ToBox;
13
14pub struct Context {
15    clock: Box<dyn Clock>,
16    cancellation_token: Option<CancellationToken>,
17    configuration: Configuration,
18}
19
20impl Context {
21    pub fn new() -> Self {
22        Self {
23            clock: SystemClock.boxed(),
24            cancellation_token: None,
25            configuration: Configuration::default(),
26        }
27    }
28
29    pub fn set_cancellation_token(&mut self, cancellation_token: CancellationToken) {
30        self.cancellation_token = Some(cancellation_token);
31    }
32
33    pub fn is_cancelled(&self) -> bool {
34        match &self.cancellation_token {
35            None => false,
36            Some(token) => token.is_cancelled(),
37        }
38    }
39
40    pub fn now(&self) -> DateTime<Utc> {
41        self.clock.now()
42    }
43
44    pub fn set_clock(&mut self, clock: Box<dyn Clock>) {
45        self.clock = clock;
46    }
47
48    pub fn set_static_time(&mut self, time: DateTime<Utc>) {
49        self.set_clock(StaticClock(time).boxed());
50    }
51
52    pub fn configuration<T: DynConfigurationKey>(&self, key: T) -> Result<T::Value, ServiceError> {
53        self.configuration.get(key.path()).map_err(|err| self.internal_error("FAILED_TO_GET_DYN_CONFIG_VALUE").with_error(err))
54    }
55
56    pub fn set_configuration(&mut self, configuration: Configuration) {
57        self.configuration = configuration
58    }
59
60    pub fn override_configuration<T: DynConfigurationKey>(&mut self, key: T, value: T::Value) -> Result<(), OverrideConfigurationError> {
61        self.configuration = self.configuration.with_override(key.path(), value.serialize(ValueSerializer)?);
62        Ok(())
63    }
64
65    #[track_caller]
66    pub fn internal_error(&self, code: impl Into<Cow<'static, str>>) -> ServiceError {
67        ServiceError::internal_error(code.into(), None, ErrorTrace::Location(Location::caller()))
68    }
69
70    #[track_caller]
71    pub fn dependency_error(
72        &self,
73        dependency_name: impl Into<Cow<'static, str>>,
74        code: impl Into<Cow<'static, str>>,
75    ) -> ServiceError {
76        ServiceError::dependency_error(
77            dependency_name.into(),
78            code.into(),
79            None,
80            ErrorTrace::Location(Location::caller()),
81        )
82    }
83}
84
85#[derive(Debug, Error)]
86#[error(transparent)]
87pub struct OverrideConfigurationError(#[from] SerializerError);
88
89pub trait ContextFactory: Send + Sync {
90    fn create(&self) -> Context;
91}