215 lines
6.1 KiB
OCaml
215 lines
6.1 KiB
OCaml
|
|
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
|