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