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}