From 2cbbb49cedb82cd980029b39149f170b08ca7267 Mon Sep 17 00:00:00 2001 From: swrup Date: Thu, 20 Nov 2025 20:03:51 +0100 Subject: [PATCH] --- default.config | 9 +++ include/parse_config.ml | 119 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 117 insertions(+), 11 deletions(-) diff --git a/default.config b/default.config index 99fdbdfb..1699fcb9 100644 --- a/default.config +++ b/default.config @@ -16,6 +16,15 @@ alt_unit_names = "{"0":"€","3":"k€"}" [dummy-section] dummy = "blah" +[currency-EUR] +enabled= NO +code= EUR +name= euro +fractional_input_digits= 2 +fractional_normal_digits= 2 +fractional_trailing_zero_digits= 2 +alt_unit_names= "{"0":"€","3":"k€"}" + [exchange] currency = EUR currency_round_unit = EUR:0.01 diff --git a/include/parse_config.ml b/include/parse_config.ml index fb50fcad..a53c79da 100644 --- a/include/parse_config.ml +++ b/include/parse_config.ml @@ -205,14 +205,14 @@ let get t ~section ~field = | None -> fail_with (Fmt.str "option `[%s].%s` not found" section field) | Some v -> v -let int v = - match int_of_string_opt v with - | None -> fail_with (Fmt.str "expected int value, got `%s`" v) +let int s = + match int_of_string_opt s with + | None -> fail_with (Fmt.str "expected int value, got `%s`" s) | Some v -> v -let float v = - match float_of_string_opt v with - | None -> fail_with (Fmt.str "expected float value, got `%s`" v) +let float s = + match float_of_string_opt s with + | None -> fail_with (Fmt.str "expected float value, got `%s`" s) | Some v -> v let const_value a b = @@ -225,19 +225,62 @@ let yes_no = function | "YES" -> `YES | s -> fail_with (Fmt.str "expected `YES`/`NO` value, got `%s`" s) -let amount v = v |> Amount.of_string |> unwrap_res -let duration v = Parse_duration.(v |> parse |> to_ptime_span) +let amount s = s |> Amount.of_string |> unwrap_res +let duration s = Parse_duration.(s |> parse |> to_ptime_span) -let ed25519 v = - v +let ed25519 s = + s |> B32.decode |> unwrap_res |> Mirage_crypto_ec.Ed25519.pub_of_octets |> Result.map_error (fun e -> Fmt.str "%a" Mirage_crypto_ec.pp_error e) |> unwrap_res +module Parse_alt_unit_names = struct + let rm_brackets s = + let s = String.trim s in + match + String.starts_with ~prefix:"{" s && String.ends_with ~suffix:"}" s + with + | false -> fail_with (Fmt.str "expected json, got `%s`" s) + | true -> + let s = String.sub s 1 (String.length s - 2) in + s + + let rm_quotes s = + let s = String.trim s in + match + String.starts_with ~prefix:"\"" s && String.ends_with ~suffix:"\"" s + with + | false -> fail_with (Fmt.str "expected quoted string, got `%s`" s) + | true -> + let s = String.sub s 1 (String.length s - 2) in + s + + let parse s = + let s = rm_brackets s in + String.split_on_char ',' s + |> List.map (String.split_on_char ':') + |> List.map (function + | [ k; v ] -> (k, v) + | _ -> fail_with "invalid json key-value map") + |> List.map (fun (k, v) -> + let k = rm_quotes k in + let v = rm_quotes v in + let k = + match int_of_string_opt k with + | None -> + fail_with + (Fmt.str + "invalid json key-value map, expected integer key, got `%s`" + k) + | Some k -> k + in + (k, v)) +end + module Config = struct - [@@@ocaml.warning "-32"] + [@@@ocaml.warning "-32-69"] let config = let read_file file = In_channel.with_open_bin file In_channel.input_all in @@ -312,4 +355,58 @@ module Config = struct let max_aml_program_runtime = get "max_aml_program_runtime" |> duration let default_purse_limit = get "default_purse_limit" |> int end + + module Currency = struct + type t = { + enabled: [ `YES | `NO ]; + code: string; + name: string; + fractional_input_digits: int; + fractional_normal_digits: int; + fractional_trailing_zero_digits: int; + alt_unit_names: (int * string) list; + } + + let currency_sections = + List.filter_map + (fun v -> + match String.starts_with ~prefix:"currency-" v.header with + | false -> None + | true -> Some v) + config + + let parse_currency section = + let get field = get config ~section:section.header ~field in + { + enabled= get "enabled" |> yes_no; + code= get "code"; + name= get "name"; + fractional_input_digits= get "fractional_input_digits" |> int; + fractional_normal_digits= get "fractional_normal_digits" |> int; + fractional_trailing_zero_digits= + get "fractional_trailing_zero_digits" |> int; + alt_unit_names= get "alt_unit_names" |> Parse_alt_unit_names.parse; + } + + let all_currencies = List.map parse_currency currency_sections + + (* I think the exchange only handle one currency *) + let v = + match + List.find_opt (fun v -> v.code = Exchange.currency) all_currencies + with + | None -> + fail_with + (Fmt.str + "section `[currency-%s]` not found, currency `%s` is not defined" + Exchange.currency Exchange.currency) + | Some v -> v + + (* + let () = + let pp_pair ppf (k, v) = Fmt.pf ppf "k: %d - v: %s" k v in + Fmt.epr "alt unit names:@\n%a@." (Fmt.list pp_pair) v.alt_unit_names; + () + *) + end end