use tonic::codegen::InterceptedService;
use tonic::metadata::MetadataValue;
use tonic::service::Interceptor;
use tonic::transport::{Channel, Endpoint};
use tonic::{Request, Status};
use jammi_db::error::{JammiError, Result};
pub const SESSION_HEADER: &str = "jammi-session-id";
#[derive(Clone)]
pub struct SessionHeader {
id: MetadataValue<tonic::metadata::Ascii>,
}
impl Interceptor for SessionHeader {
fn call(&mut self, mut request: Request<()>) -> std::result::Result<Request<()>, Status> {
request
.metadata_mut()
.insert(SESSION_HEADER, self.id.clone());
Ok(request)
}
}
#[derive(Clone)]
pub struct SessionTransport {
channel: Channel,
header: SessionHeader,
session_id: String,
}
impl SessionTransport {
pub async fn connect(endpoint: impl Into<Endpoint>) -> Result<Self> {
let channel = endpoint
.into()
.connect()
.await
.map_err(|e| JammiError::Config(format!("connect to jammi endpoint: {e}")))?;
let session_id = uuid::Uuid::new_v4().to_string();
let id: MetadataValue<tonic::metadata::Ascii> = session_id
.parse()
.map_err(|e| JammiError::Config(format!("session id metadata: {e}")))?;
Ok(Self {
channel,
header: SessionHeader { id },
session_id,
})
}
pub fn session_id(&self) -> &str {
&self.session_id
}
pub fn channel(&self) -> Channel {
self.channel.clone()
}
pub fn service<S>(&self, make: impl FnOnce(Channel, SessionHeader) -> S) -> S {
make(self.channel.clone(), self.header.clone())
}
}
pub type SessionChannel = InterceptedService<Channel, SessionHeader>;