Bevy+Ratutui powered Monitoring of Pico-Strike devices
at main 4.2 kB view raw
1use core::net::IpAddr; 2 3use bevy::{ 4 app::{Plugin, Update}, 5 ecs::{ 6 component::Component, 7 entity::Entity, 8 lifecycle::HookContext, 9 name::Name, 10 resource::Resource, 11 system::{Commands, Res, ResMut}, 12 world::DeferredWorld, 13 }, 14 prelude::Deref, 15}; 16use rapidhash::RapidHashSet; 17 18use crate::net::DiscoverResponse; 19 20#[derive(Debug, Resource, Default)] 21pub struct UniqueDevices(pub RapidHashSet<DeviceSocket>); 22 23#[derive(Debug, Component)] 24pub struct Device; 25 26#[derive(Debug, Clone, Component, Hash, PartialEq, Eq)] 27#[component(immutable, on_remove = on_remove_device)] 28pub struct DeviceSocket { 29 pub address: String, 30 pub port: u16, 31 pub ip: IpAddr, 32} 33 34#[derive(Debug, Component, Default, Clone, Copy)] 35pub struct DeviceDetector { 36 pub blip_threshold: usize, 37 pub blip_size: usize, 38 pub max_duty: u16, 39 pub duty: u16, 40} 41 42fn on_remove_device(mut world: DeferredWorld, context: HookContext) { 43 let component = world 44 .entity(context.entity) 45 .get::<DeviceSocket>() 46 .cloned() 47 .unwrap(); 48 let mut devices = world.resource_mut::<UniqueDevices>(); 49 50 devices.0.remove(&component); 51} 52 53#[derive(Debug, Component)] 54#[component(immutable)] 55pub struct StormLevel(pub u16); 56 57#[derive(Debug, Component, Deref)] 58#[component(immutable)] 59pub struct Timestamp(pub jiff::Timestamp); 60 61impl Timestamp { 62 pub fn from_seconds(stamp: i64) -> Result<Self, jiff::Error> { 63 jiff::Timestamp::from_second(stamp).map(Self) 64 } 65 66 pub fn from_microseconds(stamp: i64) -> Result<Self, jiff::Error> { 67 jiff::Timestamp::from_microsecond(stamp).map(Self) 68 } 69} 70 71#[derive(Debug, Component, Deref)] 72#[component(immutable)] 73pub struct StormSignal(Vec<i16>); 74 75impl StormSignal { 76 pub fn new(value: Vec<i16>) -> Self { 77 Self(value) 78 } 79} 80 81#[derive(Debug, Component, Deref)] 82#[component(immutable)] 83pub struct SignalAverage(pub u16); 84 85impl SignalAverage { 86 pub fn new(value: u16) -> Self { 87 Self(value) 88 } 89} 90 91#[derive(Debug, Component, Deref)] 92#[component(immutable)] 93pub struct SignalPeaks(Vec<u16>); 94 95impl SignalPeaks { 96 pub fn new(value: Vec<u16>) -> Self { 97 Self(value) 98 } 99} 100 101#[derive(Debug, Component)] 102#[relationship(relationship_target = Signals)] 103pub struct SignalSource(pub Entity); 104 105#[derive(Component, Debug, Deref)] 106#[relationship_target(relationship = SignalSource, linked_spawn)] 107pub struct Signals { 108 signals: Vec<Entity>, 109} 110 111#[derive(Debug, Component)] 112#[relationship(relationship_target = StormLevels)] 113pub struct StormSource(pub Entity); 114 115#[derive(Component, Debug, Deref)] 116#[relationship_target(relationship = StormSource, linked_spawn)] 117pub struct StormLevels { 118 levels: Vec<Entity>, 119} 120 121#[derive(Debug)] 122pub enum ConnectionState { 123 Disconnected, 124 Connecting, 125 Connected, 126} 127 128impl core::fmt::Display for ConnectionState { 129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 130 match self { 131 Self::Disconnected => write!(f, "Disconnected"), 132 Self::Connecting => write!(f, "Connecting"), 133 Self::Connected => write!(f, "Connected"), 134 } 135 } 136} 137 138#[derive(Debug, Resource)] 139pub struct ConnectedDevice { 140 pub device: Entity, 141 pub connection_state: ConnectionState, 142} 143 144fn register_devices( 145 incoming: Res<DiscoverResponse>, 146 mut unique: ResMut<UniqueDevices>, 147 mut commands: Commands, 148) { 149 let mut devices = Vec::new(); 150 151 while let Ok(discovered) = incoming.0.try_recv() { 152 let device_addr = DeviceSocket { 153 address: discovered.address, 154 port: discovered.port, 155 ip: discovered.ip, 156 }; 157 158 if !unique.0.contains(&device_addr) { 159 unique.0.insert(device_addr.clone()); 160 devices.push((Device, Name::new(discovered.host), device_addr)); 161 } 162 } 163 164 if !devices.is_empty() { 165 commands.spawn_batch(devices); 166 } 167} 168 169#[derive(Debug)] 170pub struct DevicePlugin; 171 172impl Plugin for DevicePlugin { 173 fn build(&self, app: &mut bevy::app::App) { 174 app.init_resource::<UniqueDevices>() 175 .add_systems(Update, register_devices); 176 } 177}