about summary refs log tree commit diff stats
path: root/src/io/loader.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2022-08-18 17:09:52 +0200
committerbptato <nincsnevem662@gmail.com>2022-08-18 17:09:52 +0200
commita78c26198e747d4de887e1f582d29f14fb59391b (patch)
treedbea97fe93618e146dd0e3901d54328e86d54fd1 /src/io/loader.nim
parente2203257e07aada157be9d0a948273cb9d683072 (diff)
downloadchawan-a78c26198e747d4de887e1f582d29f14fb59391b.tar.gz
Use a separate process for file loading
Not very useful for now, since we still have to load the entire page
before parsing it.
Diffstat (limited to 'src/io/loader.nim')
-rw-r--r--src/io/loader.nim125
1 files changed, 107 insertions, 18 deletions
diff --git a/src/io/loader.nim b/src/io/loader.nim
index f7ac06e6..74a692fe 100644
--- a/src/io/loader.nim
+++ b/src/io/loader.nim
@@ -4,12 +4,14 @@ import tables
 when defined(posix):
   import posix
 
+import bindings/curl
 import io/http
-import io/loadertypes
+import io/request
+import io/serialize
 import types/mime
 import types/url
 
-export loadertypes
+export request
 
 const DefaultHeaders = {
   "User-Agent": "chawan",
@@ -32,26 +34,113 @@ proc doFork(): Pid =
     quit(0)
   return 0
 
+proc loadFile(url: Url, ostream: Stream) =
+  when defined(windows) or defined(OS2) or defined(DOS):
+    let path = url.path.serialize_unicode_dos()
+  else:
+    let path = url.path.serialize_unicode()
+  let istream = newFileStream(path, fmRead)
+  ostream.swrite(if istream != nil:
+    200 # ok
+  else:
+    404 # file not found
+  )
+  ostream.swrite(guessContentType(path))
+  ostream.swrite(none(Url))
+  while not istream.atEnd:
+    const bufferSize = 4096
+    var buffer {.noinit.}: array[bufferSize, char]
+    while true:
+      let n = readData(istream, addr buffer[0], bufferSize)
+      if n == 0:
+        break
+      ostream.swrite(n)
+      ostream.writeData(addr buffer[0], n)
+      ostream.flush()
+      if n < bufferSize:
+        break
+    ostream.swrite("")
+    ostream.flush()
+
+proc loadResource(loader: FileLoader, request: Request, ostream: Stream) =
+  case request.url.scheme
+  of "file":
+    loadFile(request.url, ostream)
+  of "http", "https":
+    loadHttp(request, ostream)
+
+proc runFileLoader(loader: FileLoader) =
+  if curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK:
+    eprint "Failed to initialize libcurl."
+    quit(1)
+  let istream = newFileStream(stdin)
+  let ostream = newFileStream(stdout)
+  while true:
+    try:
+      let request = istream.readRequest()
+      loader.loadResource(request, ostream)
+    except IOError:
+      # End-of-file, quit.
+      # TODO this should be EOFError
+      break
+  istream.close()
+  ostream.close()
+  curl_global_cleanup()
+  quit(0)
+
+proc doRequest*(loader: FileLoader, request: Request): LoadResult =
+  if loader.istream != nil:
+    loader.istream.swrite(request)
+    loader.istream.flush()
+    loader.ostream.sread(result.status)
+    loader.ostream.sread(result.contenttype)
+    loader.ostream.sread(result.redirect)
+    result.s = loader.ostream
+  else:
+    eprint "Error: no loader process"
+    quit(1)
+
 proc newFileLoader*(defaultHeaders: HeaderList): FileLoader =
   new(result)
   result.defaultHeaders = defaultHeaders
+  when defined(posix):
+    var pipefd_a: array[0..1, cint]
+    var pipefd_b: array[0..1, cint]
+    if pipe(pipefd_a) == -1:
+      eprint "Failed to open pipe."
+      quit(1)
+    if pipe(pipefd_b) == -1:
+      eprint "Failed to open pipe."
+      quit(1)
+    let pid = doFork()
+    if pid == 0:
+      # child process
+      let readfd = pipefd_a[0] # get read a
+      discard close(pipefd_a[1]) # close write a
+      let writefd = pipefd_b[1] # get write b
+      discard close(pipefd_b[0]) # close read b
+      discard dup2(readfd, stdin.getFileHandle())
+      discard dup2(writefd, stdout.getFileHandle())
+      result.runFileLoader()
+    else:
+      result.process = pid
+      let writefd = pipefd_a[1] # get write a
+      discard close(pipefd_a[0]) # close read a
+      let readfd = pipefd_b[0] # get read b
+      discard close(pipefd_b[1]) # close write b
+      var readf: File
+      var writef: File
+      if not open(readf, FileHandle(readfd), fmRead):
+        eprint "Failed to open output handle."
+        quit(1)
+      if not open(writef, FileHandle(writefd), fmWrite):
+        eprint "Failed to open input handle."
+        quit(1)
+      result.ostream = newFileStream(readf)
+      result.istream = newFileStream(writef)
 
 proc newFileLoader*(): FileLoader =
   newFileLoader(DefaultHeaders)
 
-proc getPage*(loader: FileLoader, url: Url, smethod: HttpMethod = HTTP_GET, mimetype = "", body = none(string), multipart = none(MimeData)): LoadResult =
-  case url.scheme
-  of "file":
-    when defined(windows) or defined(OS2) or defined(DOS):
-      let path = url.path.serialize_unicode_dos()
-    else:
-      let path = url.path.serialize_unicode()
-    result.contenttype = guessContentType(path)
-    result.s = newFileStream(path, fmRead)
-    if result.s != nil:
-      result.status = 200 # ok
-    else:
-      result.status = 404 # file not found
-  of "http", "https":
-    let request = loader.newRequest(url, smethod, {"Content-Type": mimetype}, body, multipart)
-    return getPageHttp(request)
+proc getPage*(loader: FileLoader, request: Request): LoadResult =
+  loader.doRequest(request)