From c6075b1dc69392c2b2140b01bee3df77272cba4f Mon Sep 17 00:00:00 2001 From: Qv2ray Bot <59914293+Qv2ray@users.noreply.github.com> Date: Tue, 21 Jan 2020 11:39:41 +0800 Subject: [PATCH] fix: several fix of complex editor --- Build.Counter | 2 +- src/ui/w_RoutesEditor.cpp | 103 ++++++++++++++++++++++---------- src/ui/w_RoutesEditor.hpp | 9 +-- src/ui/w_RoutesEditor_extra.cpp | 97 ++++++++++++++++++++++-------- 4 files changed, 150 insertions(+), 61 deletions(-) diff --git a/Build.Counter b/Build.Counter index ce89b3e4..0f3c80e3 100644 --- a/Build.Counter +++ b/Build.Counter @@ -1 +1 @@ -2992 +3005 diff --git a/src/ui/w_RoutesEditor.cpp b/src/ui/w_RoutesEditor.cpp index 97e21ef9..50053adf 100644 --- a/src/ui/w_RoutesEditor.cpp +++ b/src/ui/w_RoutesEditor.cpp @@ -20,7 +20,7 @@ static bool isLoading = false; #define CHECKEMPTYRULES if (this->rules.isEmpty()) { \ LOG(MODULE_UI, "No rules currently, we add one.") \ - on_addRouteBtn_clicked(); \ + AddNewRule(); \ } #define GRAPH_GLOBAL_OFFSET_X -80 @@ -82,17 +82,17 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QDialog(pare // Show connections in the node graph for (auto in : root["inbounds"].toArray()) { INBOUND _in = INBOUND(in.toObject()); - AddNewInbound(_in); + AddInbound(_in); } for (auto out : root["outbounds"].toArray()) { OUTBOUND _out = OUTBOUND(out.toObject()); - AddNewOutbound(_out); + AddOutbound(_out); } for (auto item : root["routing"].toObject()["rules"].toArray()) { auto _rule = StructFromJsonString(JsonToString(item.toObject())); - AddNewRule(_rule); + AddRule(_rule); } // Set default outboung combo text AFTER adding all outbounds. @@ -300,11 +300,18 @@ CONFIGROOT RouteEditor::OpenEditor() // Convert our internal data format to QJsonArray for (auto x : inbounds) { + if (x.isEmpty()) + continue; + _inbounds.append(x.raw()); } for (auto x : outbounds) { + if (x.isEmpty()) + continue; + if (getTag(x) == defaultOutbound) { + LOG(MODULE_CONNECTION, "Pushing default outbound to the front.") // Put the default outbound to the first. _outbounds.push_front(x.raw()); } else { @@ -328,7 +335,13 @@ void RouteEditor::ShowCurrentRuleDetail() { LOADINGCHECK + if (currentRuleTag.isEmpty()) { + LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.") + return; + } + if (!rules.contains(currentRuleTag)) { + QvMessageBoxWarn(this, tr("Show rule details"), tr("A rule cannot be found: ") + currentRuleTag); LOG(MODULE_UI, "WARNING, trying to access a non-exist rule entry. return.") return; } @@ -389,15 +402,17 @@ void RouteEditor::ShowCurrentRuleDetail() ipList->setPlainText(ips); LOAD_FLAG_END } + void RouteEditor::on_insertDirectBtn_clicked() { auto freedom = GenerateFreedomOUT("as-is", "", 0); auto tag = "Freedom_" + QSTRN(QTime::currentTime().msecsSinceStartOfDay()); auto out = GenerateOutboundEntry("freedom", freedom, QJsonObject(), QJsonObject(), "0.0.0.0", tag); // ADD NODE - AddNewOutbound(out); + AddOutbound(out); statusLabel->setText(tr("Added DIRECT outbound")); } + void RouteEditor::on_routeProtocolHTTPCB_stateChanged(int arg1) { LOADINGCHECK @@ -488,18 +503,8 @@ void RouteEditor::on_routeUserTxt_textEdited(const QString &arg1) } void RouteEditor::on_addRouteBtn_clicked() { - LOADINGCHECK - // Add Route - RuleObject rule; - // - rule.QV2RAY_RULE_ENABLED = true; - rule.QV2RAY_RULE_USE_BALANCER = false; - // Default balancer tag, it's a random string. - auto bTag = GenerateRandomString(); - rule.QV2RAY_RULE_TAG = rules.isEmpty() ? tr("Default rule") : (tr("rule") + "-" + GenerateRandomString(5)); - rule.balancerTag = bTag; - balancers[bTag] = QStringList(); - AddNewRule(rule); + auto ruleName = AddNewRule(); + Q_UNUSED(ruleName) } void RouteEditor::on_netBothRB_clicked() { @@ -570,8 +575,8 @@ void RouteEditor::on_addDefaultBtn_clicked() auto _in_HTTP = GenerateInboundEntry(_Inconfig.listenip, _Inconfig.http_port, "http", _in_httpConf, "HTTP_gConf"); auto _in_SOCKS = GenerateInboundEntry(_Inconfig.listenip, _Inconfig.socks_port, "socks", _in_socksConf, "SOCKS_gConf"); // - AddNewInbound(_in_HTTP); - AddNewInbound(_in_SOCKS); + AddInbound(_in_HTTP); + AddInbound(_in_SOCKS); CHECKEMPTYRULES } void RouteEditor::on_insertBlackBtn_clicked() @@ -580,7 +585,7 @@ void RouteEditor::on_insertBlackBtn_clicked() auto blackHole = GenerateBlackHoleOUT(false); auto tag = "blackhole_" + QSTRN(QTime::currentTime().msecsSinceStartOfDay()); auto _blackHoleOutbound = GenerateOutboundEntry("blackhole", blackHole, QJsonObject(), QJsonObject(), "0.0.0.0", tag); - AddNewOutbound(_blackHoleOutbound); + AddOutbound(_blackHoleOutbound); } void RouteEditor::on_addInboundBtn_clicked() { @@ -589,7 +594,7 @@ void RouteEditor::on_addInboundBtn_clicked() auto _result = w.OpenEditor(); if (w.result() == QDialog::Accepted) { - AddNewInbound(_result); + AddInbound(_result); } CHECKEMPTYRULES @@ -612,7 +617,7 @@ void RouteEditor::on_addOutboundBtn_clicked() auto confList = conf["outbounds"].toArray(); for (int i = 0; i < confList.count(); i++) { - AddNewOutbound(OUTBOUND(confList[i].toObject())); + AddOutbound(OUTBOUND(confList[i].toObject())); } } @@ -642,22 +647,41 @@ void RouteEditor::on_delBtn_clicked() // Then remove the node container. if (isInbound) { currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvInboundNodeModel, InboundNodeData)->GetInbound(); - inbounds.remove(currentInboundOutboundTag); nodeScene->removeNode(*inboundNodes[currentInboundOutboundTag]); inboundNodes.remove(currentInboundOutboundTag); + + // Remove corresponded inboundtags from the rules. + for (auto k : rules.keys()) { + auto v = rules[k]; + v.inboundTag.removeAll(currentInboundOutboundTag); + rules[k] = v; + } + + inbounds.remove(currentInboundOutboundTag); } else if (isOutbound) { currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvOutboundNodeModel, OutboundNodeData)->GetOutbound(); outbounds.remove(currentInboundOutboundTag); - nodeScene->removeNode(*outboundNodes[currentInboundOutboundTag]); - outboundNodes.remove(currentInboundOutboundTag); - // - defaultOutboundCombo->removeItem(defaultOutbound.indexOf(currentInboundOutboundTag)); + defaultOutboundCombo->clear(); + defaultOutboundCombo->addItems(outbounds.keys()); + + // Remove corresponded inboundtags from the rules. + for (auto k : rules.keys()) { + auto v = rules[k]; + + if (v.outboundTag == currentInboundOutboundTag) + v.outboundTag.clear(); + + rules[k] = v; + } if (currentInboundOutboundTag == defaultOutbound) { // Set default outbound to the new one since the current has been removed. defaultOutbound = outbounds.firstKey(); - defaultOutboundCombo->setCurrentText(defaultOutbound); } + + defaultOutboundCombo->setCurrentText(defaultOutbound); + nodeScene->removeNode(*outboundNodes[currentInboundOutboundTag]); + outboundNodes.remove(currentInboundOutboundTag); } else if (isRule) { ruleEnableCB->setEnabled(false); currentRuleTag = GetFirstNodeData(*firstNode, QvRuleNodeDataModel, RuleNodeData)->GetRuleTag(); @@ -683,12 +707,18 @@ void RouteEditor::on_editBtn_clicked() QvMessageBoxWarn(this, tr("Edit Inbound/Outbound"), tr("Please select a node from the graph to continue.")); } - auto firstNode = nodeScene->selectedNodes()[0]; + auto firstNode = nodeScene->selectedNodes().at(0); auto isInbound = inboundNodes.values().contains(firstNode); auto isOutbound = outboundNodes.values().contains(firstNode); if (isInbound) { currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvInboundNodeModel, InboundNodeData)->GetInbound(); + + if (!inbounds.contains(currentInboundOutboundTag)) { + QvMessageBoxWarn(this, tr("Edit Inbound"), tr("No inbound tag found: ") + currentInboundOutboundTag); + return; + } + auto _in = inbounds[currentInboundOutboundTag]; INBOUND _result; auto protocol = _in["protocol"].toString(); @@ -719,13 +749,22 @@ void RouteEditor::on_editBtn_clicked() RenameItemTag(RENAME_INBOUND, getTag(_in), getTag(_result)); } + DEBUG(MODULE_UI, "Removed old tag: " + getTag(_in)) + inbounds.remove(getTag(_in)); + DEBUG(MODULE_UI, "Adding new tag: " + getTag(_result)) inbounds[getTag(_result)] = _result; } } else if (isOutbound) { currentInboundOutboundTag = GetFirstNodeData(*firstNode, QvOutboundNodeModel, OutboundNodeData)->GetOutbound(); + + if (!outbounds.contains(currentInboundOutboundTag)) { + QvMessageBoxWarn(this, tr("Edit Inbound"), tr("No inbound tag found: ") + currentInboundOutboundTag); + return; + } + OUTBOUND _result; auto _out = outbounds[currentInboundOutboundTag]; - auto protocol = _out["protocol"].toString(); + auto protocol = _out["protocol"].toString().toLower(); int _code; if (protocol != "vmess" && protocol != "shadowsocks" && protocol != "socks") { @@ -747,9 +786,13 @@ void RouteEditor::on_editBtn_clicked() bool isTagChanged = getTag(_out) != getTag(_result); if (isTagChanged) { + DEBUG(MODULE_UI, "Outbound tag is changed: " + QString(isTagChanged)) RenameItemTag(RENAME_OUTBOUND, getTag(_out), getTag(_result)); + DEBUG(MODULE_UI, "Removed old tag: " + getTag(_out)) + outbounds.remove(getTag(_out)); } + DEBUG(MODULE_UI, "Adding new tag: " + getTag(_result)) outbounds[getTag(_result)] = _result; statusLabel->setText(tr("OK")); } diff --git a/src/ui/w_RoutesEditor.hpp b/src/ui/w_RoutesEditor.hpp index 1b76d2fa..aa110d0e 100644 --- a/src/ui/w_RoutesEditor.hpp +++ b/src/ui/w_RoutesEditor.hpp @@ -112,7 +112,7 @@ class RouteEditor : public QDialog, private Ui::RouteEditor void onConnectionDeleted(QtNodes::Connection const &c); private: - void RenameItemTag(ROUTE_EDIT_MODE mode, const QString &originalTag, const QString &newTag); + void RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, const QString newTag); void ShowCurrentRuleDetail(); // QString currentRuleTag; @@ -136,7 +136,8 @@ class RouteEditor : public QDialog, private Ui::RouteEditor // FlowScene *nodeScene; // ---------------------------- Extra Source File Headers ---------------- - void AddNewInbound(INBOUND in); - void AddNewOutbound(OUTBOUND out); - void AddNewRule(RuleObject rule); + void AddInbound(INBOUND in); + void AddOutbound(OUTBOUND out); + void AddRule(RuleObject rule); + QString AddNewRule(); }; diff --git a/src/ui/w_RoutesEditor_extra.cpp b/src/ui/w_RoutesEditor_extra.cpp index 5de70296..d8aaf344 100644 --- a/src/ui/w_RoutesEditor_extra.cpp +++ b/src/ui/w_RoutesEditor_extra.cpp @@ -6,7 +6,7 @@ // Supplementary source file for Routes editor, basically providing routes-related operations. -void RouteEditor::AddNewInbound(INBOUND in) +void RouteEditor::AddInbound(INBOUND in) { QString tag = getTag(in); @@ -14,6 +14,7 @@ void RouteEditor::AddNewInbound(INBOUND in) tag = tag + "_" + GenerateRandomString(5); } + in["tag"] = tag; auto _nodeData = make_unique(make_shared(tag)); auto &node = nodeScene->createNode(std::move(_nodeData)); auto pos = QPointF(); @@ -24,7 +25,7 @@ void RouteEditor::AddNewInbound(INBOUND in) inbounds[getTag(in)] = in; } -void RouteEditor::AddNewOutbound(OUTBOUND out) +void RouteEditor::AddOutbound(OUTBOUND out) { QString tag = getTag(out); @@ -32,6 +33,7 @@ void RouteEditor::AddNewOutbound(OUTBOUND out) tag = tag + "_" + GenerateRandomString(5); } + out["tag"] = tag; auto _nodeData = make_unique(make_shared(tag)); auto pos = nodeGraphWidget->pos(); pos.setX(pos.x() + 850 + GRAPH_GLOBAL_OFFSET_X); @@ -43,7 +45,23 @@ void RouteEditor::AddNewOutbound(OUTBOUND out) defaultOutboundCombo->addItem(tag); } -void RouteEditor::AddNewRule(RuleObject rule) +QString RouteEditor::AddNewRule() +{ + // Add Route + RuleObject rule; + // + rule.QV2RAY_RULE_ENABLED = true; + rule.QV2RAY_RULE_USE_BALANCER = false; + // Default balancer tag, it's a random string. + auto bTag = GenerateRandomString(); + rule.QV2RAY_RULE_TAG = rules.isEmpty() ? tr("Default rule") : (tr("rule") + "-" + GenerateRandomString(6)); + rule.balancerTag = bTag; + balancers[bTag] = QStringList(); + AddRule(rule); + return rule.QV2RAY_RULE_TAG; +} + +void RouteEditor::AddRule(RuleObject rule) { // Prevent duplicate if (ruleNodes.contains(rule.QV2RAY_RULE_TAG)) { @@ -59,54 +77,68 @@ void RouteEditor::AddNewRule(RuleObject rule) nodeScene->setNodePosition(node, pos); for (auto inTag : rule.inboundTag) { - auto inboundNode = inboundNodes[inTag]; - nodeScene->createConnection(node, 0, *inboundNode, 0); + if (!inboundNodes.contains(inTag)) { + LOG(MODULE_UI, "No inbound tag found for rule: " + rule.QV2RAY_RULE_TAG + ", inbound tag: " + inTag) + QvMessageBoxWarn(this, tr("No Inbound"), tr("No inbound item found: ") + inTag); + rule.inboundTag.removeAll(inTag); + } else { + auto inboundNode = inboundNodes[inTag]; + nodeScene->createConnection(node, 0, *inboundNode, 0); + } } // If not using balancers (use outbound tag) - if (!rule.QV2RAY_RULE_USE_BALANCER && outboundNodes.contains(rule.outboundTag)) { - nodeScene->createConnection(*outboundNodes[rule.outboundTag], 0, node, 0); + if (!rule.QV2RAY_RULE_USE_BALANCER) { + if (outboundNodes.contains(rule.outboundTag)) { + DEBUG(MODULE_GRAPH, "Found outbound tag: " + rule.outboundTag + ", for rule: " + rule.QV2RAY_RULE_TAG) + nodeScene->createConnection(*outboundNodes[rule.outboundTag], 0, node, 0); + } else { + LOG(MODULE_GRAPH, "Outbound tag not found: " + rule.outboundTag + ", for: " + rule.QV2RAY_RULE_TAG) + QvMessageBoxWarn(this, tr("No outbound tag"), tr("Please connect the rule with an outbound.")); + } } this->ruleNodes[rule.QV2RAY_RULE_TAG] = &node; ruleListWidget->addItem(rule.QV2RAY_RULE_TAG); } -void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString &originalTag, const QString &newTag) +// Do not use reference here, we need deep +void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, QString newTag) { switch (mode) { case RENAME_RULE: if (rules.contains(originalTag) && ruleNodes.contains(originalTag)) { if (rules.contains(newTag) && rules.contains(newTag)) { - QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, please suggest another.")); - return; + QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix.")); + newTag += "_" + GenerateRandomString(5); } - // auto node = static_cast(ruleNodes[originalTag]->nodeDataModel()); + + if (node == nullptr) { + LOG(MODULE_GRAPH, "EMPTY NODE WARN") + } + node->setData(newTag); // rules[newTag] = rules.take(originalTag); + rules[newTag].QV2RAY_RULE_TAG = newTag; ruleNodes[newTag] = ruleNodes.take(originalTag); + // // No other operation needed, but need to rename the one in the ruleOrder list widget. auto items = ruleListWidget->findItems(originalTag, Qt::MatchExactly); - if (!items.isEmpty()) { - auto item = items.first(); - item->setText(newTag); - } else { + if (items.isEmpty()) { LOG(MODULE_UI, "Cannot find a node: " + originalTag) + } else { + items.first()->setText(newTag); } if (currentRuleTag == originalTag) { currentRuleTag = newTag; } - - // Do not move this line, since originalTag is a reference (implicitly a pointer) to this value. - // We must change this at last. - rules[newTag].QV2RAY_RULE_TAG = newTag; } else { - LOG(MODULE_UI, "There's thing match " + originalTag + " in the containers.") + LOG(MODULE_UI, "There's nothing match " + originalTag + " in the containers.") } break; @@ -114,13 +146,18 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString &originalTag case RENAME_OUTBOUND: if (outbounds.contains(originalTag) && outboundNodes.contains(originalTag)) { if (outbounds.contains(newTag) && outboundNodes.contains(newTag)) { - QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, please suggest another.")); - return; + QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix.")); + newTag += "_" + GenerateRandomString(5); } outbounds[newTag] = outbounds.take(originalTag); outboundNodes[newTag] = outboundNodes.take(originalTag); auto node = static_cast(outboundNodes[newTag]->nodeDataModel()); + + if (node == nullptr) { + LOG(MODULE_GRAPH, "EMPTY NODE WARN") + } + node->setData(newTag); // Change outbound tag in rules accordingly. @@ -142,21 +179,29 @@ void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString &originalTag case RENAME_INBOUND: if (inbounds.contains(originalTag) && inboundNodes.contains(originalTag)) { if (inbounds.contains(newTag) && inboundNodes.contains(newTag)) { - QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, please suggest another.")); - return; + QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix.")); + newTag += "_" + GenerateRandomString(5); } inbounds[newTag] = inbounds.take(originalTag); inboundNodes[newTag] = inboundNodes.take(originalTag); - static_cast(inboundNodes[newTag]->nodeDataModel())->setData(newTag); + auto node = static_cast(inboundNodes[newTag]->nodeDataModel()); + + if (node == nullptr) { + LOG(MODULE_GRAPH, "EMPTY NODE WARN") + } + + node->setData(newTag); // Change inbound tag in rules accordingly. + // k -> rule tag + // v -> rule object for (auto k : rules.keys()) { auto v = rules[k]; if (v.inboundTag.contains(originalTag)) { - v.inboundTag.removeAll(originalTag); v.inboundTag.append(newTag); + v.inboundTag.removeAll(originalTag); // Put this inside the if block since no need an extra operation if the condition is false. rules[k] = v; }