mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-07-16 21:08:13 -07:00
requests addressed, better error handling, more logging, small text corrections
This commit is contained in:
committed by
Will Greenberg
parent
ba78c7bd01
commit
5a4a3034be
+15
-8
@@ -167,15 +167,22 @@ impl DiagTask {
|
||||
if self.gps_mode == GpsMode::Fixed
|
||||
&& let Some((lat, lon)) = self.gps_fixed_coords
|
||||
&& let Some((entry_idx, _)) = qmdl_store.get_current_entry()
|
||||
&& let Ok(mut gps_file) = qmdl_store.open_entry_gps_for_append(entry_idx).await
|
||||
{
|
||||
let record = GpsRecord {
|
||||
unix_ts: 0,
|
||||
lat,
|
||||
lon,
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&record) {
|
||||
let _ = gps_file.write_all(format!("{json}\n").as_bytes()).await;
|
||||
match qmdl_store.open_entry_gps_for_append(entry_idx).await {
|
||||
Ok(Some(mut gps_file)) => {
|
||||
let record = GpsRecord {
|
||||
unix_ts: 0,
|
||||
lat,
|
||||
lon,
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&record) {
|
||||
let _ = gps_file.write_all(format!("{json}\n").as_bytes()).await;
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
error!("GPS sidecar directory not found, cannot write fixed-mode coordinates")
|
||||
}
|
||||
Err(e) => error!("failed to open GPS sidecar for fixed-mode entry: {e}"),
|
||||
}
|
||||
}
|
||||
self.stop_current_recording().await;
|
||||
|
||||
+46
-20
@@ -2,7 +2,7 @@ use axum::Json;
|
||||
use axum::extract::State;
|
||||
use axum::http::StatusCode;
|
||||
use chrono::Utc;
|
||||
use log::error;
|
||||
use log::{error, warn};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::sync::Arc;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
@@ -47,14 +47,22 @@ pub struct GpsRecord {
|
||||
pub lon: f64,
|
||||
}
|
||||
|
||||
/// Reads all GPS records from a sidecar NDJSON file, skipping malformed lines.
|
||||
/// Reads all GPS records from a sidecar NDJSON file, logging and skipping malformed lines.
|
||||
pub async fn load_gps_records(file: tokio::fs::File) -> Vec<GpsRecord> {
|
||||
let reader = BufReader::new(file);
|
||||
let mut lines = reader.lines();
|
||||
let mut records = Vec::new();
|
||||
while let Ok(Some(line)) = lines.next_line().await {
|
||||
if let Ok(record) = serde_json::from_str::<GpsRecord>(&line) {
|
||||
records.push(record);
|
||||
loop {
|
||||
match lines.next_line().await {
|
||||
Ok(Some(line)) => match serde_json::from_str::<GpsRecord>(&line) {
|
||||
Ok(record) => records.push(record),
|
||||
Err(e) => warn!("skipping malformed GPS sidecar line: {e}"),
|
||||
},
|
||||
Ok(None) => break,
|
||||
Err(e) => {
|
||||
error!("error reading GPS sidecar file: {e}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
records
|
||||
@@ -67,7 +75,8 @@ pub async fn post_gps(
|
||||
if state.config.gps_mode != GpsMode::Api {
|
||||
return Err((
|
||||
StatusCode::FORBIDDEN,
|
||||
"GPS API endpoint is disabled. Set gps_mode to 2 in configuration.".to_string(),
|
||||
"GPS API endpoint is disabled. Set gps_mode to API endpoint in configuration."
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
let mut gps = state.gps_state.write().await;
|
||||
@@ -75,21 +84,38 @@ pub async fn post_gps(
|
||||
drop(gps);
|
||||
|
||||
let qmdl_store = state.qmdl_store_lock.read().await;
|
||||
if let Some((entry_idx, _)) = qmdl_store.get_current_entry()
|
||||
&& let Ok(mut file) = qmdl_store.open_entry_gps_for_append(entry_idx).await
|
||||
{
|
||||
let record = GpsRecord {
|
||||
unix_ts: Utc::now().timestamp(),
|
||||
lat: gps_data.latitude,
|
||||
lon: gps_data.longitude,
|
||||
};
|
||||
match serde_json::to_string(&record) {
|
||||
Ok(json) => {
|
||||
if let Err(e) = file.write_all(format!("{json}\n").as_bytes()).await {
|
||||
error!("failed to write GPS record to sidecar: {e}");
|
||||
}
|
||||
if let Some((entry_idx, _)) = qmdl_store.get_current_entry() {
|
||||
match qmdl_store.open_entry_gps_for_append(entry_idx).await {
|
||||
Ok(Some(mut file)) => {
|
||||
let record = GpsRecord {
|
||||
unix_ts: Utc::now().timestamp(),
|
||||
lat: gps_data.latitude,
|
||||
lon: gps_data.longitude,
|
||||
};
|
||||
let json = serde_json::to_string(&record).map_err(|e| {
|
||||
error!("failed to serialize GPS record: {e}");
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("failed to serialize GPS record: {e}"),
|
||||
)
|
||||
})?;
|
||||
file.write_all(format!("{json}\n").as_bytes())
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("failed to write GPS record to sidecar: {e}");
|
||||
(
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("failed to write GPS record to sidecar: {e}"),
|
||||
)
|
||||
})?;
|
||||
}
|
||||
Ok(None) => error!("GPS sidecar directory not found, cannot write GPS record"),
|
||||
Err(e) => {
|
||||
return Err((
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
format!("failed to open GPS sidecar: {e}"),
|
||||
));
|
||||
}
|
||||
Err(e) => error!("failed to serialize GPS record: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -306,6 +306,8 @@ async fn run_with_config(
|
||||
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 {
|
||||
match (config.gps_fixed_latitude, config.gps_fixed_longitude) {
|
||||
(Some(lat), Some(lon)) => Some(gps::GpsData {
|
||||
|
||||
+19
-33
@@ -1,7 +1,7 @@
|
||||
use crate::config::GpsMode;
|
||||
use crate::gps::{GpsRecord, load_gps_records};
|
||||
use crate::server::ServerState;
|
||||
|
||||
use crate::config::GpsMode;
|
||||
use anyhow::Error;
|
||||
use axum::body::Body;
|
||||
use axum::extract::{Path, State};
|
||||
@@ -74,41 +74,27 @@ pub(crate) async fn load_gps_records_for_entry(
|
||||
state: &Arc<ServerState>,
|
||||
entry_index: usize,
|
||||
) -> Vec<GpsRecord> {
|
||||
// Always try the per-session sidecar first — it reflects what was actually
|
||||
// recorded regardless of what the current gps_mode config is.
|
||||
let entry_gps_mode;
|
||||
{
|
||||
let qmdl_store = state.qmdl_store_lock.read().await;
|
||||
if let Ok(file) = qmdl_store.open_entry_gps(entry_index).await {
|
||||
let records = load_gps_records(file).await;
|
||||
if !records.is_empty() {
|
||||
return records;
|
||||
let qmdl_store = state.qmdl_store_lock.read().await;
|
||||
match qmdl_store.open_entry_gps(entry_index).await {
|
||||
Ok(Some(file)) => load_gps_records(file).await,
|
||||
Ok(None) => {
|
||||
let gps_mode = qmdl_store
|
||||
.manifest
|
||||
.entries
|
||||
.get(entry_index)
|
||||
.and_then(|e| e.gps_mode);
|
||||
if gps_mode.is_some_and(|m| m != GpsMode::Disabled) {
|
||||
error!(
|
||||
"GPS sidecar expected for entry {entry_index} (mode: {gps_mode:?}) but not found"
|
||||
);
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
Err(e) => {
|
||||
error!("failed to open GPS sidecar: {e}");
|
||||
vec![]
|
||||
}
|
||||
// Capture the entry's recorded GPS mode before releasing the lock.
|
||||
entry_gps_mode = qmdl_store
|
||||
.manifest
|
||||
.entries
|
||||
.get(entry_index)
|
||||
.and_then(|e| e.gps_mode);
|
||||
}
|
||||
// Sidecar missing or empty — fall back using the entry's own recorded GPS mode,
|
||||
// not the current config, so old fixed-mode sessions still get coordinates even
|
||||
// if the mode has since been changed. Use the configured fixed coords directly
|
||||
// rather than gps_state, which can be overwritten by API calls or be None.
|
||||
if entry_gps_mode == Some(GpsMode::Fixed)
|
||||
&& let (Some(lat), Some(lon)) = (
|
||||
state.config.gps_fixed_latitude,
|
||||
state.config.gps_fixed_longitude,
|
||||
)
|
||||
{
|
||||
return vec![GpsRecord {
|
||||
unix_ts: 0,
|
||||
lat,
|
||||
lon,
|
||||
}];
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn find_nearest_gps(records: &[GpsRecord], packet_unix_ts: i64) -> Option<GpsPoint> {
|
||||
|
||||
@@ -304,24 +304,33 @@ impl RecordingStore {
|
||||
.map_err(RecordingStoreError::ReadFileError)
|
||||
}
|
||||
|
||||
pub async fn open_entry_gps(&self, entry_index: usize) -> Result<File, RecordingStoreError> {
|
||||
pub async fn open_entry_gps(
|
||||
&self,
|
||||
entry_index: usize,
|
||||
) -> Result<Option<File>, RecordingStoreError> {
|
||||
let entry = &self.manifest.entries[entry_index];
|
||||
File::open(entry.get_gps_filepath(&self.path))
|
||||
.await
|
||||
.map_err(RecordingStoreError::ReadFileError)
|
||||
match File::open(entry.get_gps_filepath(&self.path)).await {
|
||||
Ok(file) => Ok(Some(file)),
|
||||
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
|
||||
Err(e) => Err(RecordingStoreError::ReadFileError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn open_entry_gps_for_append(
|
||||
&self,
|
||||
entry_index: usize,
|
||||
) -> Result<File, RecordingStoreError> {
|
||||
) -> Result<Option<File>, RecordingStoreError> {
|
||||
let entry = &self.manifest.entries[entry_index];
|
||||
OpenOptions::new()
|
||||
match OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(entry.get_gps_filepath(&self.path))
|
||||
.await
|
||||
.map_err(RecordingStoreError::CreateFileError)
|
||||
{
|
||||
Ok(file) => Ok(Some(file)),
|
||||
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),
|
||||
Err(e) => Err(RecordingStoreError::CreateFileError(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn clear_and_open_entry_analysis(
|
||||
|
||||
Reference in New Issue
Block a user