mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-06-03 11:43:34 -07:00
address most of wills review feedback, fix serialization and stringly error handling in DiagTask::start
This commit is contained in:
committed by
Will Greenberg
parent
a58bad09fc
commit
bd5dfb1a75
+31
-43
@@ -40,7 +40,7 @@ const DISK_CHECK_BYTES_INTERVAL: usize = 256 * 1024;
|
|||||||
pub enum DiagDeviceCtrlMessage {
|
pub enum DiagDeviceCtrlMessage {
|
||||||
StopRecording,
|
StopRecording,
|
||||||
StartRecording {
|
StartRecording {
|
||||||
response_tx: Option<oneshot::Sender<Result<(), String>>>,
|
response_tx: Option<oneshot::Sender<Result<(), RecordingStoreError>>>,
|
||||||
},
|
},
|
||||||
DeleteEntry {
|
DeleteEntry {
|
||||||
name: String,
|
name: String,
|
||||||
@@ -129,7 +129,7 @@ impl DiagTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start recording, returning an error if disk space is too low.
|
/// Start recording, returning an error if disk space is too low.
|
||||||
async fn start(&mut self, qmdl_store: &mut RecordingStore) -> Result<(), String> {
|
async fn start(&mut self, qmdl_store: &mut RecordingStore) -> Result<(), RecordingStoreError> {
|
||||||
self.max_type_seen = EventType::Informational;
|
self.max_type_seen = EventType::Informational;
|
||||||
self.bytes_since_space_check = 0;
|
self.bytes_since_space_check = 0;
|
||||||
self.low_space_warned = false;
|
self.low_space_warned = false;
|
||||||
@@ -140,12 +140,10 @@ impl DiagTask {
|
|||||||
self.min_space_to_continue_mb,
|
self.min_space_to_continue_mb,
|
||||||
) {
|
) {
|
||||||
DiskSpaceCheck::Critical(mb) | DiskSpaceCheck::Warning(mb) => {
|
DiskSpaceCheck::Critical(mb) | DiskSpaceCheck::Warning(mb) => {
|
||||||
let msg = format!(
|
return Err(RecordingStoreError::InsufficientDiskSpace(
|
||||||
"Insufficient disk space: {}MB available, {}MB required",
|
mb,
|
||||||
mb, self.min_space_to_start_mb
|
self.min_space_to_start_mb,
|
||||||
);
|
));
|
||||||
error!("{msg}");
|
|
||||||
return Err(msg);
|
|
||||||
}
|
}
|
||||||
DiskSpaceCheck::Ok(mb) => {
|
DiskSpaceCheck::Ok(mb) => {
|
||||||
info!("Starting recording with {}MB disk space available", mb);
|
info!("Starting recording with {}MB disk space available", mb);
|
||||||
@@ -153,14 +151,8 @@ impl DiagTask {
|
|||||||
DiskSpaceCheck::Failed => {}
|
DiskSpaceCheck::Failed => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (qmdl_file, analysis_file) = match qmdl_store.new_entry(self.gps_mode).await {
|
let (qmdl_file, analysis_file) = qmdl_store.new_entry(self.gps_mode).await?;
|
||||||
Ok(files) => files,
|
|
||||||
Err(e) => {
|
|
||||||
let msg = format!("failed creating QMDL file entry: {e}");
|
|
||||||
error!("{msg}");
|
|
||||||
return Err(msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// For fixed-mode sessions, write the configured coordinates to the sidecar
|
// For fixed-mode sessions, write the configured coordinates to the sidecar
|
||||||
// immediately so the per-session GPS is stored durably and isn't affected
|
// immediately so the per-session GPS is stored durably and isn't affected
|
||||||
// by future config changes or GPS API calls.
|
// by future config changes or GPS API calls.
|
||||||
@@ -168,38 +160,34 @@ impl DiagTask {
|
|||||||
&& let Some((lat, lon)) = self.gps_fixed_coords
|
&& let Some((lat, lon)) = self.gps_fixed_coords
|
||||||
&& let Some((entry_idx, _)) = qmdl_store.get_current_entry()
|
&& let Some((entry_idx, _)) = qmdl_store.get_current_entry()
|
||||||
{
|
{
|
||||||
match qmdl_store.open_entry_gps_for_append(entry_idx).await {
|
let mut gps_file = qmdl_store
|
||||||
Ok(Some(mut gps_file)) => {
|
.open_entry_gps_for_append(entry_idx)
|
||||||
let record = GpsRecord {
|
.await?
|
||||||
unix_ts: 0,
|
.ok_or(RecordingStoreError::GpsSidecarNotFound)?;
|
||||||
lat,
|
|
||||||
lon,
|
let record = GpsRecord {
|
||||||
};
|
unix_ts: chrono::Utc::now().timestamp(),
|
||||||
if let Ok(json) = serde_json::to_string(&record) {
|
lat,
|
||||||
let _ = gps_file.write_all(format!("{json}\n").as_bytes()).await;
|
lon,
|
||||||
}
|
};
|
||||||
}
|
let json = serde_json::to_string(&record)?;
|
||||||
Ok(None) => {
|
gps_file
|
||||||
error!("GPS sidecar directory not found, cannot write fixed-mode coordinates")
|
.write_all(format!("{json}\n").as_bytes())
|
||||||
}
|
.await
|
||||||
Err(e) => error!("failed to open GPS sidecar for fixed-mode entry: {e}"),
|
.map_err(RecordingStoreError::WriteFileError)?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stop_current_recording().await;
|
self.stop_current_recording().await;
|
||||||
let qmdl_writer = QmdlWriter::new(qmdl_file);
|
let qmdl_writer = QmdlWriter::new(qmdl_file);
|
||||||
let analysis_writer = match AnalysisWriter::new(analysis_file, &self.analyzer_config).await
|
let analysis_writer = AnalysisWriter::new(analysis_file, &self.analyzer_config)
|
||||||
{
|
.await
|
||||||
Ok(writer) => Box::new(writer),
|
.map_err(RecordingStoreError::WriteFileError)?;
|
||||||
Err(e) => {
|
|
||||||
let msg = format!("failed to create analysis writer: {e}");
|
|
||||||
error!("{msg}");
|
|
||||||
return Err(msg);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.state = DiagState::Recording {
|
self.state = DiagState::Recording {
|
||||||
qmdl_writer,
|
qmdl_writer,
|
||||||
analysis_writer,
|
analysis_writer: Box::new(analysis_writer),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = self
|
if let Err(e) = self
|
||||||
.ui_update_sender
|
.ui_update_sender
|
||||||
.send(display::DisplayState::Recording)
|
.send(display::DisplayState::Recording)
|
||||||
@@ -530,7 +518,7 @@ pub async fn start_recording(
|
|||||||
|
|
||||||
match response_rx.await {
|
match response_rx.await {
|
||||||
Ok(Ok(())) => Ok((StatusCode::ACCEPTED, "ok".to_string())),
|
Ok(Ok(())) => Ok((StatusCode::ACCEPTED, "ok".to_string())),
|
||||||
Ok(Err(reason)) => Err((StatusCode::INSUFFICIENT_STORAGE, reason)),
|
Ok(Err(reason)) => Err((StatusCode::INSUFFICIENT_STORAGE, reason.to_string())),
|
||||||
Err(e) => Err((
|
Err(e) => Err((
|
||||||
StatusCode::INTERNAL_SERVER_ERROR,
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
format!("failed to receive start recording response: {e}"),
|
format!("failed to receive start recording response: {e}"),
|
||||||
|
|||||||
+1
-3
@@ -306,14 +306,12 @@ async fn run_with_config(
|
|||||||
config.webdav.clone().into(),
|
config.webdav.clone().into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// For fixed configuration, we use timestamp 0 to not break other
|
|
||||||
// the GET request for GPS but user won't see the 0 in PCAPs
|
|
||||||
let initial_gps = if config.gps_mode == GpsMode::Fixed {
|
let initial_gps = if config.gps_mode == GpsMode::Fixed {
|
||||||
match (config.gps_fixed_latitude, config.gps_fixed_longitude) {
|
match (config.gps_fixed_latitude, config.gps_fixed_longitude) {
|
||||||
(Some(lat), Some(lon)) => Some(gps::GpsData {
|
(Some(lat), Some(lon)) => Some(gps::GpsData {
|
||||||
latitude: lat,
|
latitude: lat,
|
||||||
longitude: lon,
|
longitude: lon,
|
||||||
timestamp: 0,
|
timestamp: chrono::Utc::now().timestamp(),
|
||||||
}),
|
}),
|
||||||
_ => {
|
_ => {
|
||||||
warn!(
|
warn!(
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ pub enum RecordingStoreError {
|
|||||||
CreateFileError(tokio::io::Error),
|
CreateFileError(tokio::io::Error),
|
||||||
#[error("Couldn't read file: {0}")]
|
#[error("Couldn't read file: {0}")]
|
||||||
ReadFileError(tokio::io::Error),
|
ReadFileError(tokio::io::Error),
|
||||||
|
#[error("Couldn't write file: {0}")]
|
||||||
|
WriteFileError(tokio::io::Error),
|
||||||
#[error("Couldn't delete file: {0}")]
|
#[error("Couldn't delete file: {0}")]
|
||||||
DeleteFileError(tokio::io::Error),
|
DeleteFileError(tokio::io::Error),
|
||||||
#[error("Couldn't open directory at path: {0}")]
|
#[error("Couldn't open directory at path: {0}")]
|
||||||
@@ -33,6 +35,12 @@ pub enum RecordingStoreError {
|
|||||||
WriteManifestError(tokio::io::Error),
|
WriteManifestError(tokio::io::Error),
|
||||||
#[error("Couldn't parse QMDL store manifest file: {0}")]
|
#[error("Couldn't parse QMDL store manifest file: {0}")]
|
||||||
ParseManifestError(toml::de::Error),
|
ParseManifestError(toml::de::Error),
|
||||||
|
#[error("Insufficient disk space: {0}MB available, {1}MB required")]
|
||||||
|
InsufficientDiskSpace(u64, u64),
|
||||||
|
#[error("GPS sidecar directory not found")]
|
||||||
|
GpsSidecarNotFound,
|
||||||
|
#[error("Serialization error: {0}")]
|
||||||
|
SerializationError(#[from] serde_json::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RecordingStore {
|
pub struct RecordingStore {
|
||||||
|
|||||||
@@ -245,6 +245,7 @@ pub fn run_webdav_upload_worker(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::config::GpsMode;
|
||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
body::Bytes,
|
body::Bytes,
|
||||||
|
|||||||
+7
-14
@@ -10,6 +10,7 @@ use pcap_file_tokio::pcapng::blocks::enhanced_packet::{EnhancedPacketBlock, Enha
|
|||||||
use pcap_file_tokio::pcapng::blocks::interface_description::InterfaceDescriptionBlock;
|
use pcap_file_tokio::pcapng::blocks::interface_description::InterfaceDescriptionBlock;
|
||||||
use pcap_file_tokio::pcapng::blocks::section_header::{SectionHeaderBlock, SectionHeaderOption};
|
use pcap_file_tokio::pcapng::blocks::section_header::{SectionHeaderBlock, SectionHeaderOption};
|
||||||
use pcap_file_tokio::{Endianness, PcapError};
|
use pcap_file_tokio::{Endianness, PcapError};
|
||||||
|
use serde::Serialize;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::io::AsyncWrite;
|
use tokio::io::AsyncWrite;
|
||||||
@@ -26,11 +27,13 @@ pub enum GsmtapPcapError {
|
|||||||
Deku(#[from] DekuError),
|
Deku(#[from] DekuError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
pub struct GpsPoint {
|
pub struct GpsPoint {
|
||||||
pub latitude: f64,
|
|
||||||
pub longitude: f64,
|
|
||||||
/// Unix timestamp of the GPS fix. 0 means fixed/synthetic (no real GPS time).
|
|
||||||
pub unix_ts: i64,
|
pub unix_ts: i64,
|
||||||
|
#[serde(rename = "lat")]
|
||||||
|
pub latitude: f64,
|
||||||
|
#[serde(rename = "lon")]
|
||||||
|
pub longitude: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct GsmtapPcapWriter<T>
|
pub struct GsmtapPcapWriter<T>
|
||||||
@@ -148,17 +151,7 @@ where
|
|||||||
|
|
||||||
let mut options = vec![];
|
let mut options = vec![];
|
||||||
if let Some(p) = gps {
|
if let Some(p) = gps {
|
||||||
let comment = if p.unix_ts == 0 {
|
let comment = serde_json::to_string(p).expect("GpsPoint serialization cannot fail");
|
||||||
format!(
|
|
||||||
r#"{{"latitude":{:.7},"longitude":{:.7}}}"#,
|
|
||||||
p.latitude, p.longitude
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
format!(
|
|
||||||
r#"{{"latitude":{:.7},"longitude":{:.7},"timestamp":{}}}"#,
|
|
||||||
p.latitude, p.longitude, p.unix_ts
|
|
||||||
)
|
|
||||||
};
|
|
||||||
options.push(EnhancedPacketOption::Comment(Cow::Owned(comment)));
|
options.push(EnhancedPacketOption::Comment(Cow::Owned(comment)));
|
||||||
}
|
}
|
||||||
let packet = EnhancedPacketBlock {
|
let packet = EnhancedPacketBlock {
|
||||||
|
|||||||
Reference in New Issue
Block a user