add: automatically update the subscriptions, with notifications

This commit is contained in:
Qv2ray-dev 2020-06-16 23:35:28 +08:00
parent 500039ccba
commit c2ec33571d
10 changed files with 106 additions and 68 deletions

View File

@ -1 +1 @@
5604
5605

View File

@ -24,6 +24,8 @@ namespace Qv2ray
DEBUG("QV2RAY_BUILD_INFO", QV2RAY_BUILD_INFO)
DEBUG("QV2RAY_BUILD_EXTRA_INFO", QV2RAY_BUILD_EXTRA_INFO)
DEBUG("QV2RAY_BUILD_NUMBER", QSTRN(QV2RAY_VERSION_BUILD))
//
hTray = new QSystemTrayIcon(this);
}
bool Qv2rayApplication::SetupQv2ray()

View File

@ -2,6 +2,7 @@
#include "libs/QJsonStruct/QJsonStruct.hpp"
#include <QSystemTrayIcon>
#include <SingleApplication>
class MainWindow;
@ -49,10 +50,25 @@ namespace Qv2ray
int RunQv2ray();
void DeallocateGlobalVariables();
public:
QSystemTrayIcon **GetTrayIcon()
{
return &hTray;
}
void showMessage(const QString &m, const QIcon &icon, int msecs = 10000)
{
hTray->showMessage("Qv2ray", m, icon, msecs);
}
void showMessage(const QString &m, QSystemTrayIcon::MessageIcon icon = QSystemTrayIcon::Information, int msecs = 10000)
{
hTray->showMessage("Qv2ray", m, icon, msecs);
}
private slots:
void onMessageReceived(quint32 clientID, QByteArray msg);
private:
QSystemTrayIcon *hTray;
MainWindow *mainWindow;
static commandline_status ParseCommandLine(QString *errorMessage);
bool initilized = false;
@ -60,3 +76,4 @@ namespace Qv2ray
} // namespace Qv2ray
#define qvApp (static_cast<Qv2ray::Qv2rayApplication *>(QCoreApplication::instance()))
#define qvAppTrayIcon (*qvApp->GetTrayIcon())

View File

@ -66,7 +66,7 @@ namespace Qv2ray::base
}
bool isEmpty() const
{
return connectionId == NullConnectionId;
return groupId == NullGroupId || connectionId == NullConnectionId;
}
friend bool operator==(const ConnectionGroupPair &lhs, const ConnectionGroupPair &rhs)
{

View File

@ -497,7 +497,10 @@ namespace Qv2ray::core::handler
CheckGroupExistanceEx(id, nothing);
if (!groups[id].isSubscription)
return;
asyncRequestHelper->AsyncHttpGet(groups[id].subscriptionOption.address, [=](const QByteArray &d) { CHUpdateSubscription_p(id, d); });
asyncRequestHelper->AsyncHttpGet(groups[id].subscriptionOption.address, [=](const QByteArray &d) {
CHUpdateSubscription_p(id, d);
emit OnSubscriptionAsyncUpdateFinished(id);
});
}
bool QvConfigHandler::UpdateSubscription(const GroupId &id)

View File

@ -68,6 +68,14 @@ namespace Qv2ray::core::handler
{
return kernelHandler->CurrentConnection().connectionId == id;
}
inline void IgnoreSubscriptionUpdate(const GroupId &group)
{
if (groups[group].isSubscription)
{
groups[group].lastUpdatedDate = system_clock::to_time_t(system_clock::now());
}
}
//
//
void SaveConnectionConfig();
@ -140,7 +148,7 @@ namespace Qv2ray::core::handler
void OnGroupRenamed(const GroupId &id, const QString &oldName, const QString &newName);
void OnGroupDeleted(const GroupId &id, const QList<ConnectionId> &connections);
//
void OnSubscriptionUpdateFinished(const GroupId &id);
void OnSubscriptionAsyncUpdateFinished(const GroupId &id);
void OnConnected(const ConnectionGroupPair &id);
void OnDisconnected(const ConnectionGroupPair &id);
void OnKernelCrashed(const ConnectionGroupPair &id, const QString &errMessage);

View File

@ -70,7 +70,7 @@ ConnectionItemWidget::ConnectionItemWidget(const GroupId &id, QWidget *parent) :
connect(ConnectionManager, &QvConfigHandler::OnConnectionCreated, this, &ConnectionItemWidget::RecalculateConnectionsCount);
connect(ConnectionManager, &QvConfigHandler::OnConnectionModified, this, &ConnectionItemWidget::RecalculateConnectionsCount);
connect(ConnectionManager, &QvConfigHandler::OnConnectionLinkedWithGroup, this, &ConnectionItemWidget::RecalculateConnectionsCount);
connect(ConnectionManager, &QvConfigHandler::OnSubscriptionUpdateFinished, this, &ConnectionItemWidget::RecalculateConnectionsCount);
connect(ConnectionManager, &QvConfigHandler::OnSubscriptionAsyncUpdateFinished, this, &ConnectionItemWidget::RecalculateConnectionsCount);
connect(ConnectionManager, &QvConfigHandler::OnConnectionRemovedFromGroup, this, &ConnectionItemWidget::RecalculateConnectionsCount);
//
connect(ConnectionManager, &QvConfigHandler::OnGroupRenamed, this, &ConnectionItemWidget::OnGroupItemRenamed);

View File

@ -1,10 +1,9 @@
#include "w_MainWindow.hpp"
#include "components/plugins/QvPluginHost.hpp"
#include "components/proxy/QvProxyConfigurator.hpp"
#include "components/update/UpdateChecker.hpp"
#include "core/handler/ConfigHandler.hpp"
#include "core/settings/SettingsBackend.hpp"
#include "src/Qv2rayApplication.hpp"
#include "ui/common/UIBase.hpp"
#include "ui/editors/w_JsonEditor.hpp"
#include "ui/editors/w_OutboundEditor.hpp"
@ -15,18 +14,6 @@
#include "ui/windows/w_PluginManager.hpp"
#include "ui/windows/w_PreferencesWindow.hpp"
#include <QCloseEvent>
#include <QDebug>
#include <QDesktopServices>
#include <QFile>
#include <QFileInfo>
#include <QHeaderView>
#include <QInputDialog>
#include <QKeyEvent>
#include <QMenu>
#include <QStandardItemModel>
#include <QUrl>
#ifdef Q_OS_MAC
#include <ApplicationServices/ApplicationServices.h>
#endif
@ -44,13 +31,16 @@ QvMessageBusSlotImpl(MainWindow)
{
switch (msg)
{
MBShowDefaultImpl MBHideDefaultImpl MBRetranslateDefaultImpl MBUpdateColorSchemeDefaultImpl
MBShowDefaultImpl;
MBHideDefaultImpl;
MBRetranslateDefaultImpl;
MBUpdateColorSchemeDefaultImpl;
}
}
void MainWindow::updateColorScheme()
{
hTray.setIcon(KernelInstance->CurrentConnection().isEmpty() ? Q_TRAYICON("tray.png") : Q_TRAYICON("tray-connected.png"));
qvAppTrayIcon->setIcon(KernelInstance->CurrentConnection().isEmpty() ? Q_TRAYICON("tray.png") : Q_TRAYICON("tray-connected.png"));
//
importConfigButton->setIcon(QICON_R("import.png"));
updownImageBox->setStyleSheet("image: url(" + QV2RAY_COLORSCHEME_ROOT + "netspeed_arrow.png)");
@ -128,7 +118,7 @@ void MainWindow::ReloadRecentConnectionList()
for (auto i = 0; i < iterateRange; i++)
{
const auto &item = GlobalConfig.uiConfig.recentConnections.at(i);
if (newRecentConnections.contains(item))
if (newRecentConnections.contains(item) || item.isEmpty())
{
continue;
}
@ -188,15 +178,25 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
connect(ConnectionManager, &QvConfigHandler::OnGroupCreated, this, &MainWindow::OnGroupCreated);
connect(ConnectionManager, &QvConfigHandler::OnGroupDeleted, this, &MainWindow::OnGroupDeleted);
//
connect(ConnectionManager, &QvConfigHandler::OnSubscriptionAsyncUpdateFinished, [](const GroupId &gid) {
qvApp->showMessage(tr("Subscription \"%1\" has been updated").arg(GetDisplayName(gid))); //
});
//
connect(ConnectionManager, &QvConfigHandler::OnConnectionRenamed, [&](const ConnectionId &id, const QString &, const QString &newName) {
ConnectionGroupPair pair = { id, ConnectionManager->GetGroupId(id).first() };
if (connectionNodes.contains(pair))
connectionNodes.value(pair)->setText(MW_ITEM_COL_NAME, newName); //
for (const auto &gid : ConnectionManager->GetGroupId(id))
{
ConnectionGroupPair pair{ id, gid };
if (connectionNodes.contains(pair))
connectionNodes.value(pair)->setText(MW_ITEM_COL_NAME, newName);
}
});
connect(ConnectionManager, &QvConfigHandler::OnLatencyTestFinished, [&](const ConnectionId &id, const int avg) {
ConnectionGroupPair pair = { id, ConnectionManager->GetGroupId(id).first() };
if (connectionNodes.contains(pair))
connectionNodes.value(pair)->setText(MW_ITEM_COL_PING, NumericString(avg)); //
for (const auto &gid : ConnectionManager->GetGroupId(id))
{
ConnectionGroupPair pair{ id, gid };
if (connectionNodes.contains(pair))
connectionNodes.value(pair)->setText(MW_ITEM_COL_PING, NumericString(avg)); //
}
});
//
connect(infoWidget, &ConnectionInfoWidget::OnEditRequested, this, &MainWindow::OnEditRequested);
@ -204,10 +204,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
//
//
// Setup System tray icons and menus
hTray.setToolTip(TRAY_TOOLTIP_PREFIX);
qvAppTrayIcon->setToolTip(TRAY_TOOLTIP_PREFIX);
qvAppTrayIcon->show();
//
// Basic tray actions
hTray.show();
tray_action_Start->setEnabled(true);
tray_action_Stop->setEnabled(false);
tray_action_Restart->setEnabled(false);
@ -232,7 +232,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
tray_RootMenu->addAction(tray_action_Restart);
tray_RootMenu->addSeparator();
tray_RootMenu->addAction(tray_action_Quit);
hTray.setContextMenu(tray_RootMenu);
qvAppTrayIcon->setContextMenu(tray_RootMenu);
//
connect(tray_action_ShowHide, &QAction::triggered, this, &MainWindow::ToggleVisibility);
connect(tray_action_ShowPreferencesWindow, &QAction::triggered, this, &MainWindow::on_preferencesBtn_clicked);
@ -247,10 +247,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
ReloadRecentConnectionList();
if (!GlobalConfig.uiConfig.quietMode)
{
hTray.showMessage("Qv2ray", tr("Recent connections' jump list cleared."));
qvApp->showMessage(tr("Recent connections' jump list cleared."));
}
});
connect(&hTray, &QSystemTrayIcon::activated, this, &MainWindow::on_activatedTray);
connect(qvAppTrayIcon, &QSystemTrayIcon::activated, this, &MainWindow::on_activatedTray);
//
// Actions for right click the log text browser
//
@ -457,7 +457,6 @@ void MainWindow::on_action_StartThis_triggered()
MainWindow::~MainWindow()
{
hTray.hide();
}
void MainWindow::closeEvent(QCloseEvent *event)
@ -652,7 +651,7 @@ void MainWindow::on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item
void MainWindow::OnDisconnected(const ConnectionGroupPair &id)
{
Q_UNUSED(id)
hTray.setIcon(Q_TRAYICON("tray.png"));
qvAppTrayIcon->setIcon(Q_TRAYICON("tray.png"));
tray_action_Start->setEnabled(true);
tray_action_Stop->setEnabled(false);
tray_action_Restart->setEnabled(false);
@ -661,22 +660,22 @@ void MainWindow::OnDisconnected(const ConnectionGroupPair &id)
locateBtn->setEnabled(false);
if (!GlobalConfig.uiConfig.quietMode)
{
this->hTray.showMessage("Qv2ray", tr("Disconnected from: ") + GetDisplayName(id.connectionId), this->windowIcon());
qvApp->showMessage(tr("Disconnected from: ") + GetDisplayName(id.connectionId), this->windowIcon());
}
hTray.setToolTip(TRAY_TOOLTIP_PREFIX);
qvAppTrayIcon->setToolTip(TRAY_TOOLTIP_PREFIX);
netspeedLabel->setText("0.00 B/s" NEWLINE "0.00 B/s");
dataamountLabel->setText("0.00 B" NEWLINE "0.00 B");
connetionStatusLabel->setText(tr("Not Connected"));
if (GlobalConfig.inboundConfig.systemProxySettings.setSystemProxy)
{
ClearSystemProxy();
MWClearSystemProxy();
}
}
void MainWindow::OnConnected(const ConnectionGroupPair &id)
{
Q_UNUSED(id)
hTray.setIcon(Q_TRAYICON("tray-connected.png"));
qvAppTrayIcon->setIcon(Q_TRAYICON("tray-connected.png"));
tray_action_Start->setEnabled(false);
tray_action_Stop->setEnabled(true);
tray_action_Restart->setEnabled(true);
@ -687,9 +686,9 @@ void MainWindow::OnConnected(const ConnectionGroupPair &id)
auto name = GetDisplayName(id.connectionId);
if (!GlobalConfig.uiConfig.quietMode)
{
this->hTray.showMessage("Qv2ray", tr("Connected: ") + name, this->windowIcon());
qvApp->showMessage(tr("Connected: ") + name, this->windowIcon());
}
hTray.setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE + tr("Connected: ") + name);
qvAppTrayIcon->setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE + tr("Connected: ") + name);
connetionStatusLabel->setText(tr("Connected: ") + name);
//
GlobalConfig.uiConfig.recentConnections.removeAll(id);
@ -783,8 +782,8 @@ void MainWindow::OnStatsAvailable(const ConnectionGroupPair &id, const quint64 u
netspeedLabel->setText(totalSpeedUp + NEWLINE + totalSpeedDown);
dataamountLabel->setText(totalDataUp + NEWLINE + totalDataDown);
//
hTray.setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE + tr("Connected: ") + GetDisplayName(id.connectionId) + //
NEWLINE "Up: " + totalSpeedUp + " Down: " + totalSpeedDown);
qvAppTrayIcon->setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE + tr("Connected: ") + GetDisplayName(id.connectionId) + //
NEWLINE "Up: " + totalSpeedUp + " Down: " + totalSpeedDown);
//
// Set data accordingly
if (connectionNodes.contains(id))
@ -908,7 +907,7 @@ void MainWindow::on_action_RCM_DuplicateThese_triggered()
{
QList<ConnectionGroupPair> connlist;
for (auto item : connectionListWidget->selectedItems())
for (const auto &item : connectionListWidget->selectedItems())
{
auto widget = GetItemWidget(item);
if (widget->IsConnection())
@ -995,7 +994,7 @@ void MainWindow::on_action_RCM_SetAutoConnection_triggered()
GlobalConfig.autoStartBehavior = AUTO_CONNECTION_FIXED;
if (!GlobalConfig.uiConfig.quietMode)
{
hTray.showMessage(tr("Set auto connection"), tr("Set %1 as auto connect.").arg(GetDisplayName(identifier.connectionId)));
qvApp->showMessage(tr("%1 has been set as auto connect.").arg(GetDisplayName(identifier.connectionId)));
}
SaveGlobalSettings();
}

View File

@ -7,9 +7,6 @@
#include "ui_w_MainWindow.h"
#include <QMainWindow>
#include <QMenu>
#include <QScrollBar>
#include <QSystemTrayIcon>
// ==========================================================================================
#include "ui/widgets/ConnectionInfoWidget.hpp"
@ -111,7 +108,6 @@ class MainWindow
QHash<ConnectionGroupPair, std::shared_ptr<QTreeWidgetItem>> connectionNodes;
// Charts
SpeedWidget *speedChartWidget;
QSystemTrayIcon hTray;
SyntaxHighlighter *vCoreLogHighlighter;
ConnectionInfoWidget *infoWidget;
//

View File

@ -1,5 +1,6 @@
#include "common/QvHelpers.hpp"
#include "components/proxy/QvProxyConfigurator.hpp"
#include "src/Qv2rayApplication.hpp"
#include "w_MainWindow.hpp"
void MainWindow::MWSetSystemProxy()
@ -16,10 +17,10 @@ void MainWindow::MWSetSystemProxy()
{
proxyAddress = "localhost";
SetSystemProxy(proxyAddress, httpPort, socksPort);
hTray.setIcon(Q_TRAYICON("tray-systemproxy.png"));
qvAppTrayIcon->setIcon(Q_TRAYICON("tray-systemproxy.png"));
if (!GlobalConfig.uiConfig.quietMode)
{
hTray.showMessage("Qv2ray", tr("System proxy configured."));
qvApp->showMessage(tr("System proxy configured."));
}
}
else
@ -32,10 +33,10 @@ void MainWindow::MWSetSystemProxy()
void MainWindow::MWClearSystemProxy()
{
ClearSystemProxy();
hTray.setIcon(KernelInstance->CurrentConnection().isEmpty() ? Q_TRAYICON("tray.png") : Q_TRAYICON("tray-connected.png"));
qvAppTrayIcon->setIcon(KernelInstance->CurrentConnection().isEmpty() ? Q_TRAYICON("tray.png") : Q_TRAYICON("tray-connected.png"));
if (!GlobalConfig.uiConfig.quietMode)
{
hTray.showMessage("Qv2ray", tr("System proxy removed."));
qvApp->showMessage(tr("System proxy removed."));
}
}
@ -52,7 +53,8 @@ bool MainWindow::StartAutoConnectionEntry()
void MainWindow::CheckSubscriptionsUpdate()
{
QStringList updateList;
QList<QPair<QString, GroupId>> updateList;
QStringList updateNamesList;
for (const auto &entry : ConnectionManager->Subscriptions())
{
@ -64,27 +66,38 @@ void MainWindow::CheckSubscriptionsUpdate()
//
const auto lastRenewDate = QDateTime::fromTime_t(info.lastUpdatedDate);
const auto renewTime = lastRenewDate.addSecs(info.subscriptionOption.updateInterval * 86400);
LOG(MODULE_SUBSCRIPTION, //
"Subscription \"" + info.displayName + "\": " + //
NEWLINE + " --> Last renewal time: " + lastRenewDate.toString() + //
NEWLINE + " --> Renew interval: " + QSTRN(info.subscriptionOption.updateInterval) + //
NEWLINE + " --> Ideal renew time: " + renewTime.toString()) //
if (renewTime <= QDateTime::currentDateTime())
{
LOG(MODULE_SUBSCRIPTION, "Subscription: " + info.displayName + " needs to be updated.")
updateList.append(info.displayName);
updateList << QPair{ info.displayName, entry };
updateNamesList << info.displayName;
LOG(MODULE_SUBSCRIPTION, QString("Subscription update \"%1\": L=%2 R=%3 I=%4")
.arg(info.displayName)
.arg(lastRenewDate.toString())
.arg(QSTRN(info.subscriptionOption.updateInterval))
.arg(renewTime.toString()))
}
}
if (!updateList.isEmpty())
{
QvMessageBoxWarn(this, tr("Update Subscriptions"),
tr("There are subscriptions to be updated, please go to Group Manager to update them.") + //
NEWLINE + NEWLINE + //
tr("These subscriptions are out-of-date: ") + //
NEWLINE + //
updateList.join(NEWLINE));
on_subsButton_clicked();
auto result = QvMessageBoxAsk(this, tr("Update Subscriptions"), //
tr("Do you want to update these subscriptions?") + NEWLINE + //
updateNamesList.join(NEWLINE), //
QMessageBox::Ignore);
for (const auto &[name, id] : updateList)
{
if (result == QMessageBox::Yes)
{
LOG(MODULE_UI, "Updating subscription: " + name)
ConnectionManager->UpdateSubscriptionAsync(id);
}
else if (result == QMessageBox::Ignore)
{
LOG(MODULE_UI, "Ignored subscription update: " + name)
ConnectionManager->IgnoreSubscriptionUpdate(id);
}
}
}
}