use aura_lang::{Budget, Script};
use serde::{Deserialize, Serialize};
const TELEMETRY: &str = r#"
# Which readings are alerts. Edit this file to change the rule; the service
# picks it up without being rebuilt.
pub def summarize(events)
hot = events.filter (e, i) -> e.temp_c > 80.0 end
total: events.len()
alerts: hot.len()
worst: hot.len() > 0 ? hot.map (e, i) -> e.temp_c end.max() : null
end
version: "telemetry-v4"
"#;
#[derive(Serialize)]
struct Event {
device: String,
temp_c: f64,
}
#[derive(Deserialize, Debug, PartialEq)]
struct Summary {
total: u64,
alerts: u64,
worst: Option<f64>,
}
#[derive(Default, Debug)]
struct Totals {
events: u64,
alerts: u64,
worst: Option<f64>,
}
impl Totals {
fn merge(&mut self, s: Summary) {
self.events += s.total;
self.alerts += s.alerts;
self.worst = match (self.worst, s.worst) {
(Some(a), Some(b)) => Some(a.max(b)),
(a, b) => a.or(b),
};
}
}
fn main() -> Result<(), aura_lang::Error> {
let rules = Script::builder()
.source("telemetry.aura", TELEMETRY)
.budget(Budget::per_call().steps(5_000_000).memory_mb(32))
.load()?;
let version: String = rules.get("version")?;
println!("rules: {version}");
let summarize = rules.function::<(&[Event],), Summary>("summarize")?;
let mut totals = Totals::default();
for chunk in incoming_events().chunks(10_000) {
totals.merge(summarize.call((chunk,))?);
}
println!(
"{} events, {} alerts, worst {:?} °C",
totals.events, totals.alerts, totals.worst
);
Ok(())
}
fn incoming_events() -> Vec<Event> {
(0..50_000)
.map(|i| Event {
device: format!("sensor-{}", i % 64),
temp_c: 20.0 + (i % 90) as f64,
})
.collect()
}