geochan/src/client/network.ml

215 lines
6.1 KiB
OCaml
Raw Normal View History

2023-12-18 00:45:46 +01:00
open Types
open Client_types
open Util
(* TODO handle no network connection/unreachable server *)
let handle_response meth fetch read_ok on_ok =
let open Brr_io.Fetch in
let read_body response res =
match res with
| Error e -> Error (Body_err (str_of_error e))
| Ok jstr -> (
let url = Jstr.to_string (Response.url response) in
let status = Response.status response in
let status_text = Jstr.to_string (Response.status_text response) in
let body = Jstr.to_string jstr in
let r = { meth; url; status; status_text; body } in
match Response.ok response with
| true -> (
match read_ok r.body with
| Error e -> Error (Read_err (e, r))
| Ok v -> Ok (Either.Left v) )
| false -> (
match Json_data.Read.err r.body with
| Error e -> Error (Read_err (e, r))
| Ok v -> Ok (Either.Right v) ) )
in
let read_response res =
match res with
| Error e -> Fut.return @@ Error (Fetch_err (str_of_error e))
| Ok response ->
let body = Response.as_body response in
Body.text body |> Fut.map (read_body response)
in
let f res =
read_response res
|> Fut.map (function
| Error e ->
Events.send_error (Network_err e);
()
| Ok (Either.Left v) ->
on_ok v;
()
| Ok (Either.Right err) ->
Events.send_error (Err_response err);
() )
in
Fut.bind (fetch ()) f
module GET = struct
type _ t =
| Catalog : thread list t
| Thread : int -> Thread_w_reply.t t
| Post : int -> post t
| Admin : report list t
| User : string -> user t
| Session : session t
let reader : type a. a t -> string -> (a, string) result =
fun t ->
let open Json_data.Read in
match t with
| Catalog -> catalog
| Thread _id -> thread_w_reply
| Post _id -> post
| Admin -> reports
| User _id -> user
| Session -> session
let url : type a. a t -> string =
fun t ->
Fmt.str "/api%s"
( match t with
| Catalog -> "/catalog"
| Thread id -> Fmt.str "/thread/%d" id
| Post id -> Fmt.str "/post/%d" id
| Admin -> "/admin"
| User id -> Fmt.str "/user/%s" id
| Session -> "/session" )
let on_ok : type a. a t -> a -> unit =
fun req v ->
let open Client_types in
let open Events in
begin
match req with
| Catalog -> send_data_update (Catalog_update v)
| Thread _id -> send_data_update (Thread_update v)
| Post _id -> send_data_update (Post_update v)
| Admin -> send_data_update (Reports_update v)
| User _id -> send_data_update (User_update v)
| Session -> send_data_update (Session_update v)
end;
()
let fetch t =
let s = url t in
Fmt.pr "fetch `%s`@." s;
let fetch () = Brr_io.Fetch.url (Jstr.v s) in
let _fut = handle_response GET fetch (reader t) (on_ok t) in
()
let catalog () = fetch Catalog
let thread id = fetch (Thread id)
let post id = fetch (Post id)
let admin () = fetch Admin
let user id = fetch (User id)
let session () = fetch Session
let f page =
let open Page in
match page with
| About | Register | Login -> ()
| Account | Profile -> session ()
| Home | New_thread -> catalog ()
| Admin _ -> admin ()
| Thread v ->
let id = unwrap_thread_id v in
thread id;
catalog ()
| Delete v | Report v ->
let id = unwrap_post_id v in
post id
| User v ->
let id = unwrap_user_id v in
user id
end
module POST = struct
open Form_kind
let reader : type a. a t -> string -> (a, string) result =
fun t ->
let open Json_data.Read in
match t with
| Home -> thread_w_reply
| Register -> session
| Login -> session
| Logout -> session
| Profile -> session
| Account -> session
| Thread _ -> thread_w_reply
| Delete _ -> post
| Report _ -> reports
| Admin_ignore _ -> reports
| Admin_delete _ -> post
| Admin_banish _ -> user
(* TODO implement redirection mechanism *)
let on_ok : type a. a t -> a -> unit =
fun o v ->
let open Client_types in
let open Events in
begin
match o with
| Home ->
send_data_update (Thread_update v);
send_action (Post_form_change Form_reset);
let id = v.op.id in
Navigation.load (Thread (Loading id))
| Thread _ ->
(* server respond to successful POST with full thread *)
send_data_update (Thread_update v);
send_action (Post_form_change Form_reset);
let id = v.op.id in
Navigation.load (Thread (Loading id))
| Register ->
send_data_update (Session_update v);
Navigation.load Profile
| Login ->
send_data_update (Session_update v);
Navigation.load Home
| Logout -> send_data_update (Session_update v)
| Delete _ -> (
let is_op = Int.equal v.id v.parent_t_id in
match is_op with
| true -> Navigation.load Home
| false -> Navigation.load (Thread (Loading v.parent_t_id)) )
| Report _ ->
send_data_update (Reports_update v);
(* TODO need redirection to page before report here *)
Navigation.load Home
| Admin_ignore _ -> send_data_update (Reports_update v)
| Admin_delete _ -> ()
| Admin_banish _ -> ()
| Profile -> send_data_update (Session_update v)
| Account -> send_data_update (Session_update v)
end;
()
let fetch t request =
let fetch () = Brr_io.Fetch.request request in
handle_response POST fetch (reader t) (on_ok t)
let f kind form_el csrf_token =
let open Brr_io in
let method' = Jstr.v "POST" in
let form = Form.of_el form_el in
let action = Form_kind.action kind |> Jstr.v in
let form_data = Form.Data.of_form form in
Form.Data.set form_data (Jstr.v "dream.csrf") (Jstr.v csrf_token);
let body = Fetch.Body.of_form_data form_data in
let init = Fetch.Request.init ~method' ~body () in
let request = Fetch.Request.v ~init action in
let fut = fetch kind request in
let _fut : unit Fut.t =
Fut.map (fun () -> Fmt.pr "`%s` xhr done@." (Form_kind.name kind)) fut
in
()
end