use crate::message::{DynamicSubjectNatsMessage, NatsCoreMessageSendTrait, StaticSubjectNatsMessage};
use crate::NatsMessage;
#[doc(hidden)]
pub trait NatsRpcServiceMeta {
const SERVICE_NAME: &'static str;
const SERVICE_VERSION: &'static str;
const SERVICE_DESCRIPTION: Option<&'static str> = None;
const QUEUE_GROUP: Option<&'static str> = None;
}
#[doc(hidden)]
#[async_trait::async_trait]
pub trait NatsRpcService: Send + Sync {
async fn set_up_service(
nats: &async_nats::Client,
) -> Result<async_nats::service::Service, async_nats::Error>;
}
#[async_trait::async_trait]
pub trait NatsRpcRequest: NatsMessage + NatsRpcRequestMeta {
type Response: NatsMessage;
async fn process_request(
service_state: &Self::Service,
request: Self,
) -> anyhow::Result<Self::Response>;
}
pub trait NatsRpcRequestMeta {
const ENDPOINT_NAME: &'static str;
type Service: NatsRpcService;
}
#[async_trait::async_trait]
pub trait NatsRpcCallTrait: NatsRpcRequest + StaticSubjectNatsMessage {
async fn call(self, nats: &async_nats::Client) -> anyhow::Result<Self::Response> {
let subject = self.subject();
let req_bytes = self.to_bytes()?;
let res = nats.request(subject, req_bytes.to_vec().into()).await?;
let res = Self::Response::parse_from_bytes(res.payload)?;
Ok(res)
}
async fn call_void(self, nats: &async_nats::Client) -> anyhow::Result<()> {
let subject = self.subject();
let req_bytes = self.to_bytes()?;
nats.publish(subject, req_bytes.to_vec().into()).await?;
Ok(())
}
}
impl<T> NatsRpcCallTrait for T
where
T: NatsRpcRequest + StaticSubjectNatsMessage,
{
}
impl<T> StaticSubjectNatsMessage for T
where
T: NatsRpcRequestMeta + NatsMessage,
T::Service: NatsRpcServiceMeta,
{
fn subject() -> String {
format!("$SRV.{}.{}", T::Service::SERVICE_NAME, T::ENDPOINT_NAME)
}
}
impl<T> NatsCoreMessageSendTrait for T
where
T: NatsRpcRequestMeta + NatsMessage,
T::Service: NatsRpcServiceMeta,
{
}