···
(** {1 JSON Codecs for Bot Storage} *)
(* Storage response type - {"storage": {...}} *)
type storage_response = {
-
storage : (string * string) list;
unknown : Jsont.json; (** Unknown/extra JSON fields preserved during parsing *)
-
(* Custom codec for storage_response that handles the dictionary *)
let storage_response_jsont : storage_response Jsont.t =
-
match Jsont_bytesrw.decode_string' Jsont.json s with
-
| Error _ -> Error "Failed to decode JSON"
-
| Jsont.Object (fields, _) ->
-
let assoc = List.map (fun ((k, _), v) -> (k, v)) fields in
-
(match List.assoc_opt "storage" assoc with
-
| Some (Jsont.Object (storage_fields, _)) ->
-
let storage = List.filter_map (fun ((k, _), v) ->
-
| Jsont.String (s, _) -> Some (k, s)
-
(* Keep unknown fields *)
-
let unknown_fields = List.filter (fun (k, _) -> k <> "storage") assoc in
-
let unknown_mems = List.map (fun (k, v) -> ((k, Jsont.Meta.none), v)) unknown_fields in
-
let unknown = Jsont.Object (unknown_mems, Jsont.Meta.none) in
-
Ok { storage; unknown }
-
| Some _ -> Error "Expected 'storage' field to be an object"
-
| None -> Ok { storage = []; unknown = Jsont.Object ([], Jsont.Meta.none) })
-
| _ -> Error "Expected JSON object for storage response"
-
let to_string { storage; unknown } =
-
(* Create storage object *)
-
let storage_fields = List.map (fun (k, v) ->
-
((k, Jsont.Meta.none), Jsont.String (v, Jsont.Meta.none))
-
let storage_obj = Jsont.Object (storage_fields, Jsont.Meta.none) in
-
(* Merge with unknown fields *)
-
let storage_mem = (("storage", Jsont.Meta.none), storage_obj) in
-
let unknown_mems = match unknown with
-
| Jsont.Object (fields, _) -> fields
-
let json = Jsont.Object (storage_mem :: unknown_mems, Jsont.Meta.none) in
-
match Jsont_bytesrw.encode_string' Jsont.json json with
-
| Error e -> failwith ("Failed to encode storage response: " ^ Jsont.Error.to_string e)
-
Jsont.of_of_string ~kind:"StorageResponse" of_string ~enc:to_string
let create client ~bot_email =
Log.info (fun m -> m "Creating bot storage for %s" bot_email);
···
(match Zulip.Encode.from_json storage_response_jsont json with
-
List.iter (fun (k, v) ->
Log.debug (fun m -> m "Loaded key from server: %s" k);
···
(match Zulip.Encode.from_json storage_response_jsont json with
-
(match List.assoc_opt key response.storage with
Log.debug (fun m -> m "Retrieved key from API: %s" key);
···
(match Zulip.Encode.from_json storage_response_jsont json with
-
let api_keys = List.map fst response.storage in
(* Merge with cache keys *)
let cache_keys = Hashtbl.fold (fun k _ acc -> k :: acc) t.cache [] in
let all_keys = List.sort_uniq String.compare (api_keys @ cache_keys) in