Skip to main content

a3s_runtime/contract/
network.rs

1use serde::{Deserialize, Serialize};
2use std::collections::BTreeSet;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub enum NetworkMode {
7    None,
8    Outbound,
9    Service,
10}
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum TransportProtocol {
15    Tcp,
16    Udp,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
20#[serde(deny_unknown_fields)]
21pub struct RuntimePort {
22    pub name: String,
23    pub container_port: u16,
24    pub protocol: TransportProtocol,
25}
26
27impl RuntimePort {
28    pub(crate) fn validate(&self) -> Result<(), String> {
29        super::validate_name("port name", &self.name)?;
30        if self.container_port == 0 {
31            return Err("container_port must be positive".into());
32        }
33        Ok(())
34    }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38#[serde(deny_unknown_fields)]
39pub struct RuntimeNetworkSpec {
40    pub mode: NetworkMode,
41    pub ports: Vec<RuntimePort>,
42}
43
44impl RuntimeNetworkSpec {
45    pub(crate) fn validate(&self) -> Result<(), String> {
46        if self.ports.len() > 64 {
47            return Err("Runtime unit declares more than 64 ports".into());
48        }
49        if self.mode != NetworkMode::Service && !self.ports.is_empty() {
50            return Err("declared ports require service network mode".into());
51        }
52        let mut names = BTreeSet::new();
53        let mut sockets = BTreeSet::new();
54        for port in &self.ports {
55            port.validate()?;
56            if !names.insert(&port.name) {
57                return Err(format!("duplicate Runtime port name {:?}", port.name));
58            }
59            if !sockets.insert((port.container_port, port.protocol)) {
60                return Err(format!(
61                    "duplicate Runtime port socket {}/{}",
62                    port.container_port,
63                    match port.protocol {
64                        TransportProtocol::Tcp => "tcp",
65                        TransportProtocol::Udp => "udp",
66                    }
67                ));
68            }
69        }
70        Ok(())
71    }
72
73    pub(crate) fn has_port(&self, name: &str) -> bool {
74        self.ports.iter().any(|port| port.name == name)
75    }
76}