Add caching to buffers

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/4/head
trivernis 3 years ago
parent bf6f50ecdd
commit 09c4776321

@ -29,11 +29,15 @@ pub async fn read_file_by_hash(
api_state: ApiAccess<'_>,
buffer_state: BufferAccess<'_>,
) -> PluginResult<String> {
let api = api_state.api().await?;
let content = api.file.read_file_by_hash(hash.clone()).await?;
let uri = add_once_buffer(buffer_state, hash, mime_type, content);
if buffer_state.reserve_entry(&hash) {
Ok(format!("once://{}", hash)) // entry has been cached
} else {
let api = api_state.api().await?;
let content = api.file.read_file_by_hash(hash.clone()).await?;
let uri = add_once_buffer(buffer_state, hash, mime_type, content);
Ok(uri)
Ok(uri)
}
}
#[tauri::command]
@ -54,9 +58,13 @@ pub async fn read_thumbnail(
api_state: ApiAccess<'_>,
buffer_state: BufferAccess<'_>,
) -> PluginResult<String> {
let api = api_state.api().await?;
let content = api.file.read_thumbnail(hash.clone()).await?;
let uri = add_once_buffer(buffer_state, hash, mime_type, content);
if buffer_state.reserve_entry(&hash) {
Ok(format!("once://{}", hash)) // entry has been cached
} else {
let api = api_state.api().await?;
let content = api.file.read_thumbnail(hash.clone()).await?;
let uri = add_once_buffer(buffer_state, hash, mime_type, content);
Ok(uri)
Ok(uri)
}
}

@ -4,7 +4,7 @@ pub use file::*;
pub use repo::*;
pub use tag::*;
use crate::tauri_plugin::state::{ApiState, AppState, BufferState, OnceBuffer};
use crate::tauri_plugin::state::{ApiState, AppState, BufferState, VolatileBuffer};
pub mod file;
pub mod repo;
@ -22,7 +22,7 @@ fn add_once_buffer(
buf: Vec<u8>,
) -> String {
let uri = format!("once://{}", key);
let once_buffer = OnceBuffer::new(mime, buf);
let once_buffer = VolatileBuffer::new(mime, buf);
let mut once_buffers = buffer_state.buffer.lock();
once_buffers.insert(key, once_buffer);

@ -6,10 +6,9 @@ pub fn register_custom_uri_schemes<R: Runtime>(builder: Builder<R>) -> Builder<R
builder.register_uri_scheme_protocol("once", |app, request| {
let buf_state = app.state::<BufferState>();
let resource_key = request.uri().trim_start_matches("once://");
let buffer = {
let mut buffers = buf_state.buffer.lock();
buffers.remove(resource_key)
};
let buffer = buf_state.get_entry(resource_key);
buf_state.clear_expired();
if let Some(buffer) = buffer {
ResponseBuilder::new()
.mimetype(&buffer.mime)

@ -1,9 +1,11 @@
use std::collections::HashMap;
use std::mem;
use std::sync::Arc;
use std::time::Duration;
use parking_lot::Mutex;
use tauri::async_runtime::RwLock;
use tokio::time::Instant;
use crate::client_api::ApiClient;
use crate::tauri_plugin::error::{PluginError, PluginResult};
@ -37,20 +39,75 @@ impl ApiState {
}
}
pub struct OnceBuffer {
#[derive(Clone)]
pub struct VolatileBuffer {
pub accessed: bool,
pub valid_until: Instant,
pub mime: String,
pub buf: Vec<u8>,
}
impl OnceBuffer {
impl VolatileBuffer {
pub fn new(mime: String, buf: Vec<u8>) -> Self {
Self { mime, buf }
Self {
accessed: false,
valid_until: Instant::now() + Duration::from_secs(60),
mime,
buf,
}
}
}
#[derive(Default)]
pub struct BufferState {
pub buffer: Arc<Mutex<HashMap<String, OnceBuffer>>>,
pub buffer: Arc<Mutex<HashMap<String, VolatileBuffer>>>,
}
impl BufferState {
/// Checks if an entry for the specific key exists and resets
/// its state so that it can safely be accessed again.
pub fn reserve_entry(&self, key: &String) -> bool {
let mut buffers = self.buffer.lock();
let entry = buffers.get_mut(key);
if let Some(entry) = entry {
entry.accessed = false; // reset that it has been accessed so it can be reused
true
} else {
false
}
}
/// Returns the cloned buffer entry and flags it for expiration
pub fn get_entry(&self, key: &str) -> Option<VolatileBuffer> {
let mut buffers = self.buffer.lock();
let entry = buffers.get_mut(key);
if let Some(entry) = entry {
entry.accessed = true;
entry.valid_until = Instant::now() + Duration::from_secs(10); // time to live is 10 seconds
Some(entry.clone())
} else {
None
}
}
/// Clears all expired entries
pub fn clear_expired(&self) {
let mut buffer = self.buffer.lock();
let keys: Vec<String> = buffer.keys().cloned().collect();
for key in keys {
let (accessed, valid_until) = {
let entry = buffer.get(&key).unwrap();
(entry.accessed, entry.valid_until.clone())
};
if accessed && valid_until < Instant::now() {
buffer.remove(&key);
}
}
}
}
pub struct AppState {

Loading…
Cancel
Save