use sift_stream::{
AutoRegisterStream, ChannelConfig, ChannelDataType, ChannelValue, Credentials, Flow,
FlowConfig, IngestionConfigForm, RunForm, SiftStreamAutoRegister, SiftStreamBuilder, TimeValue,
};
use std::{
env,
error::Error,
time::{Duration, SystemTime, UNIX_EPOCH},
};
const SEND_INTERVAL: Duration = Duration::from_millis(200);
const NUM_SAMPLES: u32 = 25;
fn timestamp_suffix() -> String {
format!(
"{:x}",
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
tracing_subscriber::fmt().init();
dotenvy::dotenv()?;
let credentials = Credentials::Config {
apikey: env::var("SIFT_API_KEY")?,
uri: env::var("SIFT_GRPC_URL")?,
};
let suffix = timestamp_suffix();
let asset_name = format!("demo_asset_{suffix}");
let run_name = format!("{asset_name}_run");
let stream = SiftStreamBuilder::new(credentials)
.ingestion_config(IngestionConfigForm {
asset_name: asset_name.clone(),
client_key: format!("{asset_name}_v1"),
flows: vec![FlowConfig {
name: "gps-position".to_string(),
channels: vec![
ChannelConfig {
name: "latitude".to_string(),
data_type: ChannelDataType::Double.into(),
unit: "deg".to_string(),
description: "WGS-84 latitude".to_string(),
..Default::default()
},
ChannelConfig {
name: "longitude".to_string(),
data_type: ChannelDataType::Double.into(),
unit: "deg".to_string(),
description: "WGS-84 longitude".to_string(),
..Default::default()
},
],
}],
})
.attach_run(RunForm {
name: run_name.clone(),
client_key: run_name,
..Default::default()
})
.live_with_backups()
.build()
.await?;
let staged_configs = vec![FlowConfig {
name: "vehicle-dynamics".to_string(),
channels: vec![
ChannelConfig {
name: "velocity".to_string(),
data_type: ChannelDataType::Double.into(),
unit: "m/s".to_string(),
description: "Longitudinal vehicle speed".to_string(),
..Default::default()
},
ChannelConfig {
name: "heading".to_string(),
data_type: ChannelDataType::Float.into(),
unit: "deg".to_string(),
description: "Vehicle heading angle (0-360, clockwise from north)".to_string(),
..Default::default()
},
],
}];
let mut auto = SiftStreamAutoRegister::new(stream, staged_configs);
for i in 0..NUM_SAMPLES {
let t = i as f64;
auto.send(Flow::new(
"gps-position",
TimeValue::now(),
&[
ChannelValue::new("latitude", 37.7749 + t * 0.0001_f64),
ChannelValue::new("longitude", -122.4194 + t * 0.0001_f64),
],
))
.await?;
auto.send(Flow::new(
"vehicle-dynamics",
TimeValue::now(),
&[
ChannelValue::new("velocity", t * 0.5_f64),
ChannelValue::new("heading", (t * 3.6) as f32),
],
))
.await?;
auto.send(Flow::new(
"engine-telemetry",
TimeValue::now(),
&[
ChannelValue::new("rpm", (3000.0 + t * 10.0) as f32),
ChannelValue::new("oil-temp", 85.0 + t * 0.1_f64),
],
))
.await?;
tokio::time::sleep(SEND_INTERVAL).await;
}
auto.finish().await?;
tracing::info!(
"done — {} samples sent for 3 flows (pre-registered, staged, dynamic)",
NUM_SAMPLES
);
Ok(())
}