use classy::extract::FromContext;
use classy::proxy_wasm::types::Bytes;
use std::convert::Infallible;
pub use self::properties::*;
use crate::host::{self};
use anyhow::format_err;
mod properties;
pub trait PropertyAccessor {
fn read_property(&self, path: &[&str]) -> Option<Bytes>;
fn set_property(&self, path: &[&str], value: &[u8]);
}
pub struct PropertyMapper<'a> {
property_accessor: &'a dyn PropertyAccessor,
}
impl<'a> PropertyMapper<'a> {
fn string_property(&self, path: &[&str]) -> host::Result<Option<String>> {
if let Some(bytes) = self.property_accessor.read_property(path) {
String::from_utf8(bytes).map(Option::from).map_err(|e| {
format_err!("Retrieved value for property {path:?} was not valid: {e:?}")
})
} else {
Ok(None)
}
}
pub fn from(property_accessor: &'a dyn PropertyAccessor) -> Self {
Self { property_accessor }
}
}
impl dyn PropertyAccessor {
#[allow(clippy::should_implement_trait)]
pub fn default() -> &'static dyn PropertyAccessor {
&impls::Host
}
}
impl<'a> dyn PropertyAccessor + 'a {
pub fn request(&'a self) -> RequestInfo<'a> {
RequestInfo {
mapper: PropertyMapper::from(self),
}
}
pub fn source(&'a self) -> SourceInfo<'a> {
SourceInfo {
mapper: PropertyMapper::from(self),
}
}
pub fn destination(&'a self) -> DestinationInfo<'a> {
DestinationInfo {
mapper: PropertyMapper::from(self),
}
}
pub fn tracing(&'a self) -> TracingInfo<'a> {
TracingInfo {
mapper: PropertyMapper::from(self),
}
}
}
pub struct RequestInfo<'a> {
mapper: PropertyMapper<'a>,
}
impl RequestInfo<'_> {
pub fn id(&self) -> host::Result<Option<String>> {
self.mapper.string_property(REQUEST_ID)
}
pub fn protocol(&self) -> host::Result<Option<String>> {
self.mapper.string_property(REQUEST_PROTOCOL)
}
pub fn scheme(&self) -> host::Result<Option<String>> {
self.mapper.string_property(REQUEST_SCHEME)
}
}
pub struct SourceInfo<'a> {
mapper: PropertyMapper<'a>,
}
impl SourceInfo<'_> {
pub fn address(&self) -> host::Result<Option<String>> {
self.mapper.string_property(SOURCE_ADDRESS)
}
}
pub struct DestinationInfo<'a> {
mapper: PropertyMapper<'a>,
}
impl DestinationInfo<'_> {
pub fn address(&self) -> host::Result<Option<String>> {
self.mapper.string_property(DESTINATION_ADDRESS)
}
}
pub struct TracingInfo<'a> {
mapper: PropertyMapper<'a>,
}
impl TracingInfo<'_> {
pub fn id(&self) -> host::Result<Option<String>> {
self.mapper.string_property(TRACING_ID_PATH)
}
}
impl<C> FromContext<C> for &'static dyn PropertyAccessor {
type Error = Infallible;
fn from_context(_: &C) -> Result<Self, Self::Error> {
Ok(<dyn PropertyAccessor>::default())
}
}
mod impls {
use crate::host::property::PropertyAccessor;
use classy::proxy_wasm::types::Bytes;
use classy::Host as ClassyHost;
pub(super) struct Host;
impl PropertyAccessor for Host {
fn read_property(&self, path: &[&str]) -> Option<Bytes> {
crate::Host.get_property(path.to_vec())
}
fn set_property(&self, path: &[&str], value: &[u8]) {
crate::Host.set_property(path.to_vec(), Some(value))
}
}
}