Skip to content

Commit

Permalink
Version 7.1 with let%rpc
Browse files Browse the repository at this point in the history
  • Loading branch information
balat committed Oct 7, 2023
1 parent a4c4855 commit e592934
Show file tree
Hide file tree
Showing 139 changed files with 68 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ Js_of_ocaml is using a syntax extension to call JavaScript methods:
* {{{new%js constr a b c}}} to call a JavaScript constructor.
More information can be found in the Js_of_ocaml manual, in module
<<a_api project="js_of_ocaml" subproject="js_of_ocaml-ppx" | module Ppx_js >>.
<<a_api project="js_of_ocaml" subproject="js_of_ocaml-ppx"| module Ppx_js >>.

>>

Expand Down Expand Up @@ -710,14 +710,14 @@ functions can cause the entre server to hang!// Remember:

title="Handling events with Lwt"|
Module <<a_api project="js_of_ocaml" subproject="js_of_ocaml-lwt" | module Js_of_ocaml_lwt.Lwt_js_events>>
Module <<a_api project="js_of_ocaml" subproject="js_of_ocaml-lwt"| module Js_of_ocaml_lwt.Lwt_js_events>>
allows easily defining event listeners using Lwt. For example,
<<a_api project="js_of_ocaml" subproject="js_of_ocaml-lwt"| val Js_of_ocaml_lwt.Lwt_js_events.click >> takes a
DOM element and returns an Lwt thread that will wait until a click
occures on this element.
Functions with an ending "s" (<<a_api project="js_of_ocaml" subproject="js_of_ocaml-lwt" | val
Js_of_ocaml_lwt.Lwt_js_events.clicks >>, <<a_api project="js_of_ocaml" subproject="js_of_ocaml-lwt" | val
Functions with an ending "s" (<<a_api project="js_of_ocaml" subproject="js_of_ocaml-lwt"| val
Js_of_ocaml_lwt.Lwt_js_events.clicks >>, <<a_api project="js_of_ocaml" subproject="js_of_ocaml-lwt"| val
Js_of_ocaml_lwt.Lwt_js_events.mousedowns >>, ...) start again waiting after the
handler terminates.
Expand Down
12 changes: 5 additions & 7 deletions tutos/7.0/manual/basics.wiki → tutos/7.1/manual/basics.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -549,15 +549,13 @@ Eliom makes it possible to call server side OCaml functions from your
client-side program. You must export these functions explicitely,
and declare the type of their parameters. Example:

<<code language="ocaml" class="server"|
let%server g i = Lwt.return (string_of_int (i + Random.int 1000))
>>
<<code language="ocaml" class="client"|let%client g =
~%(Eliom_client.server_function ~name:"g" [%json: int] g)
<<code language="ocaml" class="shared"|
let%rpc g (i : int) : string Lwt.t = Lwt.return (string_of_int (i + Random.int 1000))
>>

Syntax {{{[%json: t]}}} corresponds to the serialisation functions of type {{{t}}}
from JSON. They are generated automatically by
Warning: type annotations are mandatory here
so that the ppx can automatically inject the right conversion functions.
These functions are generated automatically by
[[https://github.com/ocsigen/deriving|Deriving]], as long as it knows
a deriver for each subtype. To create a deriver for your own types
just append {{{[@@deriving json]}}} after your type declaration. Example:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
=How to call a server-side function from client-side?=

It is possible to call server-side functions in client-side code using
the {{{~%}}} syntax. For security reasons, these functions must first
be declared explicitely as "server functions" (with the type of their
It is possible to call server-side functions in client-side.
For security reasons, these functions must first
be declared explicitely as RPCs (with the type of their
argument).

<<code language="ocaml"|
let f x = ...

let%client f_rpc = ~%(Eliom_client.server_function [%derive.json: int] f)

<<code language="ocaml" class="shared"|
let%rpc f (x : int) : string Lwt.t = ...
...

[%client ... f_rpc 4 ... ]
>>
<<code language="ocaml" class="client"|
[%client ... f 4 ... ]
>>

The syntax is provided by opam package {{{ocsigen-ppx-rpc}}}.

The server-side function ({{{f}}} in the example) needs to return an
The server-side function ({{{f}}} in the example) needs to return a
Lwt value.

Server functions are just syntactic sugar for pathless services
Expand Down
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
=How to make the client side program get an HTML element from the server and insert it in the page?=

A very convenient way to do that is to use server functions :

<<code language="ocaml"|
let get_mydiv () = div [ ... ]

let%client get_mydiv_rpc =
~%(server_function [%derive.json: unit] get_mydiv)
...
A very convenient way to do that is to use RPCs :

<<code language="ocaml" class="shared"|
let%rpc get_mydiv (() : unit) : _ Lwt.t = div [ ... ]
>>
<<code language="ocaml" class="client"|
[%client
...
let%lwt mydiv = get_mydiv_rpc () in
let%lwt mydiv = get_mydiv () in
Dom.appendChild parent (To_dom.of_element mydiv)
...
]
>>

Server functions take exactly one parameter.

Server functions are just syntactic sugar for non-attached coservices
RPCs are just syntactic sugar for pathless services
returning OCaml values.

The type of the function parameter must have been declared with the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ If you want to store server side data for one browser (one session),
use scope {{{Eliom_common.default_session_scope}}}.

If you want to store server side data for one tab of your browser (one client process),
use scope {{{Eliom_common.default_process_scope}}}.
use scope {{{Eliom_common.default_process_scope}}} (available only if you
have a client-server Eliom application).

If you want to store server side data during one request,
use scope {{{Eliom_common.request_scope}}}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ This requires Eliom ≥ 3.1.

Due to security reasons, browsers have limitations on sending files.
But if the file is chosen by the user through an input file element,
there is a way to send it to the server. You can't use the {{{server_function}}} syntax for this, but you can use
there is a way to send it to the server. You can't use the {{{server_function}}}
or {{{let%rpc}}} syntax for this, but you can use
{{{Eliom_client.call_caml_service}}}.

Example:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
114 changes: 37 additions & 77 deletions tutos/7.0/manual/tutoreact.wiki → tutos/7.1/manual/tutoreact.wiki
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,11 @@ let%server display userid_o =
=== Make function {{{Db.add_message}}} accessible from the client

To be able to call a function from the client-side program,
use {{{server_function}}}:
<<code language="ocaml" class="server"|
let%server add_message_rpc =
Eliom_client.server_function
[%json: string]
(Os_session.connected_rpc (fun _userid value -> Db.add_message value))
use {{{let%rpc}}}:
<<code language="ocaml" class="shared"|
let%rpc add_message (value : string) : unit Lwt.t =
let%lwt _ = Os_current_user.get_current_userid () (* fails if not connected *) in
Db.add_message value
>>

The parameter {{{[%json: string]}}} describes the type of
Expand All @@ -212,12 +211,6 @@ the function parameter. This exhibits the syntax provided by
with our JSON plugin. We use this for safe server-side unmarshalling of data
sent by the client.

We use the wrapper {{{Os_session.connected_rpc}}} to make the
function accessible only by connected users. Otherwise, the function
fails with an exception. If you want to make your function accessible
for both connected and non-connected users, see the function
{{{Os_session.Opt.connected_rpc}}}.

=== Bind the input to call the function

To call the function from the client program, we will define a
Expand All @@ -235,7 +228,7 @@ let _ = [%client
async (fun () -> changes inp (fun _ _ ->
let value = Js_of_ocaml.Js.to_string inp##.value in
inp##.value := Js_of_ocaml.Js.string "";
let%lwt _ = ~%add_message_rpc value in
let%lwt _ = add_message value in
Lwt.return ()))
: unit)
] in
Expand Down Expand Up @@ -306,16 +299,8 @@ We implement a function {{{get_data}}} to fetch the
data from the database. This function must have an implementation both
server-side and client-side:

<<code language="ocaml" class="server"|
let%server get_data = Db.get_message

let%server get_data_rpc =
Eliom_client.server_function [%json: int]
(Os_session.Opt.connected_rpc (fun _userid_o id -> get_data id))

>>
<<code language="ocaml" class="client"|
let%client get_data id = ~%get_data_rpc id
<<code language="ocaml" class="shared"|
let%rpc get_data (id : int) : string Lwt.t = Db.get_message id
>>
<<code language="ocaml" class="server"|
let%server cache : (int, string) Eliom_cscache.t =
Expand Down Expand Up @@ -448,15 +433,11 @@ let%server display_messages () =
When we add a message, we notify all the clients listening on this
piece of data:

<<code language="ocaml" class="server"|
let%server add_message_rpc =
Eliom_client.server_function
[%json: string]
(Os_session.connected_rpc
(fun _userid value ->
let%lwt id = Db.add_message value in
Forum_notif.notify () id;
Lwt.return ()))
<<code language="ocaml" class="shared"|
let%rpc add_message (value : string) : unit Lwt.t =
let%lwt id = Db.add_message value in
Forum_notif.notify () id;
Lwt.return ()
>>

The program is now fully functional, you can now test it! You should see the
Expand Down Expand Up @@ -650,23 +631,19 @@ database, we need to specify a new type:
>>

We don't forget to take that into consideration in the function
{{{add_message_rpc}}}.
{{{add_message}}}.

<<code language="ocaml" class="server"|
let%server add_message_rpc =
Eliom_client.server_function
[%json: add_message_type]
(Os_session.connected_rpc
(fun _userid (forumid, value) ->
let%lwt id = Db.add_message forumid value in
Forum_notif.notify () id;
Lwt.return ()))
let%rpc add_message ((forumid, value) : add_message_type) : unit Lwt.t =
let%lwt id = Db.add_message forumid value in
Forum_notif.notify () id;
Lwt.return ()
>>

In the function {{{display}}}, in the client section:
<<code language="ocaml" class="client"|
...
~%add_message_rpc (~%forumid, value)
add_message (~%forumid, value)
...
>>

Expand Down Expand Up @@ -700,20 +677,15 @@ To do that, we provide an optional argument {{{?default}}} to the function
(optionally) containing the current reactive list. If it does not
exist in the cache, a new one will be created like previously:

<<code language="ocaml" class="server"|
let%server get_data_forum forumid =
<<code language="ocaml" class="shared"|
let%rpc get_data_forum (forumid : int) : _ Lwt.t =
let%lwt messages = Db.get_messages forumid in
let default = [%client
((try Some (Eliom_cscache.find_if_ready ~%forumcache ~%forumid)
with _ -> None)
: 'a option)
] in
Lwt.return (Eliom_shared.ReactiveData.RList.create ~default messages)

let%server get_data_forum_rpc =
Eliom_client.server_function [%json: int]
(Os_session.Opt.connected_rpc
(fun _userid_o forumid -> get_data_forum forumid))
>>

{{{display_messages}}} now takes the reactive list from the cache:
Expand Down Expand Up @@ -742,11 +714,11 @@ end)
]
>>

The function {{{Forum_notif.notify}}} used in the function {{{add_message_rpc}}}
The function {{{Forum_notif.notify}}} used in the function {{{add_message}}}
now takes the {{{forumid}}} parameter.

<<code language="ocaml" class="server"|
let%server add_message_rpc =
<<code language="ocaml" class="shared"|
let%rpc add_message ... =
...
Forum_notif.notify forumid id;
...
Expand Down Expand Up @@ -871,38 +843,31 @@ end)
]
>>

<<code language="ocaml" class="server"|
let%server add_message_rpc =
Eliom_client.server_function [%json: add_message_type]
(Os_session.connected_rpc (fun _userid (forumid, value) ->
let%lwt id = Db.add_message forumid value in
Forum_notif.notify forumid (id : int);
Lwt.return ()))
<<code language="ocaml" class="shared"|
let%rpc add_message ((forumid, value) : add_message_type) : unit Lwt.t =
let%lwt id = Db.add_message forumid value in
Forum_notif.notify forumid (id : int);
Lwt.return ()
>>

<<code language="ocaml" class="server"|
let%server cache : (int, string) Eliom_cscache.t = Eliom_cscache.create ()

let%server forumcache :
(int,
int Eliom_shared.ReactiveData.RList.t *
int Eliom_shared.ReactiveData.RList.handle) Eliom_cscache.t =
Eliom_cscache.create ()
>>

let%server get_data id =
<<code language="ocaml" class="shared"|
ler%rpc get_data (id : int) : string Lwt.t =
let%lwt () = Lwt_unix.sleep 2.0 in
Db.get_message id

let%server get_data_rpc =
Eliom_client.server_function [%json: int]
(Os_session.Opt.connected_rpc
(fun _userid_o id -> get_data id))
>>

<<code language="ocaml" class="client"|
let%client get_data id = ~%get_data_rpc id
>>

<<code language="ocaml" class="server"|
let%server get_data_forum forumid =
<<code language="ocaml" class="shared"|
let%rpc get_data_forum (forumid : int) : _ Lwt.t =
let%lwt messages = Db.get_messages forumid in
let default = [%client
(try
Expand All @@ -912,11 +877,6 @@ let%server get_data_forum forumid =
: 'a option)
] in
Lwt.return (Eliom_shared.ReactiveData.RList.create ~default messages)

let%server get_data_forum_rpc =
Eliom_client.server_function [%json: int]
(Os_session.Opt.connected_rpc
(fun _userid_o forumid -> get_data_forum forumid))
>>

<<code language="ocaml" class="shared"|
Expand Down Expand Up @@ -973,7 +933,7 @@ let%server display userid_o forumid =
changes inp (fun _ _ ->
let value = Js_of_ocaml.Js.to_string inp##.value in
inp##.value := Js_of_ocaml.Js.string "";
let%lwt _ = ~%add_message_rpc (~%forumid, value) in
let%lwt _ = add_message (~%forumid, value) in
Lwt.return ()))
: unit)]
in
Expand Down
File renamed without changes.

0 comments on commit e592934

Please sign in to comment.