Process manager fixes (#71)

* fix: launching on linux

* feat: #70

* feat: add dummy store page

* feat: add store redir and refresh button to library

* feat: cache first object fetching

* feat: Remove let_chains feature and update to Rust 2024

Signed-off-by: quexeky <git@quexeky.dev>

* feat: Check for if process was manually stopped

Signed-off-by: quexeky <git@quexeky.dev>

* fix: use bitcode instead of serde

* chore: remove logs

* fix: clippy

* fix: clippy 2

* fix: swap to stop icon

---------

Signed-off-by: quexeky <git@quexeky.dev>
Co-authored-by: quexeky <git@quexeky.dev>
This commit is contained in:
DecDuck
2025-07-25 10:44:40 +10:00
committed by GitHub
parent 7aee57038d
commit f0112ec027
26 changed files with 426 additions and 227 deletions
+43 -10
View File
@@ -1,11 +1,15 @@
use std::{
fmt::Display,
time::{Duration, SystemTime},
};
use crate::{
database::{db::borrow_db_checked, models::data::Database},
error::remote_access_error::RemoteAccessError,
};
use bitcode::{Decode, DecodeOwned, Encode};
use cacache::Integrity;
use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder, Response};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use serde_binary::binary_stream::Endian;
use http::{Response, header::CONTENT_TYPE, response::Builder as ResponseBuilder};
#[macro_export]
macro_rules! offline {
@@ -19,31 +23,48 @@ macro_rules! offline {
}
}
pub fn cache_object<K: AsRef<str>, D: Serialize + DeserializeOwned>(
pub fn cache_object<K: AsRef<str>, D: Encode>(
key: K,
data: &D,
) -> Result<Integrity, RemoteAccessError> {
let bytes = serde_binary::to_vec(data, Endian::Little).unwrap();
let bytes = bitcode::encode(data);
cacache::write_sync(&borrow_db_checked().cache_dir, key, bytes)
.map_err(RemoteAccessError::Cache)
}
pub fn get_cached_object<K: AsRef<str>, D: Serialize + DeserializeOwned>(
pub fn get_cached_object<K: AsRef<str> + Display, D: Encode + DecodeOwned>(
key: K,
) -> Result<D, RemoteAccessError> {
get_cached_object_db::<K, D>(key, &borrow_db_checked())
}
pub fn get_cached_object_db<K: AsRef<str>, D: Serialize + DeserializeOwned>(
pub fn get_cached_object_db<K: AsRef<str> + Display, D: DecodeOwned>(
key: K,
db: &Database,
) -> Result<D, RemoteAccessError> {
let bytes = cacache::read_sync(&db.cache_dir, key).map_err(RemoteAccessError::Cache)?;
let data = serde_binary::from_slice::<D>(&bytes, Endian::Little).unwrap();
let bytes = cacache::read_sync(&db.cache_dir, &key).map_err(RemoteAccessError::Cache)?;
let data = bitcode::decode::<D>(&bytes).map_err(|_| {
RemoteAccessError::Cache(cacache::Error::EntryNotFound(
db.cache_dir.clone(),
key.to_string(),
))
})?;
Ok(data)
}
#[derive(Serialize, Deserialize)]
#[derive(Encode, Decode)]
pub struct ObjectCache {
content_type: String,
body: Vec<u8>,
expiry: u128,
}
impl ObjectCache {
pub fn has_expired(&self) -> bool {
let duration = Duration::from_millis(self.expiry.try_into().unwrap());
SystemTime::UNIX_EPOCH
.checked_add(duration)
.unwrap()
.elapsed()
.is_err()
}
}
impl From<Response<Vec<u8>>> for ObjectCache {
@@ -57,6 +78,12 @@ impl From<Response<Vec<u8>>> for ObjectCache {
.unwrap()
.to_owned(),
body: value.body().clone(),
expiry: SystemTime::now()
.checked_add(Duration::from_days(1))
.unwrap()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_millis(),
}
}
}
@@ -66,3 +93,9 @@ impl From<ObjectCache> for Response<Vec<u8>> {
resp_builder.body(value.body).unwrap()
}
}
impl From<&ObjectCache> for Response<Vec<u8>> {
fn from(value: &ObjectCache) -> Self {
let resp_builder = ResponseBuilder::new().header(CONTENT_TYPE, value.content_type.clone());
resp_builder.body(value.body.clone()).unwrap()
}
}
+13 -5
View File
@@ -12,6 +12,14 @@ pub fn fetch_object(request: http::Request<Vec<u8>>, responder: UriSchemeRespond
// Drop leading /
let object_id = &request.uri().path()[1..];
let cache_result = get_cached_object::<&str, ObjectCache>(object_id);
if let Ok(cache_result) = &cache_result
&& !cache_result.has_expired()
{
responder.respond(cache_result.into());
return;
}
let header = generate_authorization_header();
let client: reqwest::blocking::Client = reqwest::blocking::Client::new();
let response = make_request(&client, &["/api/v1/client/object/", object_id], &[], |f| {
@@ -20,10 +28,8 @@ pub fn fetch_object(request: http::Request<Vec<u8>>, responder: UriSchemeRespond
.unwrap()
.send();
if response.is_err() {
let data = get_cached_object::<&str, ObjectCache>(object_id);
match data {
Ok(data) => responder.respond(data.into()),
match cache_result {
Ok(cache_result) => responder.respond(cache_result.into()),
Err(e) => {
warn!("{e}")
}
@@ -38,7 +44,9 @@ pub fn fetch_object(request: http::Request<Vec<u8>>, responder: UriSchemeRespond
);
let data = Vec::from(response.bytes().unwrap());
let resp = resp_builder.body(data).unwrap();
cache_object::<&str, ObjectCache>(object_id, &resp.clone().into()).unwrap();
if cache_result.is_err() || cache_result.unwrap().has_expired() {
cache_object::<&str, ObjectCache>(object_id, &resp.clone().into()).unwrap();
}
responder.respond(resp);
}
+1 -1
View File
@@ -3,6 +3,6 @@ pub mod auth;
pub mod cache;
pub mod commands;
pub mod fetch_object;
pub mod utils;
pub mod requests;
pub mod server_proto;
pub mod utils;
+1 -4
View File
@@ -33,10 +33,7 @@ pub fn handle_server_proto(request: Request<Vec<u8>>, responder: UriSchemeRespon
let whitelist_prefix = ["/store", "/api", "/_", "/fonts"];
if whitelist_prefix
.iter()
.all(|f| !path.starts_with(f))
{
if whitelist_prefix.iter().all(|f| !path.starts_with(f)) {
webbrowser::open(&new_uri.to_string()).unwrap();
return;
}