Getting to work on caching
This commit is contained in:
parent
b90f65d713
commit
ae7d3f7123
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@
|
||||
|
||||
# direnv cache (should not be committed)
|
||||
.direnv/
|
||||
waycast_cache
|
||||
|
152
Cargo.lock
generated
152
Cargo.lock
generated
@ -38,6 +38,35 @@ dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
|
||||
dependencies = [
|
||||
"bincode_derive",
|
||||
"serde",
|
||||
"unty",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bincode_derive"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf95709a440f45e986983918d0e8a1f30a9b1df04918fc828670606804ac3c09"
|
||||
dependencies = [
|
||||
"virtue",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.9.3"
|
||||
@ -110,6 +139,22 @@ version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "field-offset"
|
||||
version = "0.3.6"
|
||||
@ -249,7 +294,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.4+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -552,6 +609,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.27"
|
||||
@ -589,7 +652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@ -602,6 +665,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "option-ext"
|
||||
version = "0.2.0"
|
||||
@ -677,13 +746,28 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "r-efi"
|
||||
version = "5.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||
|
||||
[[package]]
|
||||
name = "redb"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3fefa3e5ff4a369819c3d6df4195873d6f9abad109f13c0d505dbe119cfabb10"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.16",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
]
|
||||
@ -703,6 +787,19 @@ dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
@ -789,6 +886,19 @@ version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.16"
|
||||
@ -875,12 +985,24 @@ version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "unty"
|
||||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
|
||||
|
||||
[[package]]
|
||||
name = "virtue"
|
||||
version = "0.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "051eb1abcf10076295e815102942cc58f9d5e3b4560e46e53c21e8ff6f3af7b1"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
@ -897,18 +1019,36 @@ version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.4+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a"
|
||||
dependencies = [
|
||||
"wit-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "waycast-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode 1.3.3",
|
||||
"redb",
|
||||
"serde",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "waycast-gtk"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bincode 2.0.1",
|
||||
"gio",
|
||||
"glib",
|
||||
"gtk4",
|
||||
"gtk4-layer-shell",
|
||||
"redb",
|
||||
"serde",
|
||||
"waycast-core",
|
||||
"waycast-plugins",
|
||||
]
|
||||
@ -1106,6 +1246,12 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen"
|
||||
version = "0.45.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36"
|
||||
|
||||
[[package]]
|
||||
name = "xml-rs"
|
||||
version = "0.8.27"
|
||||
|
84
tmp.txt
84
tmp.txt
@ -1,84 +0,0 @@
|
||||
cargo run -p waycast-gtk
|
||||
/home/javi/projects/homelab-ansible
|
||||
/home/javi/projects/gla-old
|
||||
/home/javi/projects/filebrowser-agent
|
||||
/home/javi/projects/ttrpg-cms
|
||||
/home/javi/projects/desktop-setup
|
||||
/home/javi/projects/ravensofravnica.stream
|
||||
/home/javi/projects/nix
|
||||
/home/javi/projects/demos
|
||||
/home/javi/projects/resumeforge.app
|
||||
/home/javi/projects/videos
|
||||
/home/javi/projects/authentikate.dev
|
||||
/home/javi/projects/blogimage.app
|
||||
/home/javi/projects/arch-hyprland-setup
|
||||
/home/javi/projects/laravel-dockerized
|
||||
/home/javi/projects/alex-nix-config
|
||||
/home/javi/projects/thegrind-tools
|
||||
/home/javi/projects/imgsrc-app
|
||||
/home/javi/projects/scripthost
|
||||
/home/javi/projects/foundryvtt-docker
|
||||
/home/javi/projects/launchlet.app
|
||||
/home/javi/projects/yourfluence.dev
|
||||
/home/javi/projects/thegrind.dev
|
||||
/home/javi/projects/opnsensebackup
|
||||
/home/javi/projects/project-picker
|
||||
/home/javi/projects/thegrind.dev-old-jigsaw
|
||||
/home/javi/projects/og-cli
|
||||
/home/javi/projects/do-flow
|
||||
/home/javi/projects/carti-python
|
||||
/home/javi/projects/rack-planner
|
||||
/home/javi/projects/ember-db
|
||||
/home/javi/projects/local-ai
|
||||
/home/javi/projects/zap
|
||||
/home/javi/projects/flowtodo
|
||||
/home/javi/projects/temp
|
||||
/home/javi/projects/blog-backup
|
||||
/home/javi/projects/javierfeliz.com
|
||||
/home/javi/projects/thc-demo
|
||||
/home/javi/projects/crawler-linkedin
|
||||
/home/javi/projects/vikunja-planka-transfer
|
||||
/home/javi/projects/desktop-backup
|
||||
/home/javi/projects/authentikate
|
||||
/home/javi/projects/scratchfl.com
|
||||
/home/javi/projects/cs-trade-bot
|
||||
/home/javi/projects/leetcode
|
||||
/home/javi/projects/screenshotter
|
||||
/home/javi/projects/docker-compose-builder
|
||||
/home/javi/projects/javif89
|
||||
/home/javi/projects/papibot
|
||||
/home/javi/projects/crypt
|
||||
/home/javi/projects/analysis
|
||||
/home/javi/projects/go-starter-kit
|
||||
/home/javi/projects/vue3-learning
|
||||
/home/javi/projects/homelab-docker
|
||||
/home/javi/projects/sitemapper
|
||||
/home/javi/projects/dotnet-deployment-ansible
|
||||
/home/javi/projects/planka
|
||||
/home/javi/projects/waycast-cpp
|
||||
/home/javi/projects/hubspot-assessment
|
||||
/home/javi/projects/go-doit
|
||||
/home/javi/projects/alex-demo
|
||||
/home/javi/projects/docker-laravel-base
|
||||
/home/javi/projects/staticforge
|
||||
/home/javi/projects/jigsaw
|
||||
/home/javi/projects/theresaleconcierge
|
||||
/home/javi/projects/nico-stuff
|
||||
/home/javi/projects/zold-javierfeliz.com
|
||||
/home/javi/projects/ansible-starter-kit
|
||||
/home/javi/projects/oidctester
|
||||
/home/javi/projects/waycast
|
||||
/home/javi/projects/ubuntu-setup
|
||||
/home/javi/projects/caddy-test
|
||||
/home/javi/projects/dotfiles
|
||||
/home/javi/projects/bazzitouchedhisconfig.dev
|
||||
/home/javi/projects/cs2-server-manager
|
||||
/home/javi/projects/noconfig
|
||||
/home/javi/projects/gamelineanalytics.com
|
||||
/home/javi/projects/thegrind-de
|
||||
/home/javi/projects/data-parser
|
||||
/home/javi/projects/test-dotnet-blazor-project
|
||||
/home/javi/projects/homies
|
||||
/home/javi/projects/ogimage-click
|
||||
/home/javi/projects/ansible-on-prem
|
||||
Projects plugin: Found 82 projects
|
@ -4,4 +4,10 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.3"
|
||||
redb = "3.0.1"
|
||||
serde = { version = "1.0.219", features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.21.0"
|
||||
# No dependencies for core traits and launcher logic
|
50
waycast-core/src/cache/errors.rs
vendored
Normal file
50
waycast-core/src/cache/errors.rs
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
use redb::{CommitError, DatabaseError, StorageError, TableError, TransactionError};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CacheError {
|
||||
DatabaseError(String),
|
||||
SerializationError(String),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl From<DatabaseError> for CacheError {
|
||||
fn from(err: DatabaseError) -> Self {
|
||||
CacheError::DatabaseError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TransactionError> for CacheError {
|
||||
fn from(err: TransactionError) -> Self {
|
||||
CacheError::DatabaseError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TableError> for CacheError {
|
||||
fn from(err: TableError) -> Self {
|
||||
CacheError::DatabaseError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StorageError> for CacheError {
|
||||
fn from(err: StorageError) -> Self {
|
||||
CacheError::DatabaseError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CommitError> for CacheError {
|
||||
fn from(err: CommitError) -> Self {
|
||||
CacheError::DatabaseError(err.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CacheError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
CacheError::DatabaseError(e) => write!(f, "Database error: {}", e),
|
||||
CacheError::SerializationError(e) => write!(f, "Serialization error: {}", e),
|
||||
CacheError::Other(msg) => write!(f, "Cache error: {}", msg),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for CacheError {}
|
236
waycast-core/src/cache/mod.rs
vendored
Normal file
236
waycast-core/src/cache/mod.rs
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
pub mod errors;
|
||||
use redb::{Database, ReadableDatabase, ReadableTable, TableDefinition};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use std::time::{Duration, SystemTime};
|
||||
|
||||
use crate::cache::errors::CacheError;
|
||||
|
||||
const CACHE_TABLE: TableDefinition<&str, &[u8]> = TableDefinition::new("cache");
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct CacheEntry<T> {
|
||||
data: T,
|
||||
expires_at: Option<SystemTime>,
|
||||
}
|
||||
|
||||
pub struct Cache {
|
||||
db: Database,
|
||||
}
|
||||
|
||||
pub fn new<P: AsRef<Path>>(db_path: P) -> Result<Cache, CacheError> {
|
||||
let db = Database::create(db_path)?;
|
||||
|
||||
// Initialize the table if it doesn't exist
|
||||
let write_txn = db.begin_write()?;
|
||||
{
|
||||
let _ = write_txn.open_table(CACHE_TABLE)?;
|
||||
}
|
||||
write_txn.commit()?;
|
||||
|
||||
Ok(Cache { db })
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
/// Cache a value with an optional TTL. If TTL is None, the value never expires.
|
||||
pub fn remember_with_ttl<T>(
|
||||
&self,
|
||||
key: &str,
|
||||
ttl: Option<Duration>,
|
||||
compute: impl FnOnce() -> T,
|
||||
) -> Result<T, CacheError>
|
||||
where
|
||||
T: Serialize + DeserializeOwned + Clone,
|
||||
{
|
||||
// Try to get from cache first
|
||||
if let Some(entry) = self.get_cached_entry::<T>(key)? {
|
||||
// Check if entry has expired
|
||||
if let Some(expires_at) = entry.expires_at {
|
||||
if SystemTime::now() < expires_at {
|
||||
println!("Cache hit");
|
||||
return Ok(entry.data);
|
||||
}
|
||||
// Entry has expired, continue to recompute
|
||||
} else {
|
||||
// No expiration, return cached data
|
||||
return Ok(entry.data);
|
||||
}
|
||||
}
|
||||
|
||||
println!("Cache miss");
|
||||
|
||||
// Not in cache or expired, compute the value
|
||||
let data = compute();
|
||||
let expires_at = ttl.map(|duration| SystemTime::now() + duration);
|
||||
let entry = CacheEntry {
|
||||
data: data.clone(),
|
||||
expires_at,
|
||||
};
|
||||
|
||||
// Store in cache
|
||||
self.store_entry(key, &entry)?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
/// Cache a value with no expiration
|
||||
pub fn remember<T>(&self, key: &str, compute: impl FnOnce() -> T) -> Result<T, CacheError>
|
||||
where
|
||||
T: Serialize + DeserializeOwned + Clone,
|
||||
{
|
||||
self.remember_with_ttl(key, None, compute)
|
||||
}
|
||||
|
||||
/// Get a cached value if it exists and hasn't expired
|
||||
pub fn get<T>(&self, key: &str) -> Result<Option<T>, CacheError>
|
||||
where
|
||||
T: Serialize + DeserializeOwned,
|
||||
{
|
||||
if let Some(entry) = self.get_cached_entry::<T>(key)? {
|
||||
// Check if entry has expired
|
||||
if let Some(expires_at) = entry.expires_at {
|
||||
if SystemTime::now() < expires_at {
|
||||
return Ok(Some(entry.data));
|
||||
}
|
||||
// Entry has expired, remove it and return None
|
||||
self.forget(key)?;
|
||||
return Ok(None);
|
||||
} else {
|
||||
// No expiration, return cached data
|
||||
return Ok(Some(entry.data));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Store a value in the cache with optional TTL
|
||||
pub fn put<T>(&self, key: &str, value: T, ttl: Option<Duration>) -> Result<(), CacheError>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let expires_at = ttl.map(|duration| SystemTime::now() + duration);
|
||||
let entry = CacheEntry {
|
||||
data: value,
|
||||
expires_at,
|
||||
};
|
||||
self.store_entry(key, &entry)
|
||||
}
|
||||
|
||||
/// Remove a key from the cache
|
||||
pub fn forget(&self, key: &str) -> Result<(), CacheError> {
|
||||
let write_txn = self.db.begin_write()?;
|
||||
{
|
||||
let mut table = write_txn.open_table(CACHE_TABLE)?;
|
||||
table.remove(key)?;
|
||||
}
|
||||
write_txn.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Clear all cached entries
|
||||
pub fn clear(&self) -> Result<(), CacheError> {
|
||||
let write_txn = self.db.begin_write()?;
|
||||
{
|
||||
let mut table = write_txn.open_table(CACHE_TABLE)?;
|
||||
// Remove all entries
|
||||
let keys: Vec<String> = {
|
||||
let mut keys = Vec::new();
|
||||
let mut iter = table.iter()?;
|
||||
while let Some(Ok((key, _))) = iter.next() {
|
||||
keys.push(key.value().to_string());
|
||||
}
|
||||
keys
|
||||
};
|
||||
|
||||
for key in keys {
|
||||
table.remove(key.as_str())?;
|
||||
}
|
||||
}
|
||||
write_txn.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_cached_entry<T>(&self, key: &str) -> Result<Option<CacheEntry<T>>, CacheError>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
let read_txn = self.db.begin_read()?;
|
||||
let table = read_txn.open_table(CACHE_TABLE)?;
|
||||
|
||||
if let Some(cached_bytes) = table.get(key)? {
|
||||
match bincode::deserialize::<CacheEntry<T>>(cached_bytes.value()) {
|
||||
Ok(entry) => Ok(Some(entry)),
|
||||
Err(_) => {
|
||||
// Failed to deserialize, probably corrupted or wrong format
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn store_entry<T>(&self, key: &str, entry: &CacheEntry<T>) -> Result<(), CacheError>
|
||||
where
|
||||
T: Serialize,
|
||||
{
|
||||
let write_txn = self.db.begin_write()?;
|
||||
{
|
||||
let mut table = write_txn.open_table(CACHE_TABLE)?;
|
||||
let serialized = bincode::serialize(entry)
|
||||
.map_err(|e| CacheError::SerializationError(e.to_string()))?;
|
||||
table.insert(key, serialized.as_slice())?;
|
||||
}
|
||||
write_txn.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::time::Duration;
|
||||
use tempfile::NamedTempFile;
|
||||
|
||||
#[test]
|
||||
fn test_cache_remember() {
|
||||
let temp_file = NamedTempFile::new().unwrap();
|
||||
let cache = Cache::new(temp_file.path()).unwrap();
|
||||
|
||||
let result = cache
|
||||
.remember("test_key", || "computed_value".to_string())
|
||||
.unwrap();
|
||||
assert_eq!(result, "computed_value");
|
||||
|
||||
// Second call should return cached value
|
||||
let result2 = cache
|
||||
.remember("test_key", || "different_value".to_string())
|
||||
.unwrap();
|
||||
assert_eq!(result2, "computed_value");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_ttl() {
|
||||
let temp_file = NamedTempFile::new().unwrap();
|
||||
let cache = Cache::new(temp_file.path()).unwrap();
|
||||
|
||||
// Cache with very short TTL
|
||||
let result = cache
|
||||
.remember_with_ttl("ttl_key", Some(Duration::from_millis(1)), || {
|
||||
"cached_value".to_string()
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(result, "cached_value");
|
||||
|
||||
// Wait for expiration
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
|
||||
// Should recompute after expiration
|
||||
let result2 = cache
|
||||
.remember_with_ttl("ttl_key", Some(Duration::from_millis(1)), || {
|
||||
"new_value".to_string()
|
||||
})
|
||||
.unwrap();
|
||||
assert_eq!(result2, "new_value");
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub mod cache;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LaunchError {
|
||||
CouldNotLaunch(String),
|
||||
|
@ -14,3 +14,6 @@ gio = "0.21.1"
|
||||
glib = "0.21.1"
|
||||
gtk = { version = "0.10.0", package = "gtk4" }
|
||||
gtk4-layer-shell = "0.6.1"
|
||||
redb = "3.0.1"
|
||||
serde = "1.0.219"
|
||||
bincode = "2.0.1"
|
||||
|
@ -1,50 +1,70 @@
|
||||
mod ui;
|
||||
mod util;
|
||||
use std::time::Duration;
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gtk::Application;
|
||||
use ui::gtk::GtkLauncherUI;
|
||||
use waycast_core::WaycastLauncher;
|
||||
use waycast_core::cache::Cache;
|
||||
|
||||
fn main() {
|
||||
let app = Application::builder()
|
||||
.application_id("dev.thegrind.waycast")
|
||||
.build();
|
||||
|
||||
app.connect_activate(|app| {
|
||||
let mut file_search_plugin = waycast_plugins::file_search::new();
|
||||
|
||||
if let Err(e) = file_search_plugin.add_search_path("/home/javi/working-files/DJ Music/") {
|
||||
eprintln!("{}", e)
|
||||
let cache: Cache;
|
||||
if let Ok(db) = waycast_core::cache::new("waycast_cache") {
|
||||
cache = db;
|
||||
} else {
|
||||
panic!("Failed to open database");
|
||||
}
|
||||
|
||||
let mut project_plugin = waycast_plugins::projects::new();
|
||||
if let Err(e) = project_plugin.add_search_path("/home/javi/projects") {
|
||||
eprintln!("{}", e)
|
||||
}
|
||||
|
||||
// Create the core launcher
|
||||
let launcher = WaycastLauncher::new()
|
||||
.add_plugin(Box::new(waycast_plugins::drun::new()))
|
||||
.add_plugin(Box::new(file_search_plugin))
|
||||
.add_plugin(Box::new(project_plugin))
|
||||
.init();
|
||||
|
||||
// Create and show the GTK UI
|
||||
let ui = GtkLauncherUI::new(app, launcher);
|
||||
|
||||
// Apply built-in default styles
|
||||
if let Err(e) = ui.apply_default_css() {
|
||||
eprintln!("Warning: Could not apply default styles: {}", e);
|
||||
}
|
||||
|
||||
// Optionally apply user CSS overrides
|
||||
// if let Err(_) = ui.apply_css("waycast.css") {
|
||||
// // Silently ignore if user hasn't provided custom CSS
|
||||
// }
|
||||
|
||||
ui.show();
|
||||
let result = cache.remember_with_ttl("test_key", Some(Duration::from_secs(10)), || {
|
||||
String::from("my cool string value")
|
||||
});
|
||||
|
||||
app.run();
|
||||
if let Ok(val) = result {
|
||||
println!("{}", val);
|
||||
}
|
||||
}
|
||||
// mod ui;
|
||||
// mod util;
|
||||
|
||||
// use gtk::prelude::*;
|
||||
// use gtk::Application;
|
||||
// use ui::gtk::GtkLauncherUI;
|
||||
// use waycast_core::WaycastLauncher;
|
||||
|
||||
// fn main() {
|
||||
// let app = Application::builder()
|
||||
// .application_id("dev.thegrind.waycast")
|
||||
// .build();
|
||||
|
||||
// app.connect_activate(|app| {
|
||||
// let mut file_search_plugin = waycast_plugins::file_search::new();
|
||||
|
||||
// if let Err(e) = file_search_plugin.add_search_path("/home/javi/working-files/DJ Music/") {
|
||||
// eprintln!("{}", e)
|
||||
// }
|
||||
|
||||
// let mut project_plugin = waycast_plugins::projects::new();
|
||||
// if let Err(e) = project_plugin.add_search_path("/home/javi/projects") {
|
||||
// eprintln!("{}", e)
|
||||
// }
|
||||
|
||||
// // Create the core launcher
|
||||
// let launcher = WaycastLauncher::new()
|
||||
// .add_plugin(Box::new(waycast_plugins::drun::new()))
|
||||
// .add_plugin(Box::new(file_search_plugin))
|
||||
// .add_plugin(Box::new(project_plugin))
|
||||
// .init();
|
||||
|
||||
// // Create and show the GTK UI
|
||||
// let ui = GtkLauncherUI::new(app, launcher);
|
||||
|
||||
// // Apply built-in default styles
|
||||
// if let Err(e) = ui.apply_default_css() {
|
||||
// eprintln!("Warning: Could not apply default styles: {}", e);
|
||||
// }
|
||||
|
||||
// // Optionally apply user CSS overrides
|
||||
// // if let Err(_) = ui.apply_css("waycast.css") {
|
||||
// // // Silently ignore if user hasn't provided custom CSS
|
||||
// // }
|
||||
|
||||
// ui.show();
|
||||
// });
|
||||
|
||||
// app.run();
|
||||
// }
|
||||
|
Loading…
x
Reference in New Issue
Block a user