Merge branch 'dev' into 'main'
Merging dev into main See merge request mx-moment/moment!19
This commit is contained in:
		| @@ -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(); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	