about summary refs log tree commit diff stats
path: root/src/loader/loaderhandle.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-02-05 15:32:05 +0100
committerbptato <nincsnevem662@gmail.com>2024-02-07 22:21:48 +0100
commit407b525332106d84f18d74f6b51ae2f7a1ed3475 (patch)
treec4ca2ad55df079b9c49d9361bc3c495a7a5977d0 /src/loader/loaderhandle.nim
parent168bd542d989c76ce3ff09a29b8d77af448c3c12 (diff)
downloadchawan-407b525332106d84f18d74f6b51ae2f7a1ed3475.tar.gz
Incremental rendering
Yay!

Admittedly, it is not very useful in its current form, except maybe on
very slow networks.

The problem is that renderDocument is *slow*, so we only run it when
onload fails to consume all bytes from the network in a single pass.
Even then, we are guaranteed to get a FOUC, since CSS is only downloaded
in finishLoad(). Well, I think it's cool, anyway.
Diffstat (limited to 'src/loader/loaderhandle.nim')
-rw-r--r--src/loader/loaderhandle.nim110
1 files changed, 85 insertions, 25 deletions
diff --git a/src/loader/loaderhandle.nim b/src/loader/loaderhandle.nim
index 7a9b3434..5d2dee4e 100644
--- a/src/loader/loaderhandle.nim
+++ b/src/loader/loaderhandle.nim
@@ -1,3 +1,4 @@
+import std/deques
 import std/net
 import std/streams
 
@@ -7,28 +8,72 @@ import io/serialize
 import io/socketstream
 import loader/headers
 
-type LoaderHandle* = ref object
-  ostream: Stream
-  # Stream for taking input
-  istream*: PosixStream
-  # Only the first handle can be redirected, because a) mailcap can only
-  # redirect the first handle and b) async redirects would result in race
-  # conditions that would be difficult to untangle.
-  canredir: bool
-  sostream: Stream # saved ostream when redirected
-  sostream_suspend: Stream # saved ostream when suspended
-  fd: int
+import types/url
+type
+  LoaderBufferPage = array[4056, uint8] # 4096 - 8 - 32
+
+  LoaderBufferObj = object
+    page*: LoaderBufferPage
+    len: int
+
+  LoaderBuffer* = ptr LoaderBufferObj
+
+  LoaderHandle* = ref object
+    ostream*: PosixStream #TODO un-extern
+    # Stream for taking input
+    istream*: PosixStream
+    # Only the first handle can be redirected, because a) mailcap can only
+    # redirect the first handle and b) async redirects would result in race
+    # conditions that would be difficult to untangle.
+    canredir: bool
+    sostream: Stream # saved ostream when redirected
+    sostream_suspend: Stream # saved ostream when suspended
+    fd*: int # ostream fd
+    currentBuffer*: LoaderBuffer
+    currentBufferIdx*: int
+    buffers: Deque[LoaderBuffer]
+    url*: URL #TODO TODO TODO debug
 
 # Create a new loader handle, with the output stream ostream.
-proc newLoaderHandle*(ostream: Stream, canredir: bool): LoaderHandle =
+proc newLoaderHandle*(ostream: PosixStream, canredir: bool, url: URL): LoaderHandle =
   return LoaderHandle(
     ostream: ostream,
     canredir: canredir,
-    fd: int(SocketStream(ostream).source.getFd())
+    fd: int(SocketStream(ostream).source.getFd()),
+    url: url
   )
 
-proc getFd*(handle: LoaderHandle): int =
-  return handle.fd
+func `[]`*(buffer: LoaderBuffer, i: int): var uint8 {.inline.} =
+  return buffer[].page[i]
+
+func cap*(buffer: LoaderBuffer): int {.inline.} =
+  return buffer[].page.len
+
+func len*(buffer: LoaderBuffer): var int {.inline.} =
+  return buffer[].len
+
+proc `len=`*(buffer: LoaderBuffer, i: int) {.inline.} =
+  buffer[].len = i
+
+proc newLoaderBuffer*(): LoaderBuffer =
+  let buffer = cast[LoaderBuffer](alloc(sizeof(LoaderBufferObj)))
+  buffer.len = 0
+  return buffer
+
+proc addBuffer*(handle: LoaderHandle, buffer: LoaderBuffer) =
+  if handle.currentBuffer == nil:
+    handle.currentBuffer = buffer
+  else:
+    handle.buffers.addLast(buffer)
+
+proc bufferCleared*(handle: LoaderHandle) =
+  assert handle.currentBuffer != nil
+  handle.currentBufferIdx = 0
+  dealloc(handle.currentBuffer)
+  if handle.buffers.len > 0:
+    handle.currentBuffer = handle.buffers.popFirst()
+  else:
+    handle.currentBuffer = nil
 
 proc addOutputStream*(handle: LoaderHandle, stream: Stream) =
   if likely(handle.sostream_suspend != nil):
@@ -43,8 +88,18 @@ proc addOutputStream*(handle: LoaderHandle, stream: Stream) =
     # sostream_suspend is never nil when the function is called.
     # (Feel free to remove this assertion if this changes.)
     doAssert false
-    let ms = newMultiStream(handle.ostream, stream)
-    handle.ostream = ms
+    #TODO TODO TODO fix this
+    #let ms = newMultiStream(handle.ostream, stream)
+    #handle.ostream = ms
+
+proc setBlocking*(handle: LoaderHandle, blocking: bool) =
+  #TODO this is stupid
+  if handle.sostream_suspend != nil and handle.sostream_suspend of SocketStream:
+    SocketStream(handle.sostream_suspend).setBlocking(blocking)
+  elif handle.sostream != nil and handle.sostream of SocketStream:
+    SocketStream(handle.sostream).setBlocking(blocking)
+  else:
+    SocketStream(handle.ostream).setBlocking(blocking)
 
 proc sendResult*(handle: LoaderHandle, res: int, msg = "") =
   handle.ostream.swrite(res)
@@ -67,23 +122,25 @@ proc sendHeaders*(handle: LoaderHandle, headers: Headers) =
       let stream = newPosixStream(fd)
       handle.ostream = stream
 
-proc sendData*(handle: LoaderHandle, p: pointer, nmemb: int) =
-  handle.ostream.writeData(p, nmemb)
-
-proc sendData*(handle: LoaderHandle, s: string) =
-  if s.len > 0:
-    handle.sendData(unsafeAddr s[0], s.len)
+proc sendData*(handle: LoaderHandle, p: pointer, nmemb: int): int =
+  return handle.ostream.sendData(p, nmemb)
 
 proc suspend*(handle: LoaderHandle) =
+  #TODO TODO TODO fix suspend
+  doAssert false
   handle.sostream_suspend = handle.ostream
-  handle.ostream = newStringStream()
+  #handle.ostream = newStringStream()
 
 proc resume*(handle: LoaderHandle) =
+  #TODO TODO TODO fix resume
+  doAssert false
+  #[
   let ss = handle.ostream
   handle.ostream = handle.sostream_suspend
   handle.sostream_suspend = nil
   handle.sendData(ss.readAll())
   ss.close()
+  ]#
 
 proc close*(handle: LoaderHandle) =
   if handle.sostream != nil:
@@ -93,6 +150,9 @@ proc close*(handle: LoaderHandle) =
       # ignore error, that just means the buffer has already closed the stream
       discard
     handle.sostream.close()
-  handle.ostream.close()
+  if handle.ostream != nil:
+    handle.ostream.close()
+    handle.ostream = nil
   if handle.istream != nil:
     handle.istream.close()
+    handle.istream = nil