84 lines
2.1 KiB
Nim
84 lines
2.1 KiB
Nim
|
import docopt, json, posix, nre, strutils
|
||
|
import os except sleep
|
||
|
|
||
|
type
|
||
|
CombinedConfig* = object
|
||
|
docopt*: Table[string, Value]
|
||
|
json*: JsonNode
|
||
|
|
||
|
proc getVal*(cfg: CombinedConfig, key, default: string): string =
|
||
|
let argKey = "--" & key
|
||
|
let envKey = key.replace('-', '_').toUpper
|
||
|
let jsonKey = key.replace(re"(-\w)", proc (m: RegexMatch): string = ($m)[1..1].toUpper)
|
||
|
|
||
|
if cfg.docopt[argKey]: return $cfg.docopt[argKey]
|
||
|
elif existsEnv(envKey): return getEnv(envKey)
|
||
|
elif cfg.json.hasKey(jsonKey): return cfg.json[jsonKey].getStr
|
||
|
else: return default
|
||
|
|
||
|
|
||
|
var
|
||
|
pidFileInner: string
|
||
|
fi, fo, fe: File
|
||
|
|
||
|
proc onStop(sig: cint) {.noconv.} =
|
||
|
close(fi)
|
||
|
close(fo)
|
||
|
close(fe)
|
||
|
removeFile(pidFileInner)
|
||
|
|
||
|
quit(QuitSuccess)
|
||
|
|
||
|
proc daemonize*(pidfile, si, so, se: string, daemonMain: proc(): void): int =
|
||
|
|
||
|
if fileExists(pidfile):
|
||
|
raise newException(IOError, "pidfile " & pidfile & " already exists, daemon already running?")
|
||
|
|
||
|
let pid1 = fork()
|
||
|
|
||
|
# Are we the child process?
|
||
|
if pid1 == 0:
|
||
|
|
||
|
# Yes, so let's get ready to execute the main code given to us.
|
||
|
discard chdir("/")
|
||
|
discard setsid()
|
||
|
discard umask(0)
|
||
|
|
||
|
# Fork again... but I'm not sure why.
|
||
|
let pid2 = fork()
|
||
|
|
||
|
# We don't need the intermediate process, so if we are not the child this
|
||
|
# time, lets just quit
|
||
|
if pid2 > 0: quit(QuitSuccess)
|
||
|
|
||
|
# If we are the grandchild let's set up our environment.
|
||
|
flushFile(stdout)
|
||
|
flushFile(stderr)
|
||
|
|
||
|
if not si.isNil and si != "":
|
||
|
fi = open(si, fmRead)
|
||
|
discard dup2(getFileHandle(fi), getFileHandle(stdin))
|
||
|
|
||
|
if not so.isNil and so != "":
|
||
|
fo = open(so, fmAppend)
|
||
|
discard dup2(getFileHandle(fo), getFileHandle(stdout))
|
||
|
|
||
|
if not se.isNil and so != "":
|
||
|
fe = open(se, fmAppend)
|
||
|
discard dup2(getFileHandle(fe), getFileHandle(stderr))
|
||
|
|
||
|
pidFileInner = pidfile
|
||
|
|
||
|
# Add hooks to cleanup after ourselves when we're asked to die.
|
||
|
signal(SIGINT, onStop)
|
||
|
signal(SIGTERM, onStop)
|
||
|
|
||
|
# Find out what our actual PID is and save it
|
||
|
let childPid = getpid()
|
||
|
writeFile(pidfile, $childPid)
|
||
|
|
||
|
# Finally, execute our main
|
||
|
daemonMain()
|
||
|
|
||
|
return pid1
|