CacheIO#
A flexible file-based caching library for OCaml with XDG Base Directory support, TTL-based expiration, and built-in cmdliner integration.
Features#
- File-based and Memory Storage: Choose between persistent file storage or fast in-memory caching
- XDG Compliance: Follows XDG Base Directory specification for cache locations
- TTL-based Expiration: Automatic expiration of cached entries
- JSON Support: Built-in JSON serialization/deserialization
- Hierarchical Keys: Support for path-like cache keys
- Cmdliner Integration: Ready-to-use command-line options for cache management
- Thread-safe: Safe concurrent access using Eio mutexes
- Statistics: Track cache hits, misses, size, and entry count
Installation#
opam install cacheio
Or add to your dune-project:
(package
(name myapp)
(depends
cacheio
...))
Basic Usage#
open Cacheio
let main () =
Eio_main.run @@ fun env ->
(* Create file-based cache *)
let base_dir = Eio.Path.(Eio.Stdenv.fs env / "/tmp/cache") in
let storage = FileStorage.create ~base_dir ~app_name:"myapp" () in
let cache = create ~storage:(`File storage) in
(* Store and retrieve data *)
put cache ~key:"user:123" ~data:"John Doe" ~ttl:3600.0;
match get cache ~key:"user:123" with
| Some data -> Printf.printf "Found: %s\n" data
| None -> Printf.printf "Not found or expired\n"
JSON Support#
(* Store JSON data *)
let user_data = `Assoc [
("id", `Int 123);
("name", `String "John Doe");
("email", `String "john@example.com")
] in
put_json cache ~key:"user:123" ~data:user_data ~ttl:3600.0;
(* Retrieve and parse JSON *)
match get_json cache ~key:"user:123" with
| Some json -> (* Handle JSON data *)
| None -> (* Handle cache miss *)
Hierarchical Keys#
(* Build structured cache keys *)
let key = make_key ["github"; "ocaml"; "ocaml"; "issues"; "1234"] in
(* Results in: "github/ocaml/ocaml/issues/1234" *)
(* Split keys back into components *)
let components = split_key key in
(* Returns: ["github"; "ocaml"; "ocaml"; "issues"; "1234"] *)
Cmdliner Integration#
Add cache management options to your CLI application:
open Cmdliner
let main cache_config =
Eio_main.run @@ fun env ->
(* Setup cache with CLI configuration *)
match Cacheio.Cmdliner.setup_cache ~env ~app_name:"myapp" ~config:cache_config with
| None -> print_endline "Caching disabled"
| Some cache ->
(* Use cache in your application *)
...
let cmd =
let doc = "My application with caching" in
let info = Cmd.info "myapp" ~doc in
Cmd.v info Term.(const main $ Cacheio.Cmdliner.cache_config)
let () = exit (Cmd.eval cmd)
This provides the following CLI options:
--cache-dir DIR: Override cache directory--no-cache: Disable caching--cache-clear: Clear cache before running--cache-stats: Show cache statistics--cache-max-age HOURS: Set maximum cache age
XDG Support#
The library follows XDG Base Directory specification:
(* Get standard directories using the xdg library *)
let xdg = Xdg.create ~env:Sys.getenv_opt () in
let cache_home = Xdg.cache_dir xdg in
(* Returns: $XDG_CACHE_HOME or ~/.cache *)
let app_cache = Filename.concat (Xdg.cache_dir xdg) "myapp" in
(* Returns: $XDG_CACHE_HOME/myapp or ~/.cache/myapp *)
Memory Storage#
For temporary caching without disk persistence:
let storage = MemoryStorage.create ~max_entries:1000 () in
let cache = create ~storage:(`Memory storage) in
(* Use same interface as file storage *)
put cache ~key:"temp" ~data:"value" ~ttl:60.0
Statistics#
Monitor cache performance:
let stats = stats cache in
Printf.printf "Cache hits: %d\n" stats.hits;
Printf.printf "Cache misses: %d\n" stats.misses;
Printf.printf "Total size: %s\n" (format_size stats.size);
Printf.printf "Entries: %d\n" stats.entries
Integration with Requests Library#
The cacheio library can be used with the requests library for HTTP caching:
(* In requests library *)
module Cache = struct
type 'a t = Cacheio.t
let create ~max_size:_ () =
let storage = Cacheio.MemoryStorage.create ~max_entries:max_size () in
Cacheio.create ~storage:(`Memory storage)
let get t ~method_ ~url ~headers:_ =
if method_ = `GET then
match Cacheio.get t ~key:(Uri.to_string url) with
| Some data ->
(* Deserialize response *)
Some (deserialize_response data)
| None -> None
else None
let put t ~method_ ~url ~response =
if method_ = `GET && Response.is_success response then
let data = serialize_response response in
Cacheio.put t ~key:(Uri.to_string url) ~data ~ttl:3600.0
end
License#
MIT