2020-10-12 05:21:41 +00:00
|
|
|
import NimQml, chronicles, os, strformat
|
2020-05-29 19:54:35 +00:00
|
|
|
|
2020-05-15 22:02:20 +00:00
|
|
|
import app/chat/core as chat
|
|
|
|
import app/wallet/core as wallet
|
|
|
|
import app/node/core as node
|
2020-09-15 19:47:13 +00:00
|
|
|
import app/utilsView/core as utilsView
|
2020-10-27 20:53:22 +00:00
|
|
|
import app/browser/core as browserView
|
2020-05-20 01:59:15 +00:00
|
|
|
import app/profile/core as profile
|
2020-05-20 17:36:44 +00:00
|
|
|
import app/onboarding/core as onboarding
|
2020-05-27 07:15:42 +00:00
|
|
|
import app/login/core as login
|
2020-09-22 19:16:44 +00:00
|
|
|
import app/provider/core as provider
|
2020-09-02 13:30:40 +00:00
|
|
|
import status/signals/core as signals
|
2020-07-15 17:34:14 +00:00
|
|
|
import status/libstatus/types
|
2020-11-23 14:24:09 +00:00
|
|
|
import status/libstatus/accounts/constants
|
2020-07-15 17:34:14 +00:00
|
|
|
import nim_status
|
2020-05-29 19:54:35 +00:00
|
|
|
import status/status as statuslib
|
2020-10-12 05:21:41 +00:00
|
|
|
import ./eventemitter
|
2020-05-16 23:46:46 +00:00
|
|
|
|
2020-05-18 18:48:20 +00:00
|
|
|
var signalsQObjPointer: pointer
|
2020-05-11 17:31:07 +00:00
|
|
|
|
2020-05-21 19:07:55 +00:00
|
|
|
logScope:
|
|
|
|
topics = "main"
|
|
|
|
|
2020-05-06 17:40:00 +00:00
|
|
|
proc mainProc() =
|
2020-12-10 16:56:32 +00:00
|
|
|
let fleets =
|
|
|
|
if defined(windows) and getEnv("NIM_STATUS_CLIENT_DEV").string == "":
|
|
|
|
"/../resources/fleets.json"
|
|
|
|
else:
|
|
|
|
"/../fleets.json"
|
|
|
|
|
|
|
|
let status = statuslib.newStatusInstance(readFile(joinPath(getAppDir(), fleets)))
|
2020-06-04 07:38:24 +00:00
|
|
|
status.initNode()
|
2020-05-29 19:54:35 +00:00
|
|
|
|
2020-06-23 19:31:52 +00:00
|
|
|
enableHDPI()
|
2020-07-15 21:06:47 +00:00
|
|
|
initializeOpenGL()
|
2020-06-23 19:31:52 +00:00
|
|
|
|
2020-09-04 16:07:11 +00:00
|
|
|
let app = newQApplication("Status Desktop")
|
build: implement packaging steps for the Windows build
Implement a `pkg-windows` target that ultimately results in `Status.zip` being
written to `pkg/`.
Note: this commit does not introduce code signing for the Windows build since
that piece is still a work in progress.
`pkg-windows` creates a portable folder in `tmp/windows/dist` with the help of
[`windeployqt`][windeployqt], which copies the needed portions of Qt into the
folder.
Since DLL resolution is relatively inflexible, a launcher `Status.exe` is
created at the top-level of the folder; the launcher opens `bin/Status.exe`
while adding the portable folder's `bin/` to the `PATH`, allowing
`bin/Status.exe` to resolve the DLLs in that folder.
A few additional tools need to be installed (e.g. with [scoop][scoop]) and
availble in `PATH`:
* 7-zip
* dos2unix (provides unix2dos)
* findutils
* go
* rcedit
* wget
The above list builds on the tools list in PR #521, and the other requirements
and instructions in that PR's description still apply.
**Why not build an installer?**
When starting work on packaging for the Windows build, my initial plan was to
build an installer, and for that purpose I researched the [WiX Toolset][wix],
the [Qt Installer Framework][qtif], and some other options.
I found that building an installer is a bit complex. I then recalled, from
personal experience, that [Cmder][cmder]'s [Mini download][mini] is
installer-less. You simply unzip the download and place the `cmder_mini` folder
wherever you prefer. Such an approach was also recommended to me in one of the
Nim language's community chats.
In addition to being simpler, the installer-less approach also gives
installation of Status Desktop a lower profile than an installer-application
would since nothing is written to the Windows registry, added to the *Add or
remove programs* list, etc. I think that's a benefit given the privacy-security
focus of Status, but others may feel differently so please provide feedback on
this point!
[windeployqt]: https://doc.qt.io/qt-5/windows-deployment.html
[scoop]: https://scoop.sh/
[wix]: https://wixtoolset.org/
[qtif]: https://doc.qt.io/qtinstallerframework/index.html
[cmder]: https://cmder.net/
[mini]: https://github.com/cmderdev/cmder/releases/download/v1.3.15/cmder_mini.zip
2020-07-15 22:45:56 +00:00
|
|
|
let resources =
|
|
|
|
if defined(windows) and getEnv("NIM_STATUS_CLIENT_DEV").string == "":
|
|
|
|
"/../resources/resources.rcc"
|
|
|
|
else:
|
|
|
|
"/../resources.rcc"
|
|
|
|
QResource.registerResource(app.applicationDirPath & resources)
|
|
|
|
|
2020-09-17 20:11:31 +00:00
|
|
|
let statusAppIcon =
|
|
|
|
if defined(macosx):
|
2021-01-15 21:34:50 +00:00
|
|
|
"" # not used in macOS
|
2020-09-17 20:11:31 +00:00
|
|
|
elif defined(windows) and getEnv("NIM_STATUS_CLIENT_DEV").string == "":
|
|
|
|
"/../resources/status.svg"
|
build: use a different colored app icon and a non-default STATUS_PORT for dev builds
By default the desktop app uses port 30305, unless a value is specifically set
in environment variable `STATUS_PORT`. For convenience of those developing the
app and running development builds, while simultaneously running production
builds (a.k.a. packaged builds, whether built locally or in CI), have `make
run` invoke `bin/nim_status_client` with `STATUS_PORT=30306`. That value can
still be overriden by manually invoking `make run` with a different value,
e.g. `make STATUS_PORT=30307 run` and `STATUS_PORT=30307 make run` are both
valid and achieve the same effect. NOTE: the port "sticks" in the database
after the first clean run, so when changing ports developers will need to
delete the data dir within their local repository, else the existing database
for dev builds will be stuck using whatever port was used previously. In the
future, we can figure out a means to always update the port setting in the
database just after the login event (but see #1505).
Also, for development builds use an icon (for the running app) that is
orangered (`#ff4500`) instead of the official blue color. This makes it much
easier to select between a running production instance and development instance
when Cmd-Tab'ing (on macOS, or equiv on Linux and Windows) through open
applications. Not all icons displayed at runtime have been changed in this
manner for development builds, just the main application icon, and that seems
to be sufficient to achieve the desired effect; though in the future we could
do similar for notification icon, menu bar icon, etc.
2020-12-16 01:15:44 +00:00
|
|
|
elif getEnv("NIM_STATUS_CLIENT_DEV").string != "":
|
|
|
|
"/../status-dev.svg"
|
2020-09-17 20:11:31 +00:00
|
|
|
else:
|
|
|
|
"/../status.svg"
|
2021-01-15 21:34:50 +00:00
|
|
|
if not defined(macosx):
|
|
|
|
app.icon(app.applicationDirPath & statusAppIcon)
|
2020-06-23 22:54:21 +00:00
|
|
|
|
2020-08-10 20:19:15 +00:00
|
|
|
var i18nPath = ""
|
|
|
|
if (getEnv("NIM_STATUS_CLIENT_DEV").string != ""):
|
|
|
|
i18nPath = joinPath(getAppDir(), "../ui/i18n")
|
|
|
|
elif (defined(windows)):
|
|
|
|
i18nPath = joinPath(getAppDir(), "../resources/i18n")
|
|
|
|
elif (defined(macosx)):
|
|
|
|
i18nPath = joinPath(getAppDir(), "../i18n")
|
|
|
|
elif (defined(linux)):
|
|
|
|
i18nPath = joinPath(getAppDir(), "../i18n")
|
|
|
|
|
2020-11-23 14:24:09 +00:00
|
|
|
let networkAccessFactory = newQNetworkAccessManagerFactory(TMPDIR & "netcache")
|
2020-12-14 05:50:47 +00:00
|
|
|
|
2020-05-18 20:32:53 +00:00
|
|
|
let engine = newQQmlApplicationEngine()
|
2020-11-23 14:24:09 +00:00
|
|
|
engine.setNetworkAccessManagerFactory(networkAccessFactory)
|
2020-12-14 05:50:47 +00:00
|
|
|
|
|
|
|
let netAccMgr = newQNetworkAccessManager(engine.getNetworkAccessManager())
|
|
|
|
|
|
|
|
status.events.on("network:connected") do(e: Args):
|
|
|
|
# This is a workaround for Qt bug https://bugreports.qt.io/browse/QTBUG-55180
|
|
|
|
# that was apparently reintroduced in 5.14.1 Unfortunately, the only workaround
|
|
|
|
# that could be found uses obsolete properties and methods
|
|
|
|
# (https://doc.qt.io/qt-5/qnetworkaccessmanager-obsolete.html), so this will
|
|
|
|
# need to be something we keep in mind when upgrading to Qt 6.
|
|
|
|
# The workaround is to manually set the NetworkAccessible property of the
|
|
|
|
# QNetworkAccessManager once peers have dropped (network connection is lost).
|
|
|
|
netAccMgr.clearConnectionCache()
|
|
|
|
netAccMgr.setNetworkAccessible(NetworkAccessibility.Accessible)
|
|
|
|
|
2020-09-02 13:30:40 +00:00
|
|
|
let signalController = signals.newController(status)
|
2020-05-18 18:48:20 +00:00
|
|
|
|
|
|
|
# We need this global variable in order to be able to access the application
|
|
|
|
# from the non-closure callback passed to `libstatus.setSignalEventCallback`
|
|
|
|
signalsQObjPointer = cast[pointer](signalController.vptr)
|
|
|
|
|
2020-05-29 19:54:35 +00:00
|
|
|
var wallet = wallet.newController(status)
|
2020-06-02 20:10:48 +00:00
|
|
|
engine.setRootContextProperty("walletModel", wallet.variant)
|
2020-05-13 19:14:35 +00:00
|
|
|
|
2020-05-29 19:54:35 +00:00
|
|
|
var chat = chat.newController(status)
|
2020-05-15 21:40:05 +00:00
|
|
|
engine.setRootContextProperty("chatsModel", chat.variant)
|
2020-05-11 21:24:08 +00:00
|
|
|
|
2020-12-14 05:50:47 +00:00
|
|
|
var node = node.newController(status, netAccMgr)
|
2020-05-15 21:40:05 +00:00
|
|
|
engine.setRootContextProperty("nodeModel", node.variant)
|
2020-05-20 17:11:30 +00:00
|
|
|
|
2020-09-15 19:47:13 +00:00
|
|
|
var utilsController = utilsView.newController(status)
|
|
|
|
engine.setRootContextProperty("utilsModel", utilsController.variant)
|
|
|
|
|
2020-10-27 20:53:22 +00:00
|
|
|
var browserController = browserView.newController(status)
|
|
|
|
engine.setRootContextProperty("browserModel", browserController.variant)
|
|
|
|
|
2020-07-20 14:28:32 +00:00
|
|
|
proc changeLanguage(locale: string) =
|
2020-08-10 20:19:15 +00:00
|
|
|
engine.setTranslationPackage(joinPath(i18nPath, fmt"qml_{locale}.qm"))
|
2020-07-20 14:28:32 +00:00
|
|
|
|
|
|
|
var profile = profile.newController(status, changeLanguage)
|
2020-05-20 01:59:15 +00:00
|
|
|
engine.setRootContextProperty("profileModel", profile.variant)
|
|
|
|
|
2020-09-22 19:16:44 +00:00
|
|
|
var provider = provider.newController(status)
|
|
|
|
engine.setRootContextProperty("web3Provider", provider.variant)
|
|
|
|
|
2020-08-25 20:19:46 +00:00
|
|
|
var login = login.newController(status)
|
|
|
|
var onboarding = onboarding.newController(status)
|
|
|
|
|
2020-06-17 16:13:13 +00:00
|
|
|
status.events.once("login") do(a: Args):
|
2020-05-22 12:35:40 +00:00
|
|
|
var args = AccountArgs(a)
|
2020-08-25 20:19:46 +00:00
|
|
|
# Delete login and onboarding from memory to remove any mnemonic that would have been saved in the accounts list
|
|
|
|
login.delete()
|
|
|
|
onboarding.delete()
|
|
|
|
|
2020-05-29 19:54:35 +00:00
|
|
|
status.startMessenger()
|
2020-05-27 07:15:42 +00:00
|
|
|
profile.init(args.account)
|
2020-06-25 13:26:58 +00:00
|
|
|
wallet.init()
|
2020-10-01 19:24:13 +00:00
|
|
|
provider.init()
|
2020-06-25 13:26:58 +00:00
|
|
|
chat.init()
|
2020-09-15 19:47:13 +00:00
|
|
|
utilsController.init()
|
2020-10-27 20:53:22 +00:00
|
|
|
browserController.init()
|
build: implement packaging steps for the Windows build
Implement a `pkg-windows` target that ultimately results in `Status.zip` being
written to `pkg/`.
Note: this commit does not introduce code signing for the Windows build since
that piece is still a work in progress.
`pkg-windows` creates a portable folder in `tmp/windows/dist` with the help of
[`windeployqt`][windeployqt], which copies the needed portions of Qt into the
folder.
Since DLL resolution is relatively inflexible, a launcher `Status.exe` is
created at the top-level of the folder; the launcher opens `bin/Status.exe`
while adding the portable folder's `bin/` to the `PATH`, allowing
`bin/Status.exe` to resolve the DLLs in that folder.
A few additional tools need to be installed (e.g. with [scoop][scoop]) and
availble in `PATH`:
* 7-zip
* dos2unix (provides unix2dos)
* findutils
* go
* rcedit
* wget
The above list builds on the tools list in PR #521, and the other requirements
and instructions in that PR's description still apply.
**Why not build an installer?**
When starting work on packaging for the Windows build, my initial plan was to
build an installer, and for that purpose I researched the [WiX Toolset][wix],
the [Qt Installer Framework][qtif], and some other options.
I found that building an installer is a bit complex. I then recalled, from
personal experience, that [Cmder][cmder]'s [Mini download][mini] is
installer-less. You simply unzip the download and place the `cmder_mini` folder
wherever you prefer. Such an approach was also recommended to me in one of the
Nim language's community chats.
In addition to being simpler, the installer-less approach also gives
installation of Status Desktop a lower profile than an installer-application
would since nothing is written to the Windows registry, added to the *Add or
remove programs* list, etc. I think that's a benefit given the privacy-security
focus of Status, but others may feel differently so please provide feedback on
this point!
[windeployqt]: https://doc.qt.io/qt-5/windows-deployment.html
[scoop]: https://scoop.sh/
[wix]: https://wixtoolset.org/
[qtif]: https://doc.qt.io/qtinstallerframework/index.html
[cmder]: https://cmder.net/
[mini]: https://github.com/cmderdev/cmder/releases/download/v1.3.15/cmder_mini.zip
2020-07-15 22:45:56 +00:00
|
|
|
|
2020-09-11 17:23:57 +00:00
|
|
|
wallet.checkPendingTransactions()
|
|
|
|
wallet.start()
|
|
|
|
|
2020-05-28 04:06:57 +00:00
|
|
|
engine.setRootContextProperty("loginModel", login.variant)
|
|
|
|
engine.setRootContextProperty("onboardingModel", onboarding.variant)
|
2020-05-21 20:52:00 +00:00
|
|
|
|
2020-06-26 14:08:08 +00:00
|
|
|
let isExperimental = if getEnv("EXPERIMENTAL") == "1": "1" else: "0" # value explicity passed to avoid trusting input
|
|
|
|
let experimentalFlag = newQVariant(isExperimental)
|
|
|
|
engine.setRootContextProperty("isExperimental", experimentalFlag)
|
|
|
|
|
2020-06-18 21:56:04 +00:00
|
|
|
defer:
|
|
|
|
error "TODO: if user is logged in, logout"
|
2020-09-22 19:16:44 +00:00
|
|
|
provider.delete()
|
2020-06-18 21:56:04 +00:00
|
|
|
engine.delete()
|
|
|
|
app.delete()
|
|
|
|
signalController.delete()
|
|
|
|
login.delete()
|
|
|
|
onboarding.delete()
|
|
|
|
wallet.delete()
|
|
|
|
chat.delete()
|
|
|
|
profile.delete()
|
2020-09-15 19:47:13 +00:00
|
|
|
utilsController.delete()
|
2020-10-27 20:53:22 +00:00
|
|
|
browserController.delete()
|
2020-06-18 21:56:04 +00:00
|
|
|
|
|
|
|
|
2020-06-04 07:38:24 +00:00
|
|
|
# Initialize only controllers whose init functions
|
|
|
|
# do not need a running node
|
|
|
|
proc initControllers() =
|
|
|
|
node.init()
|
|
|
|
login.init()
|
|
|
|
onboarding.init()
|
build: implement packaging steps for the Windows build
Implement a `pkg-windows` target that ultimately results in `Status.zip` being
written to `pkg/`.
Note: this commit does not introduce code signing for the Windows build since
that piece is still a work in progress.
`pkg-windows` creates a portable folder in `tmp/windows/dist` with the help of
[`windeployqt`][windeployqt], which copies the needed portions of Qt into the
folder.
Since DLL resolution is relatively inflexible, a launcher `Status.exe` is
created at the top-level of the folder; the launcher opens `bin/Status.exe`
while adding the portable folder's `bin/` to the `PATH`, allowing
`bin/Status.exe` to resolve the DLLs in that folder.
A few additional tools need to be installed (e.g. with [scoop][scoop]) and
availble in `PATH`:
* 7-zip
* dos2unix (provides unix2dos)
* findutils
* go
* rcedit
* wget
The above list builds on the tools list in PR #521, and the other requirements
and instructions in that PR's description still apply.
**Why not build an installer?**
When starting work on packaging for the Windows build, my initial plan was to
build an installer, and for that purpose I researched the [WiX Toolset][wix],
the [Qt Installer Framework][qtif], and some other options.
I found that building an installer is a bit complex. I then recalled, from
personal experience, that [Cmder][cmder]'s [Mini download][mini] is
installer-less. You simply unzip the download and place the `cmder_mini` folder
wherever you prefer. Such an approach was also recommended to me in one of the
Nim language's community chats.
In addition to being simpler, the installer-less approach also gives
installation of Status Desktop a lower profile than an installer-application
would since nothing is written to the Windows registry, added to the *Add or
remove programs* list, etc. I think that's a benefit given the privacy-security
focus of Status, but others may feel differently so please provide feedback on
this point!
[windeployqt]: https://doc.qt.io/qt-5/windows-deployment.html
[scoop]: https://scoop.sh/
[wix]: https://wixtoolset.org/
[qtif]: https://doc.qt.io/qtinstallerframework/index.html
[cmder]: https://cmder.net/
[mini]: https://github.com/cmderdev/cmder/releases/download/v1.3.15/cmder_mini.zip
2020-07-15 22:45:56 +00:00
|
|
|
|
2020-06-04 07:38:24 +00:00
|
|
|
initControllers()
|
|
|
|
|
|
|
|
# Handle node.stopped signal when user has logged out
|
2020-06-17 16:13:13 +00:00
|
|
|
status.events.once("nodeStopped") do(a: Args):
|
2020-06-04 07:38:24 +00:00
|
|
|
# TODO: remove this once accounts are not tracked in the AccountsModel
|
|
|
|
status.reset()
|
|
|
|
|
|
|
|
# 1. Reset controller data
|
|
|
|
login.reset()
|
|
|
|
onboarding.reset()
|
|
|
|
# TODO: implement all controller resets
|
|
|
|
# chat.reset()
|
|
|
|
# node.reset()
|
|
|
|
# wallet.reset()
|
|
|
|
# profile.reset()
|
build: implement packaging steps for the Windows build
Implement a `pkg-windows` target that ultimately results in `Status.zip` being
written to `pkg/`.
Note: this commit does not introduce code signing for the Windows build since
that piece is still a work in progress.
`pkg-windows` creates a portable folder in `tmp/windows/dist` with the help of
[`windeployqt`][windeployqt], which copies the needed portions of Qt into the
folder.
Since DLL resolution is relatively inflexible, a launcher `Status.exe` is
created at the top-level of the folder; the launcher opens `bin/Status.exe`
while adding the portable folder's `bin/` to the `PATH`, allowing
`bin/Status.exe` to resolve the DLLs in that folder.
A few additional tools need to be installed (e.g. with [scoop][scoop]) and
availble in `PATH`:
* 7-zip
* dos2unix (provides unix2dos)
* findutils
* go
* rcedit
* wget
The above list builds on the tools list in PR #521, and the other requirements
and instructions in that PR's description still apply.
**Why not build an installer?**
When starting work on packaging for the Windows build, my initial plan was to
build an installer, and for that purpose I researched the [WiX Toolset][wix],
the [Qt Installer Framework][qtif], and some other options.
I found that building an installer is a bit complex. I then recalled, from
personal experience, that [Cmder][cmder]'s [Mini download][mini] is
installer-less. You simply unzip the download and place the `cmder_mini` folder
wherever you prefer. Such an approach was also recommended to me in one of the
Nim language's community chats.
In addition to being simpler, the installer-less approach also gives
installation of Status Desktop a lower profile than an installer-application
would since nothing is written to the Windows registry, added to the *Add or
remove programs* list, etc. I think that's a benefit given the privacy-security
focus of Status, but others may feel differently so please provide feedback on
this point!
[windeployqt]: https://doc.qt.io/qt-5/windows-deployment.html
[scoop]: https://scoop.sh/
[wix]: https://wixtoolset.org/
[qtif]: https://doc.qt.io/qtinstallerframework/index.html
[cmder]: https://cmder.net/
[mini]: https://github.com/cmderdev/cmder/releases/download/v1.3.15/cmder_mini.zip
2020-07-15 22:45:56 +00:00
|
|
|
|
2020-06-04 07:38:24 +00:00
|
|
|
# 2. Re-init controllers that don't require a running node
|
|
|
|
initControllers()
|
|
|
|
|
2020-05-18 15:07:30 +00:00
|
|
|
engine.setRootContextProperty("signals", signalController.variant)
|
|
|
|
|
2020-06-30 21:35:24 +00:00
|
|
|
engine.load(newQUrl("qrc:///main.qml"))
|
2020-05-18 18:48:20 +00:00
|
|
|
|
|
|
|
# Please note that this must use the `cdecl` calling convention because
|
|
|
|
# it will be passed as a regular C function to libstatus. This means that
|
|
|
|
# we cannot capture any local variables here (we must rely on globals)
|
|
|
|
var callback: SignalCallback = proc(p0: cstring) {.cdecl.} =
|
2020-06-04 21:18:11 +00:00
|
|
|
setupForeignThreadGc()
|
2020-05-18 15:07:30 +00:00
|
|
|
signal_handler(signalsQObjPointer, p0, "receiveSignal")
|
2020-06-04 21:18:11 +00:00
|
|
|
tearDownForeignThreadGc()
|
2020-05-16 23:46:46 +00:00
|
|
|
|
2020-07-15 17:34:14 +00:00
|
|
|
nim_status.setSignalEventCallback(callback)
|
2020-05-15 21:10:00 +00:00
|
|
|
|
2020-05-10 23:24:06 +00:00
|
|
|
# Qt main event loop is entered here
|
|
|
|
# The termination of the loop will be performed when exit() or quit() is called
|
2020-05-21 19:07:55 +00:00
|
|
|
info "Starting application..."
|
2020-05-06 17:40:00 +00:00
|
|
|
app.exec()
|
|
|
|
|
|
|
|
when isMainModule:
|
|
|
|
mainProc()
|
|
|
|
GC_fullcollect()
|