diff --git a/ci/Jenkinsfile.combined b/ci/Jenkinsfile.combined index 387fbeb634..3385f084a2 100644 --- a/ci/Jenkinsfile.combined +++ b/ci/Jenkinsfile.combined @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' pipeline { agent { label 'linux' } diff --git a/ci/Jenkinsfile.linux b/ci/Jenkinsfile.linux index 4299b3de8a..072fe8cc45 100644 --- a/ci/Jenkinsfile.linux +++ b/ci/Jenkinsfile.linux @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() diff --git a/ci/Jenkinsfile.macos b/ci/Jenkinsfile.macos index 424ea992c9..b8bf9b96a8 100644 --- a/ci/Jenkinsfile.macos +++ b/ci/Jenkinsfile.macos @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() diff --git a/ci/Jenkinsfile.tests-e2e b/ci/Jenkinsfile.tests-e2e index 70f3c8efe4..8a87470139 100644 --- a/ci/Jenkinsfile.tests-e2e +++ b/ci/Jenkinsfile.tests-e2e @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() @@ -97,7 +97,7 @@ pipeline { stage('Client') { environment { - GANACHE_NETWORK_RPC_URL = "http://localhost:${env.GANACHE_RPC_PORT}" + STATUS_RUNTIME_GANACHE_NETWORK_RPC_URL = "http://localhost:${env.GANACHE_RPC_PORT}" } steps { script { linux.bundle('nim_status_client') diff --git a/ci/Jenkinsfile.tests-nim b/ci/Jenkinsfile.tests-nim index 53694440fb..d035a3177a 100644 --- a/ci/Jenkinsfile.tests-nim +++ b/ci/Jenkinsfile.tests-nim @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() diff --git a/ci/Jenkinsfile.windows b/ci/Jenkinsfile.windows index 1feaa0fcac..48e0a4c1f5 100644 --- a/ci/Jenkinsfile.windows +++ b/ci/Jenkinsfile.windows @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() diff --git a/ci/cpp/Jenkinsfile.linux b/ci/cpp/Jenkinsfile.linux index 7254f7490e..295f6d832f 100644 --- a/ci/cpp/Jenkinsfile.linux +++ b/ci/cpp/Jenkinsfile.linux @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() diff --git a/ci/cpp/Jenkinsfile.macos b/ci/cpp/Jenkinsfile.macos index e5a3cf1641..c43b194d25 100644 --- a/ci/cpp/Jenkinsfile.macos +++ b/ci/cpp/Jenkinsfile.macos @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() diff --git a/ci/cpp/Jenkinsfile.windows b/ci/cpp/Jenkinsfile.windows index feacaaf87f..6c551c8b66 100644 --- a/ci/cpp/Jenkinsfile.windows +++ b/ci/cpp/Jenkinsfile.windows @@ -1,5 +1,5 @@ #!/usr/bin/env groovy -library 'status-jenkins-lib@v1.7.16' +library 'status-jenkins-lib@v1.7.17' /* Options section can't access functions in objects. */ def isPRBuild = utils.isPRBuild() diff --git a/src/app/boot/app_controller.nim b/src/app/boot/app_controller.nim index 918a7b4ac1..4ec8a9edf7 100644 --- a/src/app/boot/app_controller.nim +++ b/src/app/boot/app_controller.nim @@ -135,10 +135,10 @@ proc connect(self: AppController) = if not existsEnv("LOG_LEVEL"): self.statusFoundation.events.on(node_configuration_service.SIGNAL_NODE_LOG_LEVEL_UPDATE) do(a: Args): let args = NodeLogLevelUpdatedArgs(a) - if args.logLevel == LogLevel.DEBUG: - setLogLevel(LogLevel.DEBUG) + if args.logLevel == chronicles.LogLevel.DEBUG: + setLogLevel(chronicles.LogLevel.DEBUG) elif defined(production): - setLogLevel(LogLevel.INFO) + setLogLevel(chronicles.LogLevel.INFO) proc newAppController*(statusFoundation: StatusFoundation): AppController = result = AppController() @@ -440,7 +440,7 @@ proc load(self: AppController) = # Apply runtime log level settings if not existsEnv("LOG_LEVEL"): if self.nodeConfigurationService.isDebugEnabled(): - setLogLevel(LogLevel.DEBUG) + setLogLevel(chronicles.LogLevel.DEBUG) # load main module self.mainModule.load( diff --git a/src/app_service/common/network_constants.nim b/src/app_service/common/network_constants.nim index ee3cc84519..49291687a3 100644 --- a/src/app_service/common/network_constants.nim +++ b/src/app_service/common/network_constants.nim @@ -1,74 +1,6 @@ -import json, os, chronicles, strutils +import json, os, strutils import ../../constants as main_constants -proc resolveEnvVar(envVar: string, defaultValue: string): string = - let envVarValue = $getEnv(envVar) - if envVarValue != "": - return envVarValue - else: - return defaultValue - -# provider Tokens -# allow runtime override via environment variable; core contributors can set a -# release token in this way for local development - -# set via `nim c` param `-d:POKT_TOKEN:[token]`; should be set in CI/release builds -const POKT_TOKEN {.strdefine.} = "" -let POKT_TOKEN_RESOLVED* = resolveEnvVar("POKT_TOKEN", POKT_TOKEN) - -# set via `nim c` param `-d:INFURA_TOKEN:[token]`; should be set in CI/release builds -const INFURA_TOKEN {.strdefine.} = "" -let INFURA_TOKEN_RESOLVED* = resolveEnvVar("INFURA_TOKEN", INFURA_TOKEN) - -# set via `nim c` param `-d:INFURA_TOKEN_SECRET:[token]`; should be set in CI/release builds -const INFURA_TOKEN_SECRET {.strdefine.} = "" -let INFURA_TOKEN_SECRET_RESOLVED* = resolveEnvVar("INFURA_TOKEN_SECRET", INFURA_TOKEN_SECRET) - -# set via `nim c` param `-d:ALCHEMY_ETHEREUM_MAINNET_TOKEN:[token]`; should be set in CI/release builds -const ALCHEMY_ETHEREUM_MAINNET_TOKEN {.strdefine.} = "" -let ALCHEMY_ETHEREUM_MAINNET_TOKEN_RESOLVED* = resolveEnvVar("ALCHEMY_ETHEREUM_MAINNET_TOKEN", ALCHEMY_ETHEREUM_MAINNET_TOKEN) - -# set via `nim c` param `-d:ALCHEMY_ETHEREUM_GOERLI_TOKEN:[token]`; should be set in CI/release builds -const ALCHEMY_ETHEREUM_GOERLI_TOKEN {.strdefine.} = "" -let ALCHEMY_ETHEREUM_GOERLI_TOKEN_RESOLVED* = resolveEnvVar("ALCHEMY_ETHEREUM_GOERLI_TOKEN", ALCHEMY_ETHEREUM_GOERLI_TOKEN) - -# set via `nim c` param `-d:ALCHEMY_ARBITRUM_MAINNET_TOKEN:[token]`; should be set in CI/release builds -const ALCHEMY_ARBITRUM_MAINNET_TOKEN {.strdefine.} = "" -let ALCHEMY_ARBITRUM_MAINNET_TOKEN_RESOLVED* = resolveEnvVar("ALCHEMY_ARBITRUM_MAINNET_TOKEN", ALCHEMY_ARBITRUM_MAINNET_TOKEN) - -# set via `nim c` param `-d:ALCHEMY_ARBITRUM_GOERLI_TOKEN:[token]`; should be set in CI/release builds -const ALCHEMY_ARBITRUM_GOERLI_TOKEN {.strdefine.} = "" -let ALCHEMY_ARBITRUM_GOERLI_TOKEN_RESOLVED* = resolveEnvVar("ALCHEMY_ARBITRUM_GOERLI_TOKEN", ALCHEMY_ARBITRUM_GOERLI_TOKEN) - -# set via `nim c` param `-d:ALCHEMY_OPTIMISM_MAINNET_TOKEN:[token]`; should be set in CI/release builds -const ALCHEMY_OPTIMISM_MAINNET_TOKEN {.strdefine.} = "" -let ALCHEMY_OPTIMISM_MAINNET_TOKEN_RESOLVED* = resolveEnvVar("ALCHEMY_OPTIMISM_MAINNET_TOKEN", ALCHEMY_OPTIMISM_MAINNET_TOKEN) - -# set via `nim c` param `-d:ALCHEMY_OPTIMISM_GOERLI_TOKEN:[token]`; should be set in CI/release builds -const ALCHEMY_OPTIMISM_GOERLI_TOKEN {.strdefine.} = "" -let ALCHEMY_OPTIMISM_GOERLI_TOKEN_RESOLVED* = resolveEnvVar("ALCHEMY_OPTIMISM_GOERLI_TOKEN", ALCHEMY_OPTIMISM_GOERLI_TOKEN) - -# set via `nim c` param `-d:OPENSEA_API_KEY:[token]`; should be set in CI/release builds -const OPENSEA_API_KEY {.strdefine.} = "" -let OPENSEA_API_KEY_RESOLVED* = resolveEnvVar("OPENSEA_API_KEY", OPENSEA_API_KEY) - -const GANACHE_NETWORK_RPC_URL = $getEnv("GANACHE_NETWORK_RPC_URL") - -const DEFAULT_TORRENT_CONFIG_PORT = 0 # Random -let TORRENT_CONFIG_PORT* = if (existsEnv("TORRENT_PORT")): - parseInt($getEnv("TORRENT_PORT")) - else: - DEFAULT_TORRENT_CONFIG_PORT - -const DEFAULT_WAKU_V2_PORT = 0 # Random -let WAKU_V2_PORT* = if (existsEnv("WAKU_PORT")): - parseInt($getEnv("WAKU_PORT")) - else: - DEFAULT_WAKU_V2_PORT - -let DEFAULT_TORRENT_CONFIG_DATADIR* = joinPath(main_constants.defaultDataDir(), "data", "archivedata") -let DEFAULT_TORRENT_CONFIG_TORRENTDIR* = joinPath(main_constants.defaultDataDir(), "data", "torrents") - var NETWORKS* = %* [ { "chainId": 1, @@ -344,7 +276,7 @@ var NODE_CONFIG* = %* { # Docs: https://pkg.go.dev/gopkg.in/natefinch/lumberjack.v2@v2.0.0#readme-cleaning-up-old-log-files "LogMaxBackups": 1, "LogMaxSize": 100, # MB - "LogLevel": $LogLevel.INFO, + "LogLevel": main_constants.DEFAULT_LOG_LEVEL, "MailserversConfig": { "Enabled": true }, diff --git a/src/app_service/service/accounts/service.nim b/src/app_service/service/accounts/service.nim index 05f42444eb..8adb1270aa 100644 --- a/src/app_service/service/accounts/service.nim +++ b/src/app_service/service/accounts/service.nim @@ -277,7 +277,7 @@ QtObject: "wallet-root-address": account.derivedAccounts.walletRoot.address, "preview-privacy?": true, "signing-phrase": generateSigningPhrase(3), - "log-level": $LogLevel.INFO, + "log-level": main_constants.LOG_LEVEL, "latest-derived-path": 0, "currency": "usd", "networks/networks": @[], @@ -308,7 +308,7 @@ QtObject: if(self.importedAccount.id == accountId): return self.prepareAccountSettingsJsonObject(self.importedAccount, installationId, displayName) - proc getDefaultNodeConfig*(self: Service, installationId: string, recoverAccount: bool, login: bool = false): JsonNode = + proc getDefaultNodeConfig*(self: Service, installationId: string, recoverAccount: bool): JsonNode = let fleet = Fleet.StatusProd let dnsDiscoveryURL = @["enrtree://AL65EKLJAUXKKPG43HVTML5EFFWEZ7L4LOKTLZCLJASG4DSESQZEC@prod.status.nodes.status.im"] @@ -339,26 +339,69 @@ QtObject: result["ClusterConfig"]["DiscV5BootstrapNodes"] = %* (@[]) result["Rendezvous"] = newJBool(false) - # Source the connection port from the environment for debugging or if default port not accessible - if existsEnv("STATUS_PORT"): - let wV1Port = $getEnv("STATUS_PORT") - # Waku V1 config - result["ListenAddr"] = newJString("0.0.0.0:" & wV1Port) + result["LogLevel"] = newJString(main_constants.LOG_LEVEL) - # Don't override log level on login. For onboarding it is required, nothing to override - if login: - result.delete("LogLevel") - - if existsEnv("LOG_LEVEL"): - let logLvl = getEnv("LOG_LEVEL") - if logLvl in @["ERROR", "WARN", "INFO", "DEBUG", "TRACE"]: - result["LogLevel"] = newJString($logLvl) + if STATUS_PORT != 0: + result["ListenAddr"] = newJString("0.0.0.0:" & $main_constants.STATUS_PORT) result["KeyStoreDir"] = newJString(self.keyStoreDir.replace(main_constants.STATUSGODIR, "")) result["RootDataDir"] = newJString(main_constants.STATUSGODIR) result["KeycardPairingDataFile"] = newJString(main_constants.KEYCARDPAIRINGDATAFILE) result["ProcessBackedupMessages"] = newJBool(recoverAccount) + proc getLoginNodeConfig(self: Service): JsonNode = + # To create appropriate NodeConfig for Login we set only params that maybe be set via env variables or cli flags + result = %*{} + + # mandatory params + result["NetworkId"] = NETWORKS[0]{"chainId"} + result["DataDir"] = %* "./ethereum/mainnet" + result["KeyStoreDir"] = %* "./keystore" + result["KeycardPairingDataFile"] = %* main_constants.KEYCARDPAIRINGDATAFILE + + # other params + result["Networks"] = NETWORKS + + result["UpstreamConfig"] = %* { + "URL": NETWORKS[0]{"rpcUrl"}, + "Enabled": true, + } + + result["ShhextConfig"] = %* { + "VerifyENSURL": NETWORKS[0]{"fallbackUrl"}, + "VerifyTransactionURL": NETWORKS[0]{"fallbackUrl"} + } + + result["WakuV2Config"] = %* { + "Port": WAKU_V2_PORT, + "UDPPort": WAKU_V2_PORT + } + + result["WalletConfig"] = %* { + "OpenseaAPIKey": OPENSEA_API_KEY_RESOLVED, + "InfuraAPIKey": INFURA_TOKEN_RESOLVED, + "InfuraAPIKeySecret": INFURA_TOKEN_SECRET_RESOLVED, + "AlchemyAPIKeys": %* { + "1": ALCHEMY_ETHEREUM_MAINNET_TOKEN_RESOLVED, + "5": ALCHEMY_ETHEREUM_GOERLI_TOKEN_RESOLVED, + "42161": ALCHEMY_ARBITRUM_MAINNET_TOKEN_RESOLVED, + "421613": ALCHEMY_ARBITRUM_GOERLI_TOKEN_RESOLVED, + "10": ALCHEMY_OPTIMISM_MAINNET_TOKEN_RESOLVED, + "420": ALCHEMY_OPTIMISM_GOERLI_TOKEN_RESOLVED + } + } + + result["TorrentConfig"] = %* { + "Port": TORRENT_CONFIG_PORT, + "DataDir": DEFAULT_TORRENT_CONFIG_DATADIR, + "TorrentDir": DEFAULT_TORRENT_CONFIG_TORRENTDIR + } + + result["LogLevel"] = newJString(main_constants.LOG_LEVEL) + + if STATUS_PORT != 0: + result["ListenAddr"] = newJString("0.0.0.0:" & $main_constants.STATUS_PORT) + proc setLocalAccountSettingsFile(self: Service) = if(main_constants.IS_MACOS and self.getLoggedInAccount.isValid()): singletonInstance.localAccountSettings.setFileName(self.getLoggedInAccount.name) @@ -484,7 +527,7 @@ QtObject: "wallet-root-address": walletRootAddress, "preview-privacy?": true, "signing-phrase": generateSigningPhrase(3), - "log-level": $LogLevel.INFO, + "log-level": main_constants.LOG_LEVEL, "latest-derived-path": 0, "currency": "usd", "networks/networks": @[], @@ -624,7 +667,7 @@ QtObject: error "error: ", procName="verifyDatabasePassword", errName = e.name, errDesription = e.msg proc doLogin(self: Service, account: AccountDto, hashedPassword, thumbnailImage, largeImage: string) = - let nodeConfigJson = self.getDefaultNodeConfig(installationId = "", recoverAccount = false, login = true) + let nodeConfigJson = self.getDefaultNodeConfig(installationId = "", recoverAccount = false) let response = status_account.login( account.name, account.keyUid, @@ -706,7 +749,7 @@ QtObject: "key-uid": accToBeLoggedIn.keyUid, } - let nodeConfigJson = self.getDefaultNodeConfig(installationId = "", recoverAccount = false, login = true) + let nodeConfigJson = self.getDefaultNodeConfig(installationId = "", recoverAccount = false) let response = status_account.loginWithKeycard(keycardData.whisperKey.privateKey, keycardData.encryptionKey.publicKey, diff --git a/src/constants.nim b/src/constants.nim index 5596bffa1d..12da4c63f8 100644 --- a/src/constants.nim +++ b/src/constants.nim @@ -1,69 +1,27 @@ -import os, sequtils, strutils, strformat +include env_cli_vars -import # vendor libs - confutils - -const DEFAULT_WALLET_ENABLED = true -let WALLET_ENABLED* = if (existsEnv("ENABLE_WALLET")): - parseInt($getEnv("ENABLE_WALLET")) != 0 - else: - DEFAULT_WALLET_ENABLED - -## Added a constant here cause it's easier to check the app how it behaves +## Added a constant here cause it's easier to check the app how it behaves ## on other platform if we just change the value here const IS_MACOS* = defined(macosx) - # For future supporting fingerprints on other platforms const SUPPORTS_FINGERPRINT* = IS_MACOS +# This is changed during compilation by reading the VERSION file +const DESKTOP_VERSION {.strdefine.} = "0.0.0" +const STATUSGO_VERSION* {.strdefine.} = "0.0.0" +# This is changed during compilation by executing git command +const GIT_COMMIT* {.strdefine.} = "" + +const APP_VERSION* = if defined(production): DESKTOP_VERSION else: fmt("{GIT_COMMIT}") const sep* = when defined(windows): "\\" else: "/" -proc defaultDataDir*(): string = - let homeDir = getHomeDir() - let parentDir = - if defined(development): - parentDir(getAppDir()) - elif homeDir == "": - getCurrentDir() - elif IS_MACOS: - joinPath(homeDir, "Library", "Application Support") - elif defined(windows): - let targetDir = getEnv("LOCALAPPDATA").string - if targetDir == "": - joinPath(homeDir, "AppData", "Local") - else: - targetDir - else: - let targetDir = getEnv("XDG_CONFIG_HOME").string - if targetDir == "": - joinPath(homeDir, ".config") - else: - targetDir - absolutePath(joinPath(parentDir, "Status")) - -type StatusDesktopConfig = object - dataDir* {. - defaultValue: defaultDataDir() - desc: "Status Desktop data directory" - abbr: "d" .}: string - uri* {. - defaultValue: "" - desc: "status-app:// URI to open a chat or other" - name: "uri" .}: string - - -# On macOS the first time when a user gets the "App downloaded from the -# internet" warning, and clicks the Open button, the OS passes a unique process -# serial number (PSN) as -psn_... command-line argument, which we remove before -# processing the arguments with nim-confutils. -# Credit: https://github.com/bitcoin/bitcoin/blame/b6e34afe9735faf97d6be7a90fafd33ec18c0cbb/src/util/system.cpp#L383-L389 - -var cliParams = commandLineParams() -if IS_MACOS: - cliParams.keepIf(proc(p: string): bool = not p.startsWith("-psn_")) - -let desktopConfig = StatusDesktopConfig.load(cliParams) - +################################################################################ +# The following variables are set: +# +# - via CL arguments, if they are provided +# - otherwise via env variables, if they are provided +# - otherwise the default values are used +################################################################################ let baseDir = absolutePath(expandTilde(desktopConfig.dataDir)) OPENURI* = desktopConfig.uri @@ -73,22 +31,26 @@ let TMPDIR* = joinPath(baseDir, "tmp") & sep LOGDIR* = joinPath(baseDir, "logs") & sep KEYCARDPAIRINGDATAFILE* = joinPath(baseDir, "data", "keycard/pairings.json") + DEFAULT_TORRENT_CONFIG_DATADIR* = joinPath(baseDir, "data", "archivedata") + DEFAULT_TORRENT_CONFIG_TORRENTDIR* = joinPath(baseDir, "data", "torrents") -proc ensureDirectories*(dataDir, tmpDir, logDir: string) = - createDir(dataDir) - createDir(tmpDir) - createDir(logDir) + # runtime variables + TEST_MODE_ENABLED* = desktopConfig.testMode + WALLET_ENABLED* = desktopConfig.enableWallet + GANACHE_NETWORK_RPC_URL* = desktopConfig.genacheNetworkRpcUrl + TORRENT_CONFIG_PORT* = desktopConfig.defaultTorentConfigPort + WAKU_V2_PORT* = desktopConfig.defaultWakuV2Port + STATUS_PORT* = desktopConfig.statusPort + LOG_LEVEL* = desktopConfig.logLevel -# This is changed during compilation by reading the VERSION file -const DESKTOP_VERSION {.strdefine.} = "0.0.0" -const STATUSGO_VERSION* {.strdefine.} = "0.0.0" -# This is changed during compilation by executing git command -const GIT_COMMIT* {.strdefine.} = "" - -const APP_VERSION* = if defined(production): DESKTOP_VERSION else: fmt("{GIT_COMMIT}") - -# Name of the test environment var to check for -const STATUS_RUNTIME_TEST_MODE_VAR* = "STATUS_RUNTIME_TEST_MODE" - -let TEST_MODE_ENABLED* = getEnv(STATUS_RUNTIME_TEST_MODE_VAR).toUpperAscii() == "TRUE" or - getEnv(STATUS_RUNTIME_TEST_MODE_VAR) == "1" \ No newline at end of file + # build variables + POKT_TOKEN_RESOLVED* = desktopConfig.poktToken + INFURA_TOKEN_RESOLVED* = desktopConfig.infuraToken + INFURA_TOKEN_SECRET_RESOLVED* = desktopConfig.infuraTokenSecret + ALCHEMY_ETHEREUM_MAINNET_TOKEN_RESOLVED* = desktopConfig.alchemyEthereumMainnetToken + ALCHEMY_ETHEREUM_GOERLI_TOKEN_RESOLVED* = desktopConfig.alchemyEthereumGoerliToken + ALCHEMY_ARBITRUM_MAINNET_TOKEN_RESOLVED* = desktopConfig.alchemyArbitrumMainnetToken + ALCHEMY_ARBITRUM_GOERLI_TOKEN_RESOLVED* = desktopConfig.alchemyArbitrumGoerliToken + ALCHEMY_OPTIMISM_MAINNET_TOKEN_RESOLVED* = desktopConfig.alchemyOptimismMainnetToken + ALCHEMY_OPTIMISM_GOERLI_TOKEN_RESOLVED* = desktopConfig.alchemyOptimismGoerliToken + OPENSEA_API_KEY_RESOLVED* = desktopConfig.openseaApiKey \ No newline at end of file diff --git a/src/env_cli_vars.nim b/src/env_cli_vars.nim new file mode 100644 index 0000000000..1e755942ab --- /dev/null +++ b/src/env_cli_vars.nim @@ -0,0 +1,180 @@ +import os, sequtils, strutils, strformat, chronicles + +import # vendor libs + confutils + +const BUILD_TIME_PREFIX = "STATUS_BUILD_" +const RUN_TIME_PREFIX = "STATUS_RUNTIME" + +# default log level value +const DEFAULT_LOG_LEVEL* = if defined(production): $LogLevel.INFO else: $LogLevel.DEBUG + +# build vars base name +const BASE_NAME_INFURA_TOKEN = "INFURA_TOKEN" +const BASE_NAME_INFURA_TOKEN_SECRET = "INFURA_TOKEN_SECRET" +const BASE_NAME_POKT_TOKEN = "POKT_TOKEN" +const BASE_NAME_OPENSEA_API_KEY = "OPENSEA_API_KEY" +const BASE_NAME_ALCHEMY_ETHEREUM_MAINNET_TOKEN = "ALCHEMY_ETHEREUM_MAINNET_TOKEN" +const BASE_NAME_ALCHEMY_ETHEREUM_GOERLI_TOKEN = "ALCHEMY_ETHEREUM_GOERLI_TOKEN" +const BASE_NAME_ALCHEMY_ARBITRUM_MAINNET_TOKEN = "ALCHEMY_ARBITRUM_MAINNET_TOKEN" +const BASE_NAME_ALCHEMY_ARBITRUM_GOERLI_TOKEN = "ALCHEMY_ARBITRUM_GOERLI_TOKEN" +const BASE_NAME_ALCHEMY_OPTIMISM_MAINNET_TOKEN = "ALCHEMY_OPTIMISM_MAINNET_TOKEN" +const BASE_NAME_ALCHEMY_OPTIMISM_GOERLI_TOKEN = "ALCHEMY_OPTIMISM_GOERLI_TOKEN" + + +################################################################################ +# Build time evaluated variables +################################################################################ + +const BUILD_INFURA_TOKEN = getEnv(BUILD_TIME_PREFIX & BASE_NAME_INFURA_TOKEN) +const BUILD_INFURA_TOKEN_SECRET = getEnv(BUILD_TIME_PREFIX & BASE_NAME_INFURA_TOKEN_SECRET) +const BUILD_POKT_TOKEN = getEnv(BUILD_TIME_PREFIX & BASE_NAME_POKT_TOKEN) +const BUILD_OPENSEA_API_KEY = getEnv(BUILD_TIME_PREFIX & BASE_NAME_OPENSEA_API_KEY) +const BUILD_ALCHEMY_ETHEREUM_MAINNET_TOKEN = getEnv(BUILD_TIME_PREFIX & BASE_NAME_ALCHEMY_ETHEREUM_MAINNET_TOKEN) +const BUILD_ALCHEMY_ETHEREUM_GOERLI_TOKEN = getEnv(BUILD_TIME_PREFIX & BASE_NAME_ALCHEMY_ETHEREUM_GOERLI_TOKEN) +const BUILD_ALCHEMY_ARBITRUM_MAINNET_TOKEN = getEnv(BUILD_TIME_PREFIX & BASE_NAME_ALCHEMY_ARBITRUM_MAINNET_TOKEN) +const BUILD_ALCHEMY_ARBITRUM_GOERLI_TOKEN = getEnv(BUILD_TIME_PREFIX & BASE_NAME_ALCHEMY_ARBITRUM_GOERLI_TOKEN) +const BUILD_ALCHEMY_OPTIMISM_MAINNET_TOKEN = getEnv(BUILD_TIME_PREFIX & BASE_NAME_ALCHEMY_OPTIMISM_MAINNET_TOKEN) +const BUILD_ALCHEMY_OPTIMISM_GOERLI_TOKEN = getEnv(BUILD_TIME_PREFIX & BASE_NAME_ALCHEMY_OPTIMISM_GOERLI_TOKEN) + +################################################################################ +# Run time evaluated variables +################################################################################ + +proc defaultDataDir*(): string = + try: + let homeDir = getHomeDir() + let parentDir = + if defined(development): + parentDir(getAppDir()) + elif homeDir == "": + getCurrentDir() + elif defined(macosx): + joinPath(homeDir, "Library", "Application Support") + elif defined(windows): + let targetDir = getEnv("LOCALAPPDATA").string + if targetDir == "": + joinPath(homeDir, "AppData", "Local") + else: + targetDir + else: + let targetDir = getEnv("XDG_CONFIG_HOME").string + if targetDir == "": + joinPath(homeDir, ".config") + else: + targetDir + return absolutePath(joinPath(parentDir, "Status")) + except OSError: + echo "Error: Unable to determine home directory." + +type StatusDesktopConfig = object + # runtime counterparts vars of build vars + infuraToken* {. + defaultValue: BUILD_INFURA_TOKEN + desc: "Sets infura token" + name: $BASE_NAME_INFURA_TOKEN + abbr: "infura-token" .}: string + infuraTokenSecret* {. + defaultValue: BUILD_INFURA_TOKEN_SECRET + desc: "Sets infura token secret" + name: $BASE_NAME_INFURA_TOKEN_SECRET + abbr: "infura-token-secret" .}: string + poktToken* {. + defaultValue: BUILD_POKT_TOKEN + desc: "Sets pokt token" + name: $BASE_NAME_POKT_TOKEN + abbr: "pokt-token" .}: string + openSeaApiKey* {. + defaultValue: BUILD_OPENSEA_API_KEY + desc: "Sets open sea api key" + name: $BASE_NAME_OPENSEA_API_KEY + abbr: "open-sea-api-key" .}: string + alchemyEthereumMainnetToken* {. + defaultValue: BUILD_ALCHEMY_ETHEREUM_MAINNET_TOKEN + desc: "Sets alchemy ethereum mainnet token" + name: $BASE_NAME_ALCHEMY_ETHEREUM_MAINNET_TOKEN + abbr: "alchemy-ethereum-mainnet-token" .}: string + alchemyEthereumGoerliToken* {. + defaultValue: BUILD_ALCHEMY_ETHEREUM_GOERLI_TOKEN + desc: "Sets alchemy ethereum goerli token" + name: $BASE_NAME_ALCHEMY_ETHEREUM_GOERLI_TOKEN + abbr: "alchemy-ethereum-goerli-token" .}: string + alchemyArbitrumMainnetToken* {. + defaultValue: BUILD_ALCHEMY_ARBITRUM_MAINNET_TOKEN + desc: "Sets alchemy arbitrum mainnet token" + name: $BASE_NAME_ALCHEMY_ARBITRUM_MAINNET_TOKEN + abbr: "alchemy-arbitrum-mainnet-token" .}: string + alchemyArbitrumGoerliToken* {. + defaultValue: BUILD_ALCHEMY_ARBITRUM_GOERLI_TOKEN + desc: "Sets alchemy arbitrum goerli token" + name: $BASE_NAME_ALCHEMY_ARBITRUM_GOERLI_TOKEN + abbr: "alchemy-arbitrum-goerli-token" .}: string + alchemyOptimismMainnetToken* {. + defaultValue: BUILD_ALCHEMY_OPTIMISM_MAINNET_TOKEN + desc: "Sets alchemy optimism mainnet token" + name: $BASE_NAME_ALCHEMY_OPTIMISM_MAINNET_TOKEN + abbr: "alchemy-optimism-mainnet-token" .}: string + alchemyOptimismGoerliToken* {. + defaultValue: BUILD_ALCHEMY_OPTIMISM_GOERLI_TOKEN + desc: "Sets alchemy optimism goerli token" + name: $BASE_NAME_ALCHEMY_OPTIMISM_GOERLI_TOKEN + abbr: "alchemy-optimism-goerli-token" .}: string + + # runtime vars + dataDir* {. + defaultValue: defaultDataDir() + desc: "Status Desktop data directory" + abbr: "d" .}: string + uri* {. + defaultValue: "" + desc: "status-app:// URI to open a chat or other" + name: "uri" .}: string + testMode* {. + defaultValue: false + desc: "Determines if the app should be run in test mode" + name: "TEST_MODE" + abbr: "test-mode" .}: bool + enableWallet* {. + defaultValue: true + desc: "Determines if the wallet section is enabled" + name: "ENABLE_WALLET" + abbr: "enable-wallet" .}: bool + genacheNetworkRpcUrl* {. + defaultValue: "" + desc: "Sets ganache network rpc url" + name: "GANACHE_NETWORK_RPC_URL" + abbr: "ganache-network-rpc-url" .}: string + defaultTorentConfigPort* {. + defaultValue: 0 + desc: "Sets default torrent config port" + name: "DEFAULT_TORRENT_CONFIG_PORT" + abbr: "default-torrent-config-port" .}: int + defaultWakuV2Port* {. + defaultValue: 0 + desc: "Sets default waku v2 port" + name: "DEFAULT_WAKU_V2_PORT" + abbr: "default-waku-v2-port" .}: int + statusPort* {. + defaultValue: 0 + desc: "Sets Waku V1 config port" + name: "PORT" + abbr: "status-port" .}: int + logLevel* {. + defaultValue: DEFAULT_LOG_LEVEL + desc: "Sets log level" + longdesc: "Can be one of: \"ERROR\", \"WARN\", \"INFO\", \"DEBUG\", \"TRACE\". \"INFO\" in production build, otherwise \"DEBUG\"" + name: "LOG_LEVEL" + abbr: "log-level" .}: string + + +# On macOS the first time when a user gets the "App downloaded from the +# internet" warning, and clicks the Open button, the OS passes a unique process +# serial number (PSN) as -psn_... command-line argument, which we remove before +# processing the arguments with nim-confutils. +# Credit: https://github.com/bitcoin/bitcoin/blame/b6e34afe9735faf97d6be7a90fafd33ec18c0cbb/src/util/system.cpp#L383-L389 + +var cliParams = commandLineParams() +if defined(macosx): + cliParams.keepIf(proc(p: string): bool = not p.startsWith("-psn_")) + +let desktopConfig = StatusDesktopConfig.load(cmdLine = cliParams, envVarsPrefix = RUN_TIME_PREFIX) diff --git a/src/nim_status_client.nim b/src/nim_status_client.nim index 2db71c9ed4..5dc8395c9d 100644 --- a/src/nim_status_client.nim +++ b/src/nim_status_client.nim @@ -55,9 +55,9 @@ proc prepareLogging() = except: logLoggingFailure(cstring(msg), getCurrentException()) - let defaultLogLvl = if defined(production): LogLevel.INFO else: LogLevel.DEBUG + let defaultLogLvl = if defined(production): chronicles.LogLevel.INFO else: chronicles.LogLevel.DEBUG # default log level can be overriden by LOG_LEVEL env parameter - let logLvl = try: parseEnum[LogLevel](getEnv("LOG_LEVEL")) + let logLvl = try: parseEnum[chronicles.LogLevel](main_constants.LOG_LEVEL) except: defaultLogLvl setLogLevel(logLvl) @@ -80,6 +80,11 @@ proc setupRemoteSignalsHandling() = signal_handler(keycardServiceQObjPointer, p0, "receiveKeycardSignal") keycard_go.setSignalEventCallback(callbackKeycardGo) +proc ensureDirectories*(dataDir, tmpDir, logDir: string) = + createDir(dataDir) + createDir(tmpDir) + createDir(logDir) + proc mainProc() = when defined(macosx) and defined(arm64): diff --git a/vendor/nim-confutils b/vendor/nim-confutils index 38dfeaaabd..674c9e4c8e 160000 --- a/vendor/nim-confutils +++ b/vendor/nim-confutils @@ -1 +1 @@ -Subproject commit 38dfeaaabdc6792d0f4d701621cbe34001978456 +Subproject commit 674c9e4c8e0cad2b7193cc9a59c12d39a397750f