spacegate-plugin 0.2.0-alpha.4

A library-first, lightweight, high-performance, cloud-native supported API gateway
Documentation
use std::sync::Arc;

use serde::{Deserialize, Serialize};
use spacegate_kernel::{
    service::{
        http_gateway::Gateway,
        http_route::{HttpBackend, HttpRoute, HttpRouteRule},
    },
    BoxError,
};

use crate::instance::{drop_trace, DropMarkerSet, DropTracer, PluginInstance};

#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum MountPointIndex {
    Gateway { gateway: Arc<str> },
    HttpRoute { gateway: Arc<str>, route: Arc<str> },
    HttpRouteRule { gateway: Arc<str>, route: Arc<str>, rule: usize },
    HttpBackend { gateway: Arc<str>, route: Arc<str>, rule: usize, backend: usize },
}

impl MountPointIndex {
    pub fn gateway(&self) -> &str {
        match self {
            MountPointIndex::Gateway { gateway } => gateway.as_ref(),
            MountPointIndex::HttpRoute { gateway, .. } => gateway.as_ref(),
            MountPointIndex::HttpRouteRule { gateway, .. } => gateway.as_ref(),
            MountPointIndex::HttpBackend { gateway, .. } => gateway.as_ref(),
        }
    }
}
impl Serialize for MountPointIndex {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        match self {
            MountPointIndex::Gateway { gateway } => MountPointIndexSerde::Gateway { gateway: gateway.as_ref() }.serialize(serializer),
            MountPointIndex::HttpRoute { gateway, route } => MountPointIndexSerde::HttpRoute {
                gateway: gateway.as_ref(),
                route: route.as_ref(),
            }
            .serialize(serializer),
            MountPointIndex::HttpRouteRule { gateway, route, rule } => MountPointIndexSerde::HttpRouteRule {
                gateway: gateway.as_ref(),
                route: route.as_ref(),
                rule: *rule,
            }
            .serialize(serializer),
            MountPointIndex::HttpBackend { gateway, route, rule, backend } => MountPointIndexSerde::HttpBackend {
                gateway: gateway.as_ref(),
                route: route.as_ref(),
                rule: *rule,
                backend: *backend,
            }
            .serialize(serializer),
        }
    }
}

impl<'de> Deserialize<'de> for MountPointIndex {
    fn deserialize<D>(deserializer: D) -> Result<MountPointIndex, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        let index = MountPointIndexSerde::deserialize(deserializer)?;
        match index {
            MountPointIndexSerde::Gateway { gateway } => Ok(MountPointIndex::Gateway { gateway: gateway.into() }),
            MountPointIndexSerde::HttpRoute { gateway, route } => Ok(MountPointIndex::HttpRoute {
                gateway: gateway.into(),
                route: route.into(),
            }),
            MountPointIndexSerde::HttpRouteRule { gateway, route, rule } => Ok(MountPointIndex::HttpRouteRule {
                gateway: gateway.into(),
                route: route.into(),
                rule,
            }),
            MountPointIndexSerde::HttpBackend { gateway, route, rule, backend } => Ok(MountPointIndex::HttpBackend {
                gateway: gateway.into(),
                route: route.into(),
                rule,
                backend,
            }),
        }
    }
}

#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub enum MountPointIndexSerde<'a> {
    Gateway { gateway: &'a str },
    HttpRoute { gateway: &'a str, route: &'a str },
    HttpRouteRule { gateway: &'a str, route: &'a str, rule: usize },
    HttpBackend { gateway: &'a str, route: &'a str, rule: usize, backend: usize },
}

pub trait MountPoint {
    fn mount(&mut self, instance: &mut PluginInstance) -> Result<DropTracer, BoxError>;
}

impl MountPoint for Gateway {
    fn mount(&mut self, instance: &mut PluginInstance) -> Result<DropTracer, BoxError> {
        let (tracer, marker) = drop_trace();
        self.http_plugins.push(instance.make());
        let set = self.ext.get_or_insert_default::<DropMarkerSet>();
        set.inner.insert(marker);
        Ok(tracer)
    }
}

impl MountPoint for HttpRoute {
    fn mount(&mut self, instance: &mut PluginInstance) -> Result<DropTracer, BoxError> {
        let (tracer, marker) = drop_trace();
        self.plugins.push(instance.make());
        let set = self.ext.get_or_insert_default::<DropMarkerSet>();
        set.inner.insert(marker);
        Ok(tracer)
    }
}

impl MountPoint for HttpRouteRule {
    fn mount(&mut self, instance: &mut PluginInstance) -> Result<DropTracer, BoxError> {
        let (tracer, marker) = drop_trace();
        self.plugins.push(instance.make());
        let set = self.ext.get_or_insert_default::<DropMarkerSet>();
        set.inner.insert(marker);
        Ok(tracer)
    }
}

impl MountPoint for HttpBackend {
    fn mount(&mut self, instance: &mut PluginInstance) -> Result<DropTracer, BoxError> {
        let (tracer, marker) = drop_trace();
        self.plugins.push(instance.make());
        let set = self.ext.get_or_insert_default::<DropMarkerSet>();
        set.inner.insert(marker);
        Ok(tracer)
    }
}