about summary refs log tree commit diff stats
path: root/src/io/response.nim
blob: 321f43d0cd750617d4e963a3049dd4f3004926bc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import streams

import bindings/quickjs
import io/headers
import io/promise
import io/request
import js/exception
import js/javascript
import types/url

type
  Response* = ref object
    res*: int
    fd*: int
    body*: Stream
    bodyUsed* {.jsget.}: bool
    contenttype* {.jsget.}: string
    status* {.jsget.}: uint16
    headers* {.jsget.}: Headers
    redirect*: Request
    url*: URL #TODO should be urllist?
    unregisterFun*: proc()
    bodyRead*: Promise[string]

jsDestructor(Response)

proc newResponse*(res: int, request: Request, fd = -1, stream: Stream = nil):
    Response =
  return Response(
    res: res,
    url: request.url,
    body: stream,
    bodyRead: Promise[string](),
    fd: fd
  )

func sok(response: Response): bool {.jsfget: "ok".} =
  return response.status in 200u16 .. 299u16

func surl(response: Response): string {.jsfget: "url".} =
  return $response.url

#TODO: this should be a property of body
proc close*(response: Response) {.jsfunc.} =
  response.bodyUsed = true
  if response.unregisterFun != nil:
    response.unregisterFun()
  if response.body != nil:
    response.body.close()

proc text*(response: Response): Promise[Result[string, JSError]] {.jsfunc.} =
  if response.bodyRead == nil:
    let p = Promise[Result[string, JSError]]()
    let err = Result[string, JSError]
      .err(newTypeError("Body has already been consumed"))
    p.resolve(err)
    return p
  let bodyRead = response.bodyRead
  response.bodyRead = nil
  return bodyRead.then(proc(s: string): Result[string, JSError] =
    ok(s))

proc json(ctx: JSContext, this: Response): Promise[Result[JSValue, JSError]]
    {.jsfunc.} =
  return this.text().then(proc(s: Result[string, JSError]):
      Result[JSValue, JSError] =
    let s = ?s
    return ok(JS_ParseJSON(ctx, cstring(s), cast[csize_t](s.len),
      cstring"<input>")))

proc addResponseModule*(ctx: JSContext) =
  ctx.registerType(Response)