feat(cache): Caching objects which use the useObject tauri command

This commit is contained in:
quexeky
2025-02-09 21:25:09 +11:00
parent 5c479cb283
commit b9df197534
2 changed files with 96 additions and 37 deletions

View File

@ -41,10 +41,12 @@ use log4rs::Config;
use process::commands::{kill_game, launch_game}; use process::commands::{kill_game, launch_game};
use process::process_manager::ProcessManager; use process::process_manager::ProcessManager;
use remote::auth::{self, generate_authorization_header, recieve_handshake}; use remote::auth::{self, generate_authorization_header, recieve_handshake};
use remote::cache::{cache_object, fetch_object, fetch_object_offline, get_cached_object, ObjectCache};
use remote::commands::{ use remote::commands::{
auth_initiate, fetch_drop_object, gen_drop_url, manual_recieve_handshake, retry_connect, sign_out, use_remote auth_initiate, fetch_drop_object, gen_drop_url, manual_recieve_handshake, retry_connect, sign_out, use_remote
}; };
use remote::requests::make_request; use remote::requests::make_request;
use reqwest::blocking::Body;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::env; use std::env;
use std::path::Path; use std::path::Path;
@ -358,35 +360,9 @@ pub fn run() {
Ok(()) Ok(())
}) })
.register_asynchronous_uri_scheme_protocol("object", move |_ctx, request, responder| { .register_asynchronous_uri_scheme_protocol("object", move |ctx, request, responder| {
// Drop leading / let state: tauri::State<'_, Mutex<AppState>> = ctx.app_handle().state();
let object_id = &request.uri().path()[1..]; offline!(state, fetch_object, fetch_object_offline, request, responder);
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| {
f.header("Authorization", header)
})
.unwrap()
.send();
if response.is_err() {
warn!(
"failed to fetch object with error: {}",
response.err().unwrap()
);
responder.respond(Response::builder().status(500).body(Vec::new()).unwrap());
return;
}
let response = response.unwrap();
let resp_builder = ResponseBuilder::new().header(
CONTENT_TYPE,
response.headers().get("Content-Type").unwrap(),
);
let data = Vec::from(response.bytes().unwrap());
let resp = resp_builder.body(data).unwrap();
responder.respond(resp);
}) })
.on_window_event(|window, event| { .on_window_event(|window, event| {
if let WindowEvent::CloseRequested { api, .. } = event { if let WindowEvent::CloseRequested { api, .. } = event {

View File

@ -1,8 +1,10 @@
use cacache::Integrity;
use serde::{de::DeserializeOwned, Serialize};
use crate::{database::db::borrow_db_checked, error::remote_access_error::RemoteAccessError}; use crate::{database::db::borrow_db_checked, error::remote_access_error::RemoteAccessError};
use cacache::Integrity;
use http::{header::CONTENT_TYPE, response::Builder as ResponseBuilder, Response};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tauri::{UriSchemeContext, UriSchemeResponder};
use super::{auth::generate_authorization_header, requests::make_request};
#[macro_export] #[macro_export]
macro_rules! offline { macro_rules! offline {
@ -16,12 +18,93 @@ macro_rules! offline {
} }
} }
pub fn cache_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(key: K, data: &D) -> Result<Integrity, RemoteAccessError> { pub fn cache_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(
key: K,
data: &D,
) -> Result<Integrity, RemoteAccessError> {
let bytes = serde_json::to_vec(data).unwrap(); let bytes = serde_json::to_vec(data).unwrap();
cacache::write_sync(&borrow_db_checked().cache_dir, key, bytes).map_err(|e| RemoteAccessError::Cache(e)) cacache::write_sync(&borrow_db_checked().cache_dir, key, bytes)
.map_err(|e| RemoteAccessError::Cache(e))
} }
pub fn get_cached_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(key: K) -> Result<D, RemoteAccessError> { pub fn get_cached_object<'a, K: AsRef<str>, D: Serialize + DeserializeOwned>(
let bytes = cacache::read_sync(&borrow_db_checked().cache_dir, key).map_err(|e| RemoteAccessError::Cache(e))?; key: K,
) -> Result<D, RemoteAccessError> {
let bytes = cacache::read_sync(&borrow_db_checked().cache_dir, key)
.map_err(|e| RemoteAccessError::Cache(e))?;
let data = serde_json::from_slice::<D>(&bytes).unwrap(); let data = serde_json::from_slice::<D>(&bytes).unwrap();
Ok(data) Ok(data)
} }
pub fn fetch_object(
request: http::Request<Vec<u8>>,
responder: UriSchemeResponder,
) {
// Drop leading /
let object_id = &request.uri().path()[1..];
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| {
f.header("Authorization", header)
})
.unwrap()
.send();
if response.is_err() {
let data = get_cached_object::<&str, ObjectCache>(object_id);
match data {
Ok(data) => responder.respond(data.into()),
Err(_) => todo!(),
}
return;
}
let response = response.unwrap();
let resp_builder = ResponseBuilder::new().header(
CONTENT_TYPE,
response.headers().get("Content-Type").unwrap(),
);
let data = Vec::from(response.bytes().unwrap());
let resp = resp_builder.body(data).unwrap();
cache_object::<&str, ObjectCache>(object_id, &resp.clone().into()).unwrap();
responder.respond(resp);
}
pub fn fetch_object_offline(
request: http::Request<Vec<u8>>,
responder: UriSchemeResponder,
) {
let object_id = &request.uri().path()[1..];
let data = get_cached_object::<&str, ObjectCache>(object_id);
match data {
Ok(data) => responder.respond(data.into()),
Err(_) => todo!(),
}
}
#[derive(Serialize, Deserialize)]
pub struct ObjectCache {
content_type: String,
body: Vec<u8>,
}
impl From<Response<Vec<u8>>> for ObjectCache {
fn from(value: Response<Vec<u8>>) -> Self {
ObjectCache {
content_type: value
.headers()
.get(CONTENT_TYPE)
.unwrap()
.to_str()
.unwrap()
.to_owned(),
body: value.body().clone(),
}
}
}
impl From<ObjectCache> for Response<Vec<u8>> {
fn from(value: ObjectCache) -> Self {
let resp_builder = ResponseBuilder::new().header(CONTENT_TYPE, value.content_type);
resp_builder.body(value.body).unwrap()
}
}