Constrain message types in body API

This commit is contained in:
Anton Bachin 2021-03-28 22:12:28 +03:00
parent c5ecca90af
commit 3a7a07a86c
4 changed files with 49 additions and 57 deletions

View File

@ -89,36 +89,31 @@ let bigstring_replacement = {|
|}
let next_expected = {|<div class="spec value" id="val-next">
<a href="#val-next" class="anchor"></a><code><span><span class="keyword">val</span> next : <span>bigstring:<span>(<span><a href="#type-bigstring">bigstring</a> <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span> <span>?string:<span>(<span>string <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span>
<span>?flush:<span>(<span>unit <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span> <span>close:<span>(<span>unit <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span> <span>exn:<span>(<span>exn <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span> <span><span><span class="type-var">_</span> <a href="#type-message">message</a></span> <span class="arrow">-&gt;</span></span> unit</span></code>
<a href="#val-next" class="anchor"></a><code><span><span class="keyword">val</span> next : <span>bigstring:<span>(<span><a href="#type-bigstring">bigstring</a> <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span> <span>close:<span>(<span>unit <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span> <span>exn:<span>(<span>exn <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span>
<span><a href="#type-request">request</a> <span class="arrow">-&gt;</span></span> unit</span></code>
</div>
|}
let next_replacement = {|
<pre><span class="keyword">val</span> next :
bigstring:(<a href="#type-bigstring">bigstring</a> -> int -> int -> unit) ->
?string:(string -> int -> int -> unit) ->
?flush:(unit -> unit) ->
close:(unit -> unit) ->
exn:(exn -> unit) ->
_ <a href="#type-message">message</a> ->
<a href="#type-request">request</a> ->
unit
</ore>
</pre>
|}
(* let body_stream_bigstring_expected = {|<div class="spec value" id="val-body_stream_bigstring">
<a href="#val-body_stream_bigstring" class="anchor"></a><code><span><span class="keyword">val</span> body_stream_bigstring : <span><span>(<span><a href="#type-bigstring">bigstring</a> <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span> <span><span>(<span>unit <span class="arrow">-&gt;</span></span> unit)</span> <span class="arrow">-&gt;</span></span> <span><span><span class="type-var">_</span> <a href="#type-message">message</a></span> <span class="arrow">-&gt;</span></span> unit</span></code>
let write_bigstring_expected = {|<div class="spec value" id="val-write_bigstring">
<a href="#val-write_bigstring" class="anchor"></a><code><span><span class="keyword">val</span> write_bigstring : <span><a href="#type-bigstring">bigstring</a> <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> <span>int <span class="arrow">-&gt;</span></span> <span><a href="#type-response">response</a> <span class="arrow">-&gt;</span></span> <span>unit <a href="#type-promise">promise</a></span></span></code>
</div>
|}
let body_stream_bigstring_replacement = {|
<pre><span class="keyword">val</span> body_stream_bigstring :
(<a href="#type-bigstring">bigstring</a> -> int -> int -> unit) ->
(unit -> unit) ->
(_ <a href="#type-message">message</a>) ->
unit
let write_bigstring_replacement = {|
<pre><span class="keyword">val</span> write_bigstring :
<a href="#type-bigstring">bigstring</a> -> int -> int -> <a href="#type-response">response</a> -> unit <a href="#type-promise">promise</a>
</pre>
|} *)
|}
let form_expected = {|<div class="spec type" id="type-form">
<a href="#type-form" class="anchor"></a><code><span><span class="keyword">type</span> form</span><span> = </span><span>[ </span></code>
@ -516,14 +511,14 @@ let pretty_print_signatures soup =
Soup.replace (next $ "> code") (Soup.parse next_replacement);
Soup.add_class "multiline" next);
(* let body_stream_bigstring = soup $ "#val-body_stream_bigstring" in
let write_bigstring = soup $ "#val-write_bigstring" in
if_expected
body_stream_bigstring_expected
(fun () -> pretty_print body_stream_bigstring)
write_bigstring_expected
(fun () -> pretty_print write_bigstring)
(fun () ->
Soup.replace
(body_stream_bigstring $ "> code")
(Soup.parse body_stream_bigstring_replacement)); *)
(write_bigstring $ "> code") (Soup.parse write_bigstring_replacement);
Soup.add_class "multiline" write_bigstring);
let form = soup $ "#type-form" in
if_expected

View File

@ -13,6 +13,10 @@ end
include Dream__pure.Inmost
(* Eliminate optional arguments from the public interface for now. *)
let next ~bigstring ~close ~exn request =
next ~bigstring ~close ~exn request
include Dream__middleware.Log
include Dream__middleware.Echo

View File

@ -550,30 +550,29 @@ val all_cookies : request -> (string * string) list
(* TODO Will need mappers, etc. *)
(** {1 Bodies} *)
val body : _ message -> string promise
(** Retrieves the entire message body. {!Dream.body} stores a reference to the
result string in the message, so {!Dream.body} can be used multiple
val body : request -> string promise
(** Retrieves the entire request body. {!Dream.body} stores a reference to the
result string in the request, so {!Dream.body} can be used multiple
times. *)
val with_body : string -> 'a message -> 'a message
(** Replaces the message body, creating a new message. *)
val with_body : string -> response -> response
(** Replaces the response body. *)
(** {2 Streaming} *)
(* TODO Rename to stream_body. *)
val read : _ message -> string option promise
(** Retrieves part of the message body. The promise is fulfilled with [None] if
the body is finished. The chunk is not buffered by Dream, so it can only be
read once. *)
val read : request -> string option promise
(** Retrieves a chunk of the request body. The promise is fulfilled with [None]
if the body is finished. The chunk is not buffered by Dream, so it can only
be read once. *)
(* val with_body_stream :
(unit -> string option promise) -> 'a message -> 'a message *)
(* TODO Could still use a Dream.respond_with_stream helper. *)
(* TODO Can still use a multishot, pull stream? *)
val with_stream : 'a message -> 'a message
(** Makes the message ready for stream writing with {!Dream.write}. If the
message is a response, you should return it from your handler soon after
only one call to {!Dream.write} will proceed until then. *)
val with_stream : response -> response
(** Makes the response ready for stream writing with {!Dream.write}. You should
return it from your handler soon after only one call to {!Dream.write}
will be accepted before then, and none will actually proceed. *)
(* [Dream.with_body_stream f message] creates a new message, with a stream
body represented by the function [f]. If the message is a response, after
@ -589,20 +588,19 @@ val with_stream : 'a message -> 'a message
(* TODO It would be nice if the returned message was already wrapped in a
promise. Does that preclude anything useful, however? *)
val write : string -> _ message -> unit promise
(** Streams out the string. The promise is fulfilled when the stream can accept
more writes. *)
val write : string -> response -> unit promise
(** Streams out the string. The promise is fulfilled when the response can
accept more writes. *)
val flush : _ message -> unit promise
(** Flushes write buffers. If the message is a response, data is sent to the
client. *)
val flush : response -> unit promise
(** Flushes write buffers. Data is sent to the client. *)
val close_stream : _ message -> unit promise
(** Finishes the write stream. *)
val close_stream : response -> unit promise
(** Finishes the response stream. *)
(* TODO close_stream or close_body? *)
(**/**)
val has_body : _ message -> bool
(* val has_body : _ message -> bool *)
(** Evalutes to [true] if the given message either has a body that has been
streamed and has positive length, or a body that has not been streamed yet.
This function does not stream the body it could return [true], and later
@ -630,25 +628,20 @@ type bigstring =
(* TODO Is the final unit necessary. *)
val next :
bigstring:(bigstring -> int -> int -> unit) ->
?string:(string -> int -> int -> unit) ->
?flush:(unit -> unit) ->
(* ?string:(string -> int -> int -> unit) ->
?flush:(unit -> unit) -> *)
close:(unit -> unit) ->
exn:(exn -> unit) ->
_ message ->
request ->
unit
(** Waits for the next event on the stream, and calls:
(** Waits for the next stream event, and calls:
- [~bigstring] with an offset and length, if a {!bigstring} is written.
- [~string] if a string is written.
- [~flush] if flush is requested.
- [~close] if close is requested.
- [~exn] to report an exception.
- [~exn] to report an exception. *)
If the message is a request provided by Dream, [~string] and [~flush] will
never be called, so they are optional. *)
val write_bigstring : bigstring -> int -> int -> _ message -> unit promise
(** Streams out the bigstring slice. *)
val write_bigstring : bigstring -> int -> int -> response -> unit promise
(** Streams out the {!bigstring} slice. *)
(**/**)
(* TODO Format after settling on it. *)

View File

@ -151,7 +151,7 @@ let%expect_test _ =
let next message =
let until_done, signal_done = Lwt.wait () in
let rec next accumulator =
Dream.next
Dream__pure.Inmost.next
~bigstring:(fun data start length ->
next
((Lwt_bytes.to_string
@ -161,7 +161,7 @@ let next message =
((String.sub data start length)::accumulator))
~close:(fun () -> Lwt.wakeup_later signal_done (List.rev accumulator))
~exn:ignore
message
(Obj.magic message)
in
next [];
Lwt_main.run until_done