Skip to content

Commit

Permalink
Add startup callback to settings (#89)
Browse files Browse the repository at this point in the history
* add startup callback to settings

* nimble -y test

* cancel threads

* fix

* change addExitProc condition,thread core and sys exported from nim v2

* so pthread_cancel platform specific

---------

Co-authored-by: bung87 <[email protected]>
  • Loading branch information
ThomasTJdev and bung87 authored Aug 7, 2023
1 parent 0f7b07f commit 17e322b
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 4 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ jobs:
nimversion: ${{ matrix.nimversion }}
- name: Test
run: |
nimble test
nimble -y test
nimble refresh
21 changes: 18 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
/tests/*
!/tests/*.nim
!/tests/*.cfg
*
!**/
!*.*
*.out
.DS_Store
!.gitattributes
!.gitignore
!readme.md
!.gitkeep
!*.nim
!*.nims
!*.nimble
!*.h
!*.css
!*.html
*.exe
!*/
nimbledeps
27 changes: 27 additions & 0 deletions src/httpbeast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import selectors, net, nativesockets, os, httpcore, asyncdispatch, strutils, pos
import parseutils
import options, sugar, logging
import macros
import std/exitprocs
import system / ansi_c

from posix import ENOPROTOOPT

Expand Down Expand Up @@ -51,6 +53,8 @@ type

OnRequest* = proc (req: Request): Future[void] {.gcsafe.}

Startup = proc () {.closure, gcsafe.}

Settings* = object
port*: Port
bindAddr*: string
Expand All @@ -68,15 +72,23 @@ type
## 4096 for Linux/AMD64 and 128 for others.
## * listen(2) Linux manual page: https://www.man7.org/linux/man-pages/man2/listen.2.html
## * SYN packet handling int the wild: https://blog.cloudflare.com/syn-packet-handling-in-the-wild/
startup: Startup
## An optional callback can be provided to execute at the beginning of
## the `eventLoop` function for initializing thread variables or performing other related tasks.

HttpBeastDefect* = ref object of Defect

const
serverInfo = "HttpBeast"

proc doNothing(): Startup {.gcsafe.} =
result = proc () {.closure, gcsafe.} =
discard

proc initSettings*(port: Port = Port(8080),
bindAddr: string = "",
numThreads: int = 0,
startup: Startup = doNothing(),
domain = Domain.AF_INET,
reusePort = true,
listenBacklog = SOMAXCONN): Settings =
Expand All @@ -88,6 +100,7 @@ proc initSettings*(port: Port = Port(8080),
loggers: getHandlers(),
reusePort: reusePort,
listenBacklog: listenBacklog,
startup: startup
)

proc initData(fdKind: FdKind, ip = ""): Data =
Expand Down Expand Up @@ -333,6 +346,9 @@ proc eventLoop(
) =
let (onRequest, settings, isMainThread) = params

if settings.startup != nil:
settings.startup()

if not isMainThread:
# We are on a new thread. Re-add the loggers from the main thread.
for logger in settings.loggers:
Expand Down Expand Up @@ -544,6 +560,17 @@ proc run*(onRequest: OnRequest, settings: Settings) =
createThread[(OnRequest, Settings, bool)](
t, eventLoop, (onRequest, settings, false)
)
when NimMajor >= 2:
addExitProc(proc() =
for thr in threads:
when compiles(pthread_cancel(thr.sys)):
discard pthread_cancel(thr.sys)
if not isNil(thr.core):
when defined(gcDestructors):
c_free(thr.core)
else:
deallocShared(thr.core)
)
else:
assert false
echo("Listening on port ", settings.port) # This line is used in the tester to signal readiness.
Expand Down
7 changes: 7 additions & 0 deletions tests/startup.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
charset = "utf-8"
[Package]
name = "hello"
--threads:on
[Author]
name = "nim-lang"
website = "nim-lang.org"
41 changes: 41 additions & 0 deletions tests/startup.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import os, options, asyncdispatch, parsecfg, strutils, streams
import httpbeast

const CurDir = currentSourcePath.parentDir

var threadsOn {.threadvar.}: bool
var name {.threadvar.}: string

proc onRequest(req: Request): Future[void] =
if req.httpMethod == some(HttpGet):
case req.path.get()
of "/":
req.send("name:$#,threads:$#." % [name, $threadsOn])
else:
req.send(Http404)

var startup = proc () =
let configFile = CurDir / "startup.ini"
var f = newFileStream(configFile, fmRead)
assert f != nil, "cannot open " & configFile
var p: CfgParser
var section: string
open(p, f, configFile)
while true:
var e = next(p)
case e.kind
of cfgEof: break
of cfgSectionStart: ## a `[section]` has been parsed
section = e.section
of cfgKeyValuePair:
if section == "Package" and e.key == "name":
name = e.value
of cfgOption:
if e.key == "threads":
if e.value == "on":
threadsOn = true
of cfgError:
echo e.msg
close(p)

run(onRequest, initSettings(startup = startup))

0 comments on commit 17e322b

Please sign in to comment.