elasticctl_api/rules/
window.rs1use std::collections::HashSet;
5
6use super::{RuleFilter, find};
7use crate::model::Rule;
8use elasticctl_core::{Error, ErrorKind, Result, Transport};
9
10pub const WINDOW_PAGE: u32 = 500;
13
14pub const WINDOW_MAX_RULES: u64 = 4_000;
17
18const SORT: &str = "&sort_field=created_at&sort_order=asc";
21
22const PASSES: usize = 2;
24
25pub async fn find_window(t: &Transport, filter: &RuleFilter) -> Result<Vec<Rule>> {
33 for _ in 0..PASSES {
34 if let Some(rules) = read_pass(t, filter).await? {
35 return Ok(rules);
36 }
37 }
38 Err(Error::new(
39 ErrorKind::Conflict,
40 "the matching rules changed during both corpus read passes; retry the read",
41 ))
42}
43
44async fn read_pass(t: &Transport, filter: &RuleFilter) -> Result<Option<Vec<Rule>>> {
46 let (mut rules, total) = find(t, filter, 1, WINDOW_PAGE, SORT).await?;
47 if total > WINDOW_MAX_RULES {
48 return Err(Error::new(
49 ErrorKind::Unsupported,
50 format!(
51 "{total} rules match, more than the {WINDOW_MAX_RULES} a corpus read accepts. \
52 Narrow the selection with a filter."
53 ),
54 ));
55 }
56 let last_page = total.div_ceil(u64::from(WINDOW_PAGE)) as u32;
58 let mut same_total = true;
59 for page in 2..=last_page {
60 let (more, page_total) = find(t, filter, page, WINDOW_PAGE, SORT).await?;
61 same_total &= page_total == total;
62 rules.extend(more);
63 }
64 let ids = rules
65 .iter()
66 .map(Rule::rule_id)
67 .collect::<Result<HashSet<_>>>()?;
68 let verified = same_total && rules.len() as u64 == total && ids.len() == rules.len();
69 Ok(verified.then_some(rules))
70}