aboutsummaryrefslogtreecommitdiffstats
path: root/lib/system.ml
diff options
context:
space:
mode:
authorMarcos Magueta <maguetamarcos@gmail.com>2026-04-22 22:46:41 -0300
committerGitHub <noreply@github.com>2026-04-22 22:46:41 -0300
commit29e00769046cbc8cd020b2b7c47448d89f21ab39 (patch)
treedf6601daa94f7d588708ceca5a34fa02b75d791b /lib/system.ml
parentfdc63e730f91a4605ed4ff96a908e1f5e822d1bb (diff)
downloadSakura-29e00769046cbc8cd020b2b7c47448d89f21ab39.tar.gz
Sakura-29e00769046cbc8cd020b2b7c47448d89f21ab39.zip
Prototype for configuration
Diffstat (limited to '')
-rw-r--r--lib/system.ml111
1 files changed, 111 insertions, 0 deletions
diff --git a/lib/system.ml b/lib/system.ml
new file mode 100644
index 0000000..4280dda
--- /dev/null
+++ b/lib/system.ml
@@ -0,0 +1,111 @@
+(** System assembly: registry-based configuration dispatch. This module is the
+ composition root. It owns the mapping from configuration tags to concrete
+ implemenations and assembles a server from a configuration file. *)
+
+type storage_parcel =
+ | StorageParcel :
+ (module Management.Physical.S with type t = 't and type error = string)
+ * 't
+ -> storage_parcel
+
+type transport_parcel =
+ | TransportParcel :
+ (module Transport.TRANSPORT with type t = 't) * 't
+ -> transport_parcel
+
+type storage_provider = Sexplib.Sexp.t -> (storage_parcel, string) result
+type transport_provider = Sexplib.Sexp.t -> (transport_parcel, string) result
+
+type registry = {
+ storage : storage_provider Utilities.StringMap.t;
+ transport : transport_provider Utilities.StringMap.t;
+}
+
+let registry : registry =
+ let open Utilities.StringMap in
+ { storage =
+ empty
+ |> add "memory" (fun sexp ->
+ let ( let* ) = Result.bind in
+ let* config = Management.Physical.MemoryBackend.parse sexp in
+ let* storage = Management.Physical.Memory.create config in
+ Ok (StorageParcel ((module Management.Physical.Memory), storage)))
+ ; transport =
+ empty
+ |> add "tcp" (fun sexp ->
+ let ( let* ) = Result.bind in
+ let* config = Transport.TCP.parse sexp in
+ let transport = Transport.TCP.create config in
+ Ok (TransportParcel ((module Transport.TCP), transport))) }
+
+let initialize_multigroup create_immutable_relation storage multigroup =
+ let open Prelude.Standard in
+ List.fold_left
+ (fun multigroup (rel : Relation.t) ->
+ match
+ create_immutable_relation storage multigroup ~name:rel.name
+ ~schema:rel.schema ~generator:(Option.get rel.generator)
+ ~membership_criteria:rel.membership_criteria
+ ~cardinality:rel.cardinality
+ with
+ | Ok (new_multigroup, _) -> new_multigroup
+ | Error e ->
+ Printf.eprintf
+ "Warning: failed to register prelude relation %s: %s\n%!" rel.name
+ (Sexplib.Sexp.to_string (Error.sexp_of_error e));
+ multigroup)
+ multigroup
+ [ less_than_natural;
+ less_than_or_equal_natural;
+ greater_than_natural;
+ greater_than_or_equal_natural;
+ equal_natural;
+ not_equal_natural;
+ plus_natural;
+ times_natural;
+ minus_natural;
+ divide_natural ]
+
+let assemble (config : Configuration.t) : (unit -> unit, string) result =
+ let open Utilities.Result in
+ let* storage_tag, storage_body =
+ Configuration.require_section ~name:"storage"
+ ~valid_tags:(Utilities.StringMap.bindings registry.storage |> List.map fst)
+ config
+ in
+ let* storage_provider =
+ Utilities.StringMap.find_opt storage_tag registry.storage
+ |> Option.to_result
+ ~none:(Printf.sprintf "Unknown storage backend: %s" storage_tag)
+ in
+ let* packed_storage = storage_provider storage_body in
+ let* transport_tag, transport_body =
+ Configuration.require_section ~name:"transport"
+ ~valid_tags:
+ (Utilities.StringMap.bindings registry.transport |> List.map fst)
+ config
+ in
+ let* transport_provider =
+ Utilities.StringMap.find_opt transport_tag registry.transport
+ |> Option.to_result
+ ~none:(Printf.sprintf "Unknown transport backend: %s" transport_tag)
+ in
+ let* packed_transport = transport_provider transport_body in
+ let (StorageParcel ((module S), storage)) = packed_storage in
+ let (TransportParcel ((module T), transport)) = packed_transport in
+ let module Manip = Manipulation.Make (S) in
+ let* multigroup =
+ Manip.create_database storage ~name:"sakura"
+ |> Result.map (initialize_multigroup Manip.create_immutable_relation storage)
+ |> Result.map_error (fun _ -> "Failed to create initial database")
+ in
+ let module L = Listener.Make (T) (S) in
+ Ok (fun () -> Scl.Executor.set_sessions (Session.create ());
+ L.run transport multigroup storage)
+
+let run_from_config (path : string) : (unit -> unit, string) result =
+ let ( let* ) = Result.bind in
+ let* config =
+ Configuration.load ~expected_keys:[ "storage"; "transport" ] path
+ in
+ assemble config