1use std::{collections::HashSet, str::FromStr};
4
5use semver::{Version, VersionReq};
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8use crate::{
9 error::CniError,
10 reply::{reply, ReplyPayload},
11 Cni,
12};
13
14pub const COMPATIBLE_VERSIONS: &str = "=0.4.0||^1.0.0";
15pub const SUPPORTED_VERSIONS: &[&str] = &["0.4.0", "1.0.0"];
16
17#[derive(Clone, Deserialize)]
18#[serde(rename_all = "camelCase")]
19pub(crate) struct VersionPayload {
20 #[serde(deserialize_with = "deserialize_version")]
21 #[serde(serialize_with = "serialize_version")]
22 pub cni_version: Version,
23}
24
25impl Cni {
26 pub(crate) fn check_version(version: &Version) -> Result<(), CniError> {
27 if !VersionReq::parse(COMPATIBLE_VERSIONS)
28 .unwrap()
29 .matches(version)
30 {
31 Err(CniError::Incompatible(version.clone()))
32 } else {
33 Ok(())
34 }
35 }
36
37 pub(crate) fn handle_version(version: Version) -> ! {
38 let mut supported_versions = SUPPORTED_VERSIONS
39 .iter()
40 .map(|v| Version::parse(*v))
41 .collect::<Result<HashSet<_>, _>>()
42 .unwrap();
43
44 let supported = Self::check_version(&version).is_ok();
45 if supported {
46 supported_versions.insert(version.clone());
47 }
48
49 reply(VersionReply {
50 cni_version: version,
51 supported_versions: supported_versions.into_iter().collect(),
52 });
53 }
54}
55
56#[derive(Clone, Debug, Deserialize, Serialize)]
64#[serde(rename_all = "camelCase")]
65pub struct VersionReply {
66 #[serde(deserialize_with = "deserialize_version")]
68 #[serde(serialize_with = "serialize_version")]
69 pub cni_version: Version,
70
71 #[serde(deserialize_with = "deserialize_version_list")]
73 #[serde(serialize_with = "serialize_version_list")]
74 pub supported_versions: Vec<Version>,
75}
76
77impl<'de> ReplyPayload<'de> for VersionReply {}
78
79pub(crate) fn serialize_version<S>(version: &Version, serializer: S) -> Result<S::Ok, S::Error>
80where
81 S: Serializer,
82{
83 version.to_string().serialize(serializer)
84}
85
86pub(crate) fn serialize_version_list<S>(list: &[Version], serializer: S) -> Result<S::Ok, S::Error>
87where
88 S: Serializer,
89{
90 list.iter()
91 .map(Version::to_string)
92 .collect::<Vec<String>>()
93 .serialize(serializer)
94}
95
96pub(crate) fn deserialize_version<'de, D>(deserializer: D) -> Result<Version, D::Error>
97where
98 D: Deserializer<'de>,
99{
100 use serde::de::Error;
101 let j = String::deserialize(deserializer)?;
102 Version::from_str(&j).map_err(Error::custom)
103}
104
105pub(crate) fn deserialize_version_list<'de, D>(deserializer: D) -> Result<Vec<Version>, D::Error>
106where
107 D: Deserializer<'de>,
108{
109 use serde::de::Error;
110 let j = Vec::<String>::deserialize(deserializer)?;
111 j.iter()
112 .map(|s| Version::from_str(s).map_err(Error::custom))
113 .collect()
114}