A threaded http server for future projects
Find a file
2024-12-02 16:35:12 -05:00
src better conform to nim style guide 2024-12-02 16:35:12 -05:00
tests better conform to nim style guide 2024-12-02 16:35:12 -05:00
albaHttpServer.nimble bump 2024-12-02 16:10:17 -05:00
README.md minor changes 2024-12-02 16:09:12 -05:00

What is this?

This is alba Http Server. It is like the threaded dispatchers of old, written in Nim. This includes the following:

  • A simplified HTTP Server which does NOT use any ASYNC due to memory issues in Nim at the current moment. It also creates its own "Request" object compared to the one seen in the stdlib.
Request* = object
  path* : Uri
  verb* : HttpMethod
  headers* : Table[string, string]
  socket* : Socket
  address* : string
  • A threaded dispatcher which allocates requests to the thread with the least amount of requests currently pending. This is ideal for high-cpu using APIs.

It works using the following objects:

type
  ThreadScheduler*[T] = object
    initFunction : proc(): T{.gcsafe.}
    paths : Table[string, proc(a : Request, b : T){.gcsafe.}]
  ThreadHandler*[T] = object
    Scheduler : ThreadScheduler[T]
    communications: seq[ptr Channel[ptr Request]]
    cpuCount : int

Where, T is the thread-local storage. For example

type ControllerData* = object
  # Database connection for db operations
  db : DbConn
  # Standard response header, for all responses
  headers : TableRef[string, string]
  # Pre-generated response
  dbInfo : string
  # Pre-generated data
  allUsers : seq[string]

All endpoints registered in paths must take the type [T] in.

Usage

import albaHttpServer
import httpclient
import tables
import net
type MyObject = object
  foo : string
  bar : string
proc doThing(a : Request, b : MyObject) =
  if a.verb != HttpGet:
    a.respond(405, "")
  a.respond(200, b.foo)

proc init() : MyObject =
  result.foo = "hello"
  result.bar = "world"

var paths : Table[string, proc(a: Request, b: MyObject){.gcsafe.}]
paths["/"] = doThing
let handler = initHandler[MyObject](init, paths)

let socket = newSocket()
socket.setSockOpt(OptReusePort, true)
socket.bindAddr(Port(5000))
socket.listen()
while true:
  var request = getRequest(socket)
  #Checks for invalid requests.
  if request.isNone():
    continue
  else:
    let req = request.get()
    dispatch(req, handler)