vtx-sdk 0.1.14

Official SDK for developing VTX plugins using Rust and WebAssembly.
Documentation
//! Capability declaration builders and permission helpers.

use crate::error::VtxError;
use crate::{Capabilities, HttpAllowRule};

pub const PERM_BUFFER_CREATE: &str = "buffer:create";
pub const PERM_FILE_READ: &str = "file:read";
pub const PERM_FILE_WRITE: &str = "file:write";
pub const PERM_FFMPEG_EXECUTE: &str = "ffmpeg:execute";
pub const PERM_SQL_WRITE: &str = "sql:write";

pub trait CapabilitiesExt {
    fn has_permission(&self, perm: &str) -> bool;
}

impl CapabilitiesExt for Capabilities {
    fn has_permission(&self, perm: &str) -> bool {
        self.permissions.iter().any(|p| p == perm)
    }
}

pub trait VtxErrorExt {
    fn is_permission_denied(&self) -> bool;
}

impl VtxErrorExt for VtxError {
    fn is_permission_denied(&self) -> bool {
        matches!(self, VtxError::PermissionDenied(_))
    }
}

/// Builder for `Capabilities`.
pub struct CapabilitiesBuilder {
    subscriptions: Vec<String>,
    permissions: Vec<String>,
    http: Vec<HttpAllowRule>,
}

impl CapabilitiesBuilder {
    pub fn new() -> Self {
        Self {
            subscriptions: Vec::new(),
            permissions: Vec::new(),
            http: Vec::new(),
        }
    }

    pub fn subscription(mut self, topic: impl Into<String>) -> Self {
        self.subscriptions.push(topic.into());
        self
    }

    pub fn subscriptions<I, S>(mut self, topics: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: Into<String>,
    {
        self.subscriptions
            .extend(topics.into_iter().map(Into::into));
        self
    }

    pub fn permission(mut self, perm: impl Into<String>) -> Self {
        self.permissions.push(perm.into());
        self
    }

    pub fn permissions<I, S>(mut self, perms: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: Into<String>,
    {
        self.permissions.extend(perms.into_iter().map(Into::into));
        self
    }

    pub fn http_rule(mut self, rule: HttpAllowRule) -> Self {
        self.http.push(rule);
        self
    }

    pub fn http_rules<I>(mut self, rules: I) -> Self
    where
        I: IntoIterator<Item = HttpAllowRule>,
    {
        self.http.extend(rules);
        self
    }

    pub fn build(self) -> Capabilities {
        let http = if self.http.is_empty() {
            None
        } else {
            Some(self.http)
        };
        Capabilities {
            subscriptions: self.subscriptions,
            permissions: self.permissions,
            http,
        }
    }
}

impl Default for CapabilitiesBuilder {
    fn default() -> Self {
        Self::new()
    }
}

/// Builder for `HttpAllowRule`.
pub struct HttpAllowRuleBuilder {
    scheme: String,
    host: String,
    port: Option<u16>,
    path: Option<String>,
    methods: Option<Vec<String>>,
    allow_headers: Option<Vec<String>>,
    max_request_bytes: Option<u64>,
    max_response_bytes: Option<u64>,
    follow_redirects: Option<bool>,
    redirect_policy: Option<String>,
}

impl HttpAllowRuleBuilder {
    pub fn new(scheme: impl Into<String>, host: impl Into<String>) -> Self {
        Self {
            scheme: scheme.into(),
            host: host.into(),
            port: None,
            path: None,
            methods: None,
            allow_headers: None,
            max_request_bytes: None,
            max_response_bytes: None,
            follow_redirects: None,
            redirect_policy: None,
        }
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }

    pub fn path(mut self, path: impl Into<String>) -> Self {
        self.path = Some(path.into());
        self
    }

    pub fn methods<I, S>(mut self, methods: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: Into<String>,
    {
        self.methods = Some(methods.into_iter().map(Into::into).collect());
        self
    }

    pub fn allow_headers<I, S>(mut self, headers: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: Into<String>,
    {
        self.allow_headers = Some(headers.into_iter().map(Into::into).collect());
        self
    }

    pub fn max_request_bytes(mut self, bytes: u64) -> Self {
        self.max_request_bytes = Some(bytes);
        self
    }

    pub fn max_response_bytes(mut self, bytes: u64) -> Self {
        self.max_response_bytes = Some(bytes);
        self
    }

    pub fn follow_redirects(mut self, enabled: bool) -> Self {
        self.follow_redirects = Some(enabled);
        self
    }

    pub fn redirect_policy(mut self, policy: impl Into<String>) -> Self {
        self.redirect_policy = Some(policy.into());
        self
    }

    pub fn build(self) -> HttpAllowRule {
        HttpAllowRule {
            scheme: self.scheme,
            host: self.host,
            port: self.port,
            path: self.path,
            methods: self.methods,
            allow_headers: self.allow_headers,
            max_request_bytes: self.max_request_bytes,
            max_response_bytes: self.max_response_bytes,
            follow_redirects: self.follow_redirects,
            redirect_policy: self.redirect_policy,
        }
    }
}