saddle-boundary 0.3.29

Saddle 0.3 ProfuseContract unary boundary transport
//! Fixed envelope validation and prepaid metadata; no serde scratch or Value.
use super::*;
use saddle_admission::{AdmissionError, InputDocument, InputKind, InputValue};

#[derive(Debug)]
pub enum ManagedIngressError { Codec(CodecError), Storage(AdmissionError) }
impl ManagedIngressError {
    pub fn http_status(&self) -> u16 { match self { Self::Codec(e) => e.http_status, Self::Storage(_) => 503 } }
}
impl std::fmt::Display for ManagedIngressError {
    fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result { write!(f,"{self:?}") }
}
impl std::error::Error for ManagedIngressError {
    fn source(&self)->Option<&(dyn std::error::Error+'static)> { match self { Self::Storage(e)=>Some(e), _=>None } }
}
impl From<CodecError> for ManagedIngressError { fn from(e:CodecError)->Self { Self::Codec(e) } }
impl From<AdmissionError> for ManagedIngressError { fn from(e:AdmissionError)->Self { Self::Storage(e) } }
fn shape(value:InputValue<'_>, keys:&[&str], optional:Option<&str>)->Result<(),CodecError> {
    let mut seen=0u64;
    for (key,_) in value.fields().ok_or(error(400,"INVALID_JSON_ENVELOPE"))? {
        let i=keys.iter().position(|k|*k==key).ok_or(error(400,"INVALID_JSON_ENVELOPE"))?;
        if seen&(1<<i)!=0 { return Err(error(400,"INVALID_JSON_ENVELOPE")); }
        seen|=1<<i;
    }
    for (i,key) in keys.iter().enumerate() { if seen&(1<<i)==0 && Some(*key)!=optional { return Err(error(400,"INVALID_JSON_ENVELOPE")); } }
    Ok(())
}
fn string<'a>(v:InputValue<'a>,key:&str)->Result<&'a str,CodecError> {
    let value=v.field(key).ok_or(error(400,"INVALID_JSON_ENVELOPE"))?;
    if value.kind()!=InputKind::String { return Err(error(400,"INVALID_JSON_ENVELOPE")); }
    Ok(value.text().unwrap())
}
impl ProfuseGwListenerAdapter {
    #[doc(hidden)]
    pub fn validate_managed_transport(&self,method:&str,path:&str,content_type:&str,identity:&IngressIdentity,body:&[u8])->Result<(),ManagedIngressError> {
        validate_identity(identity)?; validate_transport(method,path,content_type,body)?; Ok(())
    }
    #[doc(hidden)]
    pub fn accept_managed(&self,method:&str,path:&str,content_type:&str,identity:&IngressIdentity,body:&[u8],document:InputDocument)->Result<AcceptedIngress,ManagedIngressError> {
        validate_identity(identity)?;
        validate_transport(method,path,content_type,body)?;
        let root=document.root();
        shape(root,&["target","profuseGwContext","requestData"],None)?;
        let target=root.field("target").unwrap();
        shape(target,&["app","interfaceId"],None)?;
        let app=string(target,"app")?;
        let interface=string(target,"interfaceId")?;
        let context=root.field("profuseGwContext").unwrap();
        shape(context,&["userInfo","traceInfo","ldcInfo"],None)?;
        let user=context.field("userInfo").unwrap(); shape(user,&["userId"],None)?;
        let user=string(user,"userId")?;
        let trace=context.field("traceInfo").unwrap(); shape(trace,&["traceId","rpcId"],Some("traceId"))?;
        let trace_id=if trace.field("traceId").is_some() { string(trace,"traceId")? } else { "" };
        let rpc=string(trace,"rpcId")?;
        let ldc=context.field("ldcInfo").unwrap(); shape(ldc,&["zone","idc","env"],None)?;
        let zone=string(ldc,"zone")?; let idc=string(ldc,"idc")?; let env=string(ldc,"env")?;
        for value in [app,interface,user,rpc,zone,idc,env] { validate_id(value)?; }
        if !trace_id.is_empty() { validate_trace_id(trace_id)?; }
        if root.field("requestData").unwrap().kind()!=InputKind::Object { return Err(error(400,"INVALID_REQUEST_DATA").into()); }
        if app!=self.application.as_str() { return Err(error(404,"APPLICATION_NOT_FOUND").into()); }
        let metadata=root.framework_input(|b| Ok(IngressMetadata {
            identity: IngressIdentity { request_id:b.copy_text(&[&identity.request_id])?, call_id:b.copy_text(&[&identity.call_id])?, deadline_unix_ms:identity.deadline_unix_ms },
            interface_id:b.copy_text(&[interface])?, user_id:b.copy_text(&[user])?,
            trace_id:if trace_id.is_empty() { b.copy_text(&["saddle-",&identity.request_id])? } else { b.copy_text(&[trace_id])? },
            rpc_id:b.copy_text(&[rpc])?, zone:b.copy_text(&[zone])?, idc:b.copy_text(&[idc])?, env:b.copy_text(&[env])?,
        }))?;
        Ok(AcceptedIngress { metadata:AcceptedMetadata::Managed(metadata),request_data:AcceptedRequestData::Managed(document) })
    }
}