2024-03-13 17:38:54 +00:00
|
|
|
import NimQml, chronicles, os, stew/shims/strformat, strutils, times, md5, json
|
2020-05-29 19:54:35 +00:00
|
|
|
|
2021-03-15 19:24:45 +00:00
|
|
|
import status_go
|
2022-07-21 11:29:18 +00:00
|
|
|
import keycard_go
|
2021-11-16 14:56:12 +00:00
|
|
|
import app/core/main
|
2023-01-20 08:31:11 +00:00
|
|
|
import constants as main_constants
|
2020-05-16 23:46:46 +00:00
|
|
|
|
2021-11-16 13:49:51 +00:00
|
|
|
import app/global/global_singleton
|
2021-10-06 20:05:13 +00:00
|
|
|
import app/boot/app_controller
|
|
|
|
|
2023-03-10 10:36:03 +00:00
|
|
|
when defined(macosx) and defined(arm64):
|
|
|
|
import posix
|
|
|
|
|
2020-05-21 19:07:55 +00:00
|
|
|
logScope:
|
2021-11-17 15:22:26 +00:00
|
|
|
topics = "status-app"
|
2021-09-07 19:14:56 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
var signalsManagerQObjPointer: pointer
|
2022-07-21 11:29:18 +00:00
|
|
|
var keycardServiceQObjPointer: pointer
|
2020-05-29 19:54:35 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
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
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
proc determineResourcePath(): string =
|
|
|
|
result = if defined(windows) and defined(production): "/../resources/resources.rcc" else: "/../resources.rcc"
|
2021-07-21 05:50:35 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
proc determineFleetsPath(): string =
|
|
|
|
result = if defined(windows) and defined(production): "/../resources/fleets.json" else: "/../fleets.json"
|
2021-10-06 20:05:13 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
proc determineOpenUri(): string =
|
2021-09-10 08:56:20 +00:00
|
|
|
if OPENURI.len > 0:
|
2022-07-13 15:48:12 +00:00
|
|
|
result = OPENURI
|
2021-11-17 15:22:26 +00:00
|
|
|
|
|
|
|
proc determineStatusAppIconPath(): string =
|
|
|
|
if defined(production):
|
2023-01-20 08:31:11 +00:00
|
|
|
if main_constants.IS_MACOS:
|
2021-11-17 15:22:26 +00:00
|
|
|
return "" # not used in macOS
|
2023-03-22 09:26:00 +00:00
|
|
|
elif defined(windows):
|
2021-11-17 15:22:26 +00:00
|
|
|
return "/../resources/status.svg"
|
2020-09-17 20:11:31 +00:00
|
|
|
else:
|
2021-11-17 15:22:26 +00:00
|
|
|
return "/../status.svg"
|
|
|
|
else:
|
2023-01-20 08:31:11 +00:00
|
|
|
if main_constants.IS_MACOS:
|
2021-11-17 15:22:26 +00:00
|
|
|
return "" # not used in macOS
|
|
|
|
else:
|
|
|
|
return "/../status-dev.svg"
|
2020-05-18 18:48:20 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
proc prepareLogging() =
|
2022-07-01 14:59:25 +00:00
|
|
|
# Outputs logs in the node tab
|
2021-09-14 19:39:29 +00:00
|
|
|
when compiles(defaultChroniclesStream.output.writer):
|
|
|
|
defaultChroniclesStream.output.writer =
|
|
|
|
proc (logLevel: LogLevel, msg: LogOutputStr) {.gcsafe, raises: [Defect].} =
|
|
|
|
try:
|
2021-11-17 12:57:19 +00:00
|
|
|
if signalsManagerQObjPointer != nil:
|
2023-12-04 17:11:54 +00:00
|
|
|
signal_handler(signalsManagerQObjPointer, ($(%* {"type": "chronicles-log", "event": msg})).cstring, "receiveChroniclesLogEvent")
|
2021-09-14 19:39:29 +00:00
|
|
|
except:
|
|
|
|
logLoggingFailure(cstring(msg), getCurrentException())
|
2021-09-24 12:03:57 +00:00
|
|
|
|
2023-10-16 19:47:12 +00:00
|
|
|
let defaultLogLvl = if defined(production): chronicles.LogLevel.INFO else: chronicles.LogLevel.DEBUG
|
2023-01-03 20:17:13 +00:00
|
|
|
# default log level can be overriden by LOG_LEVEL env parameter
|
2023-10-16 19:47:12 +00:00
|
|
|
let logLvl = try: parseEnum[chronicles.LogLevel](main_constants.LOG_LEVEL)
|
2023-01-03 20:17:13 +00:00
|
|
|
except: defaultLogLvl
|
2022-07-01 14:59:25 +00:00
|
|
|
|
2023-01-03 20:17:13 +00:00
|
|
|
setLogLevel(logLvl)
|
2022-07-01 14:59:25 +00:00
|
|
|
|
2023-01-03 20:17:13 +00:00
|
|
|
let formattedDate = now().format("yyyyMMdd'_'HHmmss")
|
|
|
|
let logFile = fmt"app_{formattedDate}.log"
|
|
|
|
discard defaultChroniclesStream.outputs[1].open(LOGDIR & logFile, fmAppend)
|
2021-09-14 19:39:29 +00:00
|
|
|
|
2022-02-09 09:43:23 +00:00
|
|
|
proc setupRemoteSignalsHandling() =
|
2021-11-17 15:22:26 +00:00
|
|
|
# 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)
|
2022-07-21 11:29:18 +00:00
|
|
|
var callbackStatusGo: status_go.SignalCallback = proc(p0: cstring) {.cdecl.} =
|
2021-11-17 15:22:26 +00:00
|
|
|
if signalsManagerQObjPointer != nil:
|
|
|
|
signal_handler(signalsManagerQObjPointer, p0, "receiveSignal")
|
2022-07-21 11:29:18 +00:00
|
|
|
status_go.setSignalEventCallback(callbackStatusGo)
|
2021-08-13 20:04:04 +00:00
|
|
|
|
2022-07-21 11:29:18 +00:00
|
|
|
var callbackKeycardGo: keycard_go.KeycardSignalCallback = proc(p0: cstring) {.cdecl.} =
|
|
|
|
if keycardServiceQObjPointer != nil:
|
|
|
|
signal_handler(keycardServiceQObjPointer, p0, "receiveKeycardSignal")
|
|
|
|
keycard_go.setSignalEventCallback(callbackKeycardGo)
|
2020-05-11 21:24:08 +00:00
|
|
|
|
2023-10-16 19:47:12 +00:00
|
|
|
proc ensureDirectories*(dataDir, tmpDir, logDir: string) =
|
|
|
|
createDir(dataDir)
|
|
|
|
createDir(tmpDir)
|
|
|
|
createDir(logDir)
|
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
proc mainProc() =
|
2023-03-10 10:36:03 +00:00
|
|
|
|
|
|
|
when defined(macosx) and defined(arm64):
|
|
|
|
echo "Experimental support for Apple Silicon"
|
|
|
|
var signalStack: cstring = cast[cstring](allocShared(SIGSTKSZ))
|
|
|
|
var ss: ptr Stack = cast[ptr Stack](allocShared0(sizeof(Stack)))
|
|
|
|
var ss2: ptr Stack = nil
|
|
|
|
ss.ss_sp = signalStack
|
|
|
|
ss.ss_flags = 0
|
|
|
|
ss.ss_size = SIGSTKSZ
|
|
|
|
if sigaltstack(ss[], ss2[]) < 0:
|
|
|
|
echo("sigaltstack error!")
|
|
|
|
quit()
|
|
|
|
|
2023-08-09 14:26:19 +00:00
|
|
|
var sa: ptr Sigaction = cast[ptr Sigaction](allocShared0(sizeof(Sigaction)))
|
|
|
|
var sa2: Sigaction
|
|
|
|
|
|
|
|
sa.sa_handler = SIG_DFL
|
|
|
|
sa.sa_flags = SA_ONSTACK
|
|
|
|
|
|
|
|
if sigaction(SIGURG, sa[], addr sa2) < 0:
|
|
|
|
echo("sigaction error!")
|
|
|
|
quit()
|
|
|
|
|
2023-01-20 08:31:11 +00:00
|
|
|
if main_constants.IS_MACOS and defined(production):
|
2021-11-17 15:22:26 +00:00
|
|
|
setCurrentDir(getAppDir())
|
2020-05-20 17:11:30 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
ensureDirectories(DATADIR, TMPDIR, LOGDIR)
|
2020-09-15 19:47:13 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
let isExperimental = isExperimental()
|
|
|
|
let resourcesPath = determineResourcePath()
|
|
|
|
let fleetsPath = determineFleetsPath()
|
|
|
|
let openUri = determineOpenUri()
|
|
|
|
let statusAppIconPath = determineStatusAppIconPath()
|
2022-02-09 09:43:23 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
let fleetConfig = readFile(joinPath(getAppDir(), fleetsPath))
|
|
|
|
let statusFoundation = newStatusFoundation(fleetConfig)
|
|
|
|
let uiScaleFilePath = joinPath(DATADIR, "ui-scale")
|
|
|
|
enableHDPI(uiScaleFilePath)
|
2023-03-02 09:08:09 +00:00
|
|
|
tryEnableThreadedRenderer()
|
2021-11-17 15:22:26 +00:00
|
|
|
initializeOpenGL()
|
2020-08-25 20:19:46 +00:00
|
|
|
|
2022-02-08 16:28:25 +00:00
|
|
|
let imageCert = imageServerTLSCert()
|
|
|
|
installSelfSignedCertificate(imageCert)
|
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
let app = newQGuiApplication()
|
2022-10-20 09:05:10 +00:00
|
|
|
|
2023-10-03 15:43:35 +00:00
|
|
|
# Required by the WalletConnectSDK view right after creating the QGuiApplication instance
|
|
|
|
initializeWebView()
|
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
let singleInstance = newSingleInstance($toMD5(DATADIR), openUri)
|
2022-10-20 09:05:10 +00:00
|
|
|
let urlSchemeEvent = newStatusUrlSchemeEventObject()
|
|
|
|
# init url manager before app controller
|
|
|
|
statusFoundation.initUrlSchemeManager(urlSchemeEvent, singleInstance, openUri)
|
|
|
|
|
|
|
|
let appController = newAppController(statusFoundation)
|
2021-11-17 15:22:26 +00:00
|
|
|
let networkAccessFactory = newQNetworkAccessManagerFactory(TMPDIR & "netcache")
|
2022-02-09 09:43:23 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
let isProductionQVariant = newQVariant(if defined(production): true else: false)
|
|
|
|
let isExperimentalQVariant = newQVariant(isExperimental)
|
|
|
|
let signalsManagerQVariant = newQVariant(statusFoundation.signalsManager)
|
2021-09-22 08:10:54 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
QResource.registerResource(app.applicationDirPath & resourcesPath)
|
|
|
|
# Register events objects
|
|
|
|
let osThemeEvent = newStatusOSThemeEventObject(singletonInstance.engine)
|
2021-07-05 12:34:56 +00:00
|
|
|
|
2023-01-20 08:31:11 +00:00
|
|
|
if not main_constants.IS_MACOS:
|
2021-11-17 15:22:26 +00:00
|
|
|
app.icon(app.applicationDirPath & statusAppIconPath)
|
2020-09-11 17:23:57 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
prepareLogging()
|
2021-08-12 11:26:08 +00:00
|
|
|
|
2023-04-14 08:18:56 +00:00
|
|
|
singletonInstance.engine.addImportPath("qrc:/")
|
2021-11-17 15:22:26 +00:00
|
|
|
singletonInstance.engine.addImportPath("qrc:/./imports")
|
2022-03-03 22:50:53 +00:00
|
|
|
singletonInstance.engine.addImportPath("qrc:/./app");
|
2021-11-17 15:22:26 +00:00
|
|
|
singletonInstance.engine.setNetworkAccessManagerFactory(networkAccessFactory)
|
|
|
|
singletonInstance.engine.setRootContextProperty("uiScaleFilePath", newQVariant(uiScaleFilePath))
|
2021-10-06 20:05:13 +00:00
|
|
|
singletonInstance.engine.setRootContextProperty("singleInstance", newQVariant(singleInstance))
|
2021-11-17 15:22:26 +00:00
|
|
|
singletonInstance.engine.setRootContextProperty("isExperimental", isExperimentalQVariant)
|
2024-03-06 09:14:48 +00:00
|
|
|
singletonInstance.engine.setRootContextProperty("fleetSelectionEnabled", newQVariant(FLEET_SELECTION_ENABLED))
|
2021-11-17 12:57:19 +00:00
|
|
|
singletonInstance.engine.setRootContextProperty("signals", signalsManagerQVariant)
|
2021-11-17 15:22:26 +00:00
|
|
|
singletonInstance.engine.setRootContextProperty("production", isProductionQVariant)
|
2020-05-18 15:07:30 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
app.installEventFilter(osThemeEvent)
|
2022-03-17 16:24:50 +00:00
|
|
|
app.installEventFilter(urlSchemeEvent)
|
2022-02-09 09:43:23 +00:00
|
|
|
|
|
|
|
defer:
|
2021-11-17 15:22:26 +00:00
|
|
|
info "shutting down..."
|
|
|
|
signalsManagerQObjPointer = nil
|
2022-07-21 11:29:18 +00:00
|
|
|
keycardServiceQObjPointer = nil
|
2021-11-17 15:22:26 +00:00
|
|
|
isProductionQVariant.delete()
|
|
|
|
isExperimentalQVariant.delete()
|
|
|
|
signalsManagerQVariant.delete()
|
|
|
|
networkAccessFactory.delete()
|
|
|
|
osThemeEvent.delete()
|
|
|
|
appController.delete()
|
2023-02-02 15:52:45 +00:00
|
|
|
statusFoundation.delete()
|
2021-11-17 15:22:26 +00:00
|
|
|
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
|
|
|
|
2022-07-21 11:29:18 +00:00
|
|
|
# We need these global variables 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)
|
|
|
|
keycardServiceQObjPointer = cast[pointer](appController.keycardService.vptr)
|
|
|
|
setupRemoteSignalsHandling()
|
|
|
|
|
2023-01-31 15:52:57 +00:00
|
|
|
info fmt("Version: {APP_VERSION}")
|
2022-03-24 11:51:24 +00:00
|
|
|
info fmt("Commit: {GIT_COMMIT}")
|
|
|
|
info "Current date:", currentDateTime=now()
|
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
info "starting application controller..."
|
2021-10-15 19:58:14 +00:00
|
|
|
appController.start()
|
2022-01-27 15:29:17 +00:00
|
|
|
|
2021-11-17 15:22:26 +00:00
|
|
|
info "starting application..."
|
2020-05-06 17:40:00 +00:00
|
|
|
app.exec()
|
|
|
|
|
|
|
|
when isMainModule:
|
|
|
|
mainProc()
|