mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 02:40:20 +08:00
add: added connection edit feature
This commit is contained in:
parent
f339b814e1
commit
b03849d9df
@ -15,8 +15,10 @@ INCLUDEPATH += /usr/local/include/
|
|||||||
message(" --> Linking against protobuf library.")
|
message(" --> Linking against protobuf library.")
|
||||||
LIBS += -L/usr/local/lib -lprotobuf
|
LIBS += -L/usr/local/lib -lprotobuf
|
||||||
|
|
||||||
message(" --> Generating geosite headers for Unix")
|
!no_generate_headers {
|
||||||
system("$$PWD/../tools/unix-generate-geosite.sh $$PWD")
|
message(" --> Generating geosite headers for Unix")
|
||||||
|
system("$$PWD/../tools/unix-generate-geosite.sh $$PWD")
|
||||||
|
}
|
||||||
|
|
||||||
use_grpc {
|
use_grpc {
|
||||||
no_generate_headers {
|
no_generate_headers {
|
||||||
|
@ -1 +1 @@
|
|||||||
3963
|
3986
|
||||||
|
@ -46,6 +46,7 @@ namespace Qv2ray::common
|
|||||||
}
|
}
|
||||||
|
|
||||||
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||||
|
request.setAttribute(QNetworkRequest::HTTP2AllowedAttribute, true);
|
||||||
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Mozilla/5.0 (rv:71.0) Gecko/20100101 Firefox/71.0");
|
request.setHeader(QNetworkRequest::KnownHeaders::UserAgentHeader, "Mozilla/5.0 (rv:71.0) Gecko/20100101 Firefox/71.0");
|
||||||
reply = accessManager.get(request);
|
reply = accessManager.get(request);
|
||||||
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
|
connect(reply, &QNetworkReply::finished, this, &QvHttpRequestHelper::onRequestFinished_p);
|
||||||
@ -105,6 +106,10 @@ namespace Qv2ray::common
|
|||||||
|
|
||||||
void QvHttpRequestHelper::onRequestFinished_p()
|
void QvHttpRequestHelper::onRequestFinished_p()
|
||||||
{
|
{
|
||||||
|
if (reply->attribute(QNetworkRequest::HTTP2WasUsedAttribute).toBool()) {
|
||||||
|
DEBUG(MODULE_NETWORK, "HTTP/2 was used.")
|
||||||
|
}
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
QString error = QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error());
|
QString error = QMetaEnum::fromType<QNetworkReply::NetworkError>().key(reply->error());
|
||||||
LOG(MODULE_NETWORK, "Network request error string: " + error)
|
LOG(MODULE_NETWORK, "Network request error string: " + error)
|
||||||
|
@ -31,15 +31,19 @@ namespace Qv2ray::common
|
|||||||
source->close();
|
source->close();
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
bool StringToFile(const QString &text, const QString &targetpath)
|
||||||
bool StringToFile(const QString *text, QFile *targetFile)
|
|
||||||
{
|
{
|
||||||
bool override = targetFile->exists();
|
auto file = QFile(targetpath);
|
||||||
targetFile->open(QFile::WriteOnly);
|
return StringToFile(text, file);
|
||||||
QTextStream stream(targetFile);
|
}
|
||||||
stream << *text << endl;
|
bool StringToFile(const QString &text, QFile &targetFile)
|
||||||
|
{
|
||||||
|
bool override = targetFile.exists();
|
||||||
|
targetFile.open(QFile::WriteOnly);
|
||||||
|
QTextStream stream(&targetFile);
|
||||||
|
stream << text << endl;
|
||||||
stream.flush();
|
stream.flush();
|
||||||
targetFile->close();
|
targetFile.close();
|
||||||
return override;
|
return override;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,8 @@ namespace Qv2ray::common
|
|||||||
//
|
//
|
||||||
QString StringFromFile(const QString &filePath);
|
QString StringFromFile(const QString &filePath);
|
||||||
QString StringFromFile(QFile *source);
|
QString StringFromFile(QFile *source);
|
||||||
bool StringToFile(const QString *text, QFile *target);
|
bool StringToFile(const QString &text, QFile &target);
|
||||||
|
bool StringToFile(const QString &text, const QString &targetpath);
|
||||||
//
|
//
|
||||||
QJsonObject JsonFromString(QString string);
|
QJsonObject JsonFromString(QString string);
|
||||||
QString JsonToString(QJsonObject json, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
|
QString JsonToString(QJsonObject json, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
#include "CoreUtils.hpp"
|
#include "CoreUtils.hpp"
|
||||||
|
#include "common/QvHelpers.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::core
|
namespace Qv2ray::core
|
||||||
{
|
{
|
||||||
bool IsComplexConfig(CONFIGROOT root)
|
bool IsComplexConfig(const CONFIGROOT &root)
|
||||||
{
|
{
|
||||||
bool cRouting = root.contains("routing");
|
bool cRouting = root.contains("routing");
|
||||||
bool cRule = cRouting && root["routing"].toObject().contains("rules");
|
bool cRule = cRouting && root["routing"].toObject().contains("rules");
|
||||||
@ -15,5 +16,34 @@ namespace Qv2ray::core
|
|||||||
bool cOutboundCount = cOutbounds && root["outbounds"].toArray().count() > 1;
|
bool cOutboundCount = cOutbounds && root["outbounds"].toArray().count() > 1;
|
||||||
return cRules || cInboundCount || cOutboundCount;
|
return cRules || cInboundCount || cOutboundCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool GetOutboundData(const OUTBOUND &out, QString *host, int *port, QString *protocol)
|
||||||
|
{
|
||||||
|
// Set initial values.
|
||||||
|
*host = QObject::tr("N/A");
|
||||||
|
*port = 0;
|
||||||
|
*protocol = out["protocol"].toString(QObject::tr("N/A")).toLower();
|
||||||
|
|
||||||
|
if (*protocol == "vmess") {
|
||||||
|
auto Server = StructFromJsonString<VMessServerObject>(JsonToString(out["settings"].toObject()["vnext"].toArray().first().toObject()));
|
||||||
|
*host = Server.address;
|
||||||
|
*port = Server.port;
|
||||||
|
return true;
|
||||||
|
} else if (*protocol == "shadowsocks") {
|
||||||
|
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
|
||||||
|
auto Server = StructFromJsonString<ShadowSocksServerObject>(x);
|
||||||
|
*host = Server.address;
|
||||||
|
*port = Server.port;
|
||||||
|
return true;
|
||||||
|
} else if (*protocol == "socks") {
|
||||||
|
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
|
||||||
|
auto Server = StructFromJsonString<SocksServerObject>(x);
|
||||||
|
*host = Server.address;
|
||||||
|
*port = Server.port;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,8 @@ namespace Qv2ray::core
|
|||||||
return in.QV2RAY_RULE_TAG;
|
return in.QV2RAY_RULE_TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsComplexConfig(CONFIGROOT root);
|
bool GetOutboundData(const OUTBOUND &out, QString *host, int *port, QString *protocol);
|
||||||
|
bool IsComplexConfig(const CONFIGROOT &root);
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace Qv2ray::core;
|
using namespace Qv2ray::core;
|
||||||
|
@ -6,9 +6,8 @@ namespace Qv2ray::core::config
|
|||||||
void SaveGlobalConfig(const Qv2rayConfig &conf)
|
void SaveGlobalConfig(const Qv2rayConfig &conf)
|
||||||
{
|
{
|
||||||
GlobalConfig = conf;
|
GlobalConfig = conf;
|
||||||
QFile config(QV2RAY_CONFIG_FILE);
|
|
||||||
QString str = StructToJsonString(conf);
|
QString str = StructToJsonString(conf);
|
||||||
StringToFile(&str, &config);
|
StringToFile(str, QV2RAY_CONFIG_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetConfigDirPath(const QString &path)
|
void SetConfigDirPath(const QString &path)
|
||||||
|
@ -5,12 +5,6 @@ namespace Qv2ray::core::connection
|
|||||||
{
|
{
|
||||||
namespace ConnectionIO
|
namespace ConnectionIO
|
||||||
{
|
{
|
||||||
|
|
||||||
//CONFIGROOT GetConnectionRoot(const SubscriptionId &subscription, const ConnectionId &id)
|
|
||||||
//{
|
|
||||||
// return ReadConnectionInternal(QV2RAY_SUBSCRIPTION_DIR + subscription.toString() + "/" + id.toString() + QV2RAY_CONFIG_FILE_EXTENSION);
|
|
||||||
//}
|
|
||||||
|
|
||||||
////
|
////
|
||||||
//// Save Connection to a place, with checking if there's existing file.
|
//// Save Connection to a place, with checking if there's existing file.
|
||||||
//// If so, append "_N" to the name.
|
//// If so, append "_N" to the name.
|
||||||
|
@ -284,7 +284,6 @@ namespace Qv2ray::core::handlers
|
|||||||
path.prepend(groups[group].isSubscription ? QV2RAY_SUBSCRIPTION_DIR : QV2RAY_CONNECTIONS_DIR);
|
path.prepend(groups[group].isSubscription ? QV2RAY_SUBSCRIPTION_DIR : QV2RAY_CONNECTIONS_DIR);
|
||||||
return CONFIGROOT(JsonFromString(StringFromFile(path)));
|
return CONFIGROOT(JsonFromString(StringFromFile(path)));
|
||||||
}
|
}
|
||||||
//
|
|
||||||
|
|
||||||
const tuple<QString, int> QvConnectionHandler::GetConnectionInfo(const ConnectionId &id) const
|
const tuple<QString, int> QvConnectionHandler::GetConnectionInfo(const ConnectionId &id) const
|
||||||
{
|
{
|
||||||
@ -296,7 +295,7 @@ namespace Qv2ray::core::handlers
|
|||||||
for (auto item : root["outbounds"].toArray()) {
|
for (auto item : root["outbounds"].toArray()) {
|
||||||
OUTBOUND outBoundRoot = OUTBOUND(item.toObject());
|
OUTBOUND outBoundRoot = OUTBOUND(item.toObject());
|
||||||
QString outboundType = "";
|
QString outboundType = "";
|
||||||
validOutboundFound = CHGetOutboundData_p(outBoundRoot, &host, &port);
|
validOutboundFound = GetOutboundData(outBoundRoot, &host, &port, &outboundType);
|
||||||
|
|
||||||
if (validOutboundFound) {
|
if (validOutboundFound) {
|
||||||
return make_tuple(host, port);
|
return make_tuple(host, port);
|
||||||
@ -308,34 +307,7 @@ namespace Qv2ray::core::handlers
|
|||||||
return make_tuple(QObject::tr("N/A"), 0);
|
return make_tuple(QObject::tr("N/A"), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QvConnectionHandler::CHGetOutboundData_p(const OUTBOUND &out, QString *host, int *port) const
|
|
||||||
{
|
|
||||||
// Set initial values.
|
|
||||||
*host = QObject::tr("N/A");
|
|
||||||
*port = 0;
|
|
||||||
auto protocol = out["protocol"].toString(QObject::tr("N/A")).toLower();
|
|
||||||
|
|
||||||
if (protocol == "vmess") {
|
|
||||||
auto Server = StructFromJsonString<VMessServerObject>(JsonToString(out["settings"].toObject()["vnext"].toArray().first().toObject()));
|
|
||||||
*host = Server.address;
|
|
||||||
*port = Server.port;
|
|
||||||
return true;
|
|
||||||
} else if (protocol == "shadowsocks") {
|
|
||||||
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
|
|
||||||
auto Server = StructFromJsonString<ShadowSocksServerObject>(x);
|
|
||||||
*host = Server.address;
|
|
||||||
*port = Server.port;
|
|
||||||
return true;
|
|
||||||
} else if (protocol == "socks") {
|
|
||||||
auto x = JsonToString(out["settings"].toObject()["servers"].toArray().first().toObject());
|
|
||||||
auto Server = StructFromJsonString<SocksServerObject>(x);
|
|
||||||
*host = Server.address;
|
|
||||||
*port = Server.port;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QvConnectionHandler::OnLatencyDataArrived(const QvTCPingResultObject &result)
|
void QvConnectionHandler::OnLatencyDataArrived(const QvTCPingResultObject &result)
|
||||||
{
|
{
|
||||||
@ -346,4 +318,13 @@ namespace Qv2ray::core::handlers
|
|||||||
LOG(MODULE_CORE_HANDLER, "Received a latecy result with non-exist connection id.")
|
LOG(MODULE_CORE_HANDLER, "Received a latecy result with non-exist connection id.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool QvConnectionHandler::UpdateConnection(const ConnectionId &id, const CONFIGROOT &root)
|
||||||
|
{
|
||||||
|
auto groupId = connections[id].groupId;
|
||||||
|
auto path = (groups[groupId].isSubscription ? QV2RAY_SUBSCRIPTION_DIR : QV2RAY_CONNECTIONS_DIR)
|
||||||
|
+ groupId.toString() + "/" + id.toString() + QV2RAY_CONFIG_FILE_EXTENSION;
|
||||||
|
auto content = JsonToString(root);
|
||||||
|
return StringToFile(content, path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include "core/tcping/QvTCPing.hpp"
|
#include "core/tcping/QvTCPing.hpp"
|
||||||
#include "core/CoreSafeTypes.hpp"
|
#include "core/CoreSafeTypes.hpp"
|
||||||
#include "core/connection/ConnectionIO.hpp"
|
#include "core/connection/ConnectionIO.hpp"
|
||||||
|
#include "core/CoreUtils.hpp"
|
||||||
|
|
||||||
namespace Qv2ray::core::handlers
|
namespace Qv2ray::core::handlers
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ namespace Qv2ray::core::handlers
|
|||||||
double GetConnectionLatency(const ConnectionId &id) const;
|
double GetConnectionLatency(const ConnectionId &id) const;
|
||||||
const ConnectionId &CreateConnection(const QString &displayName, const GroupId &groupId, const CONFIGROOT &root);
|
const ConnectionId &CreateConnection(const QString &displayName, const GroupId &groupId, const CONFIGROOT &root);
|
||||||
const optional<QString> DeleteConnection(const ConnectionId &id);
|
const optional<QString> DeleteConnection(const ConnectionId &id);
|
||||||
const optional<QString> UpdateConnection(const ConnectionId &id, const CONFIGROOT &root);
|
bool UpdateConnection(const ConnectionId &id, const CONFIGROOT &root);
|
||||||
const optional<QString> RenameConnection(const ConnectionId &id, const QString &newName);
|
const optional<QString> RenameConnection(const ConnectionId &id, const QString &newName);
|
||||||
const ConnectionId DuplicateConnection(const ConnectionId &id);
|
const ConnectionId DuplicateConnection(const ConnectionId &id);
|
||||||
const optional<QString> MoveConnectionGroup(const ConnectionId &id, const GroupId &newGroupId);
|
const optional<QString> MoveConnectionGroup(const ConnectionId &id, const GroupId &newGroupId);
|
||||||
@ -101,7 +102,6 @@ namespace Qv2ray::core::handlers
|
|||||||
private:
|
private:
|
||||||
void CHSaveConnectionData_p();
|
void CHSaveConnectionData_p();
|
||||||
//
|
//
|
||||||
bool CHGetOutboundData_p(const OUTBOUND &out, QString *host, int *port) const;
|
|
||||||
optional<QString> CHStartConnection_p(const ConnectionId &id, const CONFIGROOT &root);
|
optional<QString> CHStartConnection_p(const ConnectionId &id, const CONFIGROOT &root);
|
||||||
void CHStopConnection_p();
|
void CHStopConnection_p();
|
||||||
bool CHSaveConnectionConfig_p(CONFIGROOT obj, const ConnectionId &id, bool override);
|
bool CHSaveConnectionConfig_p(CONFIGROOT obj, const ConnectionId &id, bool override);
|
||||||
@ -112,7 +112,7 @@ namespace Qv2ray::core::handlers
|
|||||||
int pingConnectionTimerId;
|
int pingConnectionTimerId;
|
||||||
QHash<GroupId, GroupMetaObject> groups;
|
QHash<GroupId, GroupMetaObject> groups;
|
||||||
QHash<ConnectionId, ConnectionMetaObject> connections;
|
QHash<ConnectionId, ConnectionMetaObject> connections;
|
||||||
QHash<ConnectionId, CONFIGROOT> connectionRootCache;
|
//QHash<ConnectionId, CONFIGROOT> connectionRootCache;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QvTCPingHelper *tcpingHelper;
|
QvTCPingHelper *tcpingHelper;
|
||||||
|
@ -147,8 +147,7 @@ namespace Qv2ray::core::kernel
|
|||||||
|
|
||||||
// Write the final configuration to the disk.
|
// Write the final configuration to the disk.
|
||||||
QString json = JsonToString(root);
|
QString json = JsonToString(root);
|
||||||
QFile configFile(QV2RAY_GENERATED_FILE_PATH);
|
StringToFile(json, QV2RAY_GENERATED_FILE_PATH);
|
||||||
StringToFile(&json, &configFile);
|
|
||||||
//
|
//
|
||||||
auto filePath = QV2RAY_GENERATED_FILE_PATH;
|
auto filePath = QV2RAY_GENERATED_FILE_PATH;
|
||||||
|
|
||||||
|
@ -157,8 +157,7 @@ void RouteEditor::onNodeClicked(Node &n)
|
|||||||
alias = GetFirstNodeData(n, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
alias = GetFirstNodeData(n, QvOutboundNodeModel, OutboundNodeData)->GetOutbound();
|
||||||
QJsonObject _root = outbounds[alias].raw();
|
QJsonObject _root = outbounds[alias].raw();
|
||||||
throw new runtime_error("Not implemented");
|
throw new runtime_error("Not implemented");
|
||||||
//auto result = GetOutboundData(OUTBOUND(_root), &host, &port, &protocol);
|
GetOutboundData(OUTBOUND(_root), &host, &port, &protocol);
|
||||||
//Q_UNUSED(result)
|
|
||||||
} else {
|
} else {
|
||||||
alias = GetFirstNodeData(n, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
alias = GetFirstNodeData(n, QvInboundNodeModel, InboundNodeData)->GetInbound();
|
||||||
QJsonObject _root = inbounds[alias].raw();
|
QJsonObject _root = inbounds[alias].raw();
|
||||||
|
@ -232,7 +232,7 @@ void ImportConfigWindow::on_editFileBtn_clicked()
|
|||||||
|
|
||||||
if (editor.result() == QDialog::Accepted) {
|
if (editor.result() == QDialog::Accepted) {
|
||||||
auto str = JsonToString(json);
|
auto str = JsonToString(json);
|
||||||
bool result = StringToFile(&str, &file);
|
bool result = StringToFile(str, file);
|
||||||
|
|
||||||
if (!result) {
|
if (!result) {
|
||||||
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Failed to save file, please check if you have proper permissions"));
|
QvMessageBoxWarn(this, tr("Edit file as JSON"), tr("Failed to save file, please check if you have proper permissions"));
|
||||||
|
@ -74,12 +74,6 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
|
|||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
MainWindow::mwInstance = this;
|
MainWindow::mwInstance = this;
|
||||||
connect(ConnectionManager, &QvConnectionHandler::OnCrashed, [&] {
|
|
||||||
this->show();
|
|
||||||
QvMessageBoxWarn(this, tr("V2ray vcore terminated."),
|
|
||||||
tr("V2ray vcore terminated unexpectedly.") + NEWLINE + NEWLINE +
|
|
||||||
tr("To solve the problem, read the V2ray log in the log text browser."));
|
|
||||||
});
|
|
||||||
QvMessageBusConnect(MainWindow);
|
QvMessageBusConnect(MainWindow);
|
||||||
//
|
//
|
||||||
infoWidget = new ConnectionInfoWidget(this);
|
infoWidget = new ConnectionInfoWidget(this);
|
||||||
@ -98,11 +92,20 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
|
|||||||
updownImageBox_2->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
|
updownImageBox_2->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
|
||||||
//
|
//
|
||||||
//
|
//
|
||||||
|
connect(ConnectionManager, &QvConnectionHandler::OnCrashed, [&] {
|
||||||
|
this->show();
|
||||||
|
QvMessageBoxWarn(this, tr("V2ray vcore terminated."),
|
||||||
|
tr("V2ray vcore terminated unexpectedly.") + NEWLINE + NEWLINE +
|
||||||
|
tr("To solve the problem, read the V2ray log in the log text browser."));
|
||||||
|
});
|
||||||
connect(ConnectionManager, &QvConnectionHandler::OnConnected, this, &MainWindow::OnConnected);
|
connect(ConnectionManager, &QvConnectionHandler::OnConnected, this, &MainWindow::OnConnected);
|
||||||
connect(ConnectionManager, &QvConnectionHandler::OnDisConnected, this, &MainWindow::OnDisConnected);
|
connect(ConnectionManager, &QvConnectionHandler::OnDisConnected, this, &MainWindow::OnDisConnected);
|
||||||
connect(ConnectionManager, &QvConnectionHandler::OnStatsAvailable, this, &MainWindow::onConnectionStatsArrived);
|
connect(ConnectionManager, &QvConnectionHandler::OnStatsAvailable, this, &MainWindow::onConnectionStatsArrived);
|
||||||
connect(ConnectionManager, &QvConnectionHandler::OnVCoreLogAvailable, this, &MainWindow::onVCoreLogArrived);
|
connect(ConnectionManager, &QvConnectionHandler::OnVCoreLogAvailable, this, &MainWindow::onVCoreLogArrived);
|
||||||
//
|
//
|
||||||
|
connect(infoWidget, &ConnectionInfoWidget::OnEditRequested, this, &MainWindow::OnEditRequested);
|
||||||
|
connect(infoWidget, &ConnectionInfoWidget::OnJsonEditRequested, this, &MainWindow::OnJsonEditRequested);
|
||||||
|
//
|
||||||
// Setup System tray icons and menus
|
// Setup System tray icons and menus
|
||||||
hTray.setToolTip(TRAY_TOOLTIP_PREFIX);
|
hTray.setToolTip(TRAY_TOOLTIP_PREFIX);
|
||||||
// Basic actions
|
// Basic actions
|
||||||
@ -201,10 +204,7 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
|
|||||||
|
|
||||||
if (!GlobalConfig.autoStartId.isEmpty()) {
|
if (!GlobalConfig.autoStartId.isEmpty()) {
|
||||||
auto id = ConnectionId(GlobalConfig.autoStartId);
|
auto id = ConnectionId(GlobalConfig.autoStartId);
|
||||||
ConnectionManager->StartConnection(id);
|
needShowWindow = ConnectionManager->StartConnection(id).has_value();
|
||||||
needShowWindow = !ConnectionManager->IsConnected(id);
|
|
||||||
} else {
|
|
||||||
needShowWindow = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needShowWindow) {
|
if (needShowWindow) {
|
||||||
@ -212,6 +212,9 @@ MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)//, vinstance(), hTr
|
|||||||
}
|
}
|
||||||
|
|
||||||
//// If we are not connected to anything, show the MainWindow.
|
//// If we are not connected to anything, show the MainWindow.
|
||||||
|
if (needShowWindow) {
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef DISABLE_AUTO_UPDATE
|
#ifndef DISABLE_AUTO_UPDATE
|
||||||
requestHelper = new QvHttpRequestHelper();
|
requestHelper = new QvHttpRequestHelper();
|
||||||
connect(requestHelper, &QvHttpRequestHelper::httpRequestFinished, this, &MainWindow::VersionUpdate);
|
connect(requestHelper, &QvHttpRequestHelper::httpRequestFinished, this, &MainWindow::VersionUpdate);
|
||||||
@ -298,24 +301,6 @@ MainWindow::~MainWindow()
|
|||||||
hTray.hide();
|
hTray.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
//void MainWindow::on_stopButton_clicked()
|
|
||||||
//{
|
|
||||||
// //hTray.setToolTip(TRAY_TOOLTIP_PREFIX);
|
|
||||||
// //statusLabel->setText(tr("Disconnected"));
|
|
||||||
// action_Tray_Start->setEnabled(true);
|
|
||||||
// action_Tray_Stop->setEnabled(false);
|
|
||||||
// action_Tray_Reconnect->setEnabled(false);
|
|
||||||
// // Set to false as the system proxy has been cleared in the StopConnection function.
|
|
||||||
// tray_SystemProxyMenu->setEnabled(false);
|
|
||||||
// //startButton->setEnabled(true);
|
|
||||||
// //stopButton->setEnabled(false);
|
|
||||||
// ////
|
|
||||||
// //netspeedLabel->setText("0.00 B/s\r\n0.00 B/s");
|
|
||||||
// //dataamountLabel->setText("0.00 B\r\n0.00 B");
|
|
||||||
// //LOG(UI, "Stopped successfully.")
|
|
||||||
// //this->hTray.showMessage("Qv2ray", tr("Disconnected from: ") + CurrentConnectionIdentifier.IdentifierString());
|
|
||||||
//}
|
|
||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent *event)
|
void MainWindow::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
this->hide();
|
this->hide();
|
||||||
@ -579,50 +564,6 @@ void MainWindow::on_importConfigButton_clicked()
|
|||||||
}
|
}
|
||||||
void MainWindow::on_editConfigButton_clicked()
|
void MainWindow::on_editConfigButton_clicked()
|
||||||
{
|
{
|
||||||
//// Check if we have a connection selected...
|
|
||||||
//if (!IsSelectionConnectable) {
|
|
||||||
// QvMessageBoxWarn(this, tr("No Config Selected"), tr("Please Select a Config"));
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//auto firstSelected = connectionListWidget->selectedItems().first();
|
|
||||||
//auto _identifier = ItemConnectionIdentifier(firstSelected);
|
|
||||||
//SUBSCRIPTION_CONFIG_MODIFY_ASK(firstSelected)
|
|
||||||
////
|
|
||||||
//auto outBoundRoot = connections[_identifier].config;
|
|
||||||
//CONFIGROOT root;
|
|
||||||
//bool isChanged = false;
|
|
||||||
//
|
|
||||||
//if (IsComplexConfig(outBoundRoot)) {
|
|
||||||
// LOG(UI, "INFO: Opening route editor.")
|
|
||||||
// RouteEditor routeWindow(outBoundRoot, this);
|
|
||||||
// root = routeWindow.OpenEditor();
|
|
||||||
// isChanged = routeWindow.result() == QDialog::Accepted;
|
|
||||||
//} else {
|
|
||||||
// LOG(UI, "INFO: Opening single connection edit window.")
|
|
||||||
// OutboundEditor w(OUTBOUND(outBoundRoot["outbounds"].toArray().first().toObject()), this);
|
|
||||||
// auto outboundEntry = w.OpenEditor();
|
|
||||||
// isChanged = w.result() == QDialog::Accepted;
|
|
||||||
// QJsonArray outboundsList;
|
|
||||||
// outboundsList.push_back(outboundEntry);
|
|
||||||
// root.insert("outbounds", outboundsList);
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//QString alias = _identifier.connectionName;
|
|
||||||
//
|
|
||||||
//if (isChanged) {
|
|
||||||
// if (CheckConfigType(firstSelected, SUBSCRIPTION)) {
|
|
||||||
// auto name = connections[_identifier].connectionName;
|
|
||||||
// // Assume name will not change.
|
|
||||||
// SaveSubscriptionConfig(root, connections[_identifier].subscriptionName, &name);
|
|
||||||
// } else {
|
|
||||||
// connections[_identifier].config = root;
|
|
||||||
// // true indicates the alias will NOT change
|
|
||||||
// SaveConnectionConfig(root, &alias, true);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// OnConfigListChanged(alias == CurrentConnectionIdentifier.connectionName);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_action_RCM_ConvToComplex_triggered()
|
void MainWindow::on_action_RCM_ConvToComplex_triggered()
|
||||||
@ -658,26 +599,6 @@ void MainWindow::on_action_RCM_ConvToComplex_triggered()
|
|||||||
|
|
||||||
void MainWindow::on_action_RCM_EditJson_triggered()
|
void MainWindow::on_action_RCM_EditJson_triggered()
|
||||||
{
|
{
|
||||||
//// Check if we have a connection selected...
|
|
||||||
//if (!IsSelectionConnectable) {
|
|
||||||
// QvMessageBoxWarn(this, tr("No Config Selected"), tr("Please Select a Config"));
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//auto selectedFirst = connectionListWidget->currentItem();
|
|
||||||
//auto _identifier = ItemConnectionIdentifier(selectedFirst);
|
|
||||||
//SUBSCRIPTION_CONFIG_MODIFY_DENY(selectedFirst)
|
|
||||||
//JsonEditor w(connections[_identifier].config, this);
|
|
||||||
//auto root = CONFIGROOT(w.OpenEditor());
|
|
||||||
//bool isChanged = w.result() == QDialog::Accepted;
|
|
||||||
//QString alias = _identifier.connectionName;
|
|
||||||
//
|
|
||||||
//if (isChanged) {
|
|
||||||
// connections[_identifier].config = root;
|
|
||||||
// // Alias here will not change.
|
|
||||||
// SaveConnectionConfig(root, &alias, true);
|
|
||||||
// ShowAndSetConnection(CurrentConnectionIdentifier, false, false);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_action_RCM_ShareQR_triggered()
|
void MainWindow::on_action_RCM_ShareQR_triggered()
|
||||||
@ -871,3 +792,50 @@ void MainWindow::onVCoreLogArrived(const ConnectionId &id, const QString &log)
|
|||||||
if (val >= max * 0.8 || val >= max - 20)
|
if (val >= max * 0.8 || val >= max - 20)
|
||||||
bar->setValue(max);
|
bar->setValue(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::OnEditRequested(const ConnectionId &id)
|
||||||
|
{
|
||||||
|
auto outBoundRoot = ConnectionManager->GetConnectionRoot(id);
|
||||||
|
CONFIGROOT root;
|
||||||
|
bool isChanged = false;
|
||||||
|
|
||||||
|
if (IsComplexConfig(outBoundRoot)) {
|
||||||
|
LOG(MODULE_UI, "INFO: Opening route editor.")
|
||||||
|
RouteEditor routeWindow(outBoundRoot, this);
|
||||||
|
root = routeWindow.OpenEditor();
|
||||||
|
isChanged = routeWindow.result() == QDialog::Accepted;
|
||||||
|
} else {
|
||||||
|
LOG(MODULE_UI, "INFO: Opening single connection edit window.")
|
||||||
|
auto out = OUTBOUND(outBoundRoot["outbounds"].toArray().first().toObject());
|
||||||
|
OutboundEditor w(out, this);
|
||||||
|
auto outboundEntry = w.OpenEditor();
|
||||||
|
isChanged = w.result() == QDialog::Accepted;
|
||||||
|
QJsonArray outboundsList;
|
||||||
|
outboundsList.push_back(outboundEntry);
|
||||||
|
root.insert("outbounds", outboundsList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isChanged) {
|
||||||
|
//if (CheckConfigType(firstSelected, SUBSCRIPTION)) {
|
||||||
|
// auto name = connections[_identifier].connectionName;
|
||||||
|
// // Assume name will not change.
|
||||||
|
// SaveSubscriptionConfig(root, connections[_identifier].subscriptionName, &name);
|
||||||
|
//} else {
|
||||||
|
// connections[_identifier].config = root;
|
||||||
|
// // true indicates the alias will NOT change
|
||||||
|
// SaveConnectionConfig(root, &alias, true);
|
||||||
|
//}
|
||||||
|
ConnectionManager->UpdateConnection(id, root);
|
||||||
|
//OnConfigListChanged(alias == CurrentConnectionIdentifier.connectionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MainWindow::OnJsonEditRequested(const ConnectionId &id)
|
||||||
|
{
|
||||||
|
JsonEditor w(ConnectionManager->GetConnectionRoot(id), this);
|
||||||
|
auto root = CONFIGROOT(w.OpenEditor());
|
||||||
|
|
||||||
|
if (w.result() == QDialog::Accepted) {
|
||||||
|
ConnectionManager->UpdateConnection(id, root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -60,6 +60,8 @@ class MainWindow : public QMainWindow, Ui::MainWindow
|
|||||||
//
|
//
|
||||||
void OnConnected(const ConnectionId &id);
|
void OnConnected(const ConnectionId &id);
|
||||||
void OnDisConnected(const ConnectionId &id);
|
void OnDisConnected(const ConnectionId &id);
|
||||||
|
void OnEditRequested(const ConnectionId &id);
|
||||||
|
void OnJsonEditRequested(const ConnectionId &id);
|
||||||
|
|
||||||
void onConnectionWidgetFocusRequested(const ConnectionItemWidget *widget);
|
void onConnectionWidgetFocusRequested(const ConnectionItemWidget *widget);
|
||||||
//void onConnectionConnected(const ConnectionId &id);
|
//void onConnectionConnected(const ConnectionId &id);
|
||||||
|
@ -892,8 +892,7 @@ void PreferencesWindow::on_pacGoBtn_clicked()
|
|||||||
QDir(QV2RAY_RULES_DIR).mkpath(QV2RAY_RULES_DIR);
|
QDir(QV2RAY_RULES_DIR).mkpath(QV2RAY_RULES_DIR);
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile privateGFWListFile(QV2RAY_RULES_GFWLIST_PATH);
|
StringToFile(fileContent, QV2RAY_RULES_GFWLIST_PATH);
|
||||||
StringToFile(&fileContent, &privateGFWListFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreferencesWindow::on_pacPortSB_valueChanged(int arg1)
|
void PreferencesWindow::on_pacPortSB_valueChanged(int arg1)
|
||||||
|
@ -120,7 +120,7 @@ void SubscribeEditor::on_updateButton_clicked()
|
|||||||
subscriptions[currentSubName].address = newAddress;
|
subscriptions[currentSubName].address = newAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveConfig();
|
//SaveConfig();
|
||||||
|
|
||||||
if (QvMessageBoxAsk(this, tr("Update Subscription"), tr("Would you like to reload this subscription from the Url?")) == QMessageBox::Yes) {
|
if (QvMessageBoxAsk(this, tr("Update Subscription"), tr("Would you like to reload this subscription from the Url?")) == QMessageBox::Yes) {
|
||||||
StartUpdateSubscription(currentSubName);
|
StartUpdateSubscription(currentSubName);
|
||||||
@ -129,10 +129,9 @@ void SubscribeEditor::on_updateButton_clicked()
|
|||||||
|
|
||||||
void SubscribeEditor::StartUpdateSubscription(const QString &subscriptionName)
|
void SubscribeEditor::StartUpdateSubscription(const QString &subscriptionName)
|
||||||
{
|
{
|
||||||
//this->setEnabled(false);
|
this->setEnabled(false);
|
||||||
//auto data = helper.syncget(subscriptions[subscriptionName].address, withProxyCB->isChecked());
|
auto data = helper.syncget(subscriptions[subscriptionName].address, withProxyCB->isChecked());
|
||||||
//auto content = DecodeSubscriptionString(data).trimmed();
|
auto content = DecodeSubscriptionString(data).trimmed();
|
||||||
//
|
|
||||||
//if (!content.isEmpty()) {
|
//if (!content.isEmpty()) {
|
||||||
// connectionsList->clear();
|
// connectionsList->clear();
|
||||||
// auto vmessList = SplitLines(content);
|
// auto vmessList = SplitLines(content);
|
||||||
@ -160,7 +159,7 @@ void SubscribeEditor::StartUpdateSubscription(const QString &subscriptionName)
|
|||||||
// QvMessageBoxWarn(this, tr("Updating subscriptions"), tr("Failed to process the result from the upstream, please check your Url."));
|
// QvMessageBoxWarn(this, tr("Updating subscriptions"), tr("Failed to process the result from the upstream, please check your Url."));
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//this->setEnabled(true);
|
this->setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubscribeEditor::on_removeSubsButton_clicked()
|
void SubscribeEditor::on_removeSubsButton_clicked()
|
||||||
@ -213,16 +212,16 @@ void SubscribeEditor::on_subscriptionList_currentRowChanged(int currentRow)
|
|||||||
|
|
||||||
void SubscribeEditor::SaveConfig()
|
void SubscribeEditor::SaveConfig()
|
||||||
{
|
{
|
||||||
QMap<QString, SubscriptionObject_Config> newConf;
|
//QMap<QString, SubscriptionObject_Config> newConf;
|
||||||
|
//
|
||||||
for (auto _ : subscriptions.toStdMap()) {
|
//for (auto _ : subscriptions.toStdMap()) {
|
||||||
if (!_.second.address.isEmpty()) {
|
// if (!_.second.address.isEmpty()) {
|
||||||
newConf[_.first] = _.second;
|
// newConf[_.first] = _.second;
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
GlobalConfig.subscriptions = newConf;
|
//GlobalConfig.subscriptions = newConf;
|
||||||
SaveGlobalConfig(GlobalConfig);
|
//SaveGlobalConfig(GlobalConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SubscribeEditor::on_buttonBox_accepted()
|
void SubscribeEditor::on_buttonBox_accepted()
|
||||||
|
@ -24,19 +24,19 @@ void ConnectionInfoWidget::ShowDetails(const tuple<GroupId, ConnectionId> &_iden
|
|||||||
{
|
{
|
||||||
groupId = get<0>(_identifier);
|
groupId = get<0>(_identifier);
|
||||||
connectionId = get<1>(_identifier);
|
connectionId = get<1>(_identifier);
|
||||||
|
bool isConnection = connectionId != NullConnectionId;
|
||||||
|
editJsonBtn->setEnabled(isConnection);
|
||||||
|
connectBtn->setEnabled(isConnection);
|
||||||
|
duplicateBtn->setEnabled(isConnection);
|
||||||
|
editBtn->setEnabled(isConnection);
|
||||||
|
|
||||||
if (connectionId != NullConnectionId) {
|
if (isConnection) {
|
||||||
//connNameLabel->setText(ConnectionManager->GetDisplayName(connectionId));
|
|
||||||
groupLabel->setText(ConnectionManager->GetDisplayName(groupId, 175));
|
groupLabel->setText(ConnectionManager->GetDisplayName(groupId, 175));
|
||||||
protocolLabel->setText(ConnectionManager->GetConnectionProtocolString(connectionId));
|
protocolLabel->setText(ConnectionManager->GetConnectionProtocolString(connectionId));
|
||||||
auto [host, port] = ConnectionManager->GetConnectionInfo(connectionId);
|
auto [host, port] = ConnectionManager->GetConnectionInfo(connectionId);
|
||||||
addressLabel->setText(host);
|
addressLabel->setText(host);
|
||||||
portLabel->setNum(port);
|
portLabel->setNum(port);
|
||||||
//
|
//
|
||||||
editJsonBtn->setEnabled(true);
|
|
||||||
connectBtn->setEnabled(true);
|
|
||||||
duplicateBtn->setEnabled(true);
|
|
||||||
//
|
|
||||||
auto shareLink = ConvertConfigToString(connectionId);
|
auto shareLink = ConvertConfigToString(connectionId);
|
||||||
shareLinkTxt->setText(shareLink);
|
shareLinkTxt->setText(shareLink);
|
||||||
shareLinkTxt->setCursorPosition(0);
|
shareLinkTxt->setCursorPosition(0);
|
||||||
@ -55,10 +55,6 @@ void ConnectionInfoWidget::ShowDetails(const tuple<GroupId, ConnectionId> &_iden
|
|||||||
addressLabel->setText(tr("N/A"));
|
addressLabel->setText(tr("N/A"));
|
||||||
portLabel->setText(tr("N/A"));
|
portLabel->setText(tr("N/A"));
|
||||||
//
|
//
|
||||||
editJsonBtn->setEnabled(false);
|
|
||||||
connectBtn->setEnabled(false);
|
|
||||||
duplicateBtn->setEnabled(false);
|
|
||||||
//
|
|
||||||
shareLinkTxt->clear();
|
shareLinkTxt->clear();
|
||||||
qrLabel->clear();
|
qrLabel->clear();
|
||||||
}
|
}
|
||||||
@ -76,27 +72,15 @@ void ConnectionInfoWidget::on_connectBtn_clicked()
|
|||||||
ConnectionManager->StartConnection(connectionId);
|
ConnectionManager->StartConnection(connectionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//// Share QR
|
|
||||||
//if (!IsSelectionConnectable) {
|
|
||||||
// return;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//auto _identifier = ItemConnectionIdentifier(connectionListWidget->currentItem());
|
|
||||||
//auto root = connections[_identifier].config;
|
|
||||||
//auto type = get<2>(GetConnectionInfo(root));
|
|
||||||
//
|
|
||||||
//if (!IsComplexConfig(root) && (type == "vmess" || type == "shadowsocks")) {
|
|
||||||
// ConfigExporter v(root, _identifier, this);
|
|
||||||
// v.OpenExport();
|
|
||||||
//} else {
|
|
||||||
// QvMessageBoxWarn(this, tr("Share Connection"), tr("There're no support of sharing configs other than vmess and shadowsocks"));
|
|
||||||
//}
|
|
||||||
void ConnectionInfoWidget::on_editBtn_clicked()
|
void ConnectionInfoWidget::on_editBtn_clicked()
|
||||||
{
|
{
|
||||||
|
emit OnEditRequested(connectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionInfoWidget::on_editJsonBtn_clicked()
|
void ConnectionInfoWidget::on_editJsonBtn_clicked()
|
||||||
{
|
{
|
||||||
|
emit OnJsonEditRequested(connectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectionInfoWidget::on_deleteBtn_clicked()
|
void ConnectionInfoWidget::on_deleteBtn_clicked()
|
||||||
|
@ -13,6 +13,10 @@ class ConnectionInfoWidget : public QWidget, private Ui::ConnectionInfoWidget
|
|||||||
void ShowDetails(const tuple<GroupId, ConnectionId> &_identifier);
|
void ShowDetails(const tuple<GroupId, ConnectionId> &_identifier);
|
||||||
~ConnectionInfoWidget();
|
~ConnectionInfoWidget();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void OnEditRequested(const ConnectionId &id);
|
||||||
|
void OnJsonEditRequested(const ConnectionId &id);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_connectBtn_clicked();
|
void on_connectBtn_clicked();
|
||||||
void on_editBtn_clicked();
|
void on_editBtn_clicked();
|
||||||
@ -25,9 +29,7 @@ class ConnectionInfoWidget : public QWidget, private Ui::ConnectionInfoWidget
|
|||||||
private slots:
|
private slots:
|
||||||
void OnConnected(const ConnectionId &id);
|
void OnConnected(const ConnectionId &id);
|
||||||
void OnDisConnected(const ConnectionId &id);
|
void OnDisConnected(const ConnectionId &id);
|
||||||
|
|
||||||
void on_duplicateBtn_clicked();
|
void on_duplicateBtn_clicked();
|
||||||
|
|
||||||
void on_latencyBtn_clicked();
|
void on_latencyBtn_clicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Loading…
Reference in New Issue
Block a user