[desktop] Fix all clippy warning. Add clippy to CI.

This commit is contained in:
Vladimir Stoilov 2024-08-02 17:50:15 +03:00
parent 9472a1f8f5
commit 4c340f7b70
No known key found for this signature in database
GPG key ID: 2F190B67A43A81AF
13 changed files with 208 additions and 167 deletions

View file

@ -34,3 +34,22 @@ jobs:
- name: Build tauri project - name: Build tauri project
run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +tauri-ci run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +tauri-ci
lint:
name: Linter
runs-on: ubuntu-latest
steps:
- uses: earthly/actions-setup@v1
with:
version: v0.8.0
- uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build tauri project
run: earthly --ci --remote-cache=ghcr.io/safing/build-cache --push +tauri-lint

View file

@ -636,6 +636,42 @@ tauri-release:
BUILD +tauri-build --target="${arch}" BUILD +tauri-build --target="${arch}"
END END
tauri-lint:
FROM +tauri-src
# Clippy (rust linter) will try to build the project before it runs the linter.
# Make sure we have evrything needed to build the project.
ARG target="x86_64-unknown-linux-gnu"
# if we want tauri to create the installer bundles we also need to provide all external binaries
# we need to do some magic here because tauri expects the binaries to include the rust target tripple.
# We already know that triple because it's a required argument. From that triple, we use +RUST_TO_GO_ARCH_STRING
# function from below to parse the triple and guess wich GOOS and GOARCH we need.
RUN mkdir /tmp/gobuild
RUN mkdir ./binaries
DO +RUST_TO_GO_ARCH_STRING --rustTarget="${target}"
RUN echo "GOOS=${GOOS} GOARCH=${GOARCH} GOARM=${GOARM} GO_ARCH_STRING=${GO_ARCH_STRING}"
# Our tauri app has externalBins configured so tauri will try to embed them when it finished compiling
# the app. Make sure we copy portmaster-start and portmaster-core in all architectures supported.
# See documentation for externalBins for more information on how tauri searches for the binaries.
COPY (+go-build/output --CMDS="portmaster-start portmaster-core" --GOOS="${GOOS}" --GOARCH="${GOARCH}" --GOARM="${GOARM}") /tmp/gobuild
# Place them in the correct folder with the rust target tripple attached.
FOR bin IN $(ls /tmp/gobuild)
# ${bin$.*} does not work in SET commands unfortunately so we use a shell
# snippet here:
RUN set -e ; \
dest="./binaries/${bin}-${target}" ; \
if [ -z "${bin##*.exe}" ]; then \
dest="./binaries/${bin%.*}-${target}.exe" ; \
fi ; \
cp "/tmp/gobuild/${bin}" "${dest}" ;
END
DO rust+SET_CACHE_MOUNTS_ENV
RUN cargo clippy --all-targets --all-features -- -D warnings
kext-build: kext-build:
FROM ${rust_builder_image} FROM ${rust_builder_image}

View file

@ -7,7 +7,7 @@ license = ""
repository = "" repository = ""
default-run = "portmaster" default-run = "portmaster"
edition = "2021" edition = "2021"
rust-version = "1.60" rust-version = "1.64"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -80,3 +80,6 @@ ctor = "0.2.6"
# If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes. # If you use cargo directly instead of tauri's cli you can use this feature flag to switch between tauri's `dev` and `build` modes.
# DO NOT REMOVE!! # DO NOT REMOVE!!
custom-protocol = [ "tauri/custom-protocol" ] custom-protocol = [ "tauri/custom-protocol" ]
[package.metadata.clippy]
allow = ["clippy::collapsible_else_if"]

View file

@ -48,7 +48,7 @@ impl portmaster::Handler for WsHandler {
"main-handler".to_string() "main-handler".to_string()
} }
fn on_connect(&mut self, cli: portapi::client::PortAPI) -> () { fn on_connect(&mut self, cli: portapi::client::PortAPI) {
info!("connection established, creating main window"); info!("connection established, creating main window");
// we successfully connected to Portmaster. Set is_first_connect to false // we successfully connected to Portmaster. Set is_first_connect to false
@ -116,11 +116,11 @@ fn show_webview_not_installed_dialog() -> i32 {
} }
} }
return FALLBACK_TO_OLD_UI_EXIT_CODE; FALLBACK_TO_OLD_UI_EXIT_CODE
} }
fn main() { fn main() {
if let Err(_) = tauri::webview_version() { if tauri::webview_version().is_err() {
std::process::exit(show_webview_not_installed_dialog()); std::process::exit(show_webview_not_installed_dialog());
} }
@ -251,8 +251,8 @@ fn main() {
.build(tauri::generate_context!()) .build(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");
app.run(|handle, e| match e { app.run(|handle, e| {
RunEvent::WindowEvent { label, event, .. } => { if let RunEvent::WindowEvent { label, event, .. } = e {
if label != "main" { if label != "main" {
// We only have one window at most so any other label is unexpected // We only have one window at most so any other label is unexpected
return; return;
@ -266,9 +266,7 @@ fn main() {
// //
// Note: the above javascript does NOT trigger the CloseRequested event so // Note: the above javascript does NOT trigger the CloseRequested event so
// there's no need to handle that case here. // there's no need to handle that case here.
// if let WindowEvent::CloseRequested { api, .. } = event {
match event {
WindowEvent::CloseRequested { api, .. } => {
debug!( debug!(
"window (label={}) close request received, forwarding to user-interface.", "window (label={}) close request received, forwarding to user-interface.",
label label
@ -284,14 +282,6 @@ fn main() {
error!("window was None"); error!("window was None");
} }
} }
_ => {}
} }
}
// TODO(vladimir): why was this needed?
// RunEvent::ExitRequested { api, .. } => {
// api.prevent_exit();
// }
_ => {}
}); });
} }

View file

@ -26,7 +26,6 @@ pub enum MessageError {
InvalidPayload(#[from] serde_json::Error), InvalidPayload(#[from] serde_json::Error),
} }
/// Payload defines the payload type and content of a PortAPI message. /// Payload defines the payload type and content of a PortAPI message.
/// ///
/// For the time being, only JSON payloads (indicated by a prefixed 'J' of the payload content) /// For the time being, only JSON payloads (indicated by a prefixed 'J' of the payload content)
@ -36,32 +35,31 @@ pub enum MessageError {
/// appropriate decoding from the `Payload::UNKNOWN` variant. /// appropriate decoding from the `Payload::UNKNOWN` variant.
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
pub enum Payload { pub enum Payload {
JSON(String), Json(String),
UNKNOWN(String), Unknown(String),
} }
/// ParseError is returned from `Payload::parse()`. /// ParseError is returned from `Payload::parse()`.
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum ParseError { pub enum ParseError {
#[error(transparent)] #[error(transparent)]
JSON(#[from] serde_json::Error), Json(#[from] serde_json::Error),
#[error("unknown error while parsing")] #[error("unknown error while parsing")]
UNKNOWN Unknown,
} }
impl Payload { impl Payload {
/// Parse the payload into T. /// Parse the payload into T.
/// ///
/// Only JSON parsing is supported for now. See [Payload] for more information. /// Only JSON parsing is supported for now. See [Payload] for more information.
pub fn parse<'a, T>(self: &'a Self) -> std::result::Result<T, ParseError> pub fn parse<'a, T>(&'a self) -> std::result::Result<T, ParseError>
where where
T: serde::de::Deserialize<'a> { T: serde::de::Deserialize<'a>,
{
match self { match self {
Payload::JSON(blob) => Ok(serde_json::from_str::<T>(blob.as_str())?), Payload::Json(blob) => Ok(serde_json::from_str::<T>(blob.as_str())?),
Payload::UNKNOWN(_) => Err(ParseError::UNKNOWN), Payload::Unknown(_) => Err(ParseError::Unknown),
} }
} }
} }
@ -77,10 +75,10 @@ impl std::convert::From<String> for Payload {
match first { match first {
Some(c) => match c { Some(c) => match c {
'J' => Payload::JSON(rest), 'J' => Payload::Json(rest),
_ => Payload::UNKNOWN(value), _ => Payload::Unknown(value),
}, },
None => Payload::UNKNOWN("".to_string()) None => Payload::Unknown("".to_string()),
} }
} }
} }
@ -89,10 +87,10 @@ impl std::convert::From<String> for Payload {
impl std::fmt::Display for Payload { impl std::fmt::Display for Payload {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Payload::JSON(payload) => { Payload::Json(payload) => {
write!(f, "J{}", payload) write!(f, "J{}", payload)
}, }
Payload::UNKNOWN(payload) => { Payload::Unknown(payload) => {
write!(f, "{}", payload) write!(f, "{}", payload)
} }
} }
@ -119,19 +117,19 @@ pub struct Message {
/// Note that this conversion does not check for invalid messages! /// Note that this conversion does not check for invalid messages!
impl std::convert::From<Message> for String { impl std::convert::From<Message> for String {
fn from(value: Message) -> Self { fn from(value: Message) -> Self {
let mut result = "".to_owned(); let mut result = String::new();
result.push_str(value.id.to_string().as_str()); result.push_str(value.id.to_string().as_str());
result.push_str("|"); result.push('|');
result.push_str(&value.cmd); result.push_str(&value.cmd);
if let Some(key) = value.key { if let Some(key) = value.key {
result.push_str("|"); result.push('|');
result.push_str(key.as_str()); result.push_str(key.as_str());
} }
if let Some(payload) = value.payload { if let Some(payload) = value.payload {
result.push_str("|"); result.push('|');
result.push_str(payload.to_string().as_str()) result.push_str(payload.to_string().as_str())
} }
@ -147,9 +145,9 @@ impl std::str::FromStr for Message {
type Err = MessageError; type Err = MessageError;
fn from_str(line: &str) -> Result<Self, Self::Err> { fn from_str(line: &str) -> Result<Self, Self::Err> {
let parts = line.split("|").collect::<Vec<&str>>(); let parts = line.split('|').collect::<Vec<&str>>();
let id = match parts.get(0) { let id = match parts.first() {
Some(s) => match (*s).parse::<usize>() { Some(s) => match (*s).parse::<usize>() {
Ok(id) => Ok(id), Ok(id) => Ok(id),
Err(_) => Err(MessageError::InvalidID), Err(_) => Err(MessageError::InvalidID),
@ -163,18 +161,15 @@ impl std::str::FromStr for Message {
}? }?
.to_string(); .to_string();
let key = parts.get(2) let key = parts.get(2).map(|key| key.to_string());
.and_then(|key| Some(key.to_string())); let payload: Option<Payload> = parts.get(3).map(|p| p.to_string().into());
let payload : Option<Payload> = parts.get(3) Ok(Message {
.and_then(|p| Some(p.to_string().into()));
return Ok(Message {
id, id,
cmd, cmd,
key, key,
payload: payload payload,
}); })
} }
} }
@ -191,67 +186,79 @@ mod tests {
#[test] #[test]
fn payload_to_string() { fn payload_to_string() {
let p = Payload::JSON("{}".to_string()); let p = Payload::Json("{}".to_string());
assert_eq!(p.to_string(), "J{}"); assert_eq!(p.to_string(), "J{}");
let p = Payload::UNKNOWN("some unknown content".to_string()); let p = Payload::Unknown("some unknown content".to_string());
assert_eq!(p.to_string(), "some unknown content"); assert_eq!(p.to_string(), "some unknown content");
} }
#[test] #[test]
fn payload_from_string() { fn payload_from_string() {
let p: Payload = "J{}".to_string().into(); let p: Payload = "J{}".to_string().into();
assert_eq!(p, Payload::JSON("{}".to_string())); assert_eq!(p, Payload::Json("{}".to_string()));
let p: Payload = "some unknown content".to_string().into(); let p: Payload = "some unknown content".to_string().into();
assert_eq!(p, Payload::UNKNOWN("some unknown content".to_string())); assert_eq!(p, Payload::Unknown("some unknown content".to_string()));
} }
#[test] #[test]
fn payload_parse() { fn payload_parse() {
let p: Payload = "J{\"a\": 100, \"s\": \"string\"}".to_string().into(); let p: Payload = "J{\"a\": 100, \"s\": \"string\"}".to_string().into();
let t: Test = p.parse() let t: Test = p.parse().expect("Expected payload parsing to work");
.expect("Expected payload parsing to work");
assert_eq!(t, Test{ assert_eq!(
t,
Test {
a: 100, a: 100,
s: "string".to_string(), s: "string".to_string(),
}); }
);
} }
#[test] #[test]
fn parse_message() { fn parse_message() {
let m = "10|insert|some:key|J{}".parse::<Message>() let m = "10|insert|some:key|J{}"
.parse::<Message>()
.expect("Expected message to parse"); .expect("Expected message to parse");
assert_eq!(m, Message{ assert_eq!(
m,
Message {
id: 10, id: 10,
cmd: "insert".to_string(), cmd: "insert".to_string(),
key: Some("some:key".to_string()), key: Some("some:key".to_string()),
payload: Some(Payload::JSON("{}".to_string())), payload: Some(Payload::Json("{}".to_string())),
}); }
);
let m = "1|done".parse::<Message>() let m = "1|done"
.parse::<Message>()
.expect("Expected message to parse"); .expect("Expected message to parse");
assert_eq!(m, Message{ assert_eq!(
m,
Message {
id: 1, id: 1,
cmd: "done".to_string(), cmd: "done".to_string(),
key: None, key: None,
payload: None payload: None
}); }
);
let m = "".parse::<Message>() let m = "".parse::<Message>().expect_err("Expected parsing to fail");
.expect_err("Expected parsing to fail"); if let MessageError::InvalidID = m {
if let MessageError::InvalidID = m {} else { } else {
panic!("unexpected error value: {}", m) panic!("unexpected error value: {}", m)
} }
let m = "1".parse::<Message>() let m = "1"
.parse::<Message>()
.expect_err("Expected parsing to fail"); .expect_err("Expected parsing to fail");
if let MessageError::MissingCommand = m {} else { if let MessageError::MissingCommand = m {
} else {
panic!("unexpected error value: {}", m) panic!("unexpected error value: {}", m)
} }
} }

View file

@ -1,5 +1,5 @@
use serde::*;
use super::super::message::Payload; use super::super::message::Payload;
use serde::*;
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct BooleanValue { pub struct BooleanValue {
@ -13,6 +13,6 @@ impl TryInto<Payload> for BooleanValue {
fn try_into(self) -> Result<Payload, Self::Error> { fn try_into(self) -> Result<Payload, Self::Error> {
let str = serde_json::to_string(&self)?; let str = serde_json::to_string(&self)?;
Ok(Payload::JSON(str)) Ok(Payload::Json(str))
} }
} }

View file

@ -86,7 +86,7 @@ pub fn get_app_info<R: Runtime>(
matching_path, matching_path,
}; };
if id == "" { if id.is_empty() {
id = uuid::Uuid::new_v4().to_string() id = uuid::Uuid::new_v4().to_string()
} }
let cloned = id.clone(); let cloned = id.clone();
@ -137,7 +137,7 @@ pub fn get_app_info<R: Runtime>(
pub fn get_service_manager_status<R: Runtime>(window: Window<R>, response_id: String) -> Result { pub fn get_service_manager_status<R: Runtime>(window: Window<R>, response_id: String) -> Result {
let mut id = response_id; let mut id = response_id;
if id == "" { if id.is_empty() {
id = uuid::Uuid::new_v4().to_string(); id = uuid::Uuid::new_v4().to_string();
} }
let cloned = id.clone(); let cloned = id.clone();
@ -161,7 +161,7 @@ pub fn get_service_manager_status<R: Runtime>(window: Window<R>, response_id: St
pub fn start_service<R: Runtime>(window: Window<R>, response_id: String) -> Result { pub fn start_service<R: Runtime>(window: Window<R>, response_id: String) -> Result {
let mut id = response_id; let mut id = response_id;
if id == "" { if id.is_empty() {
id = uuid::Uuid::new_v4().to_string(); id = uuid::Uuid::new_v4().to_string();
} }
let cloned = id.clone(); let cloned = id.clone();

View file

@ -32,14 +32,13 @@ use std::{
}; };
use log::{debug, error}; use log::{debug, error};
use serde;
use std::sync::Mutex; use std::sync::Mutex;
use tauri::{AppHandle, Emitter, Manager, Runtime}; use tauri::{AppHandle, Emitter, Manager, Runtime};
const PORTMASTER_BASE_URL: &'static str = "http://127.0.0.1:817/api/v1/"; const PORTMASTER_BASE_URL: &str = "http://127.0.0.1:817/api/v1/";
pub trait Handler { pub trait Handler {
fn on_connect(&mut self, cli: PortAPI) -> (); fn on_connect(&mut self, cli: PortAPI);
fn on_disconnect(&mut self); fn on_disconnect(&mut self);
fn name(&self) -> String; fn name(&self) -> String;
} }
@ -81,10 +80,7 @@ impl<R: Runtime> PortmasterInterface<R> {
let map = self.state.lock(); let map = self.state.lock();
if let Ok(map) = map { if let Ok(map) = map {
match map.get(&key) { map.get(&key).cloned()
Some(value) => Some(value.clone()),
None => None,
}
} else { } else {
None None
} }
@ -129,11 +125,8 @@ impl<R: Runtime> PortmasterInterface<R> {
/// Returns the current portapi client. /// Returns the current portapi client.
pub fn get_api(&self) -> Option<PortAPI> { pub fn get_api(&self) -> Option<PortAPI> {
if let Ok(mut api) = self.api.lock() { if let Ok(api) = self.api.lock() {
match &mut *api { (*api).clone()
Some(api) => Some(api.clone()),
None => None,
}
} else { } else {
None None
} }

View file

@ -29,13 +29,13 @@ pub async fn notification_handler(cli: PortAPI) {
} }
// Skip if this action has already been acted on // Skip if this action has already been acted on
if n.selected_action_id != "" { if n.selected_action_id.is_empty() {
return; return;
} }
show_notification(&cli, key, n).await; show_notification(&cli, key, n).await;
} }
Err(err) => match err { Err(err) => match err {
ParseError::JSON(err) => { ParseError::Json(err) => {
error!("failed to parse notification: {}", err); error!("failed to parse notification: {}", err);
} }
_ => { _ => {
@ -81,7 +81,7 @@ pub async fn show_notification(cli: &PortAPI, key: String, n: Notification) {
let _ = cli_clone let _ = cli_clone
.request(Request::Update( .request(Request::Update(
key, key,
Payload::JSON( Payload::Json(
json!({ json!({
"SelectedActionID": value "SelectedActionID": value
}) })
@ -125,7 +125,7 @@ pub async fn show_notification(cli: &PortAPI, key: String, n: Notification) {
let _ = cli let _ = cli
.request(Request::Update( .request(Request::Update(
key, key,
Payload::JSON( Payload::Json(
json!({ json!({
"SelectedActionID": value "SelectedActionID": value
}) })

View file

@ -26,7 +26,7 @@ impl From<std::process::Output> for ServiceManagerError {
.ok() .ok()
.filter(|s| !s.trim().is_empty()) .filter(|s| !s.trim().is_empty())
}) })
.unwrap_or_else(|| format!("Failed to run `systemctl`")); .unwrap_or_else(|| "Failed to run `systemctl`".to_string());
ServiceManagerError::Other(output.status, msg) ServiceManagerError::Other(output.status, msg)
} }
@ -231,11 +231,11 @@ fn trim_newline(s: &mut String) {
} }
fn get_sudo_cmd() -> std::result::Result<SudoCommand, std::io::Error> { fn get_sudo_cmd() -> std::result::Result<SudoCommand, std::io::Error> {
if let Ok(_) = fs::metadata("/usr/bin/pkexec") { if fs::metadata("/usr/bin/pkexec").is_ok() {
return Ok(SudoCommand::Pkexec); return Ok(SudoCommand::Pkexec);
} }
if let Ok(_) = fs::metadata("/usr/bin/gksudo") { if fs::metadata("/usr/bin/gksudo").is_ok() {
return Ok(SudoCommand::Gksu); return Ok(SudoCommand::Gksu);
} }

View file

@ -46,13 +46,11 @@ enum IconColor {
static CURRENT_ICON_COLOR: RwLock<IconColor> = RwLock::new(IconColor::Red); static CURRENT_ICON_COLOR: RwLock<IconColor> = RwLock::new(IconColor::Red);
pub static USER_THEME: RwLock<dark_light::Mode> = RwLock::new(dark_light::Mode::Default); pub static USER_THEME: RwLock<dark_light::Mode> = RwLock::new(dark_light::Mode::Default);
lazy_static! { static SPN_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
static ref SPN_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None); static SPN_BUTTON: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
static ref SPN_BUTTON: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None); static GLOBAL_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
static ref GLOBAL_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
}
const PM_TRAY_ICON_ID: &'static str = "pm_icon"; const PM_TRAY_ICON_ID: &str = "pm_icon";
// Icons // Icons
@ -64,9 +62,9 @@ fn get_theme_mode() -> dark_light::Mode {
} }
fn get_green_icon() -> &'static [u8] { fn get_green_icon() -> &'static [u8] {
const LIGHT_GREEN_ICON: &'static [u8] = const LIGHT_GREEN_ICON: &[u8] =
include_bytes!("../../../../assets/data/icons/pm_light_green_64.png"); include_bytes!("../../../../assets/data/icons/pm_light_green_64.png");
const DARK_GREEN_ICON: &'static [u8] = const DARK_GREEN_ICON: &[u8] =
include_bytes!("../../../../assets/data/icons/pm_dark_green_64.png"); include_bytes!("../../../../assets/data/icons/pm_dark_green_64.png");
match get_theme_mode() { match get_theme_mode() {
@ -76,9 +74,9 @@ fn get_green_icon() -> &'static [u8] {
} }
fn get_blue_icon() -> &'static [u8] { fn get_blue_icon() -> &'static [u8] {
const LIGHT_BLUE_ICON: &'static [u8] = const LIGHT_BLUE_ICON: &[u8] =
include_bytes!("../../../../assets/data/icons/pm_light_blue_64.png"); include_bytes!("../../../../assets/data/icons/pm_light_blue_64.png");
const DARK_BLUE_ICON: &'static [u8] = const DARK_BLUE_ICON: &[u8] =
include_bytes!("../../../../assets/data/icons/pm_dark_blue_64.png"); include_bytes!("../../../../assets/data/icons/pm_dark_blue_64.png");
match get_theme_mode() { match get_theme_mode() {
dark_light::Mode::Light => DARK_BLUE_ICON, dark_light::Mode::Light => DARK_BLUE_ICON,
@ -87,20 +85,27 @@ fn get_blue_icon() -> &'static [u8] {
} }
fn get_red_icon() -> &'static [u8] { fn get_red_icon() -> &'static [u8] {
const LIGHT_RED_ICON: &'static [u8] = const LIGHT_RED_ICON: &[u8] =
include_bytes!("../../../../assets/data/icons/pm_light_red_64.png"); include_bytes!("../../../../assets/data/icons/pm_light_red_64.png");
const DARK_RED_ICON: &'static [u8] = const DARK_RED_ICON: &'static [u8] =
include_bytes!("../../../../assets/data/icons/pm_dark_red_64.png"); include_bytes!("../../../../assets/data/icons/pm_dark_red_64.png");
match get_theme_mode() { match get_theme_mode() {
const DARK_RED_ICON: &'static [u8] =
include_bytes!("../../../../assets/data/icons/pm_dark_red_64.png");
let mode = dark_light::detect();
match mode {
const DARK_RED_ICON: &[u8] = include_bytes!("../../../../assets/data/icons/pm_dark_red_64.png");
let mode = dark_light::detect();
match mode {
dark_light::Mode::Light => DARK_RED_ICON, dark_light::Mode::Light => DARK_RED_ICON,
_ => LIGHT_RED_ICON, _ => LIGHT_RED_ICON,
} }
} }
fn get_yellow_icon() -> &'static [u8] { fn get_yellow_icon() -> &'static [u8] {
const LIGHT_YELLOW_ICON: &'static [u8] = const LIGHT_YELLOW_ICON: &[u8] =
include_bytes!("../../../../assets/data/icons/pm_light_yellow_64.png"); include_bytes!("../../../../assets/data/icons/pm_light_yellow_64.png");
const DARK_YELLOW_ICON: &'static [u8] = const DARK_YELLOW_ICON: &[u8] =
include_bytes!("../../../../assets/data/icons/pm_dark_yellow_64.png"); include_bytes!("../../../../assets/data/icons/pm_dark_yellow_64.png");
match get_theme_mode() { match get_theme_mode() {
dark_light::Mode::Light => DARK_YELLOW_ICON, dark_light::Mode::Light => DARK_YELLOW_ICON,
@ -257,32 +262,30 @@ pub fn setup_tray_menu(
button_state, button_state,
} = event } = event
{ {
if let MouseButton::Left = button { if let (MouseButton::Left, MouseButtonState::Down) = (button, button_state) {
if let MouseButtonState::Down = button_state {
let _ = open_window(tray.app_handle()); let _ = open_window(tray.app_handle());
} }
} }
}
}) })
.build(app)?; .build(app)?;
Ok(icon) Ok(icon)
} }
pub fn update_icon(icon: AppIcon, subsystems: HashMap<String, Subsystem>, spn_status: String) { pub fn update_icon(icon: AppIcon, subsystems: HashMap<String, Subsystem>, spn_status: String) {
// iterate over the subsytems and check if there's a module failure // iterate over the subsystems and check if there's a module failure
let failure = subsystems let failure = subsystems.values().map(|s| &s.module_status).fold(
.values() (subsystem::FAILURE_NONE, "".to_string()),
.into_iter() |mut acc, s| {
.map(|s| &s.module_status)
.fold((subsystem::FAILURE_NONE, "".to_string()), |mut acc, s| {
for m in s { for m in s {
if m.failure_status > acc.0 { if m.failure_status > acc.0 {
acc = (m.failure_status, m.failure_msg.clone()) acc = (m.failure_status, m.failure_msg.clone())
} }
} }
acc acc
}); },
);
#[allow(clippy::collapsible_else_if)]
if failure.0 == subsystem::FAILURE_NONE { if failure.0 == subsystem::FAILURE_NONE {
if let Some(global_status) = &mut *(GLOBAL_STATUS.lock().unwrap()) { if let Some(global_status) = &mut *(GLOBAL_STATUS.lock().unwrap()) {
_ = global_status.set_text("Status: Secured"); _ = global_status.set_text("Status: Secured");
@ -405,7 +408,7 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
update_icon(icon.clone(), subsystems.clone(), spn_status.clone()); update_icon(icon.clone(), subsystems.clone(), spn_status.clone());
}, },
Err(err) => match err { Err(err) => match err {
ParseError::JSON(err) => { ParseError::Json(err) => {
error!("failed to parse subsystem: {}", err); error!("failed to parse subsystem: {}", err);
} }
_ => { _ => {
@ -437,7 +440,7 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
update_icon(icon.clone(), subsystems.clone(), spn_status.clone()); update_icon(icon.clone(), subsystems.clone(), spn_status.clone());
}, },
Err(err) => match err { Err(err) => match err {
ParseError::JSON(err) => { ParseError::Json(err) => {
error!("failed to parse spn status value: {}", err) error!("failed to parse spn status value: {}", err)
}, },
_ => { _ => {
@ -466,7 +469,7 @@ pub async fn tray_handler(cli: PortAPI, app: tauri::AppHandle) {
update_spn_ui_state(value.value.unwrap_or(false)); update_spn_ui_state(value.value.unwrap_or(false));
}, },
Err(err) => match err { Err(err) => match err {
ParseError::JSON(err) => { ParseError::Json(err) => {
error!("failed to parse config value: {}", err) error!("failed to parse config value: {}", err)
}, },
_ => { _ => {

View file

@ -6,9 +6,8 @@ use tauri::{
use crate::{portmaster::PortmasterExt, traymenu}; use crate::{portmaster::PortmasterExt, traymenu};
const LIGHT_PM_ICON: &'static [u8] = const LIGHT_PM_ICON: &[u8] = include_bytes!("../../../../assets/data/icons/pm_light_512.png");
include_bytes!("../../../../assets/data/icons/pm_light_512.png"); const DARK_PM_ICON: &[u8] = include_bytes!("../../../../assets/data/icons/pm_dark_512.png");
const DARK_PM_ICON: &'static [u8] = include_bytes!("../../../../assets/data/icons/pm_dark_512.png");
/// Either returns the existing "main" window or creates a new one. /// Either returns the existing "main" window or creates a new one.
/// ///
@ -54,7 +53,7 @@ pub fn create_main_window(app: &AppHandle) -> Result<WebviewWindow> {
set_window_icon(&window); set_window_icon(&window);
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
if let Ok(_) = std::env::var("TAURI_SHOW_IMMEDIATELY") { if std::env::var("TAURI_SHOW_IMMEDIATELY").is_ok() {
debug!("[tauri] TAURI_SHOW_IMMEDIATELY is set, opening window"); debug!("[tauri] TAURI_SHOW_IMMEDIATELY is set, opening window");
if let Err(err) = window.show() { if let Err(err) = window.show() {
@ -92,7 +91,7 @@ pub fn close_splash_window(app: &AppHandle) -> Result<()> {
let _ = window.hide(); let _ = window.hide();
return window.destroy(); return window.destroy();
} }
return Err(tauri::Error::WindowNotFound); Err(tauri::Error::WindowNotFound)
} }
pub fn hide_splash_window(app: &AppHandle) -> Result<()> { pub fn hide_splash_window(app: &AppHandle) -> Result<()> {

View file

@ -18,7 +18,6 @@ use std::{
}; };
use thiserror::Error; use thiserror::Error;
use dirs;
use ini::{Ini, ParseOption}; use ini::{Ini, ParseOption};
static mut GTK_DEFAULT_THEME: Option<*mut GtkIconTheme> = None; static mut GTK_DEFAULT_THEME: Option<*mut GtkIconTheme> = None;
@ -146,7 +145,7 @@ pub fn get_app_info(process_info: ProcessInfo) -> Result<AppInfo> {
.unwrap() .unwrap()
.insert(process_info.exec_path, None); .insert(process_info.exec_path, None);
Err(Error::new(ErrorKind::NotFound, format!("failed to find app info")).into()) Err(Error::new(ErrorKind::NotFound, "failed to find app info".to_string()).into())
} else { } else {
// sort matches by length // sort matches by length
matches.sort_by(|a, b| a.1.cmp(&b.1)); matches.sort_by(|a, b| a.1.cmp(&b.1));
@ -178,7 +177,7 @@ pub fn get_app_info(process_info: ProcessInfo) -> Result<AppInfo> {
}; };
} }
Err(Error::new(ErrorKind::NotFound, format!("failed to find app info")).into()) Err(Error::new(ErrorKind::NotFound, "failed to find app info".to_string()).into())
} }
} }
@ -336,7 +335,7 @@ fn try_get_app_info(
} }
} }
if result.len() > 0 { if !result.is_empty() {
Ok(result) Ok(result)
} else { } else {
Err(Error::new(ErrorKind::NotFound, "no matching .desktop files found").into()) Err(Error::new(ErrorKind::NotFound, "no matching .desktop files found").into())
@ -393,7 +392,7 @@ fn get_icon_as_png_dataurl(name: &str, size: i8) -> Result<(String, String)> {
// - network // - network
// //
name_without_ext name_without_ext
.split("-") .split('-')
.for_each(|part| icons.push(part)); .for_each(|part| icons.push(part));
for name in icons { for name in icons {
@ -554,15 +553,7 @@ mod tests {
matching_path: bin.clone(), matching_path: bin.clone(),
pid: 0, pid: 0,
}) })
.expect( .unwrap_or_else(|_| panic!("expected to find app info for {} ({})", bin, cmd));
format!(
"expected to find app info for {} ({})",
bin,
cmd.to_string()
)
.as_str(),
);
let empty_string = String::from(""); let empty_string = String::from("");
// just make sure all fields are populated // just make sure all fields are populated