feat: KSUDP parser fix, warnings system, shift point rewrite, code quality (v0.5.1)
Bug Fixes:
- Fixed KSUDP binary parser offsets from packed (323B) to natural C
alignment (328B) — 3 bytes padding after char identifier, 2 bytes
after 6 bools
- Fixed setup_terminal() leaving terminal in raw mode on early exit
New Features:
- Thread-safe warning buffer (warnings.rs) with TUI bar + stderr fallback
- Rewrote shift point analysis per AC forum methodology: per-gear
acceleration curves, crossover detection, same-gear merging
- UseCase::guidance() — step-by-step recording instructions
- Recording metadata enrichment in analysis responses
- recording_id field on sessions
Code Quality:
- Extracted finalize_run() helper (session.rs)
- Extracted execute_and_store_analysis() helper (api.rs)
- Extracted lerp_search<T>() generic helper (analysis.rs)
Breaking API Changes:
- GET /api/use-cases: string[] -> [{id, name, guidance}[]]
- Shift point analysis: gear_ranges/shift_events -> gear_curves/crossover_points
Updated README.md with new API response examples and TUI warning bar.
This commit is contained in:
parent
090ab7e559
commit
e3aa511ac7
9 changed files with 696 additions and 312 deletions
89
src/warnings.rs
Normal file
89
src/warnings.rs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
use std::collections::VecDeque;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Instant;
|
||||
|
||||
const MAX_WARNINGS: usize = 50;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum WarningLevel {
|
||||
Info,
|
||||
Warn,
|
||||
Error,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct WarningEntry {
|
||||
pub message: String,
|
||||
pub timestamp: Instant,
|
||||
pub level: WarningLevel,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Warnings {
|
||||
entries: Arc<Mutex<VecDeque<WarningEntry>>>,
|
||||
}
|
||||
|
||||
impl Warnings {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
entries: Arc::new(Mutex::new(VecDeque::with_capacity(MAX_WARNINGS))),
|
||||
}
|
||||
}
|
||||
|
||||
fn push(&self, level: WarningLevel, msg: &str) {
|
||||
match level {
|
||||
WarningLevel::Error => eprintln!("[ERROR] {}", msg),
|
||||
WarningLevel::Warn => eprintln!("[WARN] {}", msg),
|
||||
WarningLevel::Info => {}
|
||||
}
|
||||
|
||||
let mut guard = match self.entries.lock() {
|
||||
Ok(g) => g,
|
||||
Err(e) => e.into_inner(),
|
||||
};
|
||||
if guard.len() >= MAX_WARNINGS {
|
||||
guard.pop_front();
|
||||
}
|
||||
guard.push_back(WarningEntry {
|
||||
message: msg.to_string(),
|
||||
timestamp: Instant::now(),
|
||||
level,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn warn(&self, msg: &str) {
|
||||
self.push(WarningLevel::Warn, msg);
|
||||
}
|
||||
|
||||
pub fn info(&self, msg: &str) {
|
||||
self.push(WarningLevel::Info, msg);
|
||||
}
|
||||
|
||||
pub fn error(&self, msg: &str) {
|
||||
self.push(WarningLevel::Error, msg);
|
||||
}
|
||||
|
||||
/// Returns warnings from the last `max_age_secs` seconds.
|
||||
/// Currently unused but kept for potential future TUI scrolling.
|
||||
#[allow(dead_code)]
|
||||
pub fn recent(&self, max_age_secs: u64) -> Vec<WarningEntry> {
|
||||
let guard = match self.entries.lock() {
|
||||
Ok(g) => g,
|
||||
Err(e) => e.into_inner(),
|
||||
};
|
||||
let cutoff = Instant::now() - std::time::Duration::from_secs(max_age_secs);
|
||||
guard
|
||||
.iter()
|
||||
.filter(|e| e.timestamp >= cutoff)
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn latest(&self) -> Option<WarningEntry> {
|
||||
let guard = match self.entries.lock() {
|
||||
Ok(g) => g,
|
||||
Err(e) => e.into_inner(),
|
||||
};
|
||||
guard.back().cloned()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue