status-desktop/src/nim_status_client.nim

149 lines
5.3 KiB
Nim
Raw Normal View History

import NimQml, chronicles, os, strformat, times, md5, json
import status_go
import app/core/main
import constants
import app/global/global_singleton
import app/boot/app_controller
2020-05-21 19:07:55 +00:00
logScope:
topics = "status-app"
var signalsManagerQObjPointer: pointer
proc isExperimental(): string =
result = if getEnv("EXPERIMENTAL") == "1": "1" else: "0" # value explicity passed to avoid trusting input
2020-06-23 19:31:52 +00:00
proc determineResourcePath(): string =
result = if defined(windows) and defined(production): "/../resources/resources.rcc" else: "/../resources.rcc"
proc determineFleetsPath(): string =
result = if defined(windows) and defined(production): "/../resources/fleets.json" else: "/../fleets.json"
proc determineOpenUri(): string =
if OPENURI.len > 0:
result = $(%* { "uri": OPENURI })
proc determineStatusAppIconPath(): string =
if defined(production):
if defined(macosx):
return "" # not used in macOS
elif defined(windows):
return "/../resources/status.svg"
else:
return "/../status.svg"
else:
if defined(macosx):
return "" # not used in macOS
else:
return "/../status-dev.svg"
2020-05-18 18:48:20 +00:00
proc prepareLogging() =
when compiles(defaultChroniclesStream.output.writer):
defaultChroniclesStream.output.writer =
proc (logLevel: LogLevel, msg: LogOutputStr) {.gcsafe, raises: [Defect].} =
try:
if signalsManagerQObjPointer != nil:
signal_handler(signalsManagerQObjPointer, ($(%* {"type": "chronicles-log", "event": msg})).cstring, "receiveSignal")
except:
logLoggingFailure(cstring(msg), getCurrentException())
2021-09-24 12:03:57 +00:00
let logFile = fmt"app_{getTime().toUnix}.log"
discard defaultChroniclesStream.outputs[1].open(LOGDIR & logFile, fmAppend)
2022-02-09 09:43:23 +00:00
proc setupRemoteSignalsHandling() =
# Please note that this must use the `cdecl` calling convention because
# it will be passed as a regular C function to statusgo_backend. This means that
# we cannot capture any local variables here (we must rely on globals)
var callback: SignalCallback = proc(p0: cstring) {.cdecl.} =
if signalsManagerQObjPointer != nil:
signal_handler(signalsManagerQObjPointer, p0, "receiveSignal")
2021-08-13 20:04:04 +00:00
status_go.setSignalEventCallback(callback)
proc mainProc() =
if defined(macosx) and defined(production):
setCurrentDir(getAppDir())
2020-05-20 17:11:30 +00:00
ensureDirectories(DATADIR, TMPDIR, LOGDIR)
let isExperimental = isExperimental()
let resourcesPath = determineResourcePath()
let fleetsPath = determineFleetsPath()
let openUri = determineOpenUri()
let statusAppIconPath = determineStatusAppIconPath()
2022-02-09 09:43:23 +00:00
let fleetConfig = readFile(joinPath(getAppDir(), fleetsPath))
let statusFoundation = newStatusFoundation(fleetConfig)
let uiScaleFilePath = joinPath(DATADIR, "ui-scale")
enableHDPI(uiScaleFilePath)
initializeOpenGL()
let imageCert = imageServerTLSCert()
installSelfSignedCertificate(imageCert)
let app = newQGuiApplication()
let appController = newAppController(statusFoundation)
let singleInstance = newSingleInstance($toMD5(DATADIR), openUri)
let networkAccessFactory = newQNetworkAccessManagerFactory(TMPDIR & "netcache")
2022-02-09 09:43:23 +00:00
let isProductionQVariant = newQVariant(if defined(production): true else: false)
let isExperimentalQVariant = newQVariant(isExperimental)
let signalsManagerQVariant = newQVariant(statusFoundation.signalsManager)
QResource.registerResource(app.applicationDirPath & resourcesPath)
# Register events objects
let dockShowAppEvent = newStatusDockShowAppEventObject(singletonInstance.engine)
let osThemeEvent = newStatusOSThemeEventObject(singletonInstance.engine)
2021-07-05 12:34:56 +00:00
if not defined(macosx):
app.icon(app.applicationDirPath & statusAppIconPath)
2020-09-11 17:23:57 +00:00
prepareLogging()
2021-08-12 11:26:08 +00:00
singletonInstance.engine.addImportPath("qrc:/./StatusQ/src")
singletonInstance.engine.addImportPath("qrc:/./imports")
singletonInstance.engine.setNetworkAccessManagerFactory(networkAccessFactory)
singletonInstance.engine.setRootContextProperty("uiScaleFilePath", newQVariant(uiScaleFilePath))
singletonInstance.engine.setRootContextProperty("singleInstance", newQVariant(singleInstance))
singletonInstance.engine.setRootContextProperty("isExperimental", isExperimentalQVariant)
singletonInstance.engine.setRootContextProperty("signals", signalsManagerQVariant)
singletonInstance.engine.setRootContextProperty("production", isProductionQVariant)
2020-05-18 15:07:30 +00:00
app.installEventFilter(dockShowAppEvent)
app.installEventFilter(osThemeEvent)
2022-02-09 09:43:23 +00:00
defer:
info "shutting down..."
signalsManagerQObjPointer = nil
isProductionQVariant.delete()
isExperimentalQVariant.delete()
signalsManagerQVariant.delete()
networkAccessFactory.delete()
dockShowAppEvent.delete()
osThemeEvent.delete()
statusFoundation.delete()
appController.delete()
singleInstance.delete()
app.delete()
# Checks below must be always after "defer", in case anything fails destructors will freed a memory.
if singleInstance.secondInstance():
info "Terminating the app as the second instance"
quit()
2022-02-09 09:43:23 +00:00
info "starting application controller..."
appController.start()
# We need this global variable in order to be able to access the application
# from the non-closure callback passed to `statusgo_backend.setSignalEventCallback`
signalsManagerQObjPointer = cast[pointer](statusFoundation.signalsManager.vptr)
setupRemoteSignalsHandling()
2022-02-09 09:43:23 +00:00
info "starting application..."
2020-05-06 17:40:00 +00:00
app.exec()
when isMainModule:
mainProc()