memflow_registry/storage/
database.rs1use std::{cmp::Reverse, collections::HashMap};
2
3use chrono::NaiveDateTime;
4use log::info;
5use memflow::plugins::plugin_analyzer::{PluginArchitecture, PluginDescriptorInfo, PluginFileType};
6use serde::{Deserialize, Serialize};
7
8use crate::{error::Result, rest::models::PluginInfo};
9
10use super::PluginMetadata;
11
12const DEFAULT_PLUGIN_VARIANTS: usize = 5;
13const MAX_PLUGIN_VARIANTS: usize = 50;
14
15#[derive(Default)]
16pub struct PluginDatabase {
17 plugins: HashMap<String, Vec<PluginVariant>>,
18}
19
20#[derive(Clone, Serialize, Deserialize)]
21pub struct PluginVariant {
22 pub digest: String,
23 pub signature: String,
24 pub created_at: NaiveDateTime,
25 pub descriptor: PluginDescriptorInfo,
26}
27
28#[derive(Debug, Default, Clone, Deserialize)]
29pub struct PluginDatabaseFindParams {
30 pub version: Option<String>,
31 pub memflow_plugin_version: Option<i32>,
32 pub file_type: Option<PluginFileType>,
33 pub architecture: Option<PluginArchitecture>,
34
35 pub skip: Option<usize>,
37 pub limit: Option<usize>,
38}
39
40impl PluginDatabase {
41 pub fn new() -> Self {
42 Self::default()
43 }
44
45 pub fn insert_all(&mut self, metadata: &PluginMetadata) -> Result<()> {
47 for descriptor in metadata.descriptors.iter() {
48 info!(
49 "adding plugin variant to db: digest={}; created_at={}; descriptor={:?}",
50 metadata.digest, metadata.created_at, descriptor
51 );
52
53 let entry = self.plugins.entry(descriptor.name.clone()).or_default();
54
55 let search_key = (
58 metadata.descriptors.first().unwrap().plugin_version,
59 metadata.created_at,
60 );
61 match entry.binary_search_by_key(&Reverse(search_key), |entry| {
62 Reverse((entry.descriptor.plugin_version, entry.created_at))
63 }) {
64 Ok(_) => unreachable!(), Err(pos) => entry.insert(
66 pos,
67 PluginVariant {
68 digest: metadata.digest.clone(),
69 signature: metadata.signature.clone(),
70 created_at: metadata.created_at,
71 descriptor: descriptor.clone(),
72 },
73 ),
74 }
75 }
76
77 Ok(())
78 }
79
80 pub fn plugins(&self) -> Vec<PluginInfo> {
82 let mut plugins = self
83 .plugins
84 .iter()
85 .flat_map(|(key, variants)| {
86 variants.iter().map(|variant| PluginInfo {
87 name: key.to_owned(),
88 description: variant.descriptor.description.clone(),
89 })
90 })
91 .collect::<Vec<_>>();
92 plugins.sort_by(|a, b| a.name.cmp(&b.name));
93 plugins.dedup_by(|a, b| a.name == b.name);
94 plugins
95 }
96
97 #[allow(unused)]
99 pub fn find_by_digest(&self, digest: &str) -> Option<PluginVariant> {
100 self.plugins
101 .iter()
102 .find_map(|(_, variants)| variants.iter().find(|variant| variant.digest == digest))
103 .cloned()
104 }
105
106 pub fn delete_by_digest(&mut self, digest: &str) {
108 for plugin in self.plugins.iter_mut() {
109 plugin.1.retain(|variant| variant.digest != digest);
110 }
111 }
112
113 pub fn plugin_variants(
116 &self,
117 plugin_name: &str,
118 params: PluginDatabaseFindParams,
119 ) -> Vec<PluginVariant> {
120 self.plugins
121 .get(plugin_name)
122 .map(|variants| {
123 variants
124 .iter()
125 .skip(params.skip.unwrap_or(0))
126 .filter(|p| p.descriptor.name == plugin_name)
127 .filter(|p| {
128 if let Some(version) = ¶ms.version {
129 if *version != p.descriptor.version
131 && *version != p.digest[..version.len()]
132 {
133 return false;
134 }
135 }
136
137 if let Some(memflow_plugin_version) = params.memflow_plugin_version {
138 if memflow_plugin_version != p.descriptor.plugin_version {
139 return false;
140 }
141 }
142
143 if let Some(file_type) = params.file_type {
144 if file_type != p.descriptor.file_type {
145 return false;
146 }
147 }
148
149 if let Some(architecture) = params.architecture {
150 if architecture != p.descriptor.architecture {
151 return false;
152 }
153 }
154
155 true
156 })
157 .take(
158 params
159 .limit
160 .unwrap_or(DEFAULT_PLUGIN_VARIANTS)
161 .min(MAX_PLUGIN_VARIANTS),
162 )
163 .cloned()
164 .collect::<Vec<_>>()
165 })
166 .unwrap_or_default()
167 }
168}