src/step.bend

emerging-ezhttp@0.15.0.0 · 50 lines · 0 definitions

1# ezhttp/src/step: what the server decides for one connection, kept pure so
2# a law can state it. server.bend runs the effects and asks this module what
3# each outcome means; it decides nothing itself.
4import Base
5import emerging-ezhttp@0.15.0.0/src/http.bend as Http
6
7# what a request asks of the server: answer it now, or call the handler
8type Step is Data:
9  Answer{reply: Http.Reply}
10  Call{req: Http.Request}
11
12# an effect's outcome on one connection: the value, or the line to log for
13# a connection that is lost
14type Got<-A: Type> is Type:
15  Kept{value: A}
16  Lost{line: String}
17
18# a bad request is answered 400 with its reason and never reaches the
19# handler; a good one goes to the handler as it was parsed
20def step.of(req: Http.Request) -> Step:
21  match req:
22    case Http.Bad{why}:
23      Answer{Http.Reply{400, [], why}}
24    case Http.Request{method, target, headers, body}:
25      Call{Http.Request{method, target, headers, body}}
26
27# the line logged for a failed effect: `ezhttp: <phase>: <why>`
28def step.line(phase: String, why: String) -> String:
29  "ezhttp: " ++ phase ++ ": " ++ why
30
31# a failed accept or recv loses the connection instead of ending the server
32def step.got(
33  -A: Type,
34  phase: String,
35  res: Result<&1, &1, U32 & String, A>
36) -> Got<A>:
37  match res:
38    case Fail{(code, why)}:
39      Lost{step.line(phase, why)}
40    case Done{value}:
41      Kept{value}
42
43# a failed send loses the connection too; the bytes it did not send are dropped
44def step.sent(res: Result<&1, &1, (U32 & String) & List<&2, U32>, Unit>)
45  -> Got<Unit>:
46  match res:
47    case Fail{((code, why), left)}:
48      Lost{step.line("write", why)}
49    case Done{value}:
50      Kept{value}