Skip to main content

rustfs_targets/runtime/
sidecar_protocol.rs

1// Copyright 2024 RustFS Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::TargetDomain;
16use serde::{Deserialize, Serialize};
17
18pub const SIDECAR_RUNTIME_PROTOCOL_VERSION: &str = "rustfs.target-runtime.v1";
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
21#[serde(rename_all = "snake_case")]
22pub enum SidecarPluginCapability {
23    HealthCheck,
24    SendEvent,
25    Shutdown,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
29#[serde(rename_all = "snake_case")]
30pub struct SidecarHandshake {
31    pub protocol_version: String,
32    pub plugin_id: String,
33    pub plugin_version: String,
34    pub supported_domains: Vec<TargetDomain>,
35    pub capabilities: Vec<SidecarPluginCapability>,
36}
37
38impl SidecarHandshake {
39    pub fn validate(&self, expected_plugin_id: &str) -> Result<(), String> {
40        if self.protocol_version != SIDECAR_RUNTIME_PROTOCOL_VERSION {
41            return Err(format!(
42                "unsupported sidecar protocol version: expected {}, got {}",
43                SIDECAR_RUNTIME_PROTOCOL_VERSION, self.protocol_version
44            ));
45        }
46
47        if self.plugin_id != expected_plugin_id {
48            return Err(format!(
49                "sidecar plugin id mismatch: expected {}, got {}",
50                expected_plugin_id, self.plugin_id
51            ));
52        }
53
54        for capability in [
55            SidecarPluginCapability::HealthCheck,
56            SidecarPluginCapability::SendEvent,
57            SidecarPluginCapability::Shutdown,
58        ] {
59            if !self.capabilities.contains(&capability) {
60                return Err(format!("sidecar handshake missing required capability: {:?}", capability));
61            }
62        }
63
64        Ok(())
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use super::{SIDECAR_RUNTIME_PROTOCOL_VERSION, SidecarHandshake, SidecarPluginCapability};
71    use crate::TargetDomain;
72
73    #[test]
74    fn sidecar_handshake_accepts_expected_contract() {
75        let handshake = SidecarHandshake {
76            protocol_version: SIDECAR_RUNTIME_PROTOCOL_VERSION.to_string(),
77            plugin_id: "external:webhook".to_string(),
78            plugin_version: "1.2.3".to_string(),
79            supported_domains: vec![TargetDomain::Notify],
80            capabilities: vec![
81                SidecarPluginCapability::HealthCheck,
82                SidecarPluginCapability::SendEvent,
83                SidecarPluginCapability::Shutdown,
84            ],
85        };
86
87        assert!(handshake.validate("external:webhook").is_ok());
88    }
89
90    #[test]
91    fn sidecar_handshake_rejects_protocol_mismatch() {
92        let handshake = SidecarHandshake {
93            protocol_version: "rustfs.target-runtime.v0".to_string(),
94            plugin_id: "external:webhook".to_string(),
95            plugin_version: "1.2.3".to_string(),
96            supported_domains: vec![TargetDomain::Notify],
97            capabilities: vec![
98                SidecarPluginCapability::HealthCheck,
99                SidecarPluginCapability::SendEvent,
100                SidecarPluginCapability::Shutdown,
101            ],
102        };
103
104        assert!(handshake.validate("external:webhook").is_err());
105    }
106}