mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-06-12 15:53:30 -07:00
added documentation and polishing UI around GPS mode
This commit is contained in:
committed by
Will Greenberg
parent
66f0c2a336
commit
5451e23293
@@ -162,49 +162,6 @@ fn resolve_bin(name: &str) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn wifi_config(&self) -> wifi_station::WifiConfig {
|
||||
let (wpa_bin, hostapd_conf, ctrl_interface) = match self.device {
|
||||
Device::Tmobile | Device::Wingtech => (
|
||||
Some("/usr/sbin/wpa_supplicant".into()),
|
||||
Some("/data/configs/hostapd.conf".into()),
|
||||
None,
|
||||
),
|
||||
Device::Uz801 => (
|
||||
Some("/system/bin/wpa_supplicant".into()),
|
||||
Some("/data/misc/wifi/hostapd.conf".into()),
|
||||
Some("/data/misc/wifi/sockets".into()),
|
||||
),
|
||||
_ => (None, None, None),
|
||||
};
|
||||
wifi_station::WifiConfig {
|
||||
wifi_enabled: self.wifi_enabled,
|
||||
dns_servers: self.dns_servers.clone(),
|
||||
wifi_ssid: self.wifi_ssid.clone(),
|
||||
wifi_password: self.wifi_password.clone(),
|
||||
security_type: self.wifi_security,
|
||||
wpa_supplicant_bin: wpa_bin.or_else(|| resolve_bin("wpa_supplicant")),
|
||||
hostapd_conf,
|
||||
ctrl_interface,
|
||||
udhcpc_hook_path: Some("/data/rayhunter/udhcpc-hook.sh".into()),
|
||||
dhcp_lease_path: Some("/data/rayhunter/dhcp_lease".into()),
|
||||
wpa_conf_path: Some("/data/rayhunter/wpa_sta.conf".into()),
|
||||
iw_bin: resolve_bin("iw"),
|
||||
udhcpc_bin: resolve_bin("udhcpc"),
|
||||
crash_log_dir: Some("/data/rayhunter/crash-logs".into()),
|
||||
wakelock_name: Some("rayhunter".into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_bin(name: &str) -> Option<String> {
|
||||
let local = format!("/data/rayhunter/bin/{name}");
|
||||
if std::path::Path::new(&local).exists() {
|
||||
return Some(local);
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub async fn parse_config<P>(path: P) -> Result<Config, RayhunterError>
|
||||
where
|
||||
P: AsRef<std::path::Path>,
|
||||
|
||||
+7
-2
@@ -56,6 +56,7 @@ pub struct DiagTask {
|
||||
notification_channel: tokio::sync::mpsc::Sender<Notification>,
|
||||
min_space_to_start_mb: u64,
|
||||
min_space_to_continue_mb: u64,
|
||||
gps_mode: u8,
|
||||
state: DiagState,
|
||||
max_type_seen: EventType,
|
||||
bytes_since_space_check: usize,
|
||||
@@ -104,6 +105,7 @@ impl DiagTask {
|
||||
notification_channel: tokio::sync::mpsc::Sender<Notification>,
|
||||
min_space_to_start_mb: u64,
|
||||
min_space_to_continue_mb: u64,
|
||||
gps_mode: u8,
|
||||
) -> Self {
|
||||
Self {
|
||||
ui_update_sender,
|
||||
@@ -112,6 +114,7 @@ impl DiagTask {
|
||||
notification_channel,
|
||||
min_space_to_start_mb,
|
||||
min_space_to_continue_mb,
|
||||
gps_mode,
|
||||
state: DiagState::Stopped,
|
||||
max_type_seen: EventType::Informational,
|
||||
bytes_since_space_check: 0,
|
||||
@@ -144,7 +147,7 @@ impl DiagTask {
|
||||
DiskSpaceCheck::Failed => {}
|
||||
}
|
||||
|
||||
let (qmdl_file, analysis_file) = match qmdl_store.new_entry().await {
|
||||
let (qmdl_file, analysis_file) = match qmdl_store.new_entry(self.gps_mode).await {
|
||||
Ok(files) => files,
|
||||
Err(e) => {
|
||||
let msg = format!("failed creating QMDL file entry: {e}");
|
||||
@@ -381,6 +384,7 @@ pub fn run_diag_read_thread(
|
||||
notification_channel: tokio::sync::mpsc::Sender<Notification>,
|
||||
min_space_to_start_mb: u64,
|
||||
min_space_to_continue_mb: u64,
|
||||
gps_mode: u8,
|
||||
) {
|
||||
task_tracker.spawn(async move {
|
||||
info!("Using configuration for device: {0:?}", device);
|
||||
@@ -396,7 +400,8 @@ pub fn run_diag_read_thread(
|
||||
analyzer_config,
|
||||
notification_channel,
|
||||
min_space_to_start_mb,
|
||||
min_space_to_continue_mb
|
||||
min_space_to_continue_mb,
|
||||
gps_mode,
|
||||
);
|
||||
qmdl_file_tx
|
||||
.send(DiagDeviceCtrlMessage::StartRecording { response_tx: None })
|
||||
|
||||
+22
-2
@@ -1,17 +1,37 @@
|
||||
use axum::Json;
|
||||
use axum::extract::State;
|
||||
use axum::http::StatusCode;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::sync::Arc;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
|
||||
use crate::server::ServerState;
|
||||
|
||||
/// Accepts both a JSON number and a numeric string (e.g. `"1234567890"` or `1234567890`).
|
||||
/// Truncates floats to seconds. Returns an error for non-numeric values.
|
||||
fn deserialize_unix_ts<'de, D>(deserializer: D) -> Result<i64, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
use serde::de;
|
||||
use serde_json::Value;
|
||||
match Value::deserialize(deserializer)? {
|
||||
Value::Number(n) => n.as_i64()
|
||||
.or_else(|| n.as_f64().map(|f| f as i64))
|
||||
.ok_or_else(|| de::Error::custom("timestamp out of range")),
|
||||
Value::String(s) => s.trim().parse::<f64>()
|
||||
.map(|f| f as i64)
|
||||
.map_err(|_| de::Error::custom("timestamp must be a numeric value")),
|
||||
_ => Err(de::Error::custom("timestamp must be a number or numeric string")),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct GpsData {
|
||||
pub latitude: f64,
|
||||
pub longitude: f64,
|
||||
pub timestamp: String,
|
||||
#[serde(deserialize_with = "deserialize_unix_ts")]
|
||||
pub timestamp: i64,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
||||
+2
-1
@@ -232,6 +232,7 @@ async fn run_with_config(
|
||||
notification_service.new_handler(),
|
||||
config.min_space_to_start_recording_mb,
|
||||
config.min_space_to_continue_recording_mb,
|
||||
config.gps_mode,
|
||||
);
|
||||
info!("Starting UI");
|
||||
|
||||
@@ -305,7 +306,7 @@ async fn run_with_config(
|
||||
(Some(lat), Some(lon)) => Some(gps::GpsData {
|
||||
latitude: lat,
|
||||
longitude: lon,
|
||||
timestamp: "fixed".to_string(),
|
||||
timestamp: 0,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
|
||||
@@ -70,10 +70,12 @@ pub struct ManifestEntry {
|
||||
/// When the manifest was uploaded to a WebDAV server
|
||||
#[cfg_attr(feature = "apidocs", schema(value_type = String))]
|
||||
pub upload_time: Option<DateTime<Local>>,
|
||||
#[serde(default)]
|
||||
pub gps_mode: Option<u8>,
|
||||
}
|
||||
|
||||
impl ManifestEntry {
|
||||
fn new() -> Self {
|
||||
fn new(gps_mode: u8) -> Self {
|
||||
let now = rayhunter::clock::get_adjusted_now();
|
||||
let metadata = RuntimeMetadata::new();
|
||||
ManifestEntry {
|
||||
@@ -86,6 +88,7 @@ impl ManifestEntry {
|
||||
arch: Some(metadata.arch),
|
||||
stop_reason: None,
|
||||
upload_time: None,
|
||||
gps_mode: Some(gps_mode),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +226,7 @@ impl RecordingStore {
|
||||
arch: None,
|
||||
stop_reason: None,
|
||||
upload_time: None,
|
||||
gps_mode: None,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -255,12 +259,12 @@ impl RecordingStore {
|
||||
// Closes the current entry (if needed), creates a new entry based on the
|
||||
// current time, and updates the manifest. Returns a tuple of the entry's
|
||||
// newly created QMDL file and analysis file.
|
||||
pub async fn new_entry(&mut self) -> Result<(File, File), RecordingStoreError> {
|
||||
pub async fn new_entry(&mut self, gps_mode: u8) -> Result<(File, File), RecordingStoreError> {
|
||||
// if we've already got an entry open, close it
|
||||
if self.current_entry.is_some() {
|
||||
self.close_current_entry().await?;
|
||||
}
|
||||
let new_entry = ManifestEntry::new();
|
||||
let new_entry = ManifestEntry::new(gps_mode);
|
||||
let qmdl_filepath = new_entry.get_qmdl_filepath(&self.path);
|
||||
let qmdl_file = File::create(&qmdl_filepath)
|
||||
.await
|
||||
@@ -545,7 +549,7 @@ mod tests {
|
||||
async fn test_creating_updating_and_closing_entries() {
|
||||
let dir = make_temp_dir();
|
||||
let mut store = RecordingStore::create(dir.path()).await.unwrap();
|
||||
let _ = store.new_entry().await.unwrap();
|
||||
let _ = store.new_entry(0).await.unwrap();
|
||||
let entry_index = store.current_entry.unwrap();
|
||||
assert_eq!(
|
||||
RecordingStore::read_manifest(dir.path()).await.unwrap(),
|
||||
@@ -582,7 +586,7 @@ mod tests {
|
||||
async fn test_create_on_existing_store() {
|
||||
let dir = make_temp_dir();
|
||||
let mut store = RecordingStore::create(dir.path()).await.unwrap();
|
||||
let _ = store.new_entry().await.unwrap();
|
||||
let _ = store.new_entry(0).await.unwrap();
|
||||
let entry_index = store.current_entry.unwrap();
|
||||
store
|
||||
.update_entry_qmdl_size(entry_index, 1000)
|
||||
@@ -596,9 +600,9 @@ mod tests {
|
||||
async fn test_repeated_new_entries() {
|
||||
let dir = make_temp_dir();
|
||||
let mut store = RecordingStore::create(dir.path()).await.unwrap();
|
||||
let _ = store.new_entry().await.unwrap();
|
||||
let _ = store.new_entry(0).await.unwrap();
|
||||
let entry_index = store.current_entry.unwrap();
|
||||
let _ = store.new_entry().await.unwrap();
|
||||
let _ = store.new_entry(0).await.unwrap();
|
||||
let new_entry_index = store.current_entry.unwrap();
|
||||
assert_ne!(entry_index, new_entry_index);
|
||||
assert_eq!(store.manifest.entries.len(), 2);
|
||||
@@ -608,7 +612,7 @@ mod tests {
|
||||
async fn test_delete_all_entries() {
|
||||
let dir = make_temp_dir();
|
||||
let mut store = RecordingStore::create(dir.path()).await.unwrap();
|
||||
let _ = store.new_entry().await.unwrap();
|
||||
let _ = store.new_entry(0).await.unwrap();
|
||||
assert!(store.current_entry.is_some());
|
||||
|
||||
store.delete_all_entries().await.unwrap();
|
||||
|
||||
@@ -523,7 +523,7 @@ mod tests {
|
||||
) -> String {
|
||||
let entry_name = {
|
||||
let mut store = store_lock.write().await;
|
||||
let (mut qmdl_file, _analysis_file) = store.new_entry().await.unwrap();
|
||||
let (mut qmdl_file, _analysis_file) = store.new_entry(0).await.unwrap();
|
||||
|
||||
if !test_data.is_empty() {
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
Reference in New Issue
Block a user