Implement org file server

This commit is contained in:
Florian Schroedl
2022-05-30 18:34:25 +02:00
parent 05ecdb1f9e
commit bbc3c9d28b
4 changed files with 143 additions and 13 deletions

View File

@@ -1,20 +1,34 @@
#+TITLE: Todo #+TITLE: Todo
* Todos * Todos
** ACTIVE Creating a server :BACK_END:
** TODO Creating a server
:LOGBOOK: :LOGBOOK:
CLOCK: [2022-05-29 Sun 11:24] CLOCK: [2022-05-30 Mon 07:52]--[2022-05-30 Mon 09:00] => 1:08
CLOCK: [2022-05-29 Sun 11:24]--[2022-05-29 Sun 16:44] => 5:20
:END: :END:
- [[https://nim-lang.org/docs/asynchttpserver.html][std/asynchttpserver]] - [[https://nim-lang.org/docs/asynchttpserver.html][std/asynchttpserver]]
- [[https://github.com/h3rald/nimhttpd/blob/master/src/nimhttpd.nim][nimhttpd/nimhttpd.nim at master · h3rald/nimhttpd]] - [[https://github.com/h3rald/nimhttpd/blob/master/src/nimhttpd.nim][nimhttpd/nimhttpd.nim at master · h3rald/nimhttpd]]
** TODO Creating hot reload ** TODO Headline content parser
** TODO Store the line numbers :PARSER:
** TODO Tag parser :PARSER:
** TODO Build Redux :FRONT_END:
:PROPERTIES:
:CREATED: [2022-05-16 Mon 22:12]
:END:
- [[https://blog.bitsrc.io/build-our-own-react-redux-using-usereducer-and-usecontext-hooks-a5574b526475][Build Your Own React-Redux Using useReducer and useContext Hooks | by Chidume Nnamdi | Bits and Pieces]]
** TODO Creating hot reload :DEV_ENVIRONMENT:
- [ ] [[https://dev.to/alemagio/implement-your-own-hot-reload-2435][Implement your own hot-reload - DEV Community]] - [ ] [[https://dev.to/alemagio/implement-your-own-hot-reload-2435][Implement your own hot-reload - DEV Community]]
- [ ] [[https://maheshsenniappan.medium.com/creating-a-module-bundler-with-hot-module-replacement-b439f0cc660f][Creating a module bundler with Hot Module Replacement | by Mahesh Senniappan | Medium]] - [ ] [[https://maheshsenniappan.medium.com/creating-a-module-bundler-with-hot-module-replacement-b439f0cc660f][Creating a module bundler with Hot Module Replacement | by Mahesh Senniappan | Medium]]
- [ ] [[https://maheshsenniappan.medium.com/creating-a-module-bundler-with-hot-module-replacement-b439f0cc660f][Creating a module bundler with Hot Module Replacement | by Mahesh Senniappan | Medium]] - [ ] [[https://maheshsenniappan.medium.com/creating-a-module-bundler-with-hot-module-replacement-b439f0cc660f][Creating a module bundler with Hot Module Replacement | by Mahesh Senniappan | Medium]]
** TODO Cordova App
https://hub.docker.com/r/xurei/docker-cordova
** DONE A nim compiler with watcher for js files ** DONE A nim compiler with watcher for js files
:PROPERTIES: :PROPERTIES:
:CREATED: [2022-05-18 Wed 14:22] :CREATED: [2022-05-18 Wed 14:22]

View File

@@ -1,24 +1,72 @@
import std/[ import std/[
mimetypes, mimetypes,
os, os,
strformat,
] ]
import fp/[
map,
]
import ./errors
const PORT_DEFAULT* = 1337 const PORT_DEFAULT* = 1337
const HTML_ROOT* = "../js" const HTML_ROOT* = "../js"
const DIST_ROOT* = HTML_ROOT.joinPath("dist") const DIST_ROOT* = HTML_ROOT.joinPath("dist")
type Env* = ref object type
port*: int orgPath* = string
mimeTypes*: MimeDb orgId* = string
htmlRoot*: string # OrgEnv* = ref object
distRoot*: string # paths*: seq[tuple[
# path: orgPath,
# id: orgId,
# ]]
proc initEnv*(): auto = type
debugLevel* = enum
log
type
Env* = ref object
port*: int
mimeTypes*: MimeDb
debugLevel*: debugLevel
htmlRoot*: string
distRoot*: string
orgEnv*: Map[orgId, orgPath]
proc debugLog*(env: Env, content: string): void =
case env.debugLevel:
of log: echo(content)
proc logErr*(env: Env, err: orgEnvErr, t1: string): void {.inline.} =
debugLog(env, stringify(err, t1))
proc initEnv*(): Env =
Env( Env(
port: PORT_DEFAULT, port: PORT_DEFAULT,
mimeTypes: newMimetypes(), mimeTypes: newMimetypes(),
debugLevel: log,
htmlRoot: HTML_ROOT, htmlRoot: HTML_ROOT,
distRoot: DIST_ROOT, distRoot: DIST_ROOT,
orgEnv: @[
("Main", "~/Documents/Org/Main/".expandTilde()),
("Work", "~/Documents/Org/Work/".expandTilde()),
].asMap()
) )
echo newMimetypes().getMimetype("txt") proc `$`*(x: Env): string =
&"""Env(
port: {x.port},
debugLevel: {x.debugLevel},
htmlRoot: {x.htmlRoot},
distRoot: {x.distRoot},
orgEnv: {x.orgEnv},
)
"""
when isMainModule:
echo initEnv()

24
src/server/errors.nim Normal file
View File

@@ -0,0 +1,24 @@
import std/[
strformat,
sugar,
]
type
orgEnvErr* = enum
invalidWorkspaceId
fileNotFound
const errorPrefix = "Error: "
const invalidWorkspaceIdMessage = "Could not find org workspace with id: "
const fileNotFoundMessage = "Could not find org file: "
func stringify*(x: orgEnvErr, t1: string): string =
let msg = case x:
of invalidWorkspaceId: invalidWorkspaceIdMessage & t1
of fileNotFound: fileNotFoundMessage & t1
errorPrefix & msg
when isMainModule:
doAssert: invalidWorkspaceId.stringify($0) == errorPrefix & invalidWorkspaceIdMessage & $0
doAssert: fileNotFound.stringify("/path/to/file") == errorPrefix & fileNotFoundMessage & "/path/to/file"

View File

@@ -11,10 +11,14 @@ import std/[
sugar, sugar,
] ]
import fp/[ import fp/[
map,
option, option,
maybe,
resultM,
] ]
import fusion/matching import fusion/matching
import ./env import ./env
import ./errors
import ./utils import ./utils
# (GET, (scheme: "", username: "", password: "", hostname: "", port: "", path: "/", query: "", anchor: "", opaque: false, isIpv6: false), {"accept": @["*/*"], "host": @["localhost:45201"], "user-agent": @["curl/7.82.0"]}) # (GET, (scheme: "", username: "", password: "", hostname: "", port: "", path: "/", query: "", anchor: "", opaque: false, isIpv6: false), {"accept": @["*/*"], "host": @["localhost:45201"], "user-agent": @["curl/7.82.0"]})
@@ -55,6 +59,44 @@ proc sendStaticFile(env: Env, path: seq[string]): NimHttpResponse =
}) })
) )
proc sendOrgFile(env: Env, id: orgId, path: seq[string]): NimHttpResponse =
type errT = tuple[err: orgEnvErr, id: orgId, path: string]
type StringResult = Result[orgPath, errT]
type FileResult = Result[string, errT]
let content = env.orgEnv
.get(id)
.fold(
() => StringResult.err((invalidWorkspaceId, id, "")),
(x: orgPath) => StringResult.ok(x),
)
.map((x: orgPath) => $x.joinPath(path.join("/")))
.flatMap((path: orgPath) => (
catch(readFile(path)).fold(
_ => FileResult.err((fileNotFound, id, path)),
(content: string) => FileResult.ok(content),
)
))
.tapErr((err: errT) => logErr(env, err[0], &"{err[1]}, path: {err[2]}"))
content.fold(
(e: errT) => (
code: Http404,
content: "File not Found",
headers: newHttpHeaders({
"Content-Type": "application/json"
})
),
(content: string) => (
code: Http200,
content: content,
headers: newHttpHeaders({
"Content-Type": "application/json"
})
)
)
proc handleRoute(env: Env, req: Request): NimHttpResponse = proc handleRoute(env: Env, req: Request): NimHttpResponse =
# Handle main route # Handle main route
if req.url.path == "/": if req.url.path == "/":
@@ -65,9 +107,11 @@ proc handleRoute(env: Env, req: Request): NimHttpResponse =
# Router # Router
return ( return (
case path: case (req.reqMethod, path):
of ["dist", .._]: of (HttpGet, ["dist", .._]):
sendStaticFile(env, path) sendStaticFile(env, path)
of (HttpGet, ["org", @id, all @rest]):
sendOrgFile(env, id, rest)
else: else:
sendNotFound(env, path) sendNotFound(env, path)
) )