rkubectl_kubeapi/
cache.rs

1use indexmap::IndexMap;
2
3use super::*;
4
5#[derive(Clone, Debug, Default)]
6pub struct Cache {
7    groups: Option<metav1::APIGroupList>,
8    resources: IndexMap<String, metav1::APIResourceList>,
9    took: time::Duration,
10    _pad: (),
11}
12
13impl Cache {
14    pub(super) fn try_load(self, path: impl AsRef<Path>) -> Self {
15        let start = time::Instant::now();
16        let cached_resources = CachedResources::new(path);
17        let groups = cached_resources.load_server_groups().ok();
18        let resources = groups
19            .as_ref()
20            .map(|groups| cached_resources.load_groups_resources(groups))
21            .unwrap_or_default();
22        let took = start.elapsed();
23        Self {
24            groups,
25            resources,
26            took,
27            ..self
28        }
29    }
30
31    pub(super) fn api_groups(&self) -> Option<metav1::APIGroupList> {
32        self.groups.clone()
33    }
34
35    pub(super) fn api_resources(&self) -> Option<Vec<metav1::APIResourceList>> {
36        let resources = self.resources.values().cloned().collect::<Vec<_>>();
37        if resources.is_empty() {
38            None
39        } else {
40            Some(resources)
41        }
42    }
43
44    pub fn took(&self) -> time::Duration {
45        self.took
46    }
47}
48
49struct CachedResources {
50    path: PathBuf,
51}
52
53impl CachedResources {
54    const SERVER_GROUPS: &'static str = "servergroups.json";
55    const SERVER_RESOURCES: &'static str = "serverresources.json";
56
57    fn new(path: impl AsRef<Path>) -> Self {
58        let path = path.as_ref().to_path_buf();
59        trace!(from = %path.display(), "Loading cached resources");
60        Self { path }
61    }
62
63    fn load_server_groups(&self) -> io::Result<metav1::APIGroupList> {
64        let path = self.path.join(Self::SERVER_GROUPS);
65        load_json(path)
66    }
67
68    fn load_groups_resources(
69        &self,
70        groups: &metav1::APIGroupList,
71    ) -> IndexMap<String, metav1::APIResourceList> {
72        groups
73            .groups
74            .iter()
75            .flat_map(|group| group.versions.iter())
76            .filter_map(|version| self.load_server_group_version_resources(version).ok())
77            .map(|arl| (arl.group_version.clone(), arl))
78            .collect()
79    }
80
81    fn load_server_group_version_resources(
82        &self,
83        version: &metav1::GroupVersionForDiscovery,
84    ) -> io::Result<metav1::APIResourceList> {
85        let path = self
86            .path
87            .join(&version.group_version)
88            .join(Self::SERVER_RESOURCES);
89        load_json(path)
90    }
91}
92
93#[tracing::instrument(level = "trace", err)]
94fn load_json<T>(path: PathBuf) -> io::Result<T>
95where
96    T: serde::de::DeserializeOwned,
97{
98    trace!("Loading cached data");
99    let text = fs::read_to_string(path)?;
100    let data = json::from_str(&text)?;
101    Ok(data)
102}