mirror of
https://github.com/safing/portmaster
synced 2025-09-01 18:19:12 +00:00
[desktop] Fix all clippy warning. Add clippy to CI.
This commit is contained in:
parent
9472a1f8f5
commit
4c340f7b70
13 changed files with 208 additions and 167 deletions
19
.github/workflows/tauri.yml
vendored
19
.github/workflows/tauri.yml
vendored
|
@ -34,3 +34,22 @@ jobs:
|
|||
|
||||
- name: Build tauri project
|
||||
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
|
||||
|
|
36
Earthfile
36
Earthfile
|
@ -636,6 +636,42 @@ tauri-release:
|
|||
BUILD +tauri-build --target="${arch}"
|
||||
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:
|
||||
FROM ${rust_builder_image}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ license = ""
|
|||
repository = ""
|
||||
default-run = "portmaster"
|
||||
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
|
||||
|
||||
|
@ -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.
|
||||
# DO NOT REMOVE!!
|
||||
custom-protocol = [ "tauri/custom-protocol" ]
|
||||
|
||||
[package.metadata.clippy]
|
||||
allow = ["clippy::collapsible_else_if"]
|
|
@ -48,7 +48,7 @@ impl portmaster::Handler for WsHandler {
|
|||
"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");
|
||||
|
||||
// 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() {
|
||||
if let Err(_) = tauri::webview_version() {
|
||||
if tauri::webview_version().is_err() {
|
||||
std::process::exit(show_webview_not_installed_dialog());
|
||||
}
|
||||
|
||||
|
@ -251,8 +251,8 @@ fn main() {
|
|||
.build(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
app.run(|handle, e| match e {
|
||||
RunEvent::WindowEvent { label, event, .. } => {
|
||||
app.run(|handle, e| {
|
||||
if let RunEvent::WindowEvent { label, event, .. } = e {
|
||||
if label != "main" {
|
||||
// We only have one window at most so any other label is unexpected
|
||||
return;
|
||||
|
@ -266,32 +266,22 @@ fn main() {
|
|||
//
|
||||
// Note: the above javascript does NOT trigger the CloseRequested event so
|
||||
// there's no need to handle that case here.
|
||||
//
|
||||
match event {
|
||||
WindowEvent::CloseRequested { api, .. } => {
|
||||
debug!(
|
||||
"window (label={}) close request received, forwarding to user-interface.",
|
||||
label
|
||||
);
|
||||
if let WindowEvent::CloseRequested { api, .. } = event {
|
||||
debug!(
|
||||
"window (label={}) close request received, forwarding to user-interface.",
|
||||
label
|
||||
);
|
||||
|
||||
api.prevent_close();
|
||||
if let Some(window) = handle.get_webview_window(label.as_str()) {
|
||||
let result = window.emit("exit-requested", "");
|
||||
if let Err(err) = result {
|
||||
error!("failed to emit event: {}", err.to_string());
|
||||
}
|
||||
} else {
|
||||
error!("window was None");
|
||||
api.prevent_close();
|
||||
if let Some(window) = handle.get_webview_window(label.as_str()) {
|
||||
let result = window.emit("exit-requested", "");
|
||||
if let Err(err) = result {
|
||||
error!("failed to emit event: {}", err.to_string());
|
||||
}
|
||||
} else {
|
||||
error!("window was None");
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(vladimir): why was this needed?
|
||||
// RunEvent::ExitRequested { api, .. } => {
|
||||
// api.prevent_exit();
|
||||
// }
|
||||
_ => {}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -26,48 +26,46 @@ pub enum MessageError {
|
|||
InvalidPayload(#[from] serde_json::Error),
|
||||
}
|
||||
|
||||
|
||||
/// 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)
|
||||
/// is directly supported in `Payload::parse()`.
|
||||
///
|
||||
///
|
||||
/// For other payload types (like CBOR, BSON, ...) it's the user responsibility to figure out
|
||||
/// appropriate decoding from the `Payload::UNKNOWN` variant.
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub enum Payload {
|
||||
JSON(String),
|
||||
UNKNOWN(String),
|
||||
Json(String),
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
/// ParseError is returned from `Payload::parse()`.
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ParseError {
|
||||
#[error(transparent)]
|
||||
JSON(#[from] serde_json::Error),
|
||||
Json(#[from] serde_json::Error),
|
||||
|
||||
#[error("unknown error while parsing")]
|
||||
UNKNOWN
|
||||
Unknown,
|
||||
}
|
||||
|
||||
|
||||
impl Payload {
|
||||
/// Parse the payload into T.
|
||||
///
|
||||
///
|
||||
/// 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
|
||||
T: serde::de::Deserialize<'a> {
|
||||
|
||||
T: serde::de::Deserialize<'a>,
|
||||
{
|
||||
match self {
|
||||
Payload::JSON(blob) => Ok(serde_json::from_str::<T>(blob.as_str())?),
|
||||
Payload::UNKNOWN(_) => Err(ParseError::UNKNOWN),
|
||||
Payload::Json(blob) => Ok(serde_json::from_str::<T>(blob.as_str())?),
|
||||
Payload::Unknown(_) => Err(ParseError::Unknown),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Supports creating a Payload instance from a String.
|
||||
///
|
||||
///
|
||||
/// See [Payload] for more information.
|
||||
impl std::convert::From<String> for Payload {
|
||||
fn from(value: String) -> Payload {
|
||||
|
@ -77,10 +75,10 @@ impl std::convert::From<String> for Payload {
|
|||
|
||||
match first {
|
||||
Some(c) => match c {
|
||||
'J' => Payload::JSON(rest),
|
||||
_ => Payload::UNKNOWN(value),
|
||||
'J' => Payload::Json(rest),
|
||||
_ => 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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Payload::JSON(payload) => {
|
||||
Payload::Json(payload) => {
|
||||
write!(f, "J{}", payload)
|
||||
},
|
||||
Payload::UNKNOWN(payload) => {
|
||||
}
|
||||
Payload::Unknown(payload) => {
|
||||
write!(f, "{}", payload)
|
||||
}
|
||||
}
|
||||
|
@ -100,9 +98,9 @@ impl std::fmt::Display for Payload {
|
|||
}
|
||||
|
||||
/// Message is an internal representation of a PortAPI message.
|
||||
/// Users should more likely use `portapi::types::Request` and `portapi::types::Response`
|
||||
/// Users should more likely use `portapi::types::Request` and `portapi::types::Response`
|
||||
/// instead of directly using `Message`.
|
||||
///
|
||||
///
|
||||
/// The struct is still public since it might be useful for debugging or to implement new
|
||||
/// commands not yet supported by the `portapi::types` crate.
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
|
@ -115,23 +113,23 @@ pub struct Message {
|
|||
|
||||
/// Implementation to marshal a PortAPI message into it's wire-format representation
|
||||
/// (which is a string).
|
||||
///
|
||||
///
|
||||
/// Note that this conversion does not check for invalid messages!
|
||||
impl std::convert::From<Message> for String {
|
||||
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("|");
|
||||
result.push('|');
|
||||
result.push_str(&value.cmd);
|
||||
|
||||
if let Some(key) = value.key {
|
||||
result.push_str("|");
|
||||
result.push('|');
|
||||
result.push_str(key.as_str());
|
||||
}
|
||||
|
||||
if let Some(payload) = value.payload {
|
||||
result.push_str("|");
|
||||
result.push('|');
|
||||
result.push_str(payload.to_string().as_str())
|
||||
}
|
||||
|
||||
|
@ -141,15 +139,15 @@ impl std::convert::From<Message> for String {
|
|||
|
||||
/// An implementation for `String::parse()` to convert a wire-format representation
|
||||
/// of a PortAPI message to a Message instance.
|
||||
///
|
||||
///
|
||||
/// Any errors returned from `String::parse()` will be of type `MessageError`
|
||||
impl std::str::FromStr for Message {
|
||||
type Err = MessageError;
|
||||
|
||||
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>() {
|
||||
Ok(id) => Ok(id),
|
||||
Err(_) => Err(MessageError::InvalidID),
|
||||
|
@ -163,18 +161,15 @@ impl std::str::FromStr for Message {
|
|||
}?
|
||||
.to_string();
|
||||
|
||||
let key = parts.get(2)
|
||||
.and_then(|key| Some(key.to_string()));
|
||||
let key = parts.get(2).map(|key| key.to_string());
|
||||
let payload: Option<Payload> = parts.get(3).map(|p| p.to_string().into());
|
||||
|
||||
let payload : Option<Payload> = parts.get(3)
|
||||
.and_then(|p| Some(p.to_string().into()));
|
||||
|
||||
return Ok(Message {
|
||||
Ok(Message {
|
||||
id,
|
||||
cmd,
|
||||
key,
|
||||
payload: payload
|
||||
});
|
||||
payload,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -191,67 +186,79 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn payload_to_string() {
|
||||
let p = Payload::JSON("{}".to_string());
|
||||
let p = Payload::Json("{}".to_string());
|
||||
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");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payload_from_string() {
|
||||
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();
|
||||
assert_eq!(p, Payload::UNKNOWN("some unknown content".to_string()));
|
||||
assert_eq!(p, Payload::Unknown("some unknown content".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn payload_parse() {
|
||||
let p: Payload = "J{\"a\": 100, \"s\": \"string\"}".to_string().into();
|
||||
|
||||
let t: Test = p.parse()
|
||||
.expect("Expected payload parsing to work");
|
||||
let t: Test = p.parse().expect("Expected payload parsing to work");
|
||||
|
||||
assert_eq!(t, Test{
|
||||
a: 100,
|
||||
s: "string".to_string(),
|
||||
});
|
||||
assert_eq!(
|
||||
t,
|
||||
Test {
|
||||
a: 100,
|
||||
s: "string".to_string(),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
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");
|
||||
|
||||
assert_eq!(m, Message{
|
||||
id: 10,
|
||||
cmd: "insert".to_string(),
|
||||
key: Some("some:key".to_string()),
|
||||
payload: Some(Payload::JSON("{}".to_string())),
|
||||
});
|
||||
assert_eq!(
|
||||
m,
|
||||
Message {
|
||||
id: 10,
|
||||
cmd: "insert".to_string(),
|
||||
key: Some("some:key".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");
|
||||
|
||||
assert_eq!(m, Message{
|
||||
id: 1,
|
||||
cmd: "done".to_string(),
|
||||
key: None,
|
||||
payload: None
|
||||
});
|
||||
assert_eq!(
|
||||
m,
|
||||
Message {
|
||||
id: 1,
|
||||
cmd: "done".to_string(),
|
||||
key: None,
|
||||
payload: None
|
||||
}
|
||||
);
|
||||
|
||||
let m = "".parse::<Message>()
|
||||
.expect_err("Expected parsing to fail");
|
||||
if let MessageError::InvalidID = m {} else {
|
||||
let m = "".parse::<Message>().expect_err("Expected parsing to fail");
|
||||
if let MessageError::InvalidID = m {
|
||||
} else {
|
||||
panic!("unexpected error value: {}", m)
|
||||
}
|
||||
|
||||
let m = "1".parse::<Message>()
|
||||
let m = "1"
|
||||
.parse::<Message>()
|
||||
.expect_err("Expected parsing to fail");
|
||||
|
||||
if let MessageError::MissingCommand = m {} else {
|
||||
if let MessageError::MissingCommand = m {
|
||||
} else {
|
||||
panic!("unexpected error value: {}", m)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use serde::*;
|
||||
use super::super::message::Payload;
|
||||
use serde::*;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
pub struct BooleanValue {
|
||||
|
@ -13,6 +13,6 @@ impl TryInto<Payload> for BooleanValue {
|
|||
fn try_into(self) -> Result<Payload, Self::Error> {
|
||||
let str = serde_json::to_string(&self)?;
|
||||
|
||||
Ok(Payload::JSON(str))
|
||||
Ok(Payload::Json(str))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ pub fn get_app_info<R: Runtime>(
|
|||
matching_path,
|
||||
};
|
||||
|
||||
if id == "" {
|
||||
if id.is_empty() {
|
||||
id = uuid::Uuid::new_v4().to_string()
|
||||
}
|
||||
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 {
|
||||
let mut id = response_id;
|
||||
|
||||
if id == "" {
|
||||
if id.is_empty() {
|
||||
id = uuid::Uuid::new_v4().to_string();
|
||||
}
|
||||
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 {
|
||||
let mut id = response_id;
|
||||
|
||||
if id == "" {
|
||||
if id.is_empty() {
|
||||
id = uuid::Uuid::new_v4().to_string();
|
||||
}
|
||||
let cloned = id.clone();
|
||||
|
|
|
@ -32,14 +32,13 @@ use std::{
|
|||
};
|
||||
|
||||
use log::{debug, error};
|
||||
use serde;
|
||||
use std::sync::Mutex;
|
||||
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 {
|
||||
fn on_connect(&mut self, cli: PortAPI) -> ();
|
||||
fn on_connect(&mut self, cli: PortAPI);
|
||||
fn on_disconnect(&mut self);
|
||||
fn name(&self) -> String;
|
||||
}
|
||||
|
@ -81,10 +80,7 @@ impl<R: Runtime> PortmasterInterface<R> {
|
|||
let map = self.state.lock();
|
||||
|
||||
if let Ok(map) = map {
|
||||
match map.get(&key) {
|
||||
Some(value) => Some(value.clone()),
|
||||
None => None,
|
||||
}
|
||||
map.get(&key).cloned()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -129,11 +125,8 @@ impl<R: Runtime> PortmasterInterface<R> {
|
|||
|
||||
/// Returns the current portapi client.
|
||||
pub fn get_api(&self) -> Option<PortAPI> {
|
||||
if let Ok(mut api) = self.api.lock() {
|
||||
match &mut *api {
|
||||
Some(api) => Some(api.clone()),
|
||||
None => None,
|
||||
}
|
||||
if let Ok(api) = self.api.lock() {
|
||||
(*api).clone()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
@ -29,13 +29,13 @@ pub async fn notification_handler(cli: PortAPI) {
|
|||
}
|
||||
|
||||
// Skip if this action has already been acted on
|
||||
if n.selected_action_id != "" {
|
||||
if n.selected_action_id.is_empty() {
|
||||
return;
|
||||
}
|
||||
show_notification(&cli, key, n).await;
|
||||
}
|
||||
Err(err) => match err {
|
||||
ParseError::JSON(err) => {
|
||||
ParseError::Json(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
|
||||
.request(Request::Update(
|
||||
key,
|
||||
Payload::JSON(
|
||||
Payload::Json(
|
||||
json!({
|
||||
"SelectedActionID": value
|
||||
})
|
||||
|
@ -125,7 +125,7 @@ pub async fn show_notification(cli: &PortAPI, key: String, n: Notification) {
|
|||
let _ = cli
|
||||
.request(Request::Update(
|
||||
key,
|
||||
Payload::JSON(
|
||||
Payload::Json(
|
||||
json!({
|
||||
"SelectedActionID": value
|
||||
})
|
||||
|
|
|
@ -26,7 +26,7 @@ impl From<std::process::Output> for ServiceManagerError {
|
|||
.ok()
|
||||
.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)
|
||||
}
|
||||
|
@ -231,11 +231,11 @@ fn trim_newline(s: &mut String) {
|
|||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
if let Ok(_) = fs::metadata("/usr/bin/gksudo") {
|
||||
if fs::metadata("/usr/bin/gksudo").is_ok() {
|
||||
return Ok(SudoCommand::Gksu);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,13 +46,11 @@ enum IconColor {
|
|||
static CURRENT_ICON_COLOR: RwLock<IconColor> = RwLock::new(IconColor::Red);
|
||||
pub static USER_THEME: RwLock<dark_light::Mode> = RwLock::new(dark_light::Mode::Default);
|
||||
|
||||
lazy_static! {
|
||||
static ref SPN_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
||||
static ref SPN_BUTTON: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
||||
static ref GLOBAL_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
||||
}
|
||||
static SPN_STATUS: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
||||
static SPN_BUTTON: Mutex<Option<MenuItem<Wry>>> = Mutex::new(None);
|
||||
static 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
|
||||
|
||||
|
@ -64,9 +62,9 @@ fn get_theme_mode() -> dark_light::Mode {
|
|||
}
|
||||
|
||||
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");
|
||||
const DARK_GREEN_ICON: &'static [u8] =
|
||||
const DARK_GREEN_ICON: &[u8] =
|
||||
include_bytes!("../../../../assets/data/icons/pm_dark_green_64.png");
|
||||
|
||||
match get_theme_mode() {
|
||||
|
@ -76,9 +74,9 @@ fn get_green_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");
|
||||
const DARK_BLUE_ICON: &'static [u8] =
|
||||
const DARK_BLUE_ICON: &[u8] =
|
||||
include_bytes!("../../../../assets/data/icons/pm_dark_blue_64.png");
|
||||
match get_theme_mode() {
|
||||
dark_light::Mode::Light => DARK_BLUE_ICON,
|
||||
|
@ -87,20 +85,27 @@ fn get_blue_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");
|
||||
const DARK_RED_ICON: &'static [u8] =
|
||||
include_bytes!("../../../../assets/data/icons/pm_dark_red_64.png");
|
||||
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,
|
||||
_ => LIGHT_RED_ICON,
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
const DARK_YELLOW_ICON: &'static [u8] =
|
||||
const DARK_YELLOW_ICON: &[u8] =
|
||||
include_bytes!("../../../../assets/data/icons/pm_dark_yellow_64.png");
|
||||
match get_theme_mode() {
|
||||
dark_light::Mode::Light => DARK_YELLOW_ICON,
|
||||
|
@ -257,10 +262,8 @@ pub fn setup_tray_menu(
|
|||
button_state,
|
||||
} = event
|
||||
{
|
||||
if let MouseButton::Left = button {
|
||||
if let MouseButtonState::Down = button_state {
|
||||
let _ = open_window(tray.app_handle());
|
||||
}
|
||||
if let (MouseButton::Left, MouseButtonState::Down) = (button, button_state) {
|
||||
let _ = open_window(tray.app_handle());
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -269,20 +272,20 @@ pub fn setup_tray_menu(
|
|||
}
|
||||
|
||||
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
|
||||
let failure = subsystems
|
||||
.values()
|
||||
.into_iter()
|
||||
.map(|s| &s.module_status)
|
||||
.fold((subsystem::FAILURE_NONE, "".to_string()), |mut acc, s| {
|
||||
// iterate over the subsystems and check if there's a module failure
|
||||
let failure = subsystems.values().map(|s| &s.module_status).fold(
|
||||
(subsystem::FAILURE_NONE, "".to_string()),
|
||||
|mut acc, s| {
|
||||
for m in s {
|
||||
if m.failure_status > acc.0 {
|
||||
acc = (m.failure_status, m.failure_msg.clone())
|
||||
}
|
||||
}
|
||||
acc
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
#[allow(clippy::collapsible_else_if)]
|
||||
if failure.0 == subsystem::FAILURE_NONE {
|
||||
if let Some(global_status) = &mut *(GLOBAL_STATUS.lock().unwrap()) {
|
||||
_ = 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());
|
||||
},
|
||||
Err(err) => match err {
|
||||
ParseError::JSON(err) => {
|
||||
ParseError::Json(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());
|
||||
},
|
||||
Err(err) => match err {
|
||||
ParseError::JSON(err) => {
|
||||
ParseError::Json(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));
|
||||
},
|
||||
Err(err) => match err {
|
||||
ParseError::JSON(err) => {
|
||||
ParseError::Json(err) => {
|
||||
error!("failed to parse config value: {}", err)
|
||||
},
|
||||
_ => {
|
||||
|
|
|
@ -6,9 +6,8 @@ use tauri::{
|
|||
|
||||
use crate::{portmaster::PortmasterExt, traymenu};
|
||||
|
||||
const LIGHT_PM_ICON: &'static [u8] =
|
||||
include_bytes!("../../../../assets/data/icons/pm_light_512.png");
|
||||
const DARK_PM_ICON: &'static [u8] = include_bytes!("../../../../assets/data/icons/pm_dark_512.png");
|
||||
const LIGHT_PM_ICON: &[u8] = include_bytes!("../../../../assets/data/icons/pm_light_512.png");
|
||||
const DARK_PM_ICON: &[u8] = include_bytes!("../../../../assets/data/icons/pm_dark_512.png");
|
||||
|
||||
/// 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);
|
||||
|
||||
#[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");
|
||||
|
||||
if let Err(err) = window.show() {
|
||||
|
@ -92,7 +91,7 @@ pub fn close_splash_window(app: &AppHandle) -> Result<()> {
|
|||
let _ = window.hide();
|
||||
return window.destroy();
|
||||
}
|
||||
return Err(tauri::Error::WindowNotFound);
|
||||
Err(tauri::Error::WindowNotFound)
|
||||
}
|
||||
|
||||
pub fn hide_splash_window(app: &AppHandle) -> Result<()> {
|
||||
|
|
|
@ -18,7 +18,6 @@ use std::{
|
|||
};
|
||||
use thiserror::Error;
|
||||
|
||||
use dirs;
|
||||
use ini::{Ini, ParseOption};
|
||||
|
||||
static mut GTK_DEFAULT_THEME: Option<*mut GtkIconTheme> = None;
|
||||
|
@ -146,7 +145,7 @@ pub fn get_app_info(process_info: ProcessInfo) -> Result<AppInfo> {
|
|||
.unwrap()
|
||||
.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 {
|
||||
// sort matches by length
|
||||
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)
|
||||
} else {
|
||||
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
|
||||
//
|
||||
name_without_ext
|
||||
.split("-")
|
||||
.split('-')
|
||||
.for_each(|part| icons.push(part));
|
||||
|
||||
for name in icons {
|
||||
|
@ -554,15 +553,7 @@ mod tests {
|
|||
matching_path: bin.clone(),
|
||||
pid: 0,
|
||||
})
|
||||
.expect(
|
||||
format!(
|
||||
"expected to find app info for {} ({})",
|
||||
bin,
|
||||
cmd.to_string()
|
||||
)
|
||||
.as_str(),
|
||||
);
|
||||
|
||||
.unwrap_or_else(|_| panic!("expected to find app info for {} ({})", bin, cmd));
|
||||
let empty_string = String::from("");
|
||||
|
||||
// just make sure all fields are populated
|
||||
|
|
Loading…
Add table
Reference in a new issue