about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2023-06-13 01:44:55 +0200
committerbptato <nincsnevem662@gmail.com>2023-06-13 01:44:55 +0200
commiteff1e064fde12fd6976919ca76b56c124231b31a (patch)
tree6df43f3cbbbb340e78b47be6334fe1ef7000e5c5
parent3a245434cd4bd75a56700ed7814f78699e3a3dd7 (diff)
downloadchawan-eff1e064fde12fd6976919ca76b56c124231b31a.tar.gz
Make Result.text, json return promise
-rw-r--r--src/buffer/buffer.nim6
-rw-r--r--src/display/client.nim6
-rw-r--r--src/img/png.nim1
-rw-r--r--src/io/loader.nim47
-rw-r--r--src/io/promise.nim12
-rw-r--r--src/io/request.nim19
6 files changed, 66 insertions, 25 deletions
diff --git a/src/buffer/buffer.nim b/src/buffer/buffer.nim
index f587c8ee..7a51792a 100644
--- a/src/buffer/buffer.nim
+++ b/src/buffer/buffer.nim
@@ -1151,8 +1151,7 @@ proc handleRead(buffer: Buffer, fd: int) =
   elif fd in buffer.loader.connecting:
     buffer.loader.onConnected(fd)
   elif fd in buffer.loader.ongoing:
-    #TODO something with readablestream?
-    discard
+    buffer.loader.onRead(fd)
   elif fd in buffer.loader.unregistered:
     discard # ignore
   else: assert false
@@ -1167,8 +1166,7 @@ proc handleError(buffer: Buffer, fd: int, err: OSErrorCode) =
     # probably shouldn't happen. TODO
     assert false, $fd & ": " & $err
   elif fd in buffer.loader.ongoing:
-    #TODO something with readablestream?
-    discard
+    buffer.loader.onError(fd)
   elif fd in buffer.loader.unregistered:
     discard # ignore
   else:
diff --git a/src/display/client.nim b/src/display/client.nim
index d3878e49..9783650f 100644
--- a/src/display/client.nim
+++ b/src/display/client.nim
@@ -293,8 +293,7 @@ proc handleRead(client: Client, fd: int) =
     client.loader.onConnected(fd)
     client.runJSJobs()
   elif fd in client.loader.ongoing:
-    #TODO something with readablestream?
-    discard
+    client.loader.onRead(fd)
   elif fd in client.loader.unregistered:
     discard # ignore
   else:
@@ -317,8 +316,7 @@ proc handleError(client: Client, fd: int) =
     #TODO handle error?
     discard
   elif fd in client.loader.ongoing:
-    #TODO something with readablestream?
-    discard
+    client.loader.onError(fd)
   elif fd in client.loader.unregistered:
     discard # already unregistered...
   else:
diff --git a/src/img/png.nim b/src/img/png.nim
index 3de395f2..ace31d00 100644
--- a/src/img/png.nim
+++ b/src/img/png.nim
@@ -413,7 +413,6 @@ proc zlibFree(opaque: pointer, address: pointer) {.cdecl.} =
   dealloc(address)
 
 proc initZStream(reader: var PNGReader) =
-  let bps = max(int(reader.bitDepth) div 8, 1)
   reader.idatBuf = newSeq[uint8](reader.scanlen * reader.height)
   reader.uprow = newSeq[uint8](reader.scanlen)
   reader.strm = z_stream(
diff --git a/src/io/loader.nim b/src/io/loader.nim
index 34eb9b42..f40882fc 100644
--- a/src/io/loader.nim
+++ b/src/io/loader.nim
@@ -23,13 +23,14 @@ import bindings/curl
 import io/about
 import io/file
 import io/http
+import io/posixstream
 import io/promise
 import io/request
 import io/urlfilter
-import js/javascript
 import ips/serialize
 import ips/serversocket
 import ips/socketstream
+import js/javascript
 import types/cookie
 import types/mime
 import types/referer
@@ -40,7 +41,7 @@ type
   FileLoader* = ref object
     process*: Pid
     connecting*: Table[int, ConnectData]
-    ongoing*: Table[int, Response]
+    ongoing*: Table[int, OngoingData]
     unregistered*: seq[int]
     registerFun*: proc(fd: int)
     unregisterFun*: proc(fd: int)
@@ -50,6 +51,11 @@ type
     stream: Stream
     request: Request
 
+  OngoingData = object
+    buf: string
+    readbufsize: int
+    response: Response
+
   ConnectErrorCode* = enum
     ERROR_SOURCE_NOT_FOUND = (-4, "clone source could not be found"),
     ERROR_LOADER_KILLED = (-3, "loader killed during transfer"),
@@ -258,9 +264,12 @@ proc newResponse(res: int, request: Request, stream: Stream = nil): Response =
   return Response(
     res: res,
     url: request.url,
-    body: stream
+    body: stream,
+    bodyRead: Promise[string]()
   )
 
+const BufferSize = 4096
+
 proc onConnected*(loader: FileLoader, fd: int) =
   let connectData = loader.connecting[fd]
   let stream = connectData.stream
@@ -279,7 +288,10 @@ proc onConnected*(loader: FileLoader, fd: int) =
     stream.sread(response.headers)
     applyHeaders(request, response)
     response.body = stream
-    loader.ongoing[fd] = response
+    loader.ongoing[fd] = OngoingData(
+      response: response,
+      readbufsize: BufferSize,
+    )
     promise.resolve(response)
   else:
     loader.unregisterFun(fd)
@@ -289,6 +301,33 @@ proc onConnected*(loader: FileLoader, fd: int) =
     promise.resolve(response)
   loader.connecting.del(fd)
 
+proc onRead*(loader: FileLoader, fd: int) =
+  loader.ongoing.withValue(fd, buffer):
+    let response = buffer[].response
+    while true:
+      let olen = buffer[].buf.len
+      buffer[].buf.setLen(olen + buffer.readbufsize)
+      try:
+        let n = response.body.readData(addr buffer[].buf[olen],
+          buffer.readbufsize)
+        if n != 0:
+          if buffer[].readbufsize < BufferSize:
+            buffer[].readbufsize = min(BufferSize, buffer[].readbufsize * 2)
+        buffer[].buf.setLen(olen + n)
+        if response.body.atEnd():
+          response.bodyRead.resolve(buffer[].buf)
+          loader.unregisterFun(fd)
+          loader.ongoing.del(fd)
+          loader.unregistered.add(fd)
+          response.body.close()
+        break
+      except ErrorAgain, ErrorWouldBlock:
+        assert buffer.readbufsize > 1
+        buffer.readbufsize = buffer.readbufsize div 2
+
+proc onError*(loader: FileLoader, fd: int) =
+  loader.onRead(fd)
+
 proc doRequest*(loader: FileLoader, request: Request, blocking = true): Response =
   new(result)
   result.url = request.url
diff --git a/src/io/promise.nim b/src/io/promise.nim
index 00702cec..0e1b6115 100644
--- a/src/io/promise.nim
+++ b/src/io/promise.nim
@@ -1,14 +1,14 @@
 import tables
 
 type
-  PromiseState = enum
+  PromiseState* = enum
     PROMISE_PENDING, PROMISE_FULFILLED, PROMISE_REJECTED
 
   EmptyPromise* = ref object of RootObj
     cb: (proc())
     next: EmptyPromise
     opaque: pointer
-    state: PromiseState
+    state*: PromiseState
 
   Promise*[T] = ref object of EmptyPromise
     res: T
@@ -100,6 +100,14 @@ proc then*[T](promise: Promise[T], cb: (proc(x: T): EmptyPromise)): EmptyPromise
         next.resolve()))
   return next
 
+proc then*[T, U](promise: Promise[T], cb: (proc(x: T): U)): Promise[U] {.discardable.} =
+  if promise == nil: return
+  let next = Promise[U]()
+  promise.then(proc(x: T) =
+    next.res = cb(x)
+    next.resolve())
+  return next
+
 proc then*[T, U](promise: Promise[T], cb: (proc(x: T): Promise[U])): Promise[U] {.discardable.} =
   if promise == nil: return
   let next = Promise[U]()
diff --git a/src/io/request.nim b/src/io/request.nim
index 4ae461df..61fee6dd 100644
--- a/src/io/request.nim
+++ b/src/io/request.nim
@@ -4,9 +4,10 @@ import strutils
 import tables
 
 import bindings/quickjs
+import io/promise
+import js/javascript
 import types/formdata
 import types/url
-import js/javascript
 import utils/twtstr
 
 type
@@ -84,6 +85,7 @@ type
     redirect*: Request
     url*: URL #TODO should be urllist?
     unregisterFun*: proc()
+    bodyRead*: Promise[string]
  
   ReadableStream* = ref object of Stream
     isource*: Stream
@@ -310,16 +312,13 @@ proc close*(response: Response) {.jsfunc.} =
   if response.body != nil:
     response.body.close()
 
-#TODO text, json should return promises, not blocking reads
-proc text*(response: Response): string {.jsfunc.} =
-  if response.body == nil:
-    return ""
-  result = response.body.readAll()
-  response.close()
+proc text*(response: Response): Promise[string] {.jsfunc.} =
+  return response.bodyRead
 
-proc json(response: Response, ctx: JSContext): JSValue {.jsfunc.} =
-  var s = response.text()
-  return JS_ParseJSON(ctx, cstring(s), cast[csize_t](s.len), cstring"<input>")
+proc json(ctx: JSContext, this: Response): Promise[JSValue] {.jsfunc.} =
+  return this.text().then(proc(s: string): JSValue =
+    return JS_ParseJSON(ctx, cstring(s), cast[csize_t](s.len),
+      cstring"<input>"))
 
 func credentialsMode*(attribute: CORSAttribute): CredentialsMode =
   case attribute