mirror of
https://github.com/EFForg/rayhunter.git
synced 2026-07-13 19:58:11 -07:00
Update ConfigForm.svelte
Signed-off-by: Simon Fondrie-Teitler <simonft@riseup.net>
This commit is contained in:
committed by
Cooper Quintin
parent
1cf6f5d339
commit
1b5575e5a6
@@ -1,14 +1,22 @@
|
||||
use std::path::Path;
|
||||
use std::{path::Path, time::Duration};
|
||||
|
||||
use log::{error, info};
|
||||
use rayhunter::Device;
|
||||
use serde::Serialize;
|
||||
use tokio::select;
|
||||
use tokio_util::{sync::CancellationToken, task::TaskTracker};
|
||||
|
||||
use crate::error::RayhunterError;
|
||||
use crate::{
|
||||
error::RayhunterError,
|
||||
notifications::{Notification, NotificationType},
|
||||
};
|
||||
|
||||
pub mod orbic;
|
||||
pub mod tmobile;
|
||||
pub mod wingtech;
|
||||
|
||||
const LOW_BATTERY_LEVEL: u8 = 10;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Debug, Serialize)]
|
||||
pub struct BatteryState {
|
||||
level: u8,
|
||||
@@ -45,3 +53,59 @@ pub async fn get_battery_status(device: &Device) -> Result<BatteryState, Rayhunt
|
||||
_ => return Err(RayhunterError::FunctionNotSupportedForDeviceError),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run_battery_notification_worker(
|
||||
task_tracker: &TaskTracker,
|
||||
device: Device,
|
||||
notification_channel: tokio::sync::mpsc::Sender<Notification>,
|
||||
shutdown_token: CancellationToken,
|
||||
) {
|
||||
task_tracker.spawn(async move {
|
||||
// Don't send a notification initially if the device starts at a low battery level.
|
||||
let mut triggered = match get_battery_status(&device).await {
|
||||
Err(RayhunterError::FunctionNotSupportedForDeviceError) => {
|
||||
info!("Battery level function not supported for device");
|
||||
false
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Failed to get battery status: {e}");
|
||||
true
|
||||
}
|
||||
Ok(status) => status.level < LOW_BATTERY_LEVEL,
|
||||
};
|
||||
|
||||
loop {
|
||||
select! {
|
||||
_ = shutdown_token.cancelled() => break,
|
||||
_ = tokio::time::sleep(Duration::from_secs(15)) => {}
|
||||
}
|
||||
|
||||
let status = match get_battery_status(&device).await {
|
||||
Err(e) => {
|
||||
error!("Failed to get battery status: {e}");
|
||||
continue;
|
||||
}
|
||||
Ok(status) => status,
|
||||
};
|
||||
|
||||
// To avoid flapping, if the notification has already been triggered
|
||||
// wait until the device has been plugged in and the battery level
|
||||
// is high enough to re-enable notifications.
|
||||
if triggered && status.is_plugged_in && status.level > LOW_BATTERY_LEVEL {
|
||||
triggered = false;
|
||||
continue;
|
||||
}
|
||||
if !triggered && !status.is_plugged_in && status.level <= LOW_BATTERY_LEVEL {
|
||||
notification_channel
|
||||
.send(Notification::new(
|
||||
NotificationType::LowBattery,
|
||||
"Rayhunter's battery is low".to_string(),
|
||||
None,
|
||||
))
|
||||
.await
|
||||
.expect("Failed to send to notification channel");
|
||||
triggered = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use rayhunter::Device;
|
||||
use rayhunter::analysis::analyzer::AnalyzerConfig;
|
||||
|
||||
use crate::error::RayhunterError;
|
||||
use crate::notifications::NotificationType;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
#[serde(default)]
|
||||
@@ -17,6 +18,7 @@ pub struct Config {
|
||||
pub colorblind_mode: bool,
|
||||
pub key_input_mode: u8,
|
||||
pub ntfy_url: Option<String>,
|
||||
pub enabled_notifications: Vec<NotificationType>,
|
||||
pub analyzers: AnalyzerConfig,
|
||||
}
|
||||
|
||||
@@ -32,6 +34,7 @@ impl Default for Config {
|
||||
key_input_mode: 0,
|
||||
analyzers: AnalyzerConfig::default(),
|
||||
ntfy_url: None,
|
||||
enabled_notifications: vec![NotificationType::Warning, NotificationType::LowBattery],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ use rayhunter::qmdl::QmdlWriter;
|
||||
|
||||
use crate::analysis::{AnalysisCtrlMessage, AnalysisWriter};
|
||||
use crate::display;
|
||||
use crate::notifications::Notification;
|
||||
use crate::notifications::{Notification, NotificationType};
|
||||
use crate::qmdl_store::{RecordingStore, RecordingStoreError};
|
||||
use crate::server::ServerState;
|
||||
|
||||
@@ -207,7 +207,7 @@ impl DiagTask {
|
||||
info!("a heuristic triggered on this run!");
|
||||
self.notification_channel
|
||||
.send(Notification::new(
|
||||
"heuristic-warning".to_string(),
|
||||
NotificationType::Warning,
|
||||
format!("Rayhunter has detected a {:?} severity event", max_type),
|
||||
Some(Duration::from_secs(60 * 5)),
|
||||
))
|
||||
|
||||
+15
-1
@@ -14,6 +14,7 @@ mod stats;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::battery::run_battery_notification_worker;
|
||||
use crate::config::{parse_args, parse_config};
|
||||
use crate::diag::run_diag_read_thread;
|
||||
use crate::error::RayhunterError;
|
||||
@@ -260,7 +261,20 @@ async fn run_with_config(
|
||||
qmdl_store_lock.clone(),
|
||||
analysis_tx.clone(),
|
||||
);
|
||||
run_notification_worker(&task_tracker, notification_service);
|
||||
|
||||
run_battery_notification_worker(
|
||||
&task_tracker,
|
||||
config.device.clone(),
|
||||
notification_service.new_handler(),
|
||||
shutdown_token.clone(),
|
||||
);
|
||||
|
||||
run_notification_worker(
|
||||
&task_tracker,
|
||||
notification_service,
|
||||
config.enabled_notifications.clone(),
|
||||
);
|
||||
|
||||
let state = Arc::new(ServerState {
|
||||
config_path: args.config_path.clone(),
|
||||
config,
|
||||
|
||||
@@ -5,19 +5,30 @@ use std::{
|
||||
};
|
||||
|
||||
use log::error;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tokio::sync::mpsc::{self, error::TryRecvError};
|
||||
use tokio_util::task::TaskTracker;
|
||||
|
||||
#[derive(Hash, Eq, PartialEq, Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum NotificationType {
|
||||
Warning,
|
||||
LowBattery,
|
||||
}
|
||||
|
||||
pub struct Notification {
|
||||
message_type: String,
|
||||
notification_type: NotificationType,
|
||||
message: String,
|
||||
debounce: Option<Duration>,
|
||||
}
|
||||
|
||||
impl Notification {
|
||||
pub fn new(message_type: String, message: String, debounce: Option<Duration>) -> Self {
|
||||
pub fn new(
|
||||
notification_type: NotificationType,
|
||||
message: String,
|
||||
debounce: Option<Duration>,
|
||||
) -> Self {
|
||||
Notification {
|
||||
message_type,
|
||||
notification_type,
|
||||
message,
|
||||
debounce,
|
||||
}
|
||||
@@ -52,6 +63,7 @@ impl NotificationService {
|
||||
pub fn run_notification_worker(
|
||||
task_tracker: &TaskTracker,
|
||||
mut notification_service: NotificationService,
|
||||
enabled_notifications: Vec<NotificationType>,
|
||||
) {
|
||||
task_tracker.spawn(async move {
|
||||
if let Some(url) = notification_service.url
|
||||
@@ -65,8 +77,12 @@ pub fn run_notification_worker(
|
||||
loop {
|
||||
match notification_service.rx.try_recv() {
|
||||
Ok(notification) => {
|
||||
if !enabled_notifications.contains(¬ification.notification_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let status = notification_statuses
|
||||
.entry(notification.message_type)
|
||||
.entry(notification.notification_type)
|
||||
.or_insert_with(|| NotificationStatus {
|
||||
message: "".to_string(),
|
||||
needs_sending: true,
|
||||
|
||||
@@ -111,18 +111,6 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="ntfy_url" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
ntfy URL for Sending Notifications
|
||||
</label>
|
||||
<input
|
||||
id="ntfy_url"
|
||||
type="url"
|
||||
bind:value={config.ntfy_url}
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-rayhunter-blue"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
@@ -137,6 +125,56 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-t pt-4 mt-6 space-y-3">
|
||||
<h3 class="text-lg font-semibold text-gray-800 mb-4">Notification Settings</h3>
|
||||
<div>
|
||||
<label for="ntfy_url" class="block text-sm font-medium text-gray-700 mb-1">
|
||||
ntfy URL for Sending Notifications (if unset you will not receive
|
||||
notifications)
|
||||
</label>
|
||||
<input
|
||||
id="ntfy_url"
|
||||
type="url"
|
||||
bind:value={config.ntfy_url}
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-rayhunter-blue"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<div class="block text-sm font-medium text-gray-700 mb-1">
|
||||
Enabled Notification Types
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="enable_warning_notifications"
|
||||
value="Warning"
|
||||
bind:group={config.enabled_notifications}
|
||||
/>
|
||||
<label
|
||||
for="enable_warning_notifications"
|
||||
class="ml-2 block text-sm text-gray-700"
|
||||
>
|
||||
Warnings
|
||||
</label>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="enable_lowbattery_notifications"
|
||||
value="LowBattery"
|
||||
bind:group={config.enabled_notifications}
|
||||
/>
|
||||
<label
|
||||
for="enable_lowbattery_notifications"
|
||||
class="ml-2 block text-sm text-gray-700"
|
||||
>
|
||||
Low Battery
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-t pt-4 mt-6">
|
||||
<h3 class="text-lg font-semibold text-gray-800 mb-4">
|
||||
Analyzer Heuristic Settings
|
||||
|
||||
@@ -12,11 +12,17 @@ export interface AnalyzerConfig {
|
||||
test_analyzer: boolean;
|
||||
}
|
||||
|
||||
export enum enabled_notifications {
|
||||
Warning = 'Warning',
|
||||
LowBattery = 'LowBattery',
|
||||
}
|
||||
|
||||
export interface Config {
|
||||
ui_level: number;
|
||||
colorblind_mode: boolean;
|
||||
key_input_mode: number;
|
||||
ntfy_url: string;
|
||||
enabled_notifications: enabled_notifications[];
|
||||
analyzers: AnalyzerConfig;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user