From bb7ab1967a450c04adac1f66d1dfbabb926de0e0 Mon Sep 17 00:00:00 2001 From: Niminem Date: Sat, 28 Oct 2023 23:21:30 -0400 Subject: [PATCH] modified shutdown timer to prevent crashes, added js module support via forcing MIME type. --- .gitignore | 3 ++- README.md | 5 +++++ src/neel.nim | 39 ++++++++++++++++++++++++--------------- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 61ac0e6..52111e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_Store -*.exe \ No newline at end of file +*.exe +*.txt \ No newline at end of file diff --git a/README.md b/README.md index 764090e..6cd0782 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,11 @@ nim c -r --threads:on --gc:orc main.nim ``` When compiling for Windows, also compile with the `--app:gui` flag. This will prevent the app opening up with the terminal. +#### Final Thoughts Before Developing With Neel +Keep the following in mind when developing you Neel App: +* All of your frontend assets are embedded into the binary at compile-time. For now you'll need to recompile when modifying/changing static frontend assets. +* To prevent crashes when users spam refresh or constantly switch between different pages, we implemented a sort of countdown timer for shutting down. Approximately 10 seconds after closing the app window, the server and program is killed if a websocket hasn't reconnected within that time period. Just keep that in mind before doing CTL+C in the terminal during testing. + ## Examples A simple Neel app that picks a random filename out of a given folder (something impossible from a browser): diff --git a/src/neel.nim b/src/neel.nim index 073c071..e3e8193 100644 --- a/src/neel.nim +++ b/src/neel.nim @@ -1,7 +1,8 @@ import std/[macros, os, strutils, osproc, json, threadpool, browsers, uri, tables] from std/sequtils import keepItIf import pkg/[mummy, mummy/routers] -export os, strutils, mummy, osproc, json, threadpool, browsers, routers +export os, strutils, osproc, json, threadpool, browsers +export mummy, routers type NeelError* = object of CatchableError @@ -12,7 +13,7 @@ proc getWebFolder*(webDirPath: string) :Table[string,string] {.compileTime.} = if path == "index.html": result["/"] = staticRead(webDirPath / path) else: - result["/" & path] = staticRead(webDirPath / path) + result["/" & path.replace('\\','/')] = staticRead(webDirPath / path) # ---------------------------------------------------------------------- @@ -182,7 +183,7 @@ proc findChromeMac*: string = if alternateDirs != @[]: result = alternateDirs[0] & "/Contents/MacOS/Google Chrome" else: - raise newException(NeelError, "could not find Chrome") + raise newException(NeelError, "could not find Chrome using `mdfind`") except: raise newException(NeelError, "could not find Chrome in Applications directory") @@ -205,14 +206,14 @@ proc findChromeWindows*: string = discard if result.len == 0: - raise newException(NeelError, "could not find Chrome in Program Files (x86) directory") + raise newException(NeelError, "could not find Chrome") proc findChromeLinux*: string = const chromeNames = ["google-chrome", "google-chrome-stable", "chromium-browser", "chromium"] for name in chromeNames: if execCmd("which " & name) == 0: return name - raise newException(NeelError, "could not find Chrome in PATH") + raise newException(NeelError, "could not find Chrome") proc findPath*: string = when hostOS == "macosx": @@ -242,19 +243,18 @@ proc openChrome*(portNo: int, chromeFlags: seq[string]) = macro startApp*(webDirPath: string, portNo: int = 5000, position: array[2, int] = [500,150], size: array[2, int] = [600,600], chromeFlags: seq[string] = @[""], appMode: bool = true) = - quote do: - const - assets = getWebFolder(`webDirPath`) - NOCACHE_HEADER = @[("Cache-Control","no-store")] - var openSockets: bool + const Assets = getWebFolder(`webDirPath`) + var openSockets = false proc handleFrontEndData*(frontEndData :string) {.gcsafe.} = callNim(frontEndData.parseJson) - proc shutdown = - sleep 1000 # *** NEED BETTER IMPLEMENTATION HERE... *** + proc shutdown = # quick implementation to reduce crashing from users spamming refresh / clicking on new pages + for i in 1 .. 10: + sleep 1000 + if openSockets: return if not openSockets: quit() if `appMode`: @@ -264,9 +264,14 @@ macro startApp*(webDirPath: string, portNo: int = 5000, proc indexHandler(request: Request) = let path = parseUri(request.uri).path - request.respond(200, NOCACHE_HEADER, assets[path]) + var headers: HttpHeaders + headers["Cache-Control"] = "no-store" + request.respond(200, headers, Assets[path]) proc jsHandler(request: Request) = - request.respond(200, NOCACHE_HEADER,"window.moveTo(" & $`position`[0] & "," & $`position`[1] & ")\n" & + var headers: HttpHeaders + headers["Cache-Control"] = "no-store" + headers["Content-Type"] = "application/javascript" + request.respond(200, headers,"window.moveTo(" & $`position`[0] & "," & $`position`[1] & ")\n" & "window.resizeTo(" & $`size`[0] & "," & $`size`[1] & ")\n" & "var ws = new WebSocket(\"ws://localhost:" & $`portNo` & "/ws\")\n" & """var connected = false @@ -328,7 +333,11 @@ macro startApp*(webDirPath: string, portNo: int = 5000, proc pathHandler(request: Request) = let path = parseUri(request.uri).path try: - request.respond(200,NOCACHE_HEADER,assets[path]) + var headers: HttpHeaders + headers["Cache-Control"] = "no-store" + if "js" == path.split('.')[^1]: # forcing MIME-type to support JS modules + headers["Content-Type"] = "application/javascript" + request.respond(200,headers,Assets[path]) except: raise newException(NeelError, "path: " & path & " doesn't exist")