Files
Graphite/desktop/ui/src/resources.rs
Timon ba0a97aefe Desktop: Isolate CEF-rendered UI into separate crate and process (#4321)
* Extract CEF rendered UI into a separate process and crate

* Review

* Review

* Review

* Review

* Remove necessary workarounds

* Block on frame copy ack

* Crop and resample frames correctly

* Skip blank frames

* Fix deps

* Fix fmt

* Fix clippy warning

* Review

* Fix todo
2026-07-14 14:51:20 -07:00

112 lines
3.2 KiB
Rust

use std::fs::File;
#[cfg(feature = "embedded_resources")]
use std::io;
use std::io::Read;
use std::path::{Component, PathBuf};
use std::sync::Arc;
#[derive(Clone)]
pub(crate) struct Resource {
pub(crate) reader: ResourceReader,
pub(crate) mimetype: Option<String>,
}
#[derive(Clone)]
pub(crate) enum ResourceReader {
#[cfg(feature = "embedded_resources")]
Embedded(io::Cursor<&'static [u8]>),
File(Arc<File>),
}
impl Read for ResourceReader {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self {
#[cfg(feature = "embedded_resources")]
ResourceReader::Embedded(cursor) => cursor.read(buf),
ResourceReader::File(file) => file.as_ref().read(buf),
}
}
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum WebResources {
Embedded,
External(PathBuf),
}
pub(crate) fn load(path: PathBuf) -> Option<Resource> {
if path.components().any(|component| matches!(component, Component::ParentDir)) {
tracing::error!("Rejected resource path with a parent directory component: {path:?}");
return None;
}
let resources = if cfg!(feature = "embedded_resources") {
WebResources::Embedded
} else {
match std::env::var("GRAPHITE_RESOURCES") {
Ok(dir) => WebResources::External(dir.into()),
Err(_) => {
tracing::error!("GRAPHITE_RESOURCES must point to the frontend assets when embedded resources are disabled");
return None;
}
}
};
let path = if path.as_os_str().is_empty() { PathBuf::from("index.html") } else { path };
let mimetype = match path.extension().and_then(|s| s.to_str()).unwrap_or("") {
"html" => Some("text/html".to_string()),
"css" => Some("text/css".to_string()),
"txt" => Some("text/plain".to_string()),
"wasm" => Some("application/wasm".to_string()),
"js" => Some("application/javascript".to_string()),
"png" => Some("image/png".to_string()),
"jpg" | "jpeg" => Some("image/jpeg".to_string()),
"svg" => Some("image/svg+xml".to_string()),
"xml" => Some("application/xml".to_string()),
"json" => Some("application/json".to_string()),
"ico" => Some("image/x-icon".to_string()),
"woff" => Some("font/woff".to_string()),
"woff2" => Some("font/woff2".to_string()),
"ttf" => Some("font/ttf".to_string()),
"otf" => Some("font/otf".to_string()),
"webmanifest" => Some("application/manifest+json".to_string()),
"graphite" => Some("application/graphite+json".to_string()),
_ => None,
};
match resources {
WebResources::Embedded => {
#[cfg(feature = "embedded_resources")]
{
if let Some(resources) = &graphite_desktop_embedded_resources::EMBEDDED_RESOURCES
&& let Some(file) = resources.get_file(&path)
{
return Some(Resource {
reader: ResourceReader::Embedded(io::Cursor::new(file.contents())),
mimetype,
});
}
None
}
#[cfg(not(feature = "embedded_resources"))]
{
tracing::error!("Embedded resources requested but the embedded_resources feature is disabled");
None
}
}
WebResources::External(dir) => {
let file_path = dir.join(path.strip_prefix("/").unwrap_or(&path));
if file_path.exists()
&& file_path.is_file()
&& let Ok(file) = std::fs::File::open(file_path)
{
return Some(Resource {
reader: ResourceReader::File(file.into()),
mimetype,
});
}
None
}
}
}