diff --git a/src/plugins/server/package.ml b/src/plugins/server/package.ml index 459737e998e1dc2e09c6391c6056105d1ea99e2a..db8e80d96647bf0c51b1a345871ef2a1a9640768 100644 --- a/src/plugins/server/package.ml +++ b/src/plugins/server/package.ml @@ -197,6 +197,9 @@ type requestInfo = { type declKindInfo = | D_signal + | D_value + | D_state + | D_array | D_type of jtype | D_enum of tagInfo list | D_record of fieldInfo list @@ -247,8 +250,7 @@ let visit_request f { rq_input ; rq_output } = ( visit_param f rq_input ; visit_param f rq_output ) let visit_dkind f = function - | D_signal -> () - | D_enum _ -> () + | D_signal | D_state | D_value | D_array | D_enum _ -> () | D_type js -> visit_jtype f js | D_record fds -> List.iter (visit_field f) fds | D_request rq -> visit_request f rq diff --git a/src/plugins/server/package.mli b/src/plugins/server/package.mli index 9fc18b1444370619f06d48d89e3f274f79cb1eff..b9b5a1bef1b271d381acc452f86f345ff122c649 100644 --- a/src/plugins/server/package.mli +++ b/src/plugins/server/package.mli @@ -70,6 +70,9 @@ type requestInfo = { type declKindInfo = | D_signal + | D_value + | D_state + | D_array | D_type of jtype | D_enum of tagInfo list | D_record of fieldInfo list diff --git a/src/plugins/server/server_doc.ml b/src/plugins/server/server_doc.ml index 05ea79e1d700ab684a1758d56da295dc5b0f2195..e0dd63f4d70f3fb9ab15ccb932e772313ba03ec1 100644 --- a/src/plugins/server/server_doc.ml +++ b/src/plugins/server/server_doc.ml @@ -133,6 +133,8 @@ let page_of_package pkg = let kind_of_decl = function | D_signal -> "SIGNAL" + | D_value | D_state -> "STATE" + | D_array -> "ARRAY" | D_type _ | D_record _ | D_enum _ -> "DATA" | D_request { rq_kind=`GET } -> "GET" | D_request { rq_kind=`SET } -> "SET" @@ -159,6 +161,9 @@ let md_named ~kind pp = function let descr_of_decl names decl = match decl.d_kind with | D_signal -> [] + | D_state -> [] (* TBC *) + | D_value -> [] (* TBC *) + | D_array -> [] (* TBC *) | D_type data -> let pp = pp_for ~decl names in Md.quote (pp.self @ Md.code "::=" @ Package.md_jtype pp data) diff --git a/src/plugins/server/states.ml b/src/plugins/server/states.ml index 8b5c990250da67b5dad22b44d381c497e69605b2..3e6a9157ef3f23986e926311e01ce59f47808c1d 100644 --- a/src/plugins/server/states.ml +++ b/src/plugins/server/states.ml @@ -43,20 +43,22 @@ let install_emit signal add_hook = (* --- Values --- *) (* -------------------------------------------------------------------------- *) -let register_value (type a) ~page ~name ~descr ?(details=[]) +let register_value (type a) ~package ~name ~descr ~(output : a Request.output) ~get ?(add_hook : unit callback option) () = let open Markdown in - let title = Printf.sprintf "`VALUE` %s" name in - let index = [ Printf.sprintf "%s (`VALUE`)" name ] in - let contents = [ Block [Text descr] ; Block details] in - let h = Server_doc.publish ~page ~name ~title ~index ~contents () in - let signal = Request.signal ~page ~name:(name ^ ".sig") - ~descr:(plain "Signal for value " @ href h) () in - Request.register ~page ~kind:`GET ~name:(name ^ ".get") - ~descr:(plain "Getter for value " @ href h) - ~input:(module Junit) ~output get ; + let href = link ~name () in + let descr = Markdown.par descr in + let () = Package.declare + ~package ~name ~descr D_value in + let signal = Request.signal + ~package ~name:(name ^ "Sig") + ~descr:(plain "Signal for state" @ href) in + let () = Request.register + ~package ~name:(name ^ "Get") + ~descr:(plain "Getter for state" @ href) + ~kind:`GET ~input:(module Junit) ~output get in install_emit signal add_hook ; signal @@ -64,22 +66,26 @@ let register_value (type a) ~page ~name ~descr ?(details=[]) (* --- States --- *) (* -------------------------------------------------------------------------- *) -let register_state (type a) ~page ~name ~descr ?(details=[]) +let register_state (type a) ~package ~name ~descr ~(data : a data) ~get ~set ?(add_hook : unit callback option) () = let open Markdown in - let title = Printf.sprintf "`STATE` %s" name in - let index = [ Printf.sprintf "%s (`STATE`)" name ] in - let contents = [ Block [Text descr] ; Block details] in - let h = Server_doc.publish ~page ~name ~title ~index ~contents () in - let signal = Request.signal ~page ~name:(name ^ ".sig") - ~descr:(plain "Signal for state " @ href h) () in - Request.register ~page ~kind:`GET ~name:(name ^ ".get") - ~descr:(plain "Getter for state " @ href h) - ~input:(module Junit) ~output:(module (val data)) get ; - Request.register ~page ~kind:`SET ~name:(name ^ ".set") - ~descr:(plain "Setter for state " @ href h) - ~input:(module (val data)) ~output:(module Junit) set ; + let module D = (val data) in + let href = link ~name () in + let descr = Markdown.par descr in + let () = Package.declare + ~package ~name ~descr D_state in + let signal = Request.signal + ~package ~name:(name ^ "Sig") + ~descr:(plain "Signal for state" @ href) in + let () = Request.register + ~package ~name:(name ^ "Get") + ~descr:(plain "Getter for state" @ href) + ~kind:`GET ~input:(module Junit) ~output:(module D) get in + let () = Request.register + ~package ~name:(name ^ "Set") + ~descr:(plain "Setter for state" @ href) + ~kind:`SET ~input:(module D) ~output:(module Junit) set in install_emit signal add_hook ; signal @@ -87,22 +93,22 @@ let register_state (type a) ~page ~name ~descr ?(details=[]) (* --- Model Signature --- *) (* -------------------------------------------------------------------------- *) -type 'a column = Syntax.field * ('a -> json) +type 'a column = Package.fieldInfo * ('a -> json) type 'a model = 'a column list ref let model () = ref [] -let column (type a b) ~(model : a model) ~name ~descr - ~(data: b Request.output) ~(get : a -> b) () = +let column (type a b) ~name ~descr + ~(data: b Request.output) ~(get : a -> b) (model : a model) = let module D = (val data) in if name = "key" || name = "index" then raise (Invalid_argument "Server.States.column: invalid name") ; - if List.exists (fun (fd,_) -> fd.Syntax.fd_name = name) !model then + if List.exists (fun (fd,_) -> fd.Package.fd_name = name) !model then raise (Invalid_argument "Server.States.column: duplicate name") ; - let fd = Syntax.{ + let fd = Package.{ fd_name = name ; - fd_syntax = D.syntax ; + fd_type = D.jtype ; fd_descr = descr ; } in model := (fd , fun a -> D.to_json (get a)) :: !model @@ -255,65 +261,61 @@ let fetch array n = (* --- Signature Registry --- *) (* -------------------------------------------------------------------------- *) -let register_array ~page ~name ~descr ?(details=[]) ~key +let register_array ~package ~name ~descr ~key ~(iter : 'a callback) ?(add_update_hook : 'a callback option) ?(add_remove_hook : 'a callback option) ?(add_reload_hook : unit callback option) model = let open Markdown in - let title = Printf.sprintf "`ARRAY` %s" name in - let index = [ Printf.sprintf "%s (`ARRAY`)" name ] in - let columns = !model in - let contents = [ - Block [Text descr] ; - Syntax.fields ~title:"Columns" - begin - Syntax.{ - fd_name = "key" ; - fd_syntax = Syntax.ident ; - fd_descr = plain "entry identifier" ; - } :: List.rev (List.map fst columns) - end ; - Block details - ] in - let mref = Server_doc.publish ~page:page ~name:name ~title ~index ~contents () in - let signal = Request.signal ~page ~name:(name ^ ".sig") - ~descr:(plain "Signal for array " @ href mref) () in - let getter = List.map Syntax.(fun (fd,to_js) -> fd.fd_name , to_js) columns in + let href = link ~name () in + let descr = Markdown.par descr in + let columns = List.rev !model in + let fields = Package.{ + fd_name = "key" ; + fd_type = Jkey name ; + fd_descr = plain "Entry identifier." ; + } :: List.map fst columns in + let () = Package.declare ~package:package ~name:name ~descr D_array in + let signal = Request.signal + ~package ~name:(name ^ "Sig") + ~descr:(plain "Signal for array" @ href) in + let row = Package.declare_id + ~package ~name:(name ^ "Row") + ~descr:(par (plain "Data rows for array" @ href)) + (D_record fields) in + let getter = + List.map Package.(fun (fd,to_js) -> fd.fd_name , to_js) columns in let array = { key ; iter ; getter ; signal ; current = None ; projects = Hashtbl.create 0 } in - let signature = - Request.signature ~kind:`GET ~page ~name:(name ^ ".fetch") - ~descr:(plain "Fetch updates for array " @ href mref) - ~input:(module Jint) - ~details:[ - Text(plain - "Collect all entry updates since the last fetch.\n\ - The number of fetched entries is limited to the\n\ - provided integer. When `reload:true` is returned,\n\ - _all_ previously received entries must be removed.")] - () in - let module Jentries = - (struct - include Jany - let syntax = Syntax.data "entry" mref - end) in + let signature = Request.signature () in + let module Jkeys = Jlist(struct + include Jstring + let jtype = Package.Jkey name + end) in + let module Jrows = Jlist (struct + include Jany + let jtype = Package.Jdata row + end) in let set_reload = Request.result signature ~name:"reload" ~descr:(plain "array fully reloaded") (module Jbool) in let set_removed = Request.result signature ~name:"removed" ~descr:(plain "removed entries") - (module Jident.Jlist) in + (module Jkeys) in let set_updated = Request.result signature ~name:"updated" ~descr:(plain "updated entries") - (module Jlist(Jentries)) in + (module Jrows) in let set_pending = Request.result signature ~name:"pending" ~descr:(plain "remaining entries to be fetched") (module Jint) in - Request.register_sig signature + Request.register_sig + ~package ~name:(name ^ "Fetch") + ~descr:(plain "Data fetcher for array" @ href) + ~kind:`GET + signature begin fun rq n -> let buffer = fetch array n in set_reload rq buffer.reload ; @@ -321,8 +323,9 @@ let register_array ~page ~name ~descr ?(details=[]) ~key set_updated rq buffer.updated ; set_pending rq buffer.pending ; end ; - Request.register ~kind:`GET ~page ~name:(name ^ ".reload") - ~descr:(plain "Force full reload for array " @ href mref) + Request.register + ~package ~name:(name ^ "Reload") ~kind:`GET + ~descr:(plain "Force full reload for array" @ href) ~input:(module Junit) ~output:(module Junit) (fun () -> reload array) ; synchronize array ; diff --git a/src/plugins/server/states.mli b/src/plugins/server/states.mli index 96ff7efa021890b2acc684e5947eae021c880505..d7c6a067eb7e22c001e1b6809b73eb39ec5fcfdf 100644 --- a/src/plugins/server/states.mli +++ b/src/plugins/server/states.mli @@ -22,6 +22,8 @@ (** Synchronized values between Server and Client *) +open Package + type 'a callback = ('a -> unit) -> unit (** Register a (projectified) value and generates the associated signal and @@ -37,10 +39,9 @@ type 'a callback = ('a -> unit) -> unit synchronize with this value. *) val register_value : - page:Server_doc.page -> + package:package -> name:string -> descr:Markdown.text -> - ?details:Markdown.block -> output:'a Request.output -> get:(unit -> 'a) -> ?add_hook:(unit callback) -> @@ -60,10 +61,9 @@ val register_value : synchronize with this state. *) val register_state : - page:Server_doc.page -> + package:package -> name:string -> descr:Markdown.text -> - ?details:Markdown.block -> data:'a Data.data -> get:(unit -> 'a) -> set:('a -> unit) -> @@ -78,12 +78,11 @@ val model : unit -> 'a model (** Populate an array model with a new field. Columns with name `"id"` and `"_index"` are reserved for internal use. *) val column : - model:'a model -> name:string -> descr:Markdown.text -> data:('b Request.output) -> get:('a -> 'b) -> - unit -> unit + 'a model -> unit (** Synchronized array state. *) type 'a array @@ -121,10 +120,9 @@ val signal : 'a array -> Request.signal [States.useSyncArray()] hook. *) val register_array : - page:Server_doc.page -> + package:package -> name:string -> descr:Markdown.text -> - ?details:Markdown.block -> key:('a -> string) -> iter:('a callback) -> ?add_update_hook:('a callback) ->