use futures::lock::Mutex;
use std::sync::Arc;
use crate::definition::Definitions;
use crate::env::Env;
use crate::service::errors::Error;
use crate::{env, errors, logger, plugin};
#[derive(Clone)]
pub struct Context {
logger: Arc<logger::Logger>,
definitions: Arc<Definitions>,
pub(crate) envs: Arc<Env>,
pub(crate) features: Arc<Mutex<Vec<Box<dyn plugin::feature::Feature>>>>,
}
impl Context {
pub(crate) fn new(
envs: Arc<Env>,
logger: Arc<logger::Logger>,
definitions: Arc<Definitions>,
features: Vec<Box<dyn plugin::feature::Feature>>,
) -> Self {
Self {
logger,
envs,
definitions,
features: Arc::new(Mutex::new(features)),
}
}
pub fn logger(&self) -> Arc<logger::Logger> {
self.logger.clone()
}
pub fn logger_ref(&self) -> &logger::Logger {
&self.logger
}
pub fn env(&self) -> Arc<env::Env> {
self.envs.clone()
}
pub fn env_ref(&self) -> &env::Env {
&self.envs
}
pub fn definitions(&self) -> Arc<Definitions> {
self.definitions.clone()
}
pub fn definitions_ref(&self) -> &Definitions {
&self.definitions
}
#[must_use]
pub fn service_name(&self) -> String {
self.definitions.name.to_string()
}
#[must_use]
pub fn client_connection_url(&self, client_name: &str) -> String {
match self.definitions.client(client_name) {
Some(c) => format!("{}:{}", c.host, c.port),
None => format!(
"{}.{}:{}",
client_name,
self.envs.coupled_namespace.clone(),
self.envs.coupled_port
),
}
}
pub async fn feature(&self, name: &str) -> errors::Result<Box<dyn plugin::feature::Feature>> {
match self
.features
.lock()
.await
.iter()
.find(|f| f.name() == name)
.cloned()
{
None => {
let error = Error::FeatureNotFound(name.to_string());
Err(errors::ServiceError::from_error(
self.clone().into(),
error.into(),
))
}
Some(f) => {
if !f.is_enabled() {
let error = Error::FeatureDisabled(name.to_string());
return Err(errors::ServiceError::from_error(
self.clone().into(),
error.into(),
));
}
Ok(f)
}
}
}
pub(crate) async fn initialize_features(&mut self) -> errors::Result<()> {
for feature in self.features.lock().await.iter_mut() {
if feature.can_be_initialized(self.definitions.clone(), self.envs.clone())? {
feature.initialize(self.clone().into()).await?;
}
}
Ok(())
}
pub(crate) async fn cleanup_features(&mut self) {
for feature in self.features.lock().await.iter() {
if feature.is_enabled() {
feature.cleanup().await;
}
}
}
}
pub fn from_request<B>(request: &tonic::Request<B>) -> Result<Arc<Context>, tonic::Status>
where
B: prost::Message,
{
match request.extensions().get::<Arc<Context>>() {
None => Err(tonic::Status::internal("could not retrieve context")),
Some(context) => Ok(context.clone()),
}
}
#[macro_export]
macro_rules! link_grpc_service {
($context:ident, $client:ident, $client_name:expr) => {{
let url = $context.client_connection_url($client_name);
match $client::connect(url).await {
Ok(c) => c,
Err(e) => {
return Err(mikros::errors::ServiceError::custom(
$context,
&e.to_string(),
));
}
}
}};
}