Merge branch 'dev' into 'main'
Merging dev into main See merge request mx-moment/moment!19
This commit is contained in:
commit
4c3a8444c6
|
@ -507,33 +507,6 @@ class Backend:
|
||||||
ping=sum(times) // len(times), status=PingStatus.Done,
|
ping=sum(times) // len(times), status=PingStatus.Done,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _get_homeserver_stability(
|
|
||||||
self, logs: List[Dict[str, Any]],
|
|
||||||
) -> Tuple[float, List[timedelta]]:
|
|
||||||
"""Return server stability % and a list of downtime durations."""
|
|
||||||
|
|
||||||
stability = 100.0
|
|
||||||
durations = []
|
|
||||||
|
|
||||||
for period in logs:
|
|
||||||
started_at = datetime.fromtimestamp(period["datetime"])
|
|
||||||
time_since_now = datetime.now() - started_at
|
|
||||||
|
|
||||||
if time_since_now.days > 30 or period["type"] != 1: # 1 = downtime
|
|
||||||
continue
|
|
||||||
|
|
||||||
lasted_minutes = period["duration"] / 60
|
|
||||||
durations.append(timedelta(seconds=period["duration"]))
|
|
||||||
|
|
||||||
stability -= (
|
|
||||||
(lasted_minutes * stability / 1000) /
|
|
||||||
max(1, time_since_now.days / 3)
|
|
||||||
)
|
|
||||||
|
|
||||||
return (stability, durations)
|
|
||||||
|
|
||||||
|
|
||||||
async def fetch_homeservers(self) -> None:
|
async def fetch_homeservers(self) -> None:
|
||||||
"""Retrieve a list of public homeservers and add them to our model."""
|
"""Retrieve a list of public homeservers and add them to our model."""
|
||||||
|
|
||||||
|
@ -557,7 +530,7 @@ class Backend:
|
||||||
connector = session.connector,
|
connector = session.connector,
|
||||||
)
|
)
|
||||||
|
|
||||||
api_list = "https://publiclist.anchel.nl/publiclist.json"
|
api_list = "https://joinmatrix.org/servers.json"
|
||||||
try:
|
try:
|
||||||
response = await session.get(api_list)
|
response = await session.get(api_list)
|
||||||
except:
|
except:
|
||||||
|
@ -568,27 +541,19 @@ class Backend:
|
||||||
coros = []
|
coros = []
|
||||||
|
|
||||||
for server in (await response.json()):
|
for server in (await response.json()):
|
||||||
homeserver_url = server["homeserver"]
|
homeserver_url = "https://" + server["domain"]
|
||||||
|
|
||||||
if homeserver_url.startswith("http://"): # insecure server
|
if not server["open"]: # ignore closed servers
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not re.match(r"^https?://.+", homeserver_url):
|
|
||||||
homeserver_url = f"https://{homeserver_url}"
|
|
||||||
|
|
||||||
if server["country"] == "USA":
|
|
||||||
server["country"] = "United States"
|
|
||||||
|
|
||||||
stability, durations = \
|
|
||||||
self._get_homeserver_stability(server["monitor"]["logs"])
|
|
||||||
|
|
||||||
self.models["homeservers"][homeserver_url] = Homeserver(
|
self.models["homeservers"][homeserver_url] = Homeserver(
|
||||||
id = homeserver_url,
|
id = homeserver_url,
|
||||||
name = server["name"],
|
name = server["name"],
|
||||||
site_url = server["url"],
|
site_url = server["domain"],
|
||||||
country = server["country"],
|
country = server["jurisdiction"],
|
||||||
stability = stability,
|
stability = 0,
|
||||||
downtimes_ms = [d.total_seconds() * 1000 for d in durations],
|
downtimes_ms = 0,
|
||||||
|
# austin's list doesn't have stability/downtime
|
||||||
)
|
)
|
||||||
|
|
||||||
coros.append(self._ping_homeserver(session, homeserver_url))
|
coros.append(self._ping_homeserver(session, homeserver_url))
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
// Copyright Mirage authors & contributors <https://github.com/mirukana/mirage>
|
|
||||||
// and Moment contributors <https://gitlab.com/mx-moment/moment>
|
|
||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
|
||||||
|
|
||||||
pragma Singleton
|
|
||||||
import QtQuick 2.12
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
|
|
||||||
property bool startInTray: false
|
|
||||||
property string loadQml: ""
|
|
||||||
|
|
||||||
readonly property string help: `Usage: ${Qt.application.name} [options]
|
|
||||||
|
|
||||||
Options:
|
|
||||||
-t, --start-in-tray Start in the system tray, without a visible window
|
|
||||||
-l, --load-qml PATH Override the file to be loaded as src/gui/UI.qml
|
|
||||||
-V, --version Show the application's version and exit
|
|
||||||
-h, --help Show this help and exit
|
|
||||||
|
|
||||||
Environment variables:
|
|
||||||
MOMENT_CONFIG_DIR Override the default configuration folder
|
|
||||||
MOMENT_DATA_DIR Override the default application data folder
|
|
||||||
MOMENT_CACHE_DIR Override the default cache and downloads folder
|
|
||||||
http_proxy Override the General.proxy setting, see settings.py
|
|
||||||
`
|
|
||||||
|
|
||||||
readonly property bool ready: {
|
|
||||||
const passedArguments = Qt.application.arguments.slice(1)
|
|
||||||
|
|
||||||
while (passedArguments.length) {
|
|
||||||
switch (passedArguments.shift()) {
|
|
||||||
case "-h":
|
|
||||||
case "--help":
|
|
||||||
print("\n\n" + help.replace(/^ {4}/gm, ""))
|
|
||||||
Qt.quit()
|
|
||||||
break
|
|
||||||
|
|
||||||
case "-v":
|
|
||||||
case "--version":
|
|
||||||
print(Qt.application.version)
|
|
||||||
Qt.quit()
|
|
||||||
break
|
|
||||||
|
|
||||||
case "-t":
|
|
||||||
case "--start-in-tray":
|
|
||||||
startInTray = true
|
|
||||||
break
|
|
||||||
|
|
||||||
case "-l":
|
|
||||||
case "--load-qml":
|
|
||||||
loadQml = passedArguments.shift()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -115,7 +115,6 @@ HBox {
|
||||||
model: [
|
model: [
|
||||||
qsTr("Ping"),
|
qsTr("Ping"),
|
||||||
qsTr("Name & location"),
|
qsTr("Name & location"),
|
||||||
qsTr("Stability"),
|
|
||||||
qsTr("Site"),
|
qsTr("Site"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -66,44 +66,10 @@ HTile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TitleRightInfoLabel {
|
|
||||||
tile: root
|
|
||||||
font.pixelSize: theme.fontSize.normal
|
|
||||||
|
|
||||||
text:
|
|
||||||
model.stability === -1 ?
|
|
||||||
"" :
|
|
||||||
qsTr("%1%").arg(Math.max(0, parseInt(model.stability, 10)))
|
|
||||||
|
|
||||||
color:
|
|
||||||
model.stability >= 95 ? theme.colors.positiveText :
|
|
||||||
model.stability >= 85 ? theme.colors.warningText :
|
|
||||||
theme.colors.errorText
|
|
||||||
|
|
||||||
HoverHandler { id: rightInfoHover }
|
|
||||||
|
|
||||||
HToolTip {
|
|
||||||
readonly property var times: JSON.parse(model.downtimes_ms)
|
|
||||||
readonly property real total: utils.sum(times)
|
|
||||||
|
|
||||||
visible: model.stability !== -1 && rightInfoHover.hovered
|
|
||||||
text:
|
|
||||||
total === 0 ?
|
|
||||||
qsTr("No downtimes in the last 30 days") :
|
|
||||||
qsTr(
|
|
||||||
"Last 30 days downtimes: %1, average: %2, " +
|
|
||||||
"longest: %3, total: %4"
|
|
||||||
).arg(times.length)
|
|
||||||
.arg(utils.formatRelativeTime(total / times.length))
|
|
||||||
.arg(utils.formatRelativeTime(Math.max.apply(Math,times)))
|
|
||||||
.arg(utils.formatRelativeTime(total))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HButton {
|
HButton {
|
||||||
icon.name: "server-visit-website"
|
icon.name: "server-visit-website"
|
||||||
backgroundColor: "transparent"
|
backgroundColor: "transparent"
|
||||||
onClicked: Qt.openUrlExternally(model.site_url)
|
onClicked: Qt.openUrlExternally("https://"+model.site_url)
|
||||||
|
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@ ApplicationWindow {
|
||||||
property var theme: null
|
property var theme: null
|
||||||
property var themeRules: null
|
property var themeRules: null
|
||||||
property string settingsFolder
|
property string settingsFolder
|
||||||
|
property bool startInTray
|
||||||
|
property string loadQml
|
||||||
|
|
||||||
readonly property var visibleMenus: ({})
|
readonly property var visibleMenus: ({})
|
||||||
readonly property var visiblePopups: ({})
|
readonly property var visiblePopups: ({})
|
||||||
|
@ -98,7 +100,7 @@ ApplicationWindow {
|
||||||
minimumHeight: theme ? theme.minimumSupportedHeight : 120
|
minimumHeight: theme ? theme.minimumSupportedHeight : 120
|
||||||
width: Math.min(screen.width, 1152)
|
width: Math.min(screen.width, 1152)
|
||||||
height: Math.min(screen.height, 768)
|
height: Math.min(screen.height, 768)
|
||||||
visible: ArgumentParser.ready && ! ArgumentParser.startInTray
|
visible: ! startInTray
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
onClosing: if (py.ready && settings.General.close_to_tray) {
|
onClosing: if (py.ready && settings.General.close_to_tray) {
|
||||||
|
@ -123,8 +125,8 @@ ApplicationWindow {
|
||||||
focus: true
|
focus: true
|
||||||
scale: py.ready ? 1 : 0.5
|
scale: py.ready ? 1 : 0.5
|
||||||
source:
|
source:
|
||||||
ArgumentParser.ready && py.ready ?
|
py.ready ?
|
||||||
(ArgumentParser.loadQml || "UI.qml") :
|
(loadQml || "UI.qml") :
|
||||||
""
|
""
|
||||||
|
|
||||||
Behavior on scale { HNumberAnimation { overshoot: 3; factor: 1.2 } }
|
Behavior on scale { HNumberAnimation { overshoot: 3; factor: 1.2 } }
|
||||||
|
|
|
@ -1,2 +1 @@
|
||||||
singleton ModelStore 0.1 ModelStore.qml
|
singleton ModelStore 0.1 ModelStore.qml
|
||||||
singleton ArgumentParser 0.1 ArgumentParser.qml
|
|
||||||
|
|
39
src/main.cpp
39
src/main.cpp
|
@ -19,6 +19,8 @@
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QLockFile>
|
#include <QLockFile>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
#include <iostream>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
|
@ -372,6 +374,38 @@ int main(int argc, char *argv[]) {
|
||||||
// because migrate displays a popup dialog
|
// because migrate displays a popup dialog
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
QCommandLineParser args;
|
||||||
|
|
||||||
|
QCommandLineOption startInTrayOption(QStringList() << "t" << "start-in-tray",
|
||||||
|
"Start in the system tray, without a visible window.");
|
||||||
|
args.addOption(startInTrayOption);
|
||||||
|
|
||||||
|
QCommandLineOption loadQmlOption(QStringList() << "l" << "load-qml",
|
||||||
|
"Override the file to be loaded as src/gui/UI.qml", "PATH");
|
||||||
|
args.addOption(loadQmlOption);
|
||||||
|
|
||||||
|
QCommandLineOption helpOption(QStringList() << "h" << "help",
|
||||||
|
"Displays help on commandline options.");
|
||||||
|
args.addOption(helpOption);
|
||||||
|
|
||||||
|
args.addVersionOption();
|
||||||
|
|
||||||
|
args.process(app);
|
||||||
|
|
||||||
|
if (args.isSet(helpOption)) {
|
||||||
|
std::cout << args.helpText().toStdString() << std::endl
|
||||||
|
<< "Environment variables:" << std::endl
|
||||||
|
<< " MOMENT_CONFIG_DIR Override the configuration folder"
|
||||||
|
<< std::endl
|
||||||
|
<< " MOMENT_DATA_DIR Override the application data folder"
|
||||||
|
<< std::endl
|
||||||
|
<< " MOMENT_CACHE_DIR Override the cache and downloads folder"
|
||||||
|
<< std::endl
|
||||||
|
<< " http_proxy Override the General.proxy setting, see "
|
||||||
|
<< "settings.py" << std::endl;
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
if (shouldMigrateFromMirage()) tryMigrateFromMirage();
|
if (shouldMigrateFromMirage()) tryMigrateFromMirage();
|
||||||
|
|
||||||
QString customConfigDir(qEnvironmentVariable("MOMENT_CONFIG_DIR"));
|
QString customConfigDir(qEnvironmentVariable("MOMENT_CONFIG_DIR"));
|
||||||
|
@ -489,7 +523,10 @@ int main(int argc, char *argv[]) {
|
||||||
app.exit(EXIT_FAILURE);
|
app.exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
component.create(objectContext)->setProperty("settingsFolder", settingsFolder);
|
QObject *comp = component.create(objectContext);
|
||||||
|
comp->setProperty("settingsFolder", "file://"+settingsFolder);
|
||||||
|
comp->setProperty("startInTray", args.isSet(startInTrayOption));
|
||||||
|
comp->setProperty("loadQml", args.value(loadQmlOption));
|
||||||
|
|
||||||
// Finally, execute the app. Return its exit code after clearing the lock.
|
// Finally, execute the app. Return its exit code after clearing the lock.
|
||||||
int exit_code = app.exec();
|
int exit_code = app.exec();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user