rpc.bend

cswap-bend-cli@0.1.0.0 · 61 lines · 7 definitions

1import Base
2import cswap-bend-cli@0.1.0.0/json.bend as Json
3import cswap-bend-cli@0.1.0.0/cmd.bend as Cmd
4import cswap-bend-cli@0.1.0.0/exec.bend as Exec
5import cswap-bend-cli@0.1.0.0/fmt/out.bend as O
6import cswap-bend-cli@0.1.0.0/fmt/yaml.bend as Yaml
7import cswap-bend-cli@0.1.0.0/fmt/toon.bend as Toon
8import cswap-bend-cli@0.1.0.0/frame.bend as Fr
9import cswap-bend-cli@0.1.0.0/rpcmsg.bend as M
10
11# One rpc message in, one response out, shared by `cswap rpc` (stdin/stdout)
12# and `cswap serve` (a unix socket). The message is in the rpc format: JSON
13# (a line), YAML or TOON (a block ended by a blank line). The command runs
14# in this process through Exec.exec_line with the output format forced to json.
15
16# A YAML or TOON message is a block, a JSON message a line.
17def is_block(f: O.Fmt) -> Bool:
18  Bool.not(O.is_json(f))
19
20def render(f: O.Fmt, +j: Json.Json) -> String:
21  match f:
22    case O.FYaml{}:
23      Yaml.emit(j) ++ "\n\n"
24    case O.FToon{}:
25      Toon.emit(j) ++ "\n\n"
26    case _:
27      Json.emit.go(j, 0, True{}, 0n) ++ "\n"
28
29def parse_req(f: O.Fmt, +msg: String) -> Result<&2, &2, String, Json.Json>:
30  match f:
31    case O.FYaml{}:
32      Yaml.parse(msg)
33    case O.FToon{}:
34      Toon.parse(msg)
35    case _:
36      Json.parse(msg)
37
38def run_req(+f: O.Fmt, r: M.Req) -> IO(String):
39  match r:
40    case M.ReqOk{id, argv}:
41      IO.bind(Cmd.Out, String, Exec.exec_line(argv, Some{O.FJson{}}), o => IO.pure(String, render(f, M.response(id, o))))
42    case M.ReqBad{id, code, msg}:
43      IO.pure(String, render(f, M.err_resp(id, code, msg, 2)))
44
45def run_doc(+f: O.Fmt, r: Result<&2, &2, String, Json.Json>) -> IO(String):
46  match r:
47    case Done{j}:
48      run_req(f, M.plan(j))
49    case Fail{e}:
50      IO.pure(String, render(f, M.err_resp(Json.JNull{}, "bad_request", e, 2)))
51
52def handle2(blank: Bool, +f: O.Fmt, +msg: String) -> IO(String):
53  match blank:
54    case True{}:
55      IO.pure(String, "")
56    case False{}:
57      run_doc(f, parse_req(f, msg))
58
59# The response text for one message ("" for a blank one).
60def handle(+f: O.Fmt, +msg: String) -> IO(String):
61  handle2(Fr.blank(msg), f, msg)