My agentic slop goes here. Not intended for anyone else!
1# CacheIO
2
3A flexible file-based caching library for OCaml with XDG Base Directory support, TTL-based expiration, and built-in cmdliner integration.
4
5## Features
6
7- **File-based and Memory Storage**: Choose between persistent file storage or fast in-memory caching
8- **XDG Compliance**: Follows XDG Base Directory specification for cache locations
9- **TTL-based Expiration**: Automatic expiration of cached entries
10- **JSON Support**: Built-in JSON serialization/deserialization
11- **Hierarchical Keys**: Support for path-like cache keys
12- **Cmdliner Integration**: Ready-to-use command-line options for cache management
13- **Thread-safe**: Safe concurrent access using Eio mutexes
14- **Statistics**: Track cache hits, misses, size, and entry count
15
16## Installation
17
18```bash
19opam install cacheio
20```
21
22Or add to your `dune-project`:
23
24```dune
25(package
26 (name myapp)
27 (depends
28 cacheio
29 ...))
30```
31
32## Basic Usage
33
34```ocaml
35open Cacheio
36
37let main () =
38 Eio_main.run @@ fun env ->
39
40 (* Create file-based cache *)
41 let base_dir = Eio.Path.(Eio.Stdenv.fs env / "/tmp/cache") in
42 let storage = FileStorage.create ~base_dir ~app_name:"myapp" () in
43 let cache = create ~storage:(`File storage) in
44
45 (* Store and retrieve data *)
46 put cache ~key:"user:123" ~data:"John Doe" ~ttl:3600.0;
47
48 match get cache ~key:"user:123" with
49 | Some data -> Printf.printf "Found: %s\n" data
50 | None -> Printf.printf "Not found or expired\n"
51```
52
53## JSON Support
54
55```ocaml
56(* Store JSON data *)
57let user_data = `Assoc [
58 ("id", `Int 123);
59 ("name", `String "John Doe");
60 ("email", `String "john@example.com")
61] in
62
63put_json cache ~key:"user:123" ~data:user_data ~ttl:3600.0;
64
65(* Retrieve and parse JSON *)
66match get_json cache ~key:"user:123" with
67| Some json -> (* Handle JSON data *)
68| None -> (* Handle cache miss *)
69```
70
71## Hierarchical Keys
72
73```ocaml
74(* Build structured cache keys *)
75let key = make_key ["github"; "ocaml"; "ocaml"; "issues"; "1234"] in
76(* Results in: "github/ocaml/ocaml/issues/1234" *)
77
78(* Split keys back into components *)
79let components = split_key key in
80(* Returns: ["github"; "ocaml"; "ocaml"; "issues"; "1234"] *)
81```
82
83## Cmdliner Integration
84
85Add cache management options to your CLI application:
86
87```ocaml
88open Cmdliner
89
90let main cache_config =
91 Eio_main.run @@ fun env ->
92
93 (* Setup cache with CLI configuration *)
94 match Cacheio.Cmdliner.setup_cache ~env ~app_name:"myapp" ~config:cache_config with
95 | None -> print_endline "Caching disabled"
96 | Some cache ->
97 (* Use cache in your application *)
98 ...
99
100let cmd =
101 let doc = "My application with caching" in
102 let info = Cmd.info "myapp" ~doc in
103 Cmd.v info Term.(const main $ Cacheio.Cmdliner.cache_config)
104
105let () = exit (Cmd.eval cmd)
106```
107
108This provides the following CLI options:
109- `--cache-dir DIR`: Override cache directory
110- `--no-cache`: Disable caching
111- `--cache-clear`: Clear cache before running
112- `--cache-stats`: Show cache statistics
113- `--cache-max-age HOURS`: Set maximum cache age
114
115## XDG Support
116
117The library follows XDG Base Directory specification:
118
119```ocaml
120(* Get standard directories using the xdg library *)
121let xdg = Xdg.create ~env:Sys.getenv_opt () in
122let cache_home = Xdg.cache_dir xdg in
123(* Returns: $XDG_CACHE_HOME or ~/.cache *)
124
125let app_cache = Filename.concat (Xdg.cache_dir xdg) "myapp" in
126(* Returns: $XDG_CACHE_HOME/myapp or ~/.cache/myapp *)
127```
128
129## Memory Storage
130
131For temporary caching without disk persistence:
132
133```ocaml
134let storage = MemoryStorage.create ~max_entries:1000 () in
135let cache = create ~storage:(`Memory storage) in
136
137(* Use same interface as file storage *)
138put cache ~key:"temp" ~data:"value" ~ttl:60.0
139```
140
141## Statistics
142
143Monitor cache performance:
144
145```ocaml
146let stats = stats cache in
147Printf.printf "Cache hits: %d\n" stats.hits;
148Printf.printf "Cache misses: %d\n" stats.misses;
149Printf.printf "Total size: %s\n" (format_size stats.size);
150Printf.printf "Entries: %d\n" stats.entries
151```
152
153## Integration with Requests Library
154
155The cacheio library can be used with the requests library for HTTP caching:
156
157```ocaml
158(* In requests library *)
159module Cache = struct
160 type 'a t = Cacheio.t
161
162 let create ~max_size:_ () =
163 let storage = Cacheio.MemoryStorage.create ~max_entries:max_size () in
164 Cacheio.create ~storage:(`Memory storage)
165
166 let get t ~method_ ~url ~headers:_ =
167 if method_ = `GET then
168 match Cacheio.get t ~key:(Uri.to_string url) with
169 | Some data ->
170 (* Deserialize response *)
171 Some (deserialize_response data)
172 | None -> None
173 else None
174
175 let put t ~method_ ~url ~response =
176 if method_ = `GET && Response.is_success response then
177 let data = serialize_response response in
178 Cacheio.put t ~key:(Uri.to_string url) ~data ~ttl:3600.0
179end
180```
181
182## License
183
184MIT