Immich bindings and CLI in OCaml
at main 110 lines 5.0 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6open Cmdliner 7 8(* Styled output helpers *) 9let header_style = Fmt.(styled `Bold string) 10let label_style = Fmt.(styled `Faint string) 11let value_style = Fmt.(styled (`Fg `Cyan) string) 12let version_style = Fmt.(styled (`Fg `Green) string) 13let success_style = Fmt.(styled (`Fg `Green) string) 14let error_style = Fmt.(styled (`Fg `Red) string) 15 16let percent_style pct = 17 if pct >= 90.0 then Fmt.(styled (`Fg `Red) (fun ppf -> Fmt.pf ppf "%.1f%%")) 18 else if pct >= 70.0 then Fmt.(styled (`Fg `Yellow) (fun ppf -> Fmt.pf ppf "%.1f%%")) 19 else Fmt.(styled (`Fg `Green) (fun ppf -> Fmt.pf ppf "%.1f%%")) 20 21(* Ping command - can work with or without auth *) 22 23let ping_action ~requests_config ~server ~profile env = 24 Immich_auth.Error.wrap (fun () -> 25 Eio.Switch.run @@ fun sw -> 26 let fs = env#fs in 27 let server_url = 28 match server with 29 | Some url -> url 30 | None -> 31 (* Try to get from session *) 32 let profile = match profile with 33 | Some p -> Some p 34 | None -> Some (Immich_auth.Session.get_current_profile fs) 35 in 36 match Immich_auth.Session.load fs ?profile () with 37 | Some session -> Immich_auth.Session.server_url session 38 | None -> 39 Fmt.epr "%a No server specified and not logged in.@." error_style "Error:"; 40 Fmt.epr "Use --server or login first.@."; 41 raise (Immich_auth.Error.Exit_code 1) 42 in 43 (* Create session using requests config *) 44 let session = Requests.Cmd.create requests_config env sw in 45 (* Resolve the API URL from .well-known/immich if available *) 46 let server_url = Immich_auth.Client.resolve_api_url ~session server_url in 47 let client = Immich.create ~session ~sw env ~base_url:server_url in 48 let resp = Immich.ServerPing.ping_server client () in 49 Fmt.pr "%a %a@." success_style "Server:" value_style (Immich.ServerPing.Response.res resp) 50 ) 51 52let ping_cmd env fs = 53 let doc = "Ping the Immich server." in 54 let info = Cmd.info "ping" ~doc in 55 let ping' (style_renderer, level) requests_config server profile = 56 Immich_auth.Cmd.setup_logging_with_config style_renderer level requests_config; 57 ping_action ~requests_config ~server ~profile env 58 in 59 Cmd.v info Term.(const ping' $ Immich_auth.Cmd.setup_logging $ Immich_auth.Cmd.requests_config_term fs $ Immich_auth.Cmd.server_opt $ Immich_auth.Cmd.profile_arg) 60 61(* Status command - requires auth *) 62 63let status_action ~requests_config ~profile env = 64 Immich_auth.Error.wrap (fun () -> 65 Immich_auth.Cmd.with_client ~requests_config ?profile (fun _fs client -> 66 let api = Immich_auth.Client.client client in 67 (* Get server version *) 68 let version = Immich.ServerVersion.get_server_version api () in 69 Fmt.pr "%a %a@." header_style "Server Version:" 70 version_style (Printf.sprintf "%d.%d.%d" 71 (Immich.ServerVersion.ResponseDto.major version) 72 (Immich.ServerVersion.ResponseDto.minor version) 73 (Immich.ServerVersion.ResponseDto.patch version)); 74 (* Get server about *) 75 let about = Immich.ServerAbout.get_about_info api () in 76 let full_version = Immich.ServerAbout.ResponseDto.version about in 77 if full_version <> "" then 78 Fmt.pr " %a %a@." label_style "Full version:" value_style full_version; 79 (match Immich.ServerAbout.ResponseDto.build about with 80 | Some b -> Fmt.pr " %a %a@." label_style "Build:" value_style b 81 | None -> ()); 82 (* Get storage info *) 83 let storage = Immich.ServerStorage.get_storage api () in 84 let pct = Immich.ServerStorage.ResponseDto.disk_usage_percentage storage in 85 Fmt.pr "%a@." header_style "Storage:"; 86 Fmt.pr " %a %a@." label_style "Disk size:" value_style (Immich.ServerStorage.ResponseDto.disk_size storage); 87 Fmt.pr " %a %a@." label_style "Disk used:" value_style (Immich.ServerStorage.ResponseDto.disk_use storage); 88 Fmt.pr " %a %a@." label_style "Disk available:" value_style (Immich.ServerStorage.ResponseDto.disk_available storage); 89 Fmt.pr " %a %a@." label_style "Usage:" (percent_style pct) pct 90 ) env 91 ) 92 93let status_cmd env fs = 94 let doc = "Show server status." in 95 let info = Cmd.info "status" ~doc in 96 let status' (style_renderer, level) requests_config profile = 97 Immich_auth.Cmd.setup_logging_with_config style_renderer level requests_config; 98 status_action ~requests_config ~profile env 99 in 100 Cmd.v info Term.(const status' $ Immich_auth.Cmd.setup_logging $ Immich_auth.Cmd.requests_config_term fs $ Immich_auth.Cmd.profile_arg) 101 102(* Server command group *) 103 104let server_cmd env fs = 105 let doc = "Server information commands." in 106 let info = Cmd.info "server" ~doc in 107 Cmd.group info 108 [ ping_cmd env fs 109 ; status_cmd env fs 110 ]