vtx_sdk/core/
capabilities.rs

1//! Capability declaration builders and permission helpers.
2
3use crate::error::VtxError;
4use crate::{Capabilities, HttpAllowRule};
5
6pub const PERM_BUFFER_CREATE: &str = "buffer:create";
7pub const PERM_FILE_READ: &str = "file:read";
8pub const PERM_FILE_WRITE: &str = "file:write";
9pub const PERM_FFMPEG_EXECUTE: &str = "ffmpeg:execute";
10pub const PERM_SQL_WRITE: &str = "sql:write";
11
12pub trait CapabilitiesExt {
13    fn has_permission(&self, perm: &str) -> bool;
14}
15
16impl CapabilitiesExt for Capabilities {
17    fn has_permission(&self, perm: &str) -> bool {
18        self.permissions.iter().any(|p| p == perm)
19    }
20}
21
22pub trait VtxErrorExt {
23    fn is_permission_denied(&self) -> bool;
24}
25
26impl VtxErrorExt for VtxError {
27    fn is_permission_denied(&self) -> bool {
28        matches!(self, VtxError::PermissionDenied(_))
29    }
30}
31
32/// Builder for `Capabilities`.
33pub struct CapabilitiesBuilder {
34    subscriptions: Vec<String>,
35    permissions: Vec<String>,
36    http: Vec<HttpAllowRule>,
37}
38
39impl CapabilitiesBuilder {
40    pub fn new() -> Self {
41        Self {
42            subscriptions: Vec::new(),
43            permissions: Vec::new(),
44            http: Vec::new(),
45        }
46    }
47
48    pub fn subscription(mut self, topic: impl Into<String>) -> Self {
49        self.subscriptions.push(topic.into());
50        self
51    }
52
53    pub fn subscriptions<I, S>(mut self, topics: I) -> Self
54    where
55        I: IntoIterator<Item = S>,
56        S: Into<String>,
57    {
58        self.subscriptions
59            .extend(topics.into_iter().map(Into::into));
60        self
61    }
62
63    pub fn permission(mut self, perm: impl Into<String>) -> Self {
64        self.permissions.push(perm.into());
65        self
66    }
67
68    pub fn permissions<I, S>(mut self, perms: I) -> Self
69    where
70        I: IntoIterator<Item = S>,
71        S: Into<String>,
72    {
73        self.permissions.extend(perms.into_iter().map(Into::into));
74        self
75    }
76
77    pub fn http_rule(mut self, rule: HttpAllowRule) -> Self {
78        self.http.push(rule);
79        self
80    }
81
82    pub fn http_rules<I>(mut self, rules: I) -> Self
83    where
84        I: IntoIterator<Item = HttpAllowRule>,
85    {
86        self.http.extend(rules);
87        self
88    }
89
90    pub fn build(self) -> Capabilities {
91        let http = if self.http.is_empty() {
92            None
93        } else {
94            Some(self.http)
95        };
96        Capabilities {
97            subscriptions: self.subscriptions,
98            permissions: self.permissions,
99            http,
100        }
101    }
102}
103
104impl Default for CapabilitiesBuilder {
105    fn default() -> Self {
106        Self::new()
107    }
108}
109
110/// Builder for `HttpAllowRule`.
111pub struct HttpAllowRuleBuilder {
112    scheme: String,
113    host: String,
114    port: Option<u16>,
115    path: Option<String>,
116    methods: Option<Vec<String>>,
117    allow_headers: Option<Vec<String>>,
118    max_request_bytes: Option<u64>,
119    max_response_bytes: Option<u64>,
120    follow_redirects: Option<bool>,
121    redirect_policy: Option<String>,
122}
123
124impl HttpAllowRuleBuilder {
125    pub fn new(scheme: impl Into<String>, host: impl Into<String>) -> Self {
126        Self {
127            scheme: scheme.into(),
128            host: host.into(),
129            port: None,
130            path: None,
131            methods: None,
132            allow_headers: None,
133            max_request_bytes: None,
134            max_response_bytes: None,
135            follow_redirects: None,
136            redirect_policy: None,
137        }
138    }
139
140    pub fn port(mut self, port: u16) -> Self {
141        self.port = Some(port);
142        self
143    }
144
145    pub fn path(mut self, path: impl Into<String>) -> Self {
146        self.path = Some(path.into());
147        self
148    }
149
150    pub fn methods<I, S>(mut self, methods: I) -> Self
151    where
152        I: IntoIterator<Item = S>,
153        S: Into<String>,
154    {
155        self.methods = Some(methods.into_iter().map(Into::into).collect());
156        self
157    }
158
159    pub fn allow_headers<I, S>(mut self, headers: I) -> Self
160    where
161        I: IntoIterator<Item = S>,
162        S: Into<String>,
163    {
164        self.allow_headers = Some(headers.into_iter().map(Into::into).collect());
165        self
166    }
167
168    pub fn max_request_bytes(mut self, bytes: u64) -> Self {
169        self.max_request_bytes = Some(bytes);
170        self
171    }
172
173    pub fn max_response_bytes(mut self, bytes: u64) -> Self {
174        self.max_response_bytes = Some(bytes);
175        self
176    }
177
178    pub fn follow_redirects(mut self, enabled: bool) -> Self {
179        self.follow_redirects = Some(enabled);
180        self
181    }
182
183    pub fn redirect_policy(mut self, policy: impl Into<String>) -> Self {
184        self.redirect_policy = Some(policy.into());
185        self
186    }
187
188    pub fn build(self) -> HttpAllowRule {
189        HttpAllowRule {
190            scheme: self.scheme,
191            host: self.host,
192            port: self.port,
193            path: self.path,
194            methods: self.methods,
195            allow_headers: self.allow_headers,
196            max_request_bytes: self.max_request_bytes,
197            max_response_bytes: self.max_response_bytes,
198            follow_redirects: self.follow_redirects,
199            redirect_policy: self.redirect_policy,
200        }
201    }
202}