mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-01-09 08:53:10 +00:00
On windows, termination of hardhat processes would not actually kill the process, and then closing the process' streams would then hang the calling nim process. To get around this, the process is now killed externally using a script, winkillhardhat.sh. This script first queries open processes by inspecting the command line value of all "node.exe" processes, searching for "vendor/codex-contracts-eth" and for the port parameter it was started with. After querying, the process is killed using the `Stop-Process` powershell command (passing the pid of the windows process).
131 lines
3.9 KiB
Nim
131 lines
3.9 KiB
Nim
import pkg/questionable
|
|
import pkg/questionable/results
|
|
import pkg/confutils
|
|
import pkg/chronicles
|
|
import pkg/chronos/asyncproc
|
|
import pkg/ethers
|
|
import pkg/libp2p
|
|
import std/os
|
|
import std/strutils
|
|
import std/times
|
|
import codex/conf
|
|
import ./codexclient
|
|
import ./nodeprocess
|
|
|
|
export codexclient
|
|
export chronicles
|
|
export nodeprocess
|
|
|
|
{.push raises: [].}
|
|
|
|
logScope:
|
|
topics = "integration testing codex process"
|
|
|
|
type
|
|
CodexProcess* = ref object of NodeProcess
|
|
client: ?CodexClient
|
|
|
|
CodexProcessError* = object of NodeProcessError
|
|
|
|
proc raiseCodexProcessError(
|
|
msg: string, parent: ref CatchableError
|
|
) {.raises: [CodexProcessError].} =
|
|
raise newException(CodexProcessError, msg & ": " & parent.msg, parent)
|
|
|
|
template convertError(msg, body: typed) =
|
|
# Don't use this in an async proc, unless body does not raise CancelledError
|
|
try:
|
|
body
|
|
except CatchableError as parent:
|
|
raiseCodexProcessError(msg, parent)
|
|
|
|
method workingDir(node: CodexProcess): string =
|
|
return currentSourcePath() / ".." / ".." / ".."
|
|
|
|
method executable(node: CodexProcess): string =
|
|
return "build" / "codex"
|
|
|
|
method startedOutput(node: CodexProcess): string =
|
|
return "REST service started"
|
|
|
|
method processOptions(node: CodexProcess): set[AsyncProcessOption] =
|
|
return {AsyncProcessOption.StdErrToStdOut}
|
|
|
|
method outputLineEndings(node: CodexProcess): string =
|
|
return "\n"
|
|
|
|
method onOutputLineCaptured(node: CodexProcess, line: string) =
|
|
discard
|
|
|
|
proc config(node: CodexProcess): CodexConf {.raises: [CodexProcessError].} =
|
|
# cannot use convertError here as it uses typed parameters which forces type
|
|
# resolution, while confutils.load uses untyped parameters and expects type
|
|
# resolution not to happen yet. In other words, it won't compile.
|
|
try:
|
|
return CodexConf.load(
|
|
cmdLine = node.arguments, quitOnFailure = false, secondarySources = nil
|
|
)
|
|
except ConfigurationError as parent:
|
|
raiseCodexProcessError "Failed to load node arguments into CodexConf", parent
|
|
|
|
proc dataDir(node: CodexProcess): string {.raises: [CodexProcessError].} =
|
|
return node.config.dataDir.string
|
|
|
|
proc ethAccount*(node: CodexProcess): Address {.raises: [CodexProcessError].} =
|
|
without ethAccount =? node.config.ethAccount:
|
|
raiseAssert "eth account not set"
|
|
return Address(ethAccount)
|
|
|
|
proc apiUrl*(node: CodexProcess): string {.raises: [CodexProcessError].} =
|
|
let config = node.config
|
|
return "http://" & config.apiBindAddress & ":" & $config.apiPort & "/api/codex/v1"
|
|
|
|
proc logFile*(node: CodexProcess): ?string {.raises: [CodexProcessError].} =
|
|
node.config.logFile
|
|
|
|
proc client*(node: CodexProcess): CodexClient {.raises: [CodexProcessError].} =
|
|
if client =? node.client:
|
|
return client
|
|
let client = CodexClient.new(node.apiUrl)
|
|
node.client = some client
|
|
return client
|
|
|
|
proc updateLogFile(node: CodexProcess, newLogFile: string) =
|
|
for arg in node.arguments.mitems:
|
|
if arg.startsWith("--log-file="):
|
|
arg = "--log-file=" & newLogFile
|
|
break
|
|
|
|
method restart*(node: CodexProcess) {.async.} =
|
|
trace "restarting codex"
|
|
await node.stop()
|
|
if logFile =? node.logFile:
|
|
# chronicles truncates the existing log file on start, so changed the log
|
|
# file cli param to create a new one
|
|
node.updateLogFile(
|
|
logFile & "_restartedAt_" & now().format("yyyy-MM-dd'_'HH-mm-ss") & ".log"
|
|
)
|
|
await node.start()
|
|
await node.waitUntilStarted()
|
|
trace "codex process restarted"
|
|
|
|
method stop*(node: CodexProcess) {.async: (raises: []).} =
|
|
logScope:
|
|
nodeName = node.name
|
|
|
|
trace "stopping codex client"
|
|
await procCall NodeProcess(node).stop()
|
|
|
|
if not node.process.isNil:
|
|
trace "closing node process' streams"
|
|
await node.process.closeWait()
|
|
trace "node process' streams closed"
|
|
|
|
if client =? node.client:
|
|
await client.close()
|
|
node.client = none CodexClient
|
|
|
|
method removeDataDir*(node: CodexProcess) {.raises: [CodexProcessError].} =
|
|
convertError("failed to remove codex node data directory"):
|
|
removeDir(node.dataDir)
|