Add Linux parsers

This commit is contained in:
Bernd Schoolmann 2024-11-27 20:43:53 +01:00
parent c51e04b242
commit e3315c9372
1 changed files with 137 additions and 51 deletions

View File

@ -3,22 +3,60 @@ use base64::{prelude::BASE64_STANDARD, Engine};
use sysinfo::{Pid, System}; use sysinfo::{Pid, System};
pub fn get_info(pid: usize) -> Result<ApplicationInfo, anyhow::Error> { pub fn get_info(pid: usize) -> Result<ApplicationInfo, anyhow::Error> {
println!("[PeerInfo] Getting info for pid: {}", pid);
let s = System::new_all(); let s = System::new_all();
let file = std::fs::read_to_string(format!("/proc/{}/cgroup", pid))?; let scope = std::fs::read_to_string(format!("/proc/{}/cgroup", pid))?;
let process_name = s let process_name = s
.process(Pid::from(pid)) .process(Pid::from(pid))
.ok_or(anyhow::anyhow!("Pid not found"))? .ok_or(anyhow::anyhow!("Pid not found"))?
.name(); .name();
println!("process name {:?}", process_name);
let scope = file println!("[PeerInfo] Checking if is flatpak");
.split('/') if let Ok(appinfo) = flatpak_parser(scope.clone()) {
.last() println!("[PeerInfo] Is flatpak");
.ok_or(anyhow::anyhow!("No scope found"))? return Ok(appinfo)
.replace(".scope", ""); }
println!("scope {:?}", scope);
if scope.starts_with("app-flatpak") { println!("[PeerInfo] Checking if is snap");
if let Ok(appinfo) = snap_parser(scope.clone()) {
println!("[PeerInfo] Is snap");
return Ok(appinfo)
}
println!("[PeerInfo] Checking if is gnome app");
if let Ok(appinfo) = gnome_app_parser(scope) {
println!("[PeerInfo] Is gnome app");
return Ok(appinfo)
}
println!("[PeerInfo] Is not a recognized app");
return Ok(ApplicationInfo {
name: process_name
.to_str()
.ok_or(anyhow::anyhow!("Could not make path into string"))?
.to_string(),
path: None,
icon: None,
is_installed_app: false,
});
}
fn gnome_app_parser(scope: String) -> Result<ApplicationInfo, anyhow::Error> {
let part = scope.split("/").find(|s| s.starts_with("app-gnome")).ok_or(anyhow::anyhow!("No gnome app found"))?;
let app_id = part.split('-').nth(2).ok_or(anyhow::anyhow!("No app id found"))?;
let desktop_file = parse_desktop_file(format!("/usr/share/applications/{}.desktop", app_id).as_str())?;
let icon = find_unsandboxed_icon(&desktop_file.icon_name);
return Ok(ApplicationInfo {
name: desktop_file.name,
path: None,
icon,
is_installed_app: true,
});
}
fn flatpak_parser(scope: String) -> Result<ApplicationInfo, anyhow::Error> {
let part = scope.split("/").find(|s| s.starts_with("app-flatpak"));
if let Some(scope) = part {
let app_id = scope let app_id = scope
.split('-') .split('-')
.nth(2) .nth(2)
@ -38,28 +76,22 @@ pub fn get_info(pid: usize) -> Result<ApplicationInfo, anyhow::Error> {
"/var/lib/flatpak/app/{}/current/active/export/share/icons/hicolor/", "/var/lib/flatpak/app/{}/current/active/export/share/icons/hicolor/",
app_id app_id
); );
let scalable = try_read_icon(&format!("{}/scalable/apps/{}.svg", path, app_id)); let scalable = read_icon(&format!("{}/scalable/apps/{}.svg", path, app_id));
if scalable.is_some() { if let Some(icon) = scalable {
let base64 = BASE64_STANDARD.encode(scalable.unwrap());
return Ok(ApplicationInfo { return Ok(ApplicationInfo {
name: name.to_string(), name: name.to_string(),
path: Some(path), path: Some(path),
icon: Some(format!("data:image/svg+xml;base64,{}", base64)), icon: Some(icon),
is_installed_app: true, is_installed_app: true,
}); });
} else { } else {
for size in vec![512, 256, 128, 64] { for size in vec![512, 256, 128, 64] {
let icon = let icon = read_icon(&format!("{}/{}x{}/apps/{}.png", path, size, size, app_id));
try_read_icon(&format!("{}/{}x{}/apps/{}.png", path, size, size, app_id)); if let Some(icon) = icon {
if icon.is_some() {
return Ok(ApplicationInfo { return Ok(ApplicationInfo {
name: name.to_string(), name: name.to_string(),
path: Some(path), path: Some(path),
icon: Some(format!( icon: Some(icon),
"data:image/png;base64,{}",
BASE64_STANDARD.encode(icon.unwrap())
)),
is_installed_app: true, is_installed_app: true,
}); });
} }
@ -67,49 +99,103 @@ pub fn get_info(pid: usize) -> Result<ApplicationInfo, anyhow::Error> {
} }
} }
if scope.starts_with("snap.") { return Err(anyhow::anyhow!("Not a flatpak app"));
}
fn snap_parser(scope: String) -> Result<ApplicationInfo, anyhow::Error> {
let part = scope.split("/").find(|s| s.starts_with("snap."));
if let Some(scope) = part {
let app_id = scope let app_id = scope
.split('.') .split('.')
.nth(1) .nth(1)
.ok_or(anyhow::anyhow!("Failed to parse snap appid"))?; .ok_or(anyhow::anyhow!("Failed to parse snap appid"))?;
let desktop_file = std::fs::read_to_string(format!(
"/var/lib/snapd/desktop/applications/{}_{}.desktop", let desktop_file = parse_desktop_file(format!("/var/lib/snapd/desktop/applications/{}_{}.desktop", app_id, app_id).as_str())?;
app_id, app_id let name = desktop_file.name;
))?; let icon = read_icon(&desktop_file.icon_name);
let name = desktop_file let icon = if let Some(icon) = icon {
.lines() Some(icon)
.find(|line| line.starts_with("Name=")) } else {
.ok_or(anyhow::anyhow!( None
"Name of application in desktop file not found" };
))?
.split('=')
.last()
.ok_or(anyhow::anyhow!(
"Failed to parse desktop file application name"
))?;
return Ok(ApplicationInfo { return Ok(ApplicationInfo {
name: name.to_string(), name: name.to_string(),
path: None, path: None,
icon: None, icon,
is_installed_app: true, is_installed_app: true,
}); });
} }
return Ok(ApplicationInfo { return Err(anyhow::anyhow!("Not a snap app"));
name: process_name
.to_str()
.ok_or(anyhow::anyhow!("Could not make path into string"))?
.to_string(),
path: None,
icon: None,
is_installed_app: false,
});
} }
fn try_read_icon(path: &str) -> Option<Vec<u8>> {
let icon = std::fs::read(path); fn find_unsandboxed_icon(app_name: &str) -> Option<String> {
if icon.is_ok() { let scalable = read_icon(&format!("/usr/share/icons/hicolor/scalable/apps/{}.svg", app_name));
return Some(icon.unwrap()); if let Some(scalable) = scalable {
println!("[PeerInfo] Found scalable icon: {}", scalable);
return Some(scalable);
}
let paths = vec![
"/usr/share/icons/hicolor/512x512/apps",
"/usr/share/icons/hicolor/256x256/apps",
"/usr/share/icons/hicolor/128x128/apps",
"/usr/share/icons/hicolor/64x64/apps",
"/usr/share/pixmaps",
];
for path in paths {
println!("[PeerInfo] Chceking path for icon: {}", path);
if let Some(icon) = read_icon(&format!("{}/{}.png", path, app_name)) {
println!("[PeerInfo] Found icon: {}", icon);
return Some(icon);
}
}
println!("[PeerInfo] Icon not found");
None
}
fn read_icon(path: &str) -> Option<String> {
// ends with .svg
if path.ends_with(".svg") {
let icon = std::fs::read(path);
if icon.is_ok() {
return Some("data:image/svg+xml;base64,".to_string() + &BASE64_STANDARD.encode(icon.unwrap()));
}
} else if path.ends_with(".png") {
let icon = std::fs::read(path);
if icon.is_ok() {
return Some("data:image/png;base64,".to_string() + &BASE64_STANDARD.encode(icon.unwrap()));
}
} }
None None
} }
#[derive(Debug)]
struct DesktopFile {
name: String,
icon_name: String,
}
fn parse_desktop_file(path: &str) -> Result<DesktopFile, anyhow::Error> {
let desktop_file = std::fs::read_to_string(path).unwrap();
let name = desktop_file
.lines()
.find(|line| line.starts_with("Name="))
.ok_or(anyhow::anyhow!("Name not found"))?
.split('=')
.nth(1)
.ok_or(anyhow::anyhow!("Name not found"))?;
let icon = desktop_file
.lines()
.find(|line| line.starts_with("Icon="))
.ok_or(anyhow::anyhow!("Icon not found"))?
.split('=')
.nth(1)
.ok_or(anyhow::anyhow!("Icon not found"))?;
return Ok(DesktopFile {
name: name.to_string(),
icon_name: icon.to_string(),
});
}