mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-05-30 08:29:27 -07:00
replacing numbered options in config with rust enum implementation, unique commit to make easier to debug or rollback
This commit is contained in:
committed by
Will Greenberg
parent
0b91a6e5d3
commit
fee082cde4
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -4881,6 +4881,7 @@ dependencies = [
|
||||
"rustls-rustcrypto",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_repr",
|
||||
"tempfile",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
|
||||
@@ -24,6 +24,7 @@ rayhunter = { path = "../lib" }
|
||||
wifi-station = "0.10.1"
|
||||
toml = "0.8.8"
|
||||
serde = { version = "1.0.193", features = ["derive"] }
|
||||
serde_repr = "0.1"
|
||||
tokio = { version = "1.44.2", default-features = false, features = ["fs", "signal", "process", "rt"] }
|
||||
axum = { version = "0.8", default-features = false, features = ["http1", "tokio", "json"] }
|
||||
thiserror = "1.0.52"
|
||||
|
||||
@@ -1,10 +1,40 @@
|
||||
use log::warn;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_repr::{Deserialize_repr, Serialize_repr};
|
||||
|
||||
use rayhunter::Device;
|
||||
use rayhunter::analysis::analyzer::AnalyzerConfig;
|
||||
|
||||
use crate::error::RayhunterError;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
|
||||
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
|
||||
pub enum GpsMode {
|
||||
Disabled = 0,
|
||||
Fixed = 1,
|
||||
Api = 2,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
|
||||
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
|
||||
pub enum UiLevel {
|
||||
Invisible = 0,
|
||||
Subtle = 1,
|
||||
Demo = 2,
|
||||
EffLogo = 3,
|
||||
HighVisibility = 4,
|
||||
TransFlag = 128,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize_repr, Deserialize_repr)]
|
||||
#[cfg_attr(feature = "apidocs", derive(utoipa::ToSchema))]
|
||||
pub enum KeyInputMode {
|
||||
Disabled = 0,
|
||||
DoubleTapPower = 1,
|
||||
}
|
||||
use crate::notifications::NotificationType;
|
||||
|
||||
/// The structure of a valid rayhunter configuration
|
||||
@@ -21,11 +51,11 @@ pub struct Config {
|
||||
/// Internal device name
|
||||
pub device: Device,
|
||||
/// UI level
|
||||
pub ui_level: u8,
|
||||
pub ui_level: UiLevel,
|
||||
/// Colorblind mode
|
||||
pub colorblind_mode: bool,
|
||||
/// Key input mode
|
||||
pub key_input_mode: u8,
|
||||
pub key_input_mode: KeyInputMode,
|
||||
/// ntfy.sh URL
|
||||
pub ntfy_url: Option<String>,
|
||||
/// Vector containing the types of enabled notifications
|
||||
@@ -36,8 +66,8 @@ pub struct Config {
|
||||
pub min_space_to_start_recording_mb: u64,
|
||||
/// Minimum disk space required to continue a recording
|
||||
pub min_space_to_continue_recording_mb: u64,
|
||||
/// GPS mode: 0=Disabled, 1=Fixed coordinates, 2=API endpoint
|
||||
pub gps_mode: u8,
|
||||
/// GPS mode
|
||||
pub gps_mode: GpsMode,
|
||||
/// Fixed latitude used when gps_mode=1
|
||||
pub gps_fixed_latitude: Option<f64>,
|
||||
/// Fixed longitude used when gps_mode=1
|
||||
@@ -98,15 +128,15 @@ impl Default for Config {
|
||||
port: 8080,
|
||||
debug_mode: false,
|
||||
device: Device::Orbic,
|
||||
ui_level: 1,
|
||||
ui_level: UiLevel::Subtle,
|
||||
colorblind_mode: false,
|
||||
key_input_mode: 0,
|
||||
key_input_mode: KeyInputMode::Disabled,
|
||||
analyzers: AnalyzerConfig::default(),
|
||||
ntfy_url: None,
|
||||
enabled_notifications: vec![NotificationType::Warning, NotificationType::LowBattery],
|
||||
min_space_to_start_recording_mb: 1,
|
||||
min_space_to_continue_recording_mb: 1,
|
||||
gps_mode: 0,
|
||||
gps_mode: GpsMode::Disabled,
|
||||
gps_fixed_latitude: None,
|
||||
gps_fixed_longitude: None,
|
||||
wifi_ssid: None,
|
||||
|
||||
@@ -28,6 +28,7 @@ use rayhunter::diag_device::DiagDevice;
|
||||
use rayhunter::qmdl::QmdlWriter;
|
||||
|
||||
use crate::analysis::{AnalysisCtrlMessage, AnalysisWriter};
|
||||
use crate::config::GpsMode;
|
||||
use crate::display;
|
||||
use crate::notifications::{Notification, NotificationType};
|
||||
use crate::qmdl_store::{RecordingStore, RecordingStoreError};
|
||||
@@ -58,7 +59,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,
|
||||
gps_mode: GpsMode,
|
||||
gps_fixed_coords: Option<(f64, f64)>,
|
||||
state: DiagState,
|
||||
max_type_seen: EventType,
|
||||
@@ -108,7 +109,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,
|
||||
gps_mode: GpsMode,
|
||||
gps_fixed_coords: Option<(f64, f64)>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -163,7 +164,7 @@ impl DiagTask {
|
||||
// For fixed-mode sessions, write the configured coordinates to the sidecar
|
||||
// immediately so the per-session GPS is stored durably and isn't affected
|
||||
// by future config changes or GPS API calls.
|
||||
if self.gps_mode == 1 {
|
||||
if self.gps_mode == GpsMode::Fixed {
|
||||
if let Some((lat, lon)) = self.gps_fixed_coords {
|
||||
if let Some((entry_idx, _)) = qmdl_store.get_current_entry() {
|
||||
if let Ok(mut gps_file) = qmdl_store.open_entry_gps_for_append(entry_idx).await
|
||||
@@ -409,7 +410,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,
|
||||
gps_mode: GpsMode,
|
||||
gps_fixed_coords: Option<(f64, f64)>,
|
||||
) {
|
||||
task_tracker.spawn(async move {
|
||||
|
||||
@@ -3,7 +3,7 @@ use image::{AnimationDecoder, DynamicImage, codecs::gif::GifDecoder, imageops::F
|
||||
use std::io::Cursor;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::config;
|
||||
use crate::config::{self, UiLevel};
|
||||
use crate::display::DisplayState;
|
||||
use rayhunter::analysis::analyzer::EventType;
|
||||
|
||||
@@ -176,7 +176,7 @@ pub fn update_ui(
|
||||
) {
|
||||
static IMAGE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/images/");
|
||||
let display_level = config.ui_level;
|
||||
if display_level == 0 {
|
||||
if display_level == UiLevel::Invisible {
|
||||
info!("Invisible mode, not spawning UI.");
|
||||
return;
|
||||
}
|
||||
@@ -187,14 +187,14 @@ pub fn update_ui(
|
||||
task_tracker.spawn(async move {
|
||||
// this feels wrong, is there a more rusty way to do this?
|
||||
let mut img: Option<&[u8]> = None;
|
||||
if display_level == 2 {
|
||||
if display_level == UiLevel::Demo {
|
||||
img = Some(
|
||||
IMAGE_DIR
|
||||
.get_file("orca.gif")
|
||||
.expect("failed to read orca.gif")
|
||||
.contents(),
|
||||
);
|
||||
} else if display_level == 3 {
|
||||
} else if display_level == UiLevel::EffLogo {
|
||||
img = Some(
|
||||
IMAGE_DIR
|
||||
.get_file("eff.png")
|
||||
@@ -217,20 +217,19 @@ pub fn update_ui(
|
||||
|
||||
let mut status_bar_height = 2;
|
||||
match display_level {
|
||||
2 => fb.draw_gif(img.unwrap()).await,
|
||||
3 => fb.draw_img(img.unwrap()).await,
|
||||
4 => {
|
||||
UiLevel::Demo => fb.draw_gif(img.unwrap()).await,
|
||||
UiLevel::EffLogo => fb.draw_img(img.unwrap()).await,
|
||||
UiLevel::HighVisibility => {
|
||||
status_bar_height = fb.dimensions().height;
|
||||
}
|
||||
128 => {
|
||||
UiLevel::TransFlag => {
|
||||
fb.draw_line(Color::Cyan, 128).await;
|
||||
fb.draw_line(Color::Pink, 102).await;
|
||||
fb.draw_line(Color::White, 76).await;
|
||||
fb.draw_line(Color::Pink, 50).await;
|
||||
fb.draw_line(Color::Cyan, 25).await;
|
||||
}
|
||||
// this branch is for ui_level 1, which is also the default if an
|
||||
// unknown value is used
|
||||
// UiLevel::Subtle (1) and anything else: just the status bar line
|
||||
_ => {}
|
||||
};
|
||||
let (color, pattern) = display_style;
|
||||
|
||||
@@ -9,7 +9,7 @@ use tokio_util::task::TaskTracker;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::config;
|
||||
use crate::config::{self, UiLevel};
|
||||
use crate::display::DisplayState;
|
||||
|
||||
macro_rules! led {
|
||||
@@ -31,7 +31,7 @@ pub fn update_ui(
|
||||
mut ui_update_rx: mpsc::Receiver<DisplayState>,
|
||||
) {
|
||||
let mut invisible: bool = false;
|
||||
if config.ui_level == 0 {
|
||||
if config.ui_level == UiLevel::Invisible {
|
||||
info!("Invisible mode, not spawning UI.");
|
||||
invisible = true;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use tokio::sync::mpsc::Receiver;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tokio_util::task::TaskTracker;
|
||||
|
||||
use crate::config;
|
||||
use crate::config::{self, UiLevel};
|
||||
use crate::display::{DisplayState, tplink_framebuffer, tplink_onebit};
|
||||
|
||||
use std::fs;
|
||||
@@ -15,7 +15,7 @@ pub fn update_ui(
|
||||
ui_update_rx: Receiver<DisplayState>,
|
||||
) {
|
||||
let display_level = config.ui_level;
|
||||
if display_level == 0 {
|
||||
if display_level == UiLevel::Invisible {
|
||||
info!("Invisible mode, not spawning UI.");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// Display module for the TP-Link M7350 oled one-bit display.
|
||||
///
|
||||
/// https://github.com/m0veax/tplink_m7350/tree/main/oled
|
||||
use crate::config;
|
||||
use crate::config::{self, UiLevel};
|
||||
use crate::display::DisplayState;
|
||||
|
||||
use log::{error, info};
|
||||
@@ -115,7 +115,7 @@ pub fn update_ui(
|
||||
mut ui_update_rx: Receiver<DisplayState>,
|
||||
) {
|
||||
let display_level = config.ui_level;
|
||||
if display_level == 0 {
|
||||
if display_level == UiLevel::Invisible {
|
||||
info!("Invisible mode, not spawning UI.");
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ pub fn update_ui(
|
||||
|
||||
// we write the status every second because it may have been overwritten through menu
|
||||
// navigation.
|
||||
if display_level != 0
|
||||
if display_level != UiLevel::Invisible
|
||||
&& let Err(e) = tokio::fs::write(OLED_PATH, pixels).await
|
||||
{
|
||||
error!("failed to write to display: {e}");
|
||||
|
||||
@@ -9,7 +9,7 @@ use tokio_util::task::TaskTracker;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::config;
|
||||
use crate::config::{self, UiLevel};
|
||||
use crate::display::DisplayState;
|
||||
|
||||
macro_rules! led {
|
||||
@@ -31,7 +31,7 @@ pub fn update_ui(
|
||||
mut ui_update_rx: mpsc::Receiver<DisplayState>,
|
||||
) {
|
||||
let mut invisible: bool = false;
|
||||
if config.ui_level == 0 {
|
||||
if config.ui_level == UiLevel::Invisible {
|
||||
info!("Invisible mode, not spawning UI.");
|
||||
invisible = true;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use serde::{Deserialize, Deserializer, Serialize};
|
||||
use std::sync::Arc;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
|
||||
use crate::config::GpsMode;
|
||||
use crate::server::ServerState;
|
||||
|
||||
fn deserialize_unix_ts<'de, D>(deserializer: D) -> Result<i64, D::Error>
|
||||
@@ -79,7 +80,7 @@ pub async fn post_gps(
|
||||
State(state): State<Arc<ServerState>>,
|
||||
Json(gps_data): Json<GpsData>,
|
||||
) -> Result<StatusCode, (StatusCode, String)> {
|
||||
if state.config.gps_mode != 2 {
|
||||
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(),
|
||||
|
||||
@@ -6,7 +6,7 @@ use tokio::sync::mpsc::Sender;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use tokio_util::task::TaskTracker;
|
||||
|
||||
use crate::config;
|
||||
use crate::config::{self, KeyInputMode};
|
||||
use crate::diag::DiagDeviceCtrlMessage;
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -23,7 +23,7 @@ pub fn run_key_input_thread(
|
||||
diag_tx: Sender<DiagDeviceCtrlMessage>,
|
||||
cancellation_token: CancellationToken,
|
||||
) {
|
||||
if config.key_input_mode == 0 {
|
||||
if config.key_input_mode == KeyInputMode::Disabled {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::battery::run_battery_notification_worker;
|
||||
use crate::config::{parse_args, parse_config};
|
||||
use crate::config::{GpsMode, parse_args, parse_config};
|
||||
use crate::diag::run_diag_read_thread;
|
||||
use crate::error::RayhunterError;
|
||||
use crate::gps::{get_gps, post_gps};
|
||||
@@ -306,7 +306,7 @@ async fn run_with_config(
|
||||
config.webdav.clone().into(),
|
||||
);
|
||||
}
|
||||
let initial_gps = if config.gps_mode == 1 {
|
||||
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 {
|
||||
latitude: lat,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use crate::config::GpsMode;
|
||||
use crate::gps::{GpsRecord, load_gps_records};
|
||||
use crate::server::ServerState;
|
||||
|
||||
@@ -95,7 +96,7 @@ pub(crate) async fn load_gps_records_for_entry(
|
||||
// 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(1) {
|
||||
if entry_gps_mode == Some(GpsMode::Fixed) {
|
||||
if let (Some(lat), Some(lon)) = (
|
||||
state.config.gps_fixed_latitude,
|
||||
state.config.gps_fixed_longitude,
|
||||
|
||||
@@ -2,6 +2,7 @@ use std::io::{self, ErrorKind};
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::config::GpsMode;
|
||||
use chrono::{DateTime, Local, TimeDelta};
|
||||
use log::{info, warn};
|
||||
use rayhunter::util::RuntimeMetadata;
|
||||
@@ -71,11 +72,11 @@ pub struct ManifestEntry {
|
||||
#[cfg_attr(feature = "apidocs", schema(value_type = String))]
|
||||
pub upload_time: Option<DateTime<Local>>,
|
||||
#[serde(default)]
|
||||
pub gps_mode: Option<u8>,
|
||||
pub gps_mode: Option<GpsMode>,
|
||||
}
|
||||
|
||||
impl ManifestEntry {
|
||||
fn new(gps_mode: u8) -> Self {
|
||||
fn new(gps_mode: GpsMode) -> Self {
|
||||
let now = rayhunter::clock::get_adjusted_now();
|
||||
let metadata = RuntimeMetadata::new();
|
||||
ManifestEntry {
|
||||
@@ -257,7 +258,10 @@ 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, gps_mode: u8) -> Result<(File, File), RecordingStoreError> {
|
||||
pub async fn new_entry(
|
||||
&mut self,
|
||||
gps_mode: GpsMode,
|
||||
) -> 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?;
|
||||
|
||||
@@ -169,11 +169,11 @@
|
||||
bind:value={config.ui_level}
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-hidden focus:ring-2 focus:ring-rayhunter-blue"
|
||||
>
|
||||
<option value={0}>0 - Invisible mode</option>
|
||||
<option value={1}>1 - Subtle mode (colored line)</option>
|
||||
<option value={2}>2 - Demo mode (orca gif)</option>
|
||||
<option value={3}>3 - EFF logo</option>
|
||||
<option value={4}>4 - High visibility (full screen color)</option>
|
||||
<option value={0}>Invisible mode</option>
|
||||
<option value={1}>Subtle mode (colored line)</option>
|
||||
<option value={2}>Demo mode (orca gif)</option>
|
||||
<option value={3}>EFF logo</option>
|
||||
<option value={4}>High visibility (full screen color)</option>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
Note: Rayhunter draws over the device's native UI, so some flickering is
|
||||
@@ -193,9 +193,8 @@
|
||||
bind:value={config.key_input_mode}
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-hidden focus:ring-2 focus:ring-rayhunter-blue"
|
||||
>
|
||||
<option value={0}>0 - Disable button control</option>
|
||||
<option value={1}>1 - Double-tap power button to start new recording</option
|
||||
>
|
||||
<option value={0}>Disable button control</option>
|
||||
<option value={1}>Double-tap power button to start new recording</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -786,9 +785,9 @@
|
||||
<div>
|
||||
<label for="gps_mode" class="block text-sm font-medium text-gray-700 mb-1">GPS Mode</label>
|
||||
<select id="gps_mode" bind:value={config.gps_mode} class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-rayhunter-blue">
|
||||
<option value={0}>0 - Disabled</option>
|
||||
<option value={1}>1 - Fixed coordinates</option>
|
||||
<option value={2}>2 - API Endpoint</option>
|
||||
<option value={0}>Disabled</option>
|
||||
<option value={1}>Fixed coordinates</option>
|
||||
<option value={2}>API endpoint</option>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">
|
||||
{#if config.gps_mode === 2}
|
||||
|
||||
Reference in New Issue
Block a user