mirror of
https://github.com/MatsuriDayo/nekoray.git
synced 2025-12-16 20:17:07 +03:00
chore: re-format code
This commit is contained in:
10
.clang-format
Normal file
10
.clang-format
Normal file
@@ -0,0 +1,10 @@
|
||||
BasedOnStyle: Google
|
||||
ColumnLimit: 0
|
||||
IndentWidth: 4
|
||||
SortIncludes: Never
|
||||
SpacesBeforeTrailingComments: 1
|
||||
NamespaceIndentation: All
|
||||
AccessModifierOffset: -4
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeRangeBasedForLoopColon: false
|
||||
@@ -11,8 +11,7 @@ namespace NekoRay {
|
||||
|
||||
// Common
|
||||
|
||||
QSharedPointer<BuildConfigResult>
|
||||
BuildConfig(const QSharedPointer<ProxyEntity> &ent, bool forTest, bool forExport) {
|
||||
QSharedPointer<BuildConfigResult> BuildConfig(const QSharedPointer<ProxyEntity> &ent, bool forTest, bool forExport) {
|
||||
if (IS_NEKO_BOX) {
|
||||
return BuildConfigSingBox(ent, forTest, forExport);
|
||||
}
|
||||
@@ -65,7 +64,7 @@ namespace NekoRay {
|
||||
if (outbound.contains(key)) {
|
||||
auto v = custom[key];
|
||||
auto v_orig = outbound[key];
|
||||
if (v.isObject() && v_orig.isObject()) {// isObject 则合并?
|
||||
if (v.isObject() && v_orig.isObject()) { // isObject 则合并?
|
||||
auto vo = v.toObject();
|
||||
QJsonObject vo_orig = v_orig.toObject();
|
||||
ApplyCustomOutboundJsonSettings(vo, vo_orig);
|
||||
@@ -79,8 +78,7 @@ namespace NekoRay {
|
||||
}
|
||||
}
|
||||
|
||||
QSharedPointer<BuildConfigResult>
|
||||
BuildConfigV2Ray(const QSharedPointer<ProxyEntity> &ent, bool forTest, bool forExport) {
|
||||
QSharedPointer<BuildConfigResult> BuildConfigV2Ray(const QSharedPointer<ProxyEntity> &ent, bool forTest, bool forExport) {
|
||||
auto result = QSharedPointer<BuildConfigResult>(new BuildConfigResult);
|
||||
auto status = QSharedPointer<BuildConfigStatus>(new BuildConfigStatus);
|
||||
status->ent = ent;
|
||||
@@ -91,11 +89,13 @@ namespace NekoRay {
|
||||
result->coreConfig.insert("log", logObj);
|
||||
|
||||
// Inbounds
|
||||
QJsonObject sniffing{{"destOverride", dataStore->fake_dns ? QJsonArray{"fakedns", "http", "tls", "quic"}
|
||||
: QJsonArray{"http", "tls", "quic"}},
|
||||
{"enabled", true},
|
||||
{"metadataOnly", false},
|
||||
{"routeOnly", dataStore->sniffing_mode == SniffingMode::FOR_ROUTING},};
|
||||
QJsonObject sniffing{
|
||||
{"destOverride", dataStore->fake_dns ? QJsonArray{"fakedns", "http", "tls", "quic"}
|
||||
: QJsonArray{"http", "tls", "quic"}},
|
||||
{"enabled", true},
|
||||
{"metadataOnly", false},
|
||||
{"routeOnly", dataStore->sniffing_mode == SniffingMode::FOR_ROUTING},
|
||||
};
|
||||
|
||||
// socks-in
|
||||
if (InRange(dataStore->inbound_socks_port, 0, 65535) && !forTest) {
|
||||
@@ -104,8 +104,10 @@ namespace NekoRay {
|
||||
socksInbound["protocol"] = "socks";
|
||||
socksInbound["listen"] = dataStore->inbound_address;
|
||||
socksInbound["port"] = dataStore->inbound_socks_port;
|
||||
socksInbound["settings"] = QJsonObject({{"auth", "noauth"},
|
||||
{"udp", true},});
|
||||
socksInbound["settings"] = QJsonObject{
|
||||
{"auth", "noauth"},
|
||||
{"udp", true},
|
||||
};
|
||||
if (dataStore->fake_dns || dataStore->sniffing_mode != SniffingMode::DISABLE) {
|
||||
socksInbound["sniffing"] = sniffing;
|
||||
}
|
||||
@@ -129,21 +131,37 @@ namespace NekoRay {
|
||||
if (!result->error.isEmpty()) return result;
|
||||
|
||||
// direct & bypass & block
|
||||
status->outbounds += QJsonObject{{"protocol", "freedom"},
|
||||
{"tag", "direct"},};
|
||||
status->outbounds += QJsonObject{{"protocol", "freedom"},
|
||||
{"tag", "bypass"},};
|
||||
status->outbounds += QJsonObject{{"protocol", "blackhole"},
|
||||
{"tag", "block"},};
|
||||
status->outbounds += QJsonObject{
|
||||
{"protocol", "freedom"},
|
||||
{"tag", "direct"},
|
||||
};
|
||||
status->outbounds += QJsonObject{
|
||||
{"protocol", "freedom"},
|
||||
{"tag", "bypass"},
|
||||
};
|
||||
status->outbounds += QJsonObject{
|
||||
{"protocol", "blackhole"},
|
||||
{"tag", "block"},
|
||||
};
|
||||
|
||||
// block for tun
|
||||
if (!forTest) {
|
||||
status->routingRules += QJsonObject{{"type", "field"},
|
||||
{"ip", QJsonArray{"224.0.0.0/3", "169.254.0.0/16",},},
|
||||
{"outboundTag", "block"},};
|
||||
status->routingRules += QJsonObject{{"type", "field"},
|
||||
{"port", "135-139"},
|
||||
{"outboundTag", "block"},};
|
||||
status->routingRules += QJsonObject{
|
||||
{"type", "field"},
|
||||
{
|
||||
"ip",
|
||||
QJsonArray{
|
||||
"224.0.0.0/3",
|
||||
"169.254.0.0/16",
|
||||
},
|
||||
},
|
||||
{"outboundTag", "block"},
|
||||
};
|
||||
status->routingRules += QJsonObject{
|
||||
{"type", "field"},
|
||||
{"port", "135-139"},
|
||||
{"outboundTag", "block"},
|
||||
};
|
||||
}
|
||||
|
||||
// DNS Routing (tun2socks 用到,防污染)
|
||||
@@ -157,17 +175,21 @@ namespace NekoRay {
|
||||
dnsOut_settings["address"] = "8.8.8.8";
|
||||
dnsOut_settings["userLevel"] = 1;
|
||||
dnsOut["settings"] = dnsOut_settings;
|
||||
dnsOut["proxySettings"] = QJsonObject{{"tag", tagProxy},
|
||||
dnsOut["proxySettings"] = QJsonObject{{"tag", tagProxy},
|
||||
{"transportLayer", true}};
|
||||
|
||||
status->outbounds += dnsOut;
|
||||
status->routingRules += QJsonObject{{"type", "field"},
|
||||
{"port", "53"},
|
||||
{"inboundTag", QJsonArray{"socks-in", "http-in"}},
|
||||
{"outboundTag", "dns-out"},};
|
||||
status->routingRules += QJsonObject{{"type", "field"},
|
||||
{"inboundTag", QJsonArray{"dns-in"}},
|
||||
{"outboundTag", "dns-out"},};
|
||||
status->routingRules += QJsonObject{
|
||||
{"type", "field"},
|
||||
{"port", "53"},
|
||||
{"inboundTag", QJsonArray{"socks-in", "http-in"}},
|
||||
{"outboundTag", "dns-out"},
|
||||
};
|
||||
status->routingRules += QJsonObject{
|
||||
{"type", "field"},
|
||||
{"inboundTag", QJsonArray{"dns-in"}},
|
||||
{"outboundTag", "dns-out"},
|
||||
};
|
||||
}
|
||||
|
||||
// custom inbound
|
||||
@@ -207,22 +229,30 @@ namespace NekoRay {
|
||||
if (directDnsAddress.contains("://")) {
|
||||
auto directDnsIp = SubStrBefore(SubStrAfter(directDnsAddress, "://"), "/");
|
||||
if (IsIpAddress(directDnsIp)) {
|
||||
status->routingRules.push_front(QJsonObject{{"type", "field"},
|
||||
{"ip", QJsonArray{directDnsIp}},
|
||||
{"outboundTag", "direct"},});
|
||||
status->routingRules.push_front(QJsonObject{
|
||||
{"type", "field"},
|
||||
{"ip", QJsonArray{directDnsIp}},
|
||||
{"outboundTag", "direct"},
|
||||
});
|
||||
} else {
|
||||
status->routingRules.push_front(QJsonObject{{"type", "field"},
|
||||
{"domain", QJsonArray{directDnsIp}},
|
||||
{"outboundTag", "direct"},});
|
||||
status->routingRules.push_front(QJsonObject{
|
||||
{"type", "field"},
|
||||
{"domain", QJsonArray{directDnsIp}},
|
||||
{"outboundTag", "direct"},
|
||||
});
|
||||
}
|
||||
} else if (directDnsAddress != "localhost") {
|
||||
status->routingRules.push_front(QJsonObject{{"type", "field"},
|
||||
{"ip", QJsonArray{directDnsAddress}},
|
||||
{"outboundTag", "direct"},});
|
||||
status->routingRules.push_front(QJsonObject{
|
||||
{"type", "field"},
|
||||
{"ip", QJsonArray{directDnsAddress}},
|
||||
{"outboundTag", "direct"},
|
||||
});
|
||||
}
|
||||
dnsServers += QJsonObject{{"address", directDnsAddress},
|
||||
{"domains", status->domainListDNSDirect},
|
||||
{"skipFallback", true},};
|
||||
dnsServers += QJsonObject{
|
||||
{"address", directDnsAddress},
|
||||
{"domains", status->domainListDNSDirect},
|
||||
{"skipFallback", true},
|
||||
};
|
||||
|
||||
dns["disableFallbackIfMatch"] = true;
|
||||
dns["servers"] = dnsServers;
|
||||
@@ -365,19 +395,25 @@ namespace NekoRay {
|
||||
if (IS_NEKO_BOX) {
|
||||
replaced["detour"] = tagOut;
|
||||
} else {
|
||||
replaced["proxySettings"] = QJsonObject{{"tag", tagOut},
|
||||
{"transportLayer", true},};
|
||||
replaced["proxySettings"] = QJsonObject{
|
||||
{"tag", tagOut},
|
||||
{"transportLayer", true},
|
||||
};
|
||||
}
|
||||
status->outbounds.removeLast();
|
||||
status->outbounds += replaced;
|
||||
} else {
|
||||
if (IS_NEKO_BOX) {
|
||||
status->routingRules += QJsonObject{{"inbound", QJsonArray{pastTag + "-mapping"}},
|
||||
{"outbound", tagOut},};
|
||||
status->routingRules += QJsonObject{
|
||||
{"inbound", QJsonArray{pastTag + "-mapping"}},
|
||||
{"outbound", tagOut},
|
||||
};
|
||||
} else {
|
||||
status->routingRules += QJsonObject{{"type", "field"},
|
||||
{"inboundTag", QJsonArray{pastTag + "-mapping"}},
|
||||
{"outboundTag", tagOut},};
|
||||
status->routingRules += QJsonObject{
|
||||
{"type", "field"},
|
||||
{"inboundTag", QJsonArray{pastTag + "-mapping"}},
|
||||
{"outboundTag", tagOut},
|
||||
};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -388,37 +424,46 @@ namespace NekoRay {
|
||||
|
||||
// chain rules: this
|
||||
auto mapping_port = MkPort();
|
||||
auto thisExternalStat = ent->bean->NeedExternal(isFirstProfile,
|
||||
dataStore->running_spmode == SystemProxyMode::VPN);
|
||||
auto thisExternalStat = ent->bean->NeedExternal(isFirstProfile, dataStore->running_spmode == SystemProxyMode::VPN);
|
||||
if (thisExternalStat == 2) dataStore->need_keep_vpn_off = true;
|
||||
if (thisExternalStat == 1) {
|
||||
// mapping
|
||||
if (IS_NEKO_BOX) {
|
||||
status->inbounds += QJsonObject{{"type", "direct"},
|
||||
{"tag", tagOut + "-mapping"},
|
||||
{"listen", "127.0.0.1"},
|
||||
{"listen_port", mapping_port},
|
||||
{"override_address", ent->bean->serverAddress},
|
||||
{"override_port", ent->bean->serverPort},};
|
||||
status->inbounds += QJsonObject{
|
||||
{"type", "direct"},
|
||||
{"tag", tagOut + "-mapping"},
|
||||
{"listen", "127.0.0.1"},
|
||||
{"listen_port", mapping_port},
|
||||
{"override_address", ent->bean->serverAddress},
|
||||
{"override_port", ent->bean->serverPort},
|
||||
};
|
||||
} else {
|
||||
status->inbounds += QJsonObject{{"protocol", "dokodemo-door"},
|
||||
{"tag", tagOut + "-mapping"},
|
||||
{"listen", "127.0.0.1"},
|
||||
{"port", mapping_port},
|
||||
{"settings", QJsonObject{ // to
|
||||
{"address", ent->bean->serverAddress},
|
||||
{"port", ent->bean->serverPort},
|
||||
{"network", "tcp,udp"},}},};
|
||||
status->inbounds += QJsonObject{
|
||||
{"protocol", "dokodemo-door"},
|
||||
{"tag", tagOut + "-mapping"},
|
||||
{"listen", "127.0.0.1"},
|
||||
{"port", mapping_port},
|
||||
{"settings", QJsonObject{
|
||||
// to
|
||||
{"address", ent->bean->serverAddress},
|
||||
{"port", ent->bean->serverPort},
|
||||
{"network", "tcp,udp"},
|
||||
}},
|
||||
};
|
||||
}
|
||||
// no chain rule and not outbound, so need to set to direct
|
||||
if (isFirstProfile) {
|
||||
if (IS_NEKO_BOX) {
|
||||
status->routingRules += QJsonObject{{"inbound", QJsonArray{tagOut + "-mapping"}},
|
||||
{"outbound", "direct"},};
|
||||
status->routingRules += QJsonObject{
|
||||
{"inbound", QJsonArray{tagOut + "-mapping"}},
|
||||
{"outbound", "direct"},
|
||||
};
|
||||
} else {
|
||||
status->routingRules += QJsonObject{{"type", "field"},
|
||||
{"inboundTag", QJsonArray{tagOut + "-mapping"}},
|
||||
{"outboundTag", "direct"},};
|
||||
status->routingRules += QJsonObject{
|
||||
{"type", "field"},
|
||||
{"inboundTag", QJsonArray{tagOut + "-mapping"}},
|
||||
{"outboundTag", "direct"},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -487,11 +532,17 @@ namespace NekoRay {
|
||||
if (IS_NEKO_BOX) {
|
||||
// TODO no such field?
|
||||
auto ds = dataStore->outbound_domain_strategy;
|
||||
if (ds == "UseIPv4") { ds = "ipv4_only"; }
|
||||
else if (ds == "UseIPv6") { ds = "ipv6_only"; }
|
||||
else if (ds == "PreferIPv4") { ds = "prefer_ipv4"; }
|
||||
else if (ds == "PreferIPv6") { ds = "prefer_ipv6"; }
|
||||
else { ds = ""; }
|
||||
if (ds == "UseIPv4") {
|
||||
ds = "ipv4_only";
|
||||
} else if (ds == "UseIPv6") {
|
||||
ds = "ipv6_only";
|
||||
} else if (ds == "PreferIPv4") {
|
||||
ds = "prefer_ipv4";
|
||||
} else if (ds == "PreferIPv6") {
|
||||
ds = "prefer_ipv6";
|
||||
} else {
|
||||
ds = "";
|
||||
}
|
||||
outbound["domain_strategy"] = ds;
|
||||
// TODO apply mux
|
||||
} else {
|
||||
@@ -500,8 +551,10 @@ namespace NekoRay {
|
||||
if (dataStore->mux_cool > 0 && !muxApplied) {
|
||||
// TODO refactor mux settings
|
||||
if (ent->type == "vmess" || ent->type == "trojan" || ent->type == "vless") {
|
||||
auto muxObj = QJsonObject{{"enabled", true},
|
||||
{"concurrency", dataStore->mux_cool},};
|
||||
auto muxObj = QJsonObject{
|
||||
{"enabled", true},
|
||||
{"concurrency", dataStore->mux_cool},
|
||||
};
|
||||
auto stream = GetStreamSettings(ent->bean.data());
|
||||
if (stream != nullptr && !stream->packet_encoding.isEmpty()) {
|
||||
muxObj["packetEncoding"] = stream->packet_encoding;
|
||||
@@ -538,8 +591,7 @@ namespace NekoRay {
|
||||
|
||||
// SingBox
|
||||
|
||||
QSharedPointer<BuildConfigResult>
|
||||
BuildConfigSingBox(const QSharedPointer<ProxyEntity> &ent, bool forTest, bool forExport) {
|
||||
QSharedPointer<BuildConfigResult> BuildConfigSingBox(const QSharedPointer<ProxyEntity> &ent, bool forTest, bool forExport) {
|
||||
auto result = QSharedPointer<BuildConfigResult>(new BuildConfigResult);
|
||||
auto status = QSharedPointer<BuildConfigStatus>(new BuildConfigStatus);
|
||||
status->ent = ent;
|
||||
@@ -560,7 +612,6 @@ namespace NekoRay {
|
||||
if (dataStore->sniffing_mode != SniffingMode::DISABLE) {
|
||||
socksInbound["sniff"] = true;
|
||||
socksInbound["sniff_override_destination"] = dataStore->sniffing_mode == SniffingMode::FOR_DESTINATION;
|
||||
|
||||
}
|
||||
status->inbounds += socksInbound;
|
||||
}
|
||||
@@ -570,14 +621,22 @@ namespace NekoRay {
|
||||
if (!result->error.isEmpty()) return result;
|
||||
|
||||
// direct & bypass & block
|
||||
status->outbounds += QJsonObject{{"type", "direct"},
|
||||
{"tag", "direct"},};
|
||||
status->outbounds += QJsonObject{{"type", "direct"},
|
||||
{"tag", "bypass"},};
|
||||
status->outbounds += QJsonObject{{"type", "block"},
|
||||
{"tag", "block"},};
|
||||
status->outbounds += QJsonObject{{"type", "dns"},
|
||||
{"tag", "dns-out"},};
|
||||
status->outbounds += QJsonObject{
|
||||
{"type", "direct"},
|
||||
{"tag", "direct"},
|
||||
};
|
||||
status->outbounds += QJsonObject{
|
||||
{"type", "direct"},
|
||||
{"tag", "bypass"},
|
||||
};
|
||||
status->outbounds += QJsonObject{
|
||||
{"type", "block"},
|
||||
{"tag", "block"},
|
||||
};
|
||||
status->outbounds += QJsonObject{
|
||||
{"type", "dns"},
|
||||
{"tag", "dns-out"},
|
||||
};
|
||||
|
||||
// custom inbound
|
||||
QJSONARRAY_ADD(status->inbounds, QString2QJsonObject(dataStore->custom_inbound)["inbounds"].toArray())
|
||||
@@ -636,8 +695,9 @@ namespace NekoRay {
|
||||
rule["ip_cidr"] = ips;
|
||||
rule["geoip"] = geoips;
|
||||
} else {
|
||||
if (domain_keyword.isEmpty() && domain_subdomain.isEmpty() && domain_full.isEmpty()
|
||||
&& geosites.isEmpty()) { return rule; }
|
||||
if (domain_keyword.isEmpty() && domain_subdomain.isEmpty() && domain_full.isEmpty() && geosites.isEmpty()) {
|
||||
return rule;
|
||||
}
|
||||
rule["domain"] = domain_full;
|
||||
rule["domain_suffix"] = domain_suffix;
|
||||
rule["domain_keyword"] = domain_keyword;
|
||||
@@ -653,10 +713,12 @@ namespace NekoRay {
|
||||
|
||||
// Remote
|
||||
if (!forTest)
|
||||
dnsServers += QJsonObject{{"tag", "dns-remote"},
|
||||
{"address_resolver", "dns-underlying"},
|
||||
{"address", dataStore->remote_dns},
|
||||
{"detour", tagProxy},};
|
||||
dnsServers += QJsonObject{
|
||||
{"tag", "dns-remote"},
|
||||
{"address_resolver", "dns-underlying"},
|
||||
{"address", dataStore->remote_dns},
|
||||
{"detour", tagProxy},
|
||||
};
|
||||
|
||||
// neko only
|
||||
auto underlyingStr = forExport ? "local" : "underlying://0.0.0.0";
|
||||
@@ -665,15 +727,19 @@ namespace NekoRay {
|
||||
auto directDNSAddress = dataStore->direct_dns;
|
||||
if (directDNSAddress == "localhost") directDNSAddress = underlyingStr;
|
||||
if (!forTest)
|
||||
dnsServers += QJsonObject{{"tag", "dns-direct"},
|
||||
{"address_resolver", "dns-underlying"},
|
||||
{"address", directDNSAddress.replace("+local://", "://")},
|
||||
{"detour", "direct"},};
|
||||
dnsServers += QJsonObject{
|
||||
{"tag", "dns-direct"},
|
||||
{"address_resolver", "dns-underlying"},
|
||||
{"address", directDNSAddress.replace("+local://", "://")},
|
||||
{"detour", "direct"},
|
||||
};
|
||||
|
||||
// Underlying 100% Working DNS
|
||||
dnsServers += QJsonObject{{"tag", "dns-underlying"},
|
||||
{"address", underlyingStr},
|
||||
{"detour", "direct"},};
|
||||
dnsServers += QJsonObject{
|
||||
{"tag", "dns-underlying"},
|
||||
{"address", underlyingStr},
|
||||
{"detour", "direct"},
|
||||
};
|
||||
|
||||
// DNS rules
|
||||
auto add_rule_dns = [&](const QJsonArray &arr, const QString &server) {
|
||||
@@ -738,11 +804,20 @@ namespace NekoRay {
|
||||
QJSONARRAY_ADD(routingRules, QString2QJsonObject(dataStore->custom_route_global)["rules"].toArray())
|
||||
QJSONARRAY_ADD(routingRules, status->routingRules)
|
||||
auto routeObj = QJsonObject{
|
||||
{"rules", routingRules},
|
||||
{"auto_detect_interface", true},
|
||||
{"geoip", QJsonObject{{"path", geoip},},},
|
||||
{"geosite", QJsonObject{{"path", geosite},},}
|
||||
};
|
||||
{"rules", routingRules},
|
||||
{"auto_detect_interface", true},
|
||||
{
|
||||
"geoip",
|
||||
QJsonObject{
|
||||
{"path", geoip},
|
||||
},
|
||||
},
|
||||
{
|
||||
"geosite",
|
||||
QJsonObject{
|
||||
{"path", geosite},
|
||||
},
|
||||
}};
|
||||
if (forExport) {
|
||||
routeObj.remove("geoip");
|
||||
routeObj.remove("geosite");
|
||||
@@ -753,14 +828,13 @@ namespace NekoRay {
|
||||
// api
|
||||
if (!forTest && !forExport && dataStore->traffic_loop_interval > 0) {
|
||||
result->coreConfig.insert("experimental", QJsonObject{
|
||||
{"v2ray_api", QJsonObject{
|
||||
{"listen", "127.0.0.1:" + Int2String(dataStore->inbound_socks_port + 10)},
|
||||
{"stats", QJsonObject{
|
||||
{"enabled", true},
|
||||
{"outbounds", QJsonArray{tagProxy, "bypass"}},
|
||||
}}
|
||||
}},
|
||||
});
|
||||
{"v2ray_api", QJsonObject{
|
||||
{"listen", "127.0.0.1:" + Int2String(dataStore->inbound_socks_port + 10)},
|
||||
{"stats", QJsonObject{
|
||||
{"enabled", true},
|
||||
{"outbounds", QJsonArray{tagProxy, "bypass"}},
|
||||
}}}},
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -771,7 +845,7 @@ namespace NekoRay {
|
||||
QString process_name_rule = dataStore->vpn_bypass_process.trimmed();
|
||||
if (!process_name_rule.isEmpty()) {
|
||||
auto arr = SplitLines(process_name_rule);
|
||||
QJsonObject rule{{"outbound", "direct"},
|
||||
QJsonObject rule{{"outbound", "direct"},
|
||||
{"process_name", QList2QJsonArray(arr)}};
|
||||
process_name_rule = "," + QJsonObject2QString(rule, false);
|
||||
}
|
||||
@@ -779,7 +853,7 @@ namespace NekoRay {
|
||||
if (!cidr_rule.isEmpty()) {
|
||||
auto arr = SplitLines(cidr_rule);
|
||||
QJsonObject rule{{"outbound", "direct"},
|
||||
{"ip_cidr", QList2QJsonArray(arr)}};
|
||||
{"ip_cidr", QList2QJsonArray(arr)}};
|
||||
cidr_rule = "," + QJsonObject2QString(rule, false);
|
||||
}
|
||||
//
|
||||
@@ -791,14 +865,14 @@ namespace NekoRay {
|
||||
auto configFn = ":/neko/vpn/sing-box-vpn.json";
|
||||
if (QFile::exists("vpn/sing-box-vpn.json")) configFn = "vpn/sing-box-vpn.json";
|
||||
auto config = ReadFileText(configFn)
|
||||
.replace("%IPV6_ADDRESS%", dataStore->vpn_ipv6 ? R"("inet6_address": "fdfe:dcba:9876::1/126",)" : "")
|
||||
.replace("%MTU%", Int2String(dataStore->vpn_mtu))
|
||||
.replace("%STACK%", Preset::SingBox::VpnImplementation.value(dataStore->vpn_implementation))
|
||||
.replace("%PROCESS_NAME_RULE%", process_name_rule)
|
||||
.replace("%CIDR_RULE%", cidr_rule)
|
||||
.replace("%TUN_NAME%", tun_name)
|
||||
.replace("%STRICT_ROUTE%", dataStore->vpn_strict_route ? "true" : "false")
|
||||
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
|
||||
.replace("%IPV6_ADDRESS%", dataStore->vpn_ipv6 ? R"("inet6_address": "fdfe:dcba:9876::1/126",)" : "")
|
||||
.replace("%MTU%", Int2String(dataStore->vpn_mtu))
|
||||
.replace("%STACK%", Preset::SingBox::VpnImplementation.value(dataStore->vpn_implementation))
|
||||
.replace("%PROCESS_NAME_RULE%", process_name_rule)
|
||||
.replace("%CIDR_RULE%", cidr_rule)
|
||||
.replace("%TUN_NAME%", tun_name)
|
||||
.replace("%STRICT_ROUTE%", dataStore->vpn_strict_route ? "true" : "false")
|
||||
.replace("%PORT%", Int2String(dataStore->inbound_socks_port));
|
||||
// write config
|
||||
QFile file;
|
||||
file.setFileName(QFileInfo(configFn).fileName());
|
||||
@@ -813,11 +887,11 @@ namespace NekoRay {
|
||||
auto scriptFn = ":/neko/vpn/vpn-run-root.sh";
|
||||
if (QFile::exists("vpn/vpn-run-root.sh")) scriptFn = "vpn/vpn-run-root.sh";
|
||||
auto script = ReadFileText(scriptFn)
|
||||
.replace("$PORT", Int2String(dataStore->inbound_socks_port))
|
||||
.replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core")
|
||||
.replace("$PROTECT_LISTEN_PATH", protectPath)
|
||||
.replace("$CONFIG_PATH", configPath)
|
||||
.replace("$TABLE_FWMARK", "514");
|
||||
.replace("$PORT", Int2String(dataStore->inbound_socks_port))
|
||||
.replace("./nekobox_core", QApplication::applicationDirPath() + "/nekobox_core")
|
||||
.replace("$PROTECT_LISTEN_PATH", protectPath)
|
||||
.replace("$CONFIG_PATH", configPath)
|
||||
.replace("$TABLE_FWMARK", "514");
|
||||
// write script
|
||||
QFile file2;
|
||||
file2.setFileName(QFileInfo(scriptFn).fileName());
|
||||
@@ -827,4 +901,4 @@ namespace NekoRay {
|
||||
return QFileInfo(file2).absoluteFilePath();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace NekoRay
|
||||
@@ -11,7 +11,7 @@ namespace NekoRay {
|
||||
QStringList tryDomains;
|
||||
|
||||
QList<QSharedPointer<traffic::TrafficData>> outboundStats; // all, but not including "bypass" "block"
|
||||
QSharedPointer<traffic::TrafficData> outboundStat; // main
|
||||
QSharedPointer<traffic::TrafficData> outboundStat; // main
|
||||
|
||||
QList<sys::ExternalProcess *> ext;
|
||||
};
|
||||
@@ -58,4 +58,4 @@ namespace NekoRay {
|
||||
QString WriteVPNSingBoxConfig();
|
||||
|
||||
QString WriteVPNLinuxScript(const QString &protectPath, const QString &configPath);
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -141,7 +141,11 @@ namespace NekoRay {
|
||||
// Profile
|
||||
|
||||
int ProfileManager::NewProfileID() const {
|
||||
if (profiles.empty()) { return 0; } else { return profiles.lastKey() + 1; }
|
||||
if (profiles.empty()) {
|
||||
return 0;
|
||||
} else {
|
||||
return profiles.lastKey() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProfileManager::AddProfile(const QSharedPointer<ProxyEntity> &ent, int gid) {
|
||||
@@ -192,7 +196,7 @@ namespace NekoRay {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//Group
|
||||
// Group
|
||||
|
||||
Group::Group() {
|
||||
_add(new configItem("id", &id, itemType::integer));
|
||||
@@ -212,7 +216,11 @@ namespace NekoRay {
|
||||
}
|
||||
|
||||
int ProfileManager::NewGroupID() const {
|
||||
if (groups.empty()) { return 0; } else { return groups.lastKey() + 1; }
|
||||
if (groups.empty()) {
|
||||
return 0;
|
||||
} else {
|
||||
return groups.lastKey() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool ProfileManager::AddGroup(const QSharedPointer<Group> &ent) {
|
||||
@@ -277,4 +285,4 @@ namespace NekoRay {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace NekoRay
|
||||
@@ -51,4 +51,4 @@ namespace NekoRay {
|
||||
};
|
||||
|
||||
extern ProfileManager *profileManager;
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -22,4 +22,4 @@ namespace NekoRay {
|
||||
// 按 显示 顺序
|
||||
[[nodiscard]] QList<QSharedPointer<ProxyEntity>> ProfilesWithOrder() const;
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -22,11 +22,10 @@ namespace NekoRay {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProfileFilter::Common(const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<ProxyEntity >> &out,
|
||||
bool by_address, bool keep_last) {
|
||||
void ProfileFilter::Common(const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<ProxyEntity>> &out,
|
||||
bool by_address, bool keep_last) {
|
||||
QMap<QString, QSharedPointer<ProxyEntity>> hashMap;
|
||||
|
||||
for (const auto &ent: src) {
|
||||
@@ -65,13 +64,12 @@ namespace NekoRay {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProfileFilter::OnlyInSrc_ByPointer(const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<ProxyEntity>> &out) {
|
||||
void ProfileFilter::OnlyInSrc_ByPointer(const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<ProxyEntity>> &out) {
|
||||
for (const auto &ent: src) {
|
||||
if (!dst.contains(ent)) out += ent;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace NekoRay
|
||||
@@ -6,31 +6,30 @@ namespace NekoRay {
|
||||
class ProfileFilter {
|
||||
public:
|
||||
static void Uniq(
|
||||
const QList<QSharedPointer<ProxyEntity>> &in,
|
||||
QList<QSharedPointer<ProxyEntity>> &out,
|
||||
bool by_address = false, //def by bean
|
||||
bool keep_last = false //def keep first
|
||||
const QList<QSharedPointer<ProxyEntity>> &in,
|
||||
QList<QSharedPointer<ProxyEntity>> &out,
|
||||
bool by_address = false, // def by bean
|
||||
bool keep_last = false // def keep first
|
||||
);
|
||||
|
||||
static void Common(
|
||||
const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<ProxyEntity>> &out,
|
||||
bool by_address = false, //def by bean
|
||||
bool keep_last = false //def keep first
|
||||
const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<ProxyEntity>> &out,
|
||||
bool by_address = false, // def by bean
|
||||
bool keep_last = false // def keep first
|
||||
);
|
||||
|
||||
static void OnlyInSrc(
|
||||
const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<NekoRay::ProxyEntity>> &out,
|
||||
bool by_address = false //def by bean
|
||||
const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<NekoRay::ProxyEntity>> &out,
|
||||
bool by_address = false // def by bean
|
||||
);
|
||||
|
||||
static void OnlyInSrc_ByPointer(
|
||||
const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<ProxyEntity>> &out
|
||||
);
|
||||
const QList<QSharedPointer<ProxyEntity>> &src,
|
||||
const QList<QSharedPointer<ProxyEntity>> &dst,
|
||||
QList<QSharedPointer<ProxyEntity>> &out);
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace NekoRay {
|
||||
class CustomBean;
|
||||
|
||||
class ChainBean;
|
||||
};
|
||||
}; // namespace fmt
|
||||
|
||||
class ProxyEntity : public JsonStore {
|
||||
public:
|
||||
@@ -29,8 +29,7 @@ namespace NekoRay {
|
||||
int gid = 0;
|
||||
int latency = 0;
|
||||
QSharedPointer<fmt::AbstractBean> bean;
|
||||
QSharedPointer<traffic::TrafficData> traffic_data = QSharedPointer<traffic::TrafficData>(
|
||||
new traffic::TrafficData(""));
|
||||
QSharedPointer<traffic::TrafficData> traffic_data = QSharedPointer<traffic::TrafficData>(new traffic::TrafficData(""));
|
||||
|
||||
// Cache
|
||||
QString full_test_report;
|
||||
@@ -68,6 +67,5 @@ namespace NekoRay {
|
||||
[[nodiscard]] fmt::CustomBean *CustomBean() const {
|
||||
return (fmt::CustomBean *) bean.get();
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -37,4 +37,4 @@ namespace NekoRay::traffic {
|
||||
return QString("%1↑ %2↓").arg(ReadableSize(uplink), ReadableSize(downlink));
|
||||
}
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay::traffic
|
||||
|
||||
@@ -111,8 +111,7 @@ namespace NekoRay::traffic {
|
||||
runOnUiThread([=] {
|
||||
auto m = GetMainWindow();
|
||||
if (proxy != nullptr) {
|
||||
m->refresh_status(
|
||||
QObject::tr("Proxy: %1\nDirect: %2").arg(proxy->DisplaySpeed(), bypass->DisplaySpeed()));
|
||||
m->refresh_status(QObject::tr("Proxy: %1\nDirect: %2").arg(proxy->DisplaySpeed(), bypass->DisplaySpeed()));
|
||||
}
|
||||
for (const auto &item: items) {
|
||||
if (item->id < 0) continue;
|
||||
@@ -125,4 +124,4 @@ namespace NekoRay::traffic {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace NekoRay::traffic
|
||||
|
||||
@@ -28,4 +28,4 @@ namespace NekoRay::traffic {
|
||||
};
|
||||
|
||||
extern TrafficLooper *trafficLooper;
|
||||
}
|
||||
} // namespace NekoRay::traffic
|
||||
|
||||
@@ -20,7 +20,8 @@ namespace NekoRay::fmt {
|
||||
url.setScheme("nekoray");
|
||||
url.setHost(type);
|
||||
url.setFragment(QJsonObject2QString(b, true)
|
||||
.toUtf8().toBase64(QByteArray::Base64UrlEncoding));
|
||||
.toUtf8()
|
||||
.toBase64(QByteArray::Base64UrlEncoding));
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
@@ -72,4 +73,4 @@ namespace NekoRay::fmt {
|
||||
onFinished();
|
||||
});
|
||||
}
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -60,7 +60,6 @@ namespace NekoRay::fmt {
|
||||
virtual QString InsecureHint() { return {}; };
|
||||
|
||||
QString DisplayInsecureHint();
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace NekoRay::fmt {
|
||||
// https://sing-box.sagernet.org/configuration/shared/v2ray-transport
|
||||
|
||||
if (network != "tcp") {
|
||||
QJsonObject transport{{"type", network},};
|
||||
QJsonObject transport{{"type", network}};
|
||||
if (network == "ws") {
|
||||
if (!path.isEmpty()) transport["path"] = path;
|
||||
if (!host.isEmpty()) transport["headers"] = QJsonObject{{"Host", host}};
|
||||
@@ -36,8 +36,8 @@ namespace NekoRay::fmt {
|
||||
}
|
||||
if (!utls.isEmpty()) {
|
||||
tls["utls"] = QJsonObject{
|
||||
{"enabled", true},
|
||||
{"fingerprint", utls},
|
||||
{"enabled", true},
|
||||
{"fingerprint", utls},
|
||||
};
|
||||
}
|
||||
outbound->insert("tls", tls);
|
||||
@@ -88,12 +88,12 @@ namespace NekoRay::fmt {
|
||||
CoreObjOutboundBuildResult VMessBean::BuildCoreObjSingBox() {
|
||||
CoreObjOutboundBuildResult result;
|
||||
QJsonObject outbound{
|
||||
{"type", "vmess"},
|
||||
{"server", serverAddress},
|
||||
{"server_port", serverPort},
|
||||
{"uuid", uuid.trimmed()},
|
||||
{"alter_id", aid},
|
||||
{"security", security},
|
||||
{"type", "vmess"},
|
||||
{"server", serverAddress},
|
||||
{"server_port", serverPort},
|
||||
{"uuid", uuid.trimmed()},
|
||||
{"alter_id", aid},
|
||||
{"security", security},
|
||||
};
|
||||
|
||||
stream->BuildStreamSettingsSingBox(&outbound);
|
||||
@@ -104,9 +104,9 @@ namespace NekoRay::fmt {
|
||||
CoreObjOutboundBuildResult TrojanVLESSBean::BuildCoreObjSingBox() {
|
||||
CoreObjOutboundBuildResult result;
|
||||
QJsonObject outbound{
|
||||
{"type", proxy_type == proxy_VLESS ? "vless" : "trojan"},
|
||||
{"server", serverAddress},
|
||||
{"server_port", serverPort},
|
||||
{"type", proxy_type == proxy_VLESS ? "vless" : "trojan"},
|
||||
{"server", serverAddress},
|
||||
{"server_port", serverPort},
|
||||
};
|
||||
|
||||
QJsonObject settings;
|
||||
@@ -154,4 +154,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
#include "db/ProxyEntity.hpp"
|
||||
#include "fmt/includes.h"
|
||||
|
||||
#define MAKE_SETTINGS_STREAM_SETTINGS \
|
||||
if (!stream->packet_encoding.isEmpty()) settings["packetEncoding"] = stream->packet_encoding; \
|
||||
outbound["settings"] = settings; \
|
||||
auto streamSettings = stream->BuildStreamSettingsV2Ray(); \
|
||||
outbound["streamSettings"] = streamSettings;
|
||||
#define MAKE_SETTINGS_STREAM_SETTINGS \
|
||||
if (!stream->packet_encoding.isEmpty()) settings["packetEncoding"] = stream->packet_encoding; \
|
||||
outbound["settings"] = settings; \
|
||||
auto streamSettings = stream->BuildStreamSettingsV2Ray(); \
|
||||
outbound["streamSettings"] = streamSettings;
|
||||
|
||||
namespace NekoRay::fmt {
|
||||
QJsonObject V2rayStreamSettings::BuildStreamSettingsV2Ray() {
|
||||
QJsonObject streamSettings{
|
||||
{"network", network},
|
||||
};
|
||||
QJsonObject streamSettings{{"network", network}};
|
||||
|
||||
if (network == "ws") {
|
||||
QJsonObject ws;
|
||||
@@ -41,8 +39,8 @@ namespace NekoRay::fmt {
|
||||
QJsonObject header{{"type", header_type}};
|
||||
if (header_type == "http") {
|
||||
header["request"] = QJsonObject{
|
||||
{"path", QList2QJsonArray(path.split(","))},
|
||||
{"headers", QJsonObject{{"Host", QList2QJsonArray(host.split(","))}}},
|
||||
{"path", QList2QJsonArray(path.split(","))},
|
||||
{"headers", QJsonObject{{"Host", QList2QJsonArray(host.split(","))}}},
|
||||
};
|
||||
}
|
||||
streamSettings["tcpSettings"] = QJsonObject{{"header", header}};
|
||||
@@ -54,9 +52,9 @@ namespace NekoRay::fmt {
|
||||
if (!sni.trimmed().isEmpty()) tls["serverName"] = sni;
|
||||
if (!certificate.trimmed().isEmpty()) {
|
||||
tls["certificates"] = QJsonArray{
|
||||
QJsonObject{
|
||||
{"certificate", QList2QJsonArray(SplitLines(certificate.trimmed()))},
|
||||
},
|
||||
QJsonObject{
|
||||
{"certificate", QList2QJsonArray(SplitLines(certificate.trimmed()))},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (!alpn.trimmed().isEmpty()) {
|
||||
@@ -131,20 +129,17 @@ namespace NekoRay::fmt {
|
||||
QJsonObject outbound{{"protocol", "vmess"}};
|
||||
|
||||
QJsonObject settings{
|
||||
{"vnext", QJsonArray{
|
||||
QJsonObject{
|
||||
{"address", serverAddress},
|
||||
{"port", serverPort},
|
||||
{"users", QJsonArray{
|
||||
QJsonObject{
|
||||
{"id", uuid.trimmed()},
|
||||
{"alterId", aid},
|
||||
{"vnext", QJsonArray{
|
||||
QJsonObject{
|
||||
{"address", serverAddress},
|
||||
{"port", serverPort},
|
||||
{"users", QJsonArray{
|
||||
QJsonObject{
|
||||
{"id", uuid.trimmed()},
|
||||
{"alterId", aid},
|
||||
{"security", security},
|
||||
}
|
||||
}},
|
||||
}
|
||||
}}
|
||||
};
|
||||
}}},
|
||||
}}}};
|
||||
|
||||
MAKE_SETTINGS_STREAM_SETTINGS
|
||||
|
||||
@@ -155,35 +150,30 @@ namespace NekoRay::fmt {
|
||||
CoreObjOutboundBuildResult TrojanVLESSBean::BuildCoreObjV2Ray() {
|
||||
CoreObjOutboundBuildResult result;
|
||||
QJsonObject outbound{
|
||||
{"protocol", proxy_type == proxy_VLESS ? "vless" : "trojan"},
|
||||
{"protocol", proxy_type == proxy_VLESS ? "vless" : "trojan"},
|
||||
};
|
||||
|
||||
QJsonObject settings;
|
||||
if (proxy_type == proxy_VLESS) {
|
||||
settings = QJsonObject{
|
||||
{"vnext", QJsonArray{
|
||||
QJsonObject{
|
||||
{"address", serverAddress},
|
||||
{"port", serverPort},
|
||||
{"users", QJsonArray{
|
||||
QJsonObject{
|
||||
{"id", password.trimmed()},
|
||||
{"vnext", QJsonArray{
|
||||
QJsonObject{
|
||||
{"address", serverAddress},
|
||||
{"port", serverPort},
|
||||
{"users", QJsonArray{
|
||||
QJsonObject{
|
||||
{"id", password.trimmed()},
|
||||
{"encryption", "none"},
|
||||
}
|
||||
}},
|
||||
}
|
||||
}}
|
||||
};
|
||||
}}},
|
||||
}}}};
|
||||
} else {
|
||||
settings = QJsonObject{
|
||||
{"servers", QJsonArray{
|
||||
QJsonObject{
|
||||
{"address", serverAddress},
|
||||
{"port", serverPort},
|
||||
{"servers", QJsonArray{
|
||||
QJsonObject{
|
||||
{"address", serverAddress},
|
||||
{"port", serverPort},
|
||||
{"password", password},
|
||||
}
|
||||
}}
|
||||
};
|
||||
}}}};
|
||||
}
|
||||
|
||||
MAKE_SETTINGS_STREAM_SETTINGS
|
||||
@@ -201,4 +191,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
@@ -5,18 +5,18 @@
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
#define WriteTempFile(fn, data) \
|
||||
QDir dir; \
|
||||
if (!dir.exists("temp")) dir.mkdir("temp"); \
|
||||
QFile f(QString("temp/") + fn); \
|
||||
bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); \
|
||||
if (ok) { \
|
||||
f.write(data); \
|
||||
} else { \
|
||||
result.error = f.errorString(); \
|
||||
} \
|
||||
f.close(); \
|
||||
auto TempFile = QFileInfo(f).absoluteFilePath();
|
||||
#define WriteTempFile(fn, data) \
|
||||
QDir dir; \
|
||||
if (!dir.exists("temp")) dir.mkdir("temp"); \
|
||||
QFile f(QString("temp/") + fn); \
|
||||
bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); \
|
||||
if (ok) { \
|
||||
f.write(data); \
|
||||
} else { \
|
||||
result.error = f.errorString(); \
|
||||
} \
|
||||
f.close(); \
|
||||
auto TempFile = QFileInfo(f).absoluteFilePath();
|
||||
|
||||
namespace NekoRay::fmt {
|
||||
// 0: no external
|
||||
@@ -123,4 +123,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
@@ -62,19 +62,19 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString VMessBean::ToShareLink() {
|
||||
QJsonObject N{
|
||||
{"v", "2"},
|
||||
{"ps", name},
|
||||
{"add", serverAddress},
|
||||
{"port", Int2String(serverPort)},
|
||||
{"id", uuid},
|
||||
{"aid", Int2String(aid)},
|
||||
{"net", stream->network},
|
||||
{"host", stream->host},
|
||||
{"path", stream->path},
|
||||
{"type", stream->header_type},
|
||||
{"scy", security},
|
||||
{"tls", stream->security == "tls" ? "tls" : ""},
|
||||
{"sni", stream->sni},
|
||||
{"v", "2"},
|
||||
{"ps", name},
|
||||
{"add", serverAddress},
|
||||
{"port", Int2String(serverPort)},
|
||||
{"id", uuid},
|
||||
{"aid", Int2String(aid)},
|
||||
{"net", stream->network},
|
||||
{"host", stream->host},
|
||||
{"path", stream->path},
|
||||
{"type", stream->header_type},
|
||||
{"scy", security},
|
||||
{"tls", stream->security == "tls" ? "tls" : ""},
|
||||
{"sni", stream->sni},
|
||||
};
|
||||
return "vmess://" + QJsonObject2QString(N, false).toUtf8().toBase64();
|
||||
}
|
||||
@@ -90,4 +90,4 @@ namespace NekoRay::fmt {
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
@@ -15,4 +15,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString DisplayAddress() override { return ""; };
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -47,4 +47,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
@@ -15,9 +15,7 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString V2rayStreamSettings::InsecureHint() const {
|
||||
if (allow_insecure) {
|
||||
return QObject::tr(
|
||||
"The configuration (insecure) can be detected and identified, the transmission is fully visible to the censor and is not resistant to man-in-the-middle tampering with the content of the communication."
|
||||
);
|
||||
return QObject::tr("The configuration (insecure) can be detected and identified, the transmission is fully visible to the censor and is not resistant to man-in-the-middle tampering with the content of the communication.");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -27,25 +25,22 @@ namespace NekoRay::fmt {
|
||||
return {};
|
||||
}
|
||||
return QObject::tr(
|
||||
"This configuration (Shadowsocks streaming cipher) can be accurately proactively detected and decrypted by censors without requiring a password, and cannot be mitigated by turning on IV replay filters on the server side.\n"
|
||||
"\n"
|
||||
"Learn more: https://github.com/net4people/bbs/issues/24"
|
||||
);
|
||||
"This configuration (Shadowsocks streaming cipher) can be accurately proactively detected and decrypted by censors without requiring a password, and cannot be mitigated by turning on IV replay filters on the server side.\n"
|
||||
"\n"
|
||||
"Learn more: https://github.com/net4people/bbs/issues/24");
|
||||
}
|
||||
|
||||
QString VMessBean::InsecureHint() {
|
||||
if (security == "none" || security == "zero") {
|
||||
if (stream->security.isEmpty()) {
|
||||
return QObject::tr(
|
||||
"This profile is cleartext, don't use it if the server is not in your local network.");
|
||||
return QObject::tr("This profile is cleartext, don't use it if the server is not in your local network.");
|
||||
}
|
||||
}
|
||||
if (aid > 0) {
|
||||
return QObject::tr(
|
||||
"This configuration (VMess MD5 authentication) has been deprecated by upstream because of its questionable resistance to tampering and concealment.\n"
|
||||
"\n"
|
||||
"As of January 1, 2022, compatibility with MD5 authentication information will be disabled on the server side by default. Any client using MD5 authentication information will not be able to connect to a server with VMess MD5 authentication information disabled."
|
||||
);
|
||||
"This configuration (VMess MD5 authentication) has been deprecated by upstream because of its questionable resistance to tampering and concealment.\n"
|
||||
"\n"
|
||||
"As of January 1, 2022, compatibility with MD5 authentication information will be disabled on the server side by default. Any client using MD5 authentication information will not be able to connect to a server with VMess MD5 authentication information disabled.");
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -63,5 +58,4 @@ namespace NekoRay::fmt {
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
|
||||
namespace NekoRay::fmt {
|
||||
|
||||
#define DECODE_V2RAY_N_1 auto linkN = DecodeB64IfValid(SubStrBefore(SubStrAfter(link, "://"), "#"), QByteArray::Base64Option::Base64UrlEncoding); \
|
||||
if (linkN.isEmpty()) return false; \
|
||||
auto hasRemarks = link.contains("#"); \
|
||||
if (hasRemarks) linkN += "#" + SubStrAfter(link, "#"); \
|
||||
#define DECODE_V2RAY_N_1 \
|
||||
auto linkN = DecodeB64IfValid(SubStrBefore(SubStrAfter(link, "://"), "#"), QByteArray::Base64Option::Base64UrlEncoding); \
|
||||
if (linkN.isEmpty()) return false; \
|
||||
auto hasRemarks = link.contains("#"); \
|
||||
if (hasRemarks) linkN += "#" + SubStrAfter(link, "#"); \
|
||||
auto url = QUrl("https://" + linkN);
|
||||
|
||||
bool SocksHttpBean::TryParseLink(const QString &link) {
|
||||
@@ -149,4 +150,4 @@ namespace NekoRay::fmt {
|
||||
return !(username.isEmpty() || password.isEmpty());
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -35,4 +35,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString ToShareLink() override;
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
@@ -3,17 +3,18 @@
|
||||
namespace Preset {
|
||||
namespace Hysteria {
|
||||
inline const char *command = "--no-check -c %config%";
|
||||
inline const char *config = "{\n"
|
||||
" \"server\": \"127.0.0.1:%mapping_port%\",\n"
|
||||
" \"server_name\": \"example.com\",\n"
|
||||
" \"obfs\": \"fuck me till the daylight\",\n"
|
||||
" \"up_mbps\": 10,\n"
|
||||
" \"down_mbps\": 50,\n"
|
||||
" \"socks5\": {\n"
|
||||
" \"listen\": \"127.0.0.1:%socks_port%\"\n"
|
||||
" }\n"
|
||||
"}";
|
||||
}
|
||||
inline const char *config =
|
||||
"{\n"
|
||||
" \"server\": \"127.0.0.1:%mapping_port%\",\n"
|
||||
" \"server_name\": \"example.com\",\n"
|
||||
" \"obfs\": \"fuck me till the daylight\",\n"
|
||||
" \"up_mbps\": 10,\n"
|
||||
" \"down_mbps\": 50,\n"
|
||||
" \"socks5\": {\n"
|
||||
" \"listen\": \"127.0.0.1:%socks_port%\"\n"
|
||||
" }\n"
|
||||
"}";
|
||||
} // namespace Hysteria
|
||||
|
||||
namespace SingBox {
|
||||
inline QStringList VpnImplementation = {"gvisor", "system"};
|
||||
@@ -25,4 +26,4 @@ namespace Preset {
|
||||
"http={ip}:{http_port};https={ip}:{http_port};ftp={ip}:{http_port};socks={ip}:{socks_port}",
|
||||
"http=http://{ip}:{http_port};https=http://{ip}:{http_port}"};
|
||||
}
|
||||
}
|
||||
} // namespace Preset
|
||||
|
||||
@@ -33,4 +33,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString InsecureHint() override;
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -38,4 +38,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString InsecureHint() override;
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -34,4 +34,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString InsecureHint() override;
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
@@ -56,4 +56,4 @@ namespace NekoRay::fmt {
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
@@ -33,5 +33,4 @@ namespace NekoRay::fmt {
|
||||
|
||||
QString InsecureHint() override;
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace NekoRay::fmt
|
||||
|
||||
2
libs/format_cpp.sh
Executable file
2
libs/format_cpp.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
git ls-files | grep -E "\.cpp|\.h" | grep -v "3rdparty" | xargs -n1 clang-format -i
|
||||
@@ -30,5 +30,4 @@ namespace NekoRay {
|
||||
SING_BOX,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
// Utils
|
||||
|
||||
#define QRegExpValidator_Number new QRegularExpressionValidator(QRegularExpression("^[0-9]+$")
|
||||
#define QRegExpValidator_Number new QRegularExpressionValidator(QRegularExpression("^[0-9]+$"), this)
|
||||
|
||||
// NekoRay Save&Load
|
||||
|
||||
@@ -23,33 +23,38 @@
|
||||
#define P_C_SAVE_STRING(a) bean->a = CACHE.a;
|
||||
#define D_C_LOAD_STRING(a) CACHE.a = NekoRay::dataStore->a;
|
||||
#define D_C_SAVE_STRING(a) NekoRay::dataStore->a = CACHE.a;
|
||||
#define P_LOAD_INT(a) ui->a->setText(Int2String(bean->a)); ui->a->setValidator(QRegExpValidator_Number, this));
|
||||
#define P_LOAD_INT(a) \
|
||||
ui->a->setText(Int2String(bean->a)); \
|
||||
ui->a->setValidator(QRegExpValidator_Number);
|
||||
#define P_SAVE_INT(a) bean->a = ui->a->text().toInt();
|
||||
#define D_LOAD_INT(a) ui->a->setText(Int2String(NekoRay::dataStore->a)); ui->a->setValidator(QRegExpValidator_Number, this));
|
||||
#define D_LOAD_INT(a) \
|
||||
ui->a->setText(Int2String(NekoRay::dataStore->a)); \
|
||||
ui->a->setValidator(QRegExpValidator_Number);
|
||||
#define D_SAVE_INT(a) NekoRay::dataStore->a = ui->a->text().toInt();
|
||||
#define P_LOAD_COMBO(a) ui->a->setCurrentText(bean->a);
|
||||
#define P_SAVE_COMBO(a) bean->a = ui->a->currentText();
|
||||
#define D_LOAD_BOOL(a) ui->a->setChecked(NekoRay::dataStore->a);
|
||||
#define D_SAVE_BOOL(a) NekoRay::dataStore->a = ui->a->isChecked();
|
||||
|
||||
#define D_LOAD_INT_ENABLE(i, e) \
|
||||
if (NekoRay::dataStore->i > 0) { \
|
||||
ui->e->setChecked(true); \
|
||||
ui->i->setText(Int2String(NekoRay::dataStore->i)); \
|
||||
} else { \
|
||||
ui->e->setChecked(false); \
|
||||
ui->i->setText(Int2String(-NekoRay::dataStore->i)); \
|
||||
} \
|
||||
ui->i->setValidator(QRegExpValidator_Number, this));
|
||||
#define D_SAVE_INT_ENABLE(i, e) \
|
||||
if (ui->e->isChecked()) { \
|
||||
NekoRay::dataStore->i = ui->i->text().toInt(); \
|
||||
} else { \
|
||||
NekoRay::dataStore->i = -ui->i->text().toInt(); \
|
||||
}
|
||||
#define D_LOAD_INT_ENABLE(i, e) \
|
||||
if (NekoRay::dataStore->i > 0) { \
|
||||
ui->e->setChecked(true); \
|
||||
ui->i->setText(Int2String(NekoRay::dataStore->i)); \
|
||||
} else { \
|
||||
ui->e->setChecked(false); \
|
||||
ui->i->setText(Int2String(-NekoRay::dataStore->i)); \
|
||||
} \
|
||||
ui->i->setValidator(QRegExpValidator_Number);
|
||||
#define D_SAVE_INT_ENABLE(i, e) \
|
||||
if (ui->e->isChecked()) { \
|
||||
NekoRay::dataStore->i = ui->i->text().toInt(); \
|
||||
} else { \
|
||||
NekoRay::dataStore->i = -ui->i->text().toInt(); \
|
||||
}
|
||||
|
||||
#define C_EDIT_JSON_ALLOW_EMPTY(a) auto editor = new JsonEditor(QString2QJsonObject(CACHE.a), this); \
|
||||
auto result = editor->OpenEditor(); \
|
||||
CACHE.a = QJsonObject2QString(result, true); \
|
||||
if (result.isEmpty()) CACHE.a = ""; \
|
||||
editor->deleteLater();
|
||||
#define C_EDIT_JSON_ALLOW_EMPTY(a) \
|
||||
auto editor = new JsonEditor(QString2QJsonObject(CACHE.a), this); \
|
||||
auto result = editor->OpenEditor(); \
|
||||
CACHE.a = QJsonObject2QString(result, true); \
|
||||
if (result.isEmpty()) CACHE.a = ""; \
|
||||
editor->deleteLater();
|
||||
|
||||
@@ -76,18 +76,20 @@ namespace NekoRay {
|
||||
// preset routing
|
||||
Routing::Routing(int preset) : JsonStore() {
|
||||
if (preset == 1) {
|
||||
direct_ip = "geoip:cn\n"
|
||||
"geoip:private";
|
||||
direct_ip =
|
||||
"geoip:cn\n"
|
||||
"geoip:private";
|
||||
direct_domain = "geosite:cn";
|
||||
proxy_ip = "";
|
||||
proxy_domain = "";
|
||||
block_ip = "";
|
||||
block_domain = "geosite:category-ads-all\n"
|
||||
"domain:appcenter.ms\n"
|
||||
"domain:app-measurement.com\n"
|
||||
"domain:firebase.io\n"
|
||||
"domain:crashlytics.com\n"
|
||||
"domain:google-analytics.com";
|
||||
block_domain =
|
||||
"geosite:category-ads-all\n"
|
||||
"domain:appcenter.ms\n"
|
||||
"domain:app-measurement.com\n"
|
||||
"domain:firebase.io\n"
|
||||
"domain:crashlytics.com\n"
|
||||
"domain:google-analytics.com";
|
||||
}
|
||||
_add(new configItem("direct_ip", &this->direct_ip, itemType::string));
|
||||
_add(new configItem("direct_domain", &this->direct_domain, itemType::string));
|
||||
@@ -100,12 +102,12 @@ namespace NekoRay {
|
||||
|
||||
QString Routing::toString() const {
|
||||
return QString("[Proxy] %1\n[Proxy] %2\n[Direct] %3\n[Direct] %4\n[Block] %5\n[Block] %6")
|
||||
.arg(SplitLines(proxy_domain).join(","))
|
||||
.arg(SplitLines(proxy_ip).join(","))
|
||||
.arg(SplitLines(direct_domain).join(","))
|
||||
.arg(SplitLines(direct_ip).join(","))
|
||||
.arg(SplitLines(block_domain).join(","))
|
||||
.arg(SplitLines(block_ip).join(","));
|
||||
.arg(SplitLines(proxy_domain).join(","))
|
||||
.arg(SplitLines(proxy_ip).join(","))
|
||||
.arg(SplitLines(direct_domain).join(","))
|
||||
.arg(SplitLines(direct_ip).join(","))
|
||||
.arg(SplitLines(block_domain).join(","))
|
||||
.arg(SplitLines(block_ip).join(","));
|
||||
}
|
||||
|
||||
QStringList Routing::List() {
|
||||
@@ -353,4 +355,4 @@ namespace NekoRay {
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -60,4 +60,4 @@ namespace NekoRay {
|
||||
|
||||
bool Load();
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace NekoRay {
|
||||
int test_concurrent = 5;
|
||||
int traffic_loop_interval = 500;
|
||||
bool connection_statistics = false;
|
||||
int current_group = 0; //group id
|
||||
int current_group = 0; // group id
|
||||
int mux_cool = -8;
|
||||
QString theme = "0";
|
||||
QString v2ray_asset_dir = "";
|
||||
@@ -137,8 +137,8 @@ namespace NekoRay {
|
||||
|
||||
inline int coreType = NekoRay::CoreType::V2RAY;
|
||||
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
#define IS_NEKO_BOX (NekoRay::coreType == NekoRay::CoreType::SING_BOX)
|
||||
#define ROUTES_PREFIX_NAME QString( IS_NEKO_BOX ? "routes_box" : "routes" )
|
||||
#define ROUTES_PREFIX QString( ROUTES_PREFIX_NAME + "/" )
|
||||
#define ROUTES_PREFIX_NAME QString(IS_NEKO_BOX ? "routes_box" : "routes")
|
||||
#define ROUTES_PREFIX QString(ROUTES_PREFIX_NAME + "/")
|
||||
|
||||
@@ -24,9 +24,14 @@ inline std::function<void(QString, QString)> MW_dialog_message;
|
||||
|
||||
// Utils
|
||||
|
||||
#define QJSONARRAY_ADD(arr, add) for(const auto &a: (add)) { (arr) += a; }
|
||||
#define QJSONOBJECT_COPY(src, dst, key) if (src.contains(key)) dst[key] = src[key];
|
||||
#define QJSONOBJECT_COPY2(src, dst, src_key, dst_key) if (src.contains(src_key)) dst[dst_key] = src[src_key];
|
||||
#define QJSONARRAY_ADD(arr, add) \
|
||||
for (const auto &a: (add)) { \
|
||||
(arr) += a; \
|
||||
}
|
||||
#define QJSONOBJECT_COPY(src, dst, key) \
|
||||
if (src.contains(key)) dst[key] = src[key];
|
||||
#define QJSONOBJECT_COPY2(src, dst, src_key, dst_key) \
|
||||
if (src.contains(src_key)) dst[dst_key] = src[src_key];
|
||||
|
||||
#define Int2String(num) QString::number(num)
|
||||
|
||||
|
||||
@@ -82,8 +82,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// icons
|
||||
QIcon::setFallbackSearchPaths(QStringList{
|
||||
":/nekoray",
|
||||
":/icon",
|
||||
":/nekoray",
|
||||
":/icon",
|
||||
});
|
||||
|
||||
// icon for no theme
|
||||
@@ -155,7 +155,7 @@ int main(int argc, char *argv[]) {
|
||||
QCoreApplication::installTranslator(&trans_qt);
|
||||
}
|
||||
|
||||
//Signals
|
||||
// Signals
|
||||
signal(SIGTERM, signal_handler);
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
|
||||
@@ -25,11 +25,10 @@ namespace Qv2ray::components::proxy {
|
||||
|
||||
using ProcessArgument = QPair<QString, QStringList>;
|
||||
#ifdef Q_OS_MACOS
|
||||
QStringList macOSgetNetworkServices()
|
||||
{
|
||||
QStringList macOSgetNetworkServices() {
|
||||
QProcess p;
|
||||
p.setProgram("/usr/sbin/networksetup");
|
||||
p.setArguments(QStringList{ "-listallnetworkservices" });
|
||||
p.setArguments(QStringList{"-listallnetworkservices"});
|
||||
p.start();
|
||||
p.waitForStarted();
|
||||
p.waitForFinished();
|
||||
@@ -39,11 +38,9 @@ namespace Qv2ray::components::proxy {
|
||||
QStringList result;
|
||||
|
||||
// Start from 1 since first line is unneeded.
|
||||
for (auto i = 1; i < lines.count(); i++)
|
||||
{
|
||||
for (auto i = 1; i < lines.count(); i++) {
|
||||
// * means disabled.
|
||||
if (!lines[i].contains("*"))
|
||||
{
|
||||
if (!lines[i].contains("*")) {
|
||||
result << lines[i];
|
||||
}
|
||||
}
|
||||
@@ -58,8 +55,7 @@ namespace Qv2ray::components::proxy {
|
||||
// NO_CONST(L"DefaultConnectionSettings");
|
||||
///
|
||||
/// INTERNAL FUNCTION
|
||||
bool __QueryProxyOptions()
|
||||
{
|
||||
bool __QueryProxyOptions() {
|
||||
INTERNET_PER_CONN_OPTION_LIST List;
|
||||
INTERNET_PER_CONN_OPTION Option[5];
|
||||
//
|
||||
@@ -76,45 +72,37 @@ namespace Qv2ray::components::proxy {
|
||||
List.dwOptionError = 0;
|
||||
List.pOptions = Option;
|
||||
|
||||
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
|
||||
{
|
||||
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) {
|
||||
LOG("InternetQueryOption failed, GLE=" + QSTRN(GetLastError()));
|
||||
}
|
||||
|
||||
LOG("System default proxy info:");
|
||||
|
||||
if (Option[0].Value.pszValue != nullptr)
|
||||
{
|
||||
if (Option[0].Value.pszValue != nullptr) {
|
||||
LOG(QString::fromWCharArray(Option[0].Value.pszValue));
|
||||
}
|
||||
|
||||
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL)
|
||||
{
|
||||
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_PROXY_URL) == PROXY_TYPE_AUTO_PROXY_URL) {
|
||||
LOG("PROXY_TYPE_AUTO_PROXY_URL");
|
||||
}
|
||||
|
||||
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT)
|
||||
{
|
||||
if ((Option[2].Value.dwValue & PROXY_TYPE_AUTO_DETECT) == PROXY_TYPE_AUTO_DETECT) {
|
||||
LOG("PROXY_TYPE_AUTO_DETECT");
|
||||
}
|
||||
|
||||
if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT)
|
||||
{
|
||||
if ((Option[2].Value.dwValue & PROXY_TYPE_DIRECT) == PROXY_TYPE_DIRECT) {
|
||||
LOG("PROXY_TYPE_DIRECT");
|
||||
}
|
||||
|
||||
if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY)
|
||||
{
|
||||
if ((Option[2].Value.dwValue & PROXY_TYPE_PROXY) == PROXY_TYPE_PROXY) {
|
||||
LOG("PROXY_TYPE_PROXY");
|
||||
}
|
||||
|
||||
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize))
|
||||
{
|
||||
if (!InternetQueryOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &List, &nSize)) {
|
||||
LOG("InternetQueryOption failed,GLE=" + QSTRN(GetLastError()));
|
||||
}
|
||||
|
||||
if (Option[4].Value.pszValue != nullptr)
|
||||
{
|
||||
if (Option[4].Value.pszValue != nullptr) {
|
||||
LOG(QString::fromStdWString(Option[4].Value.pszValue));
|
||||
}
|
||||
|
||||
@@ -122,25 +110,21 @@ namespace Qv2ray::components::proxy {
|
||||
nSize = sizeof(INTERNET_VERSION_INFO);
|
||||
InternetQueryOption(nullptr, INTERNET_OPTION_VERSION, &Version, &nSize);
|
||||
|
||||
if (Option[0].Value.pszValue != nullptr)
|
||||
{
|
||||
if (Option[0].Value.pszValue != nullptr) {
|
||||
GlobalFree(Option[0].Value.pszValue);
|
||||
}
|
||||
|
||||
if (Option[3].Value.pszValue != nullptr)
|
||||
{
|
||||
if (Option[3].Value.pszValue != nullptr) {
|
||||
GlobalFree(Option[3].Value.pszValue);
|
||||
}
|
||||
|
||||
if (Option[4].Value.pszValue != nullptr)
|
||||
{
|
||||
if (Option[4].Value.pszValue != nullptr) {
|
||||
GlobalFree(Option[4].Value.pszValue);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool __SetProxyOptions(LPWSTR proxy_full_addr, bool isPAC)
|
||||
{
|
||||
bool __SetProxyOptions(LPWSTR proxy_full_addr, bool isPAC) {
|
||||
INTERNET_PER_CONN_OPTION_LIST list;
|
||||
DWORD dwBufSize = sizeof(list);
|
||||
// Fill the list structure.
|
||||
@@ -148,16 +132,14 @@ namespace Qv2ray::components::proxy {
|
||||
// NULL == LAN, otherwise connectoid name.
|
||||
list.pszConnection = nullptr;
|
||||
|
||||
if (nullptr == proxy_full_addr)
|
||||
{
|
||||
if (nullptr == proxy_full_addr) {
|
||||
LOG("Clearing system proxy");
|
||||
//
|
||||
list.dwOptionCount = 1;
|
||||
list.pOptions = new INTERNET_PER_CONN_OPTION[1];
|
||||
|
||||
// Ensure that the memory was allocated.
|
||||
if (nullptr == list.pOptions)
|
||||
{
|
||||
if (nullptr == list.pOptions) {
|
||||
// Return if the memory wasn't allocated.
|
||||
return false;
|
||||
}
|
||||
@@ -165,16 +147,13 @@ namespace Qv2ray::components::proxy {
|
||||
// Set flags.
|
||||
list.pOptions[0].dwOption = INTERNET_PER_CONN_FLAGS;
|
||||
list.pOptions[0].Value.dwValue = PROXY_TYPE_DIRECT;
|
||||
}
|
||||
else if (isPAC)
|
||||
{
|
||||
} else if (isPAC) {
|
||||
LOG("Setting system proxy for PAC");
|
||||
//
|
||||
list.dwOptionCount = 2;
|
||||
list.pOptions = new INTERNET_PER_CONN_OPTION[2];
|
||||
|
||||
if (nullptr == list.pOptions)
|
||||
{
|
||||
if (nullptr == list.pOptions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -184,16 +163,13 @@ namespace Qv2ray::components::proxy {
|
||||
// Set proxy name.
|
||||
list.pOptions[1].dwOption = INTERNET_PER_CONN_AUTOCONFIG_URL;
|
||||
list.pOptions[1].Value.pszValue = proxy_full_addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG("Setting system proxy for Global Proxy");
|
||||
//
|
||||
list.dwOptionCount = 2;
|
||||
list.pOptions = new INTERNET_PER_CONN_OPTION[2];
|
||||
|
||||
if (nullptr == list.pOptions)
|
||||
{
|
||||
if (nullptr == list.pOptions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -210,8 +186,7 @@ namespace Qv2ray::components::proxy {
|
||||
}
|
||||
|
||||
// Set proxy for LAN.
|
||||
if (!InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize))
|
||||
{
|
||||
if (!InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize)) {
|
||||
LOG("InternetSetOption failed for LAN, GLE=" + QSTRN(GetLastError()));
|
||||
}
|
||||
|
||||
@@ -221,25 +196,21 @@ namespace Qv2ray::components::proxy {
|
||||
DWORD size = sizeof(entry), count;
|
||||
LPRASENTRYNAME entryAddr = &entry;
|
||||
auto ret = RasEnumEntries(nullptr, nullptr, entryAddr, &size, &count);
|
||||
if (ERROR_BUFFER_TOO_SMALL == ret)
|
||||
{
|
||||
if (ERROR_BUFFER_TOO_SMALL == ret) {
|
||||
entries.resize(count);
|
||||
entries[0].dwSize = sizeof(RASENTRYNAME);
|
||||
entryAddr = entries.data();
|
||||
ret = RasEnumEntries(nullptr, nullptr, entryAddr, &size, &count);
|
||||
}
|
||||
if (ERROR_SUCCESS != ret)
|
||||
{
|
||||
if (ERROR_SUCCESS != ret) {
|
||||
LOG("Failed to list entry names");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set proxy for each connectoid.
|
||||
for (DWORD i = 0; i < count; ++i)
|
||||
{
|
||||
for (DWORD i = 0; i < count; ++i) {
|
||||
list.pszConnection = entryAddr[i].szEntryName;
|
||||
if (!InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize))
|
||||
{
|
||||
if (!InternetSetOption(nullptr, INTERNET_OPTION_PER_CONNECTION_OPTION, &list, dwBufSize)) {
|
||||
LOG("InternetSetOption failed for connectoid " + QString::fromWCharArray(list.pszConnection) + ", GLE=" + QSTRN(GetLastError()));
|
||||
}
|
||||
}
|
||||
@@ -251,19 +222,16 @@ namespace Qv2ray::components::proxy {
|
||||
}
|
||||
#endif
|
||||
|
||||
void SetSystemProxy(int httpPort, int socksPort) {
|
||||
void SetSystemProxy(int httpPort, int socksPort) {
|
||||
const QString &address = "127.0.0.1";
|
||||
bool hasHTTP = (httpPort > 0 && httpPort < 65536);
|
||||
bool hasSOCKS = (socksPort > 0 && socksPort < 65536);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (!hasHTTP)
|
||||
{
|
||||
if (!hasHTTP) {
|
||||
LOG("Nothing?");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
LOG("Qv2ray will set system proxy to use HTTP");
|
||||
}
|
||||
#else
|
||||
@@ -285,8 +253,8 @@ void SetSystemProxy(int httpPort, int socksPort) {
|
||||
QString str = NekoRay::dataStore->system_proxy_format;
|
||||
if (str.isEmpty()) str = Preset::Windows::system_proxy_format[0];
|
||||
str = str.replace("{ip}", address)
|
||||
.replace("{http_port}", Int2String(httpPort))
|
||||
.replace("{socks_port}", Int2String(socksPort));
|
||||
.replace("{http_port}", Int2String(httpPort))
|
||||
.replace("{socks_port}", Int2String(socksPort));
|
||||
//
|
||||
LOG("Windows proxy string: " + str);
|
||||
auto proxyStrW = new WCHAR[str.length() + 1];
|
||||
@@ -294,8 +262,7 @@ void SetSystemProxy(int httpPort, int socksPort) {
|
||||
//
|
||||
__QueryProxyOptions();
|
||||
|
||||
if (!__SetProxyOptions(proxyStrW, false))
|
||||
{
|
||||
if (!__SetProxyOptions(proxyStrW, false)) {
|
||||
LOG("Failed to set proxy.");
|
||||
}
|
||||
|
||||
@@ -392,21 +359,18 @@ void SetSystemProxy(int httpPort, int socksPort) {
|
||||
}
|
||||
#else
|
||||
|
||||
for (const auto &service : macOSgetNetworkServices())
|
||||
{
|
||||
for (const auto &service: macOSgetNetworkServices()) {
|
||||
LOG("Setting proxy for interface: " + service);
|
||||
if (hasHTTP)
|
||||
{
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setwebproxystate", service, "on" });
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setsecurewebproxystate", service, "on" });
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setwebproxy", service, address, QSTRN(httpPort) });
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setsecurewebproxy", service, address, QSTRN(httpPort) });
|
||||
if (hasHTTP) {
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setwebproxystate", service, "on"});
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setsecurewebproxystate", service, "on"});
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setwebproxy", service, address, QSTRN(httpPort)});
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setsecurewebproxy", service, address, QSTRN(httpPort)});
|
||||
}
|
||||
|
||||
if (hasSOCKS)
|
||||
{
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setsocksfirewallproxystate", service, "on" });
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setsocksfirewallproxy", service, address, QSTRN(socksPort) });
|
||||
if (hasSOCKS) {
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setsocksfirewallproxystate", service, "on"});
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setsocksfirewallproxy", service, address, QSTRN(socksPort)});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,8 +381,7 @@ void SetSystemProxy(int httpPort, int socksPort) {
|
||||
LOG("Clearing System Proxy");
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
if (!__SetProxyOptions(nullptr, false))
|
||||
{
|
||||
if (!__SetProxyOptions(nullptr, false)) {
|
||||
LOG("Failed to clear proxy.");
|
||||
}
|
||||
#elif defined(Q_OS_LINUX)
|
||||
@@ -460,13 +423,12 @@ void SetSystemProxy(int httpPort, int socksPort) {
|
||||
}
|
||||
|
||||
#else
|
||||
for (const auto &service : macOSgetNetworkServices())
|
||||
{
|
||||
for (const auto &service: macOSgetNetworkServices()) {
|
||||
LOG("Clearing proxy for interface: " + service);
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setautoproxystate", service, "off" });
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setwebproxystate", service, "off" });
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setsecurewebproxystate", service, "off" });
|
||||
QProcess::execute("/usr/sbin/networksetup", { "-setsocksfirewallproxystate", service, "off" });
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setautoproxystate", service, "off"});
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setwebproxystate", service, "off"});
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setsecurewebproxystate", service, "off"});
|
||||
QProcess::execute("/usr/sbin/networksetup", {"-setsocksfirewallproxystate", service, "off"});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
//
|
||||
namespace Qv2ray::components::proxy
|
||||
{
|
||||
namespace Qv2ray::components::proxy {
|
||||
void ClearSystemProxy();
|
||||
void SetSystemProxy(int http_port, int socks_port);
|
||||
} // namespace Qv2ray::components::proxy
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "LogHighlighter.hpp"
|
||||
|
||||
#define TO_EOL "(([\\s\\S]*)|([\\d\\D]*)|([\\w\\W]*))$"
|
||||
#define REGEX_IPV6_ADDR \
|
||||
#define REGEX_IPV6_ADDR \
|
||||
R"(\[\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*\])"
|
||||
#define REGEX_IPV4_ADDR \
|
||||
#define REGEX_IPV4_ADDR \
|
||||
R"((\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5]))"
|
||||
#define REGEX_PORT_NUMBER R"(([0-9]|[1-9]\d{1,3}|[1-5]\d{4}|6[0-5]{2}[0-3][0-5])*)"
|
||||
|
||||
@@ -107,8 +107,7 @@ namespace Qv2ray::ui {
|
||||
rule.format = ipHostFormat;
|
||||
highlightingRules.append(rule);
|
||||
//
|
||||
rule.pattern = QRegularExpression(
|
||||
"([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/|):" REGEX_PORT_NUMBER);
|
||||
rule.pattern = QRegularExpression("([a-zA-Z0-9]([a-zA-Z0-9\\-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,6}(/|):" REGEX_PORT_NUMBER);
|
||||
rule.pattern.setPatternOptions(QRegularExpression::PatternOption::ExtendedPatternSyntaxOption);
|
||||
rule.format = ipHostFormat;
|
||||
highlightingRules.append(rule);
|
||||
@@ -120,7 +119,6 @@ namespace Qv2ray::ui {
|
||||
rule.format = tcpudpFormat;
|
||||
highlightingRules.append(rule);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SyntaxHighlighter::highlightBlock(const QString &text) {
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
|
||||
namespace Qv2ray::ui {
|
||||
class SyntaxHighlighter : public QSyntaxHighlighter {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SyntaxHighlighter(bool darkMode, QTextDocument *parent = nullptr);
|
||||
|
||||
@@ -61,10 +61,8 @@
|
||||
#include <QToolTip>
|
||||
#include <QtDebug>
|
||||
|
||||
namespace Qv2ray::ui::widgets
|
||||
{
|
||||
AutoCompleteTextEdit::AutoCompleteTextEdit(const QString &prefix, const QStringList &sourceStrings, QWidget *parent) : QPlainTextEdit(parent)
|
||||
{
|
||||
namespace Qv2ray::ui::widgets {
|
||||
AutoCompleteTextEdit::AutoCompleteTextEdit(const QString &prefix, const QStringList &sourceStrings, QWidget *parent) : QPlainTextEdit(parent) {
|
||||
this->prefix = prefix;
|
||||
this->setLineWrapMode(QPlainTextEdit::NoWrap);
|
||||
c = new QCompleter(this);
|
||||
@@ -75,12 +73,10 @@ namespace Qv2ray::ui::widgets
|
||||
QObject::connect(c, QOverload<const QString &>::of(&QCompleter::activated), this, &AutoCompleteTextEdit::insertCompletion);
|
||||
}
|
||||
|
||||
AutoCompleteTextEdit::~AutoCompleteTextEdit()
|
||||
{
|
||||
AutoCompleteTextEdit::~AutoCompleteTextEdit() {
|
||||
}
|
||||
|
||||
void AutoCompleteTextEdit::insertCompletion(const QString &completion)
|
||||
{
|
||||
void AutoCompleteTextEdit::insertCompletion(const QString &completion) {
|
||||
QTextCursor tc = textCursor();
|
||||
int extra = completion.length() - c->completionPrefix().length();
|
||||
tc.movePosition(QTextCursor::Left);
|
||||
@@ -89,30 +85,26 @@ namespace Qv2ray::ui::widgets
|
||||
setTextCursor(tc);
|
||||
}
|
||||
|
||||
QString AutoCompleteTextEdit::lineUnderCursor() const
|
||||
{
|
||||
QString AutoCompleteTextEdit::lineUnderCursor() const {
|
||||
QTextCursor tc = textCursor();
|
||||
tc.select(QTextCursor::LineUnderCursor);
|
||||
return tc.selectedText();
|
||||
}
|
||||
|
||||
QString AutoCompleteTextEdit::wordUnderCursor() const
|
||||
{
|
||||
QString AutoCompleteTextEdit::wordUnderCursor() const {
|
||||
QTextCursor tc = textCursor();
|
||||
tc.select(QTextCursor::WordUnderCursor);
|
||||
return tc.selectedText();
|
||||
}
|
||||
|
||||
void AutoCompleteTextEdit::focusInEvent(QFocusEvent *e)
|
||||
{
|
||||
void AutoCompleteTextEdit::focusInEvent(QFocusEvent *e) {
|
||||
if (c)
|
||||
c->setWidget(this);
|
||||
|
||||
QPlainTextEdit::focusInEvent(e);
|
||||
}
|
||||
|
||||
void AutoCompleteTextEdit::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
void AutoCompleteTextEdit::keyPressEvent(QKeyEvent *e) {
|
||||
const bool hasCtrlOrShiftModifier = e->modifiers().testFlag(Qt::ControlModifier) || e->modifiers().testFlag(Qt::ShiftModifier);
|
||||
const bool hasOtherModifiers = (e->modifiers() != Qt::NoModifier) && !hasCtrlOrShiftModifier; // has other modifiers
|
||||
//
|
||||
@@ -121,24 +113,24 @@ namespace Qv2ray::ui::widgets
|
||||
const bool isTab = (e->modifiers().testFlag(Qt::NoModifier) && e->key() == Qt::Key_Tab);
|
||||
const bool isOtherSpace = e->text() == " ";
|
||||
//
|
||||
if (isSpace || isTab || isOtherSpace)
|
||||
{
|
||||
if (isSpace || isTab || isOtherSpace) {
|
||||
QToolTip::showText(this->mapToGlobal(QPoint(0, 0)), tr("You can not input space characters here."), this, QRect{}, 2000);
|
||||
return;
|
||||
}
|
||||
//
|
||||
if (c && c->popup()->isVisible())
|
||||
{
|
||||
if (c && c->popup()->isVisible()) {
|
||||
// The following keys are forwarded by the completer to the widget
|
||||
switch (e->key())
|
||||
{
|
||||
switch (e->key()) {
|
||||
case Qt::Key_Enter:
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Escape:
|
||||
case Qt::Key_Tab:
|
||||
case Qt::Key_Backtab: e->ignore(); return; // let the completer do default behavior
|
||||
case Qt::Key_Backtab:
|
||||
e->ignore();
|
||||
return; // let the completer do default behavior
|
||||
|
||||
default: break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,14 +140,12 @@ namespace Qv2ray::ui::widgets
|
||||
return;
|
||||
|
||||
// if we have other modifiers, or the text is empty, or the line does not start with our prefix.
|
||||
if (hasOtherModifiers || e->text().isEmpty() || !lineUnderCursor().startsWith(prefix))
|
||||
{
|
||||
if (hasOtherModifiers || e->text().isEmpty() || !lineUnderCursor().startsWith(prefix)) {
|
||||
c->popup()->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
if (auto word = wordUnderCursor(); word != c->completionPrefix())
|
||||
{
|
||||
if (auto word = wordUnderCursor(); word != c->completionPrefix()) {
|
||||
c->setCompletionPrefix(word);
|
||||
c->popup()->setCurrentIndex(c->completionModel()->index(0, 0));
|
||||
}
|
||||
|
||||
@@ -55,24 +55,22 @@ QT_BEGIN_NAMESPACE
|
||||
class QCompleter;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Qv2ray::ui::widgets
|
||||
{
|
||||
class AutoCompleteTextEdit : public QPlainTextEdit
|
||||
{
|
||||
namespace Qv2ray::ui::widgets {
|
||||
class AutoCompleteTextEdit : public QPlainTextEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
public:
|
||||
AutoCompleteTextEdit(const QString &prefix, const QStringList &sourceStrings, QWidget *parent = nullptr);
|
||||
~AutoCompleteTextEdit();
|
||||
|
||||
protected:
|
||||
protected:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
void focusInEvent(QFocusEvent *e) override;
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void insertCompletion(const QString &completion);
|
||||
|
||||
private:
|
||||
private:
|
||||
QString lineUnderCursor() const;
|
||||
QString wordUnderCursor() const;
|
||||
|
||||
|
||||
@@ -27,107 +27,86 @@
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
|
||||
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent)
|
||||
{
|
||||
QJsonTreeItem::QJsonTreeItem(QJsonTreeItem *parent) {
|
||||
mParent = parent;
|
||||
}
|
||||
|
||||
QJsonTreeItem::~QJsonTreeItem()
|
||||
{
|
||||
QJsonTreeItem::~QJsonTreeItem() {
|
||||
qDeleteAll(mChilds);
|
||||
}
|
||||
|
||||
void QJsonTreeItem::appendChild(QJsonTreeItem *item)
|
||||
{
|
||||
void QJsonTreeItem::appendChild(QJsonTreeItem *item) {
|
||||
mChilds.append(item);
|
||||
}
|
||||
|
||||
QJsonTreeItem *QJsonTreeItem::child(int row)
|
||||
{
|
||||
QJsonTreeItem *QJsonTreeItem::child(int row) {
|
||||
return mChilds.value(row);
|
||||
}
|
||||
|
||||
QJsonTreeItem *QJsonTreeItem::parent()
|
||||
{
|
||||
QJsonTreeItem *QJsonTreeItem::parent() {
|
||||
return mParent;
|
||||
}
|
||||
|
||||
int QJsonTreeItem::childCount() const
|
||||
{
|
||||
int QJsonTreeItem::childCount() const {
|
||||
return mChilds.count();
|
||||
}
|
||||
|
||||
int QJsonTreeItem::row() const
|
||||
{
|
||||
int QJsonTreeItem::row() const {
|
||||
if (mParent)
|
||||
return mParent->mChilds.indexOf(const_cast<QJsonTreeItem *>(this));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void QJsonTreeItem::setKey(const QString &key)
|
||||
{
|
||||
void QJsonTreeItem::setKey(const QString &key) {
|
||||
mKey = key;
|
||||
}
|
||||
|
||||
void QJsonTreeItem::setValue(const QString &value)
|
||||
{
|
||||
void QJsonTreeItem::setValue(const QString &value) {
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
void QJsonTreeItem::setType(const QJsonValue::Type &type)
|
||||
{
|
||||
void QJsonTreeItem::setType(const QJsonValue::Type &type) {
|
||||
mType = type;
|
||||
}
|
||||
|
||||
QString QJsonTreeItem::key() const
|
||||
{
|
||||
QString QJsonTreeItem::key() const {
|
||||
return mKey;
|
||||
}
|
||||
|
||||
QString QJsonTreeItem::value() const
|
||||
{
|
||||
QString QJsonTreeItem::value() const {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
QJsonValue::Type QJsonTreeItem::type() const
|
||||
{
|
||||
QJsonValue::Type QJsonTreeItem::type() const {
|
||||
return mType;
|
||||
}
|
||||
|
||||
QJsonTreeItem *QJsonTreeItem::load(const QJsonValue &value, QJsonTreeItem *parent)
|
||||
{
|
||||
QJsonTreeItem *QJsonTreeItem::load(const QJsonValue &value, QJsonTreeItem *parent) {
|
||||
QJsonTreeItem *rootItem = new QJsonTreeItem(parent);
|
||||
rootItem->setKey("root");
|
||||
|
||||
if (value.isObject())
|
||||
{
|
||||
if (value.isObject()) {
|
||||
// Get all QJsonValue childs
|
||||
for (QString key : value.toObject().keys())
|
||||
{
|
||||
for (QString key: value.toObject().keys()) {
|
||||
QJsonValue v = value.toObject().value(key);
|
||||
QJsonTreeItem *child = load(v, rootItem);
|
||||
child->setKey(key);
|
||||
child->setType(v.type());
|
||||
rootItem->appendChild(child);
|
||||
}
|
||||
}
|
||||
else if (value.isArray())
|
||||
{
|
||||
} else if (value.isArray()) {
|
||||
// Get all QJsonValue childs
|
||||
int index = 0;
|
||||
|
||||
for (QJsonValue v : value.toArray())
|
||||
{
|
||||
for (QJsonValue v: value.toArray()) {
|
||||
QJsonTreeItem *child = load(v, rootItem);
|
||||
child->setKey(QString::number(index));
|
||||
child->setType(v.type());
|
||||
rootItem->appendChild(child);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
rootItem->setValue(value.toVariant().toString());
|
||||
rootItem->setType(value.type());
|
||||
}
|
||||
@@ -137,75 +116,61 @@ QJsonTreeItem *QJsonTreeItem::load(const QJsonValue &value, QJsonTreeItem *paren
|
||||
|
||||
//=========================================================================
|
||||
|
||||
QJsonModel::QJsonModel(QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
|
||||
{
|
||||
QJsonModel::QJsonModel(QObject *parent) : QAbstractItemModel(parent), mRootItem{new QJsonTreeItem} {
|
||||
mHeaders.append("key");
|
||||
mHeaders.append("value");
|
||||
}
|
||||
|
||||
QJsonModel::QJsonModel(const QString &fileName, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
|
||||
{
|
||||
QJsonModel::QJsonModel(const QString &fileName, QObject *parent) : QAbstractItemModel(parent), mRootItem{new QJsonTreeItem} {
|
||||
mHeaders.append("key");
|
||||
mHeaders.append("value");
|
||||
load(fileName);
|
||||
}
|
||||
|
||||
QJsonModel::QJsonModel(QIODevice *device, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
|
||||
{
|
||||
QJsonModel::QJsonModel(QIODevice *device, QObject *parent) : QAbstractItemModel(parent), mRootItem{new QJsonTreeItem} {
|
||||
mHeaders.append("key");
|
||||
mHeaders.append("value");
|
||||
load(device);
|
||||
}
|
||||
|
||||
QJsonModel::QJsonModel(const QByteArray &json, QObject *parent) : QAbstractItemModel(parent), mRootItem{ new QJsonTreeItem }
|
||||
{
|
||||
QJsonModel::QJsonModel(const QByteArray &json, QObject *parent) : QAbstractItemModel(parent), mRootItem{new QJsonTreeItem} {
|
||||
mHeaders.append("key");
|
||||
mHeaders.append("value");
|
||||
loadJson(json);
|
||||
}
|
||||
|
||||
QJsonModel::~QJsonModel()
|
||||
{
|
||||
QJsonModel::~QJsonModel() {
|
||||
delete mRootItem;
|
||||
}
|
||||
|
||||
bool QJsonModel::load(const QString &fileName)
|
||||
{
|
||||
bool QJsonModel::load(const QString &fileName) {
|
||||
QFile file(fileName);
|
||||
bool success = false;
|
||||
|
||||
if (file.open(QIODevice::ReadOnly))
|
||||
{
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
success = load(&file);
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
} else
|
||||
success = false;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool QJsonModel::load(QIODevice *device)
|
||||
{
|
||||
bool QJsonModel::load(QIODevice *device) {
|
||||
return loadJson(device->readAll());
|
||||
}
|
||||
|
||||
bool QJsonModel::loadJson(const QByteArray &json)
|
||||
{
|
||||
bool QJsonModel::loadJson(const QByteArray &json) {
|
||||
auto const &jdoc = QJsonDocument::fromJson(json);
|
||||
|
||||
if (!jdoc.isNull())
|
||||
{
|
||||
if (!jdoc.isNull()) {
|
||||
beginResetModel();
|
||||
delete mRootItem;
|
||||
|
||||
if (jdoc.isArray())
|
||||
{
|
||||
if (jdoc.isArray()) {
|
||||
mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.array()));
|
||||
mRootItem->setType(QJsonValue::Array);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
mRootItem = QJsonTreeItem::load(QJsonValue(jdoc.object()));
|
||||
mRootItem->setType(QJsonValue::Object);
|
||||
}
|
||||
@@ -218,25 +183,20 @@ bool QJsonModel::loadJson(const QByteArray &json)
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant QJsonModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QVariant QJsonModel::data(const QModelIndex &index, int role) const {
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (index.column() == 0)
|
||||
return QString("%1").arg(item->key());
|
||||
|
||||
if (index.column() == 1)
|
||||
return QString("%1").arg(item->value());
|
||||
}
|
||||
else if (Qt::EditRole == role)
|
||||
{
|
||||
if (index.column() == 1)
|
||||
{
|
||||
} else if (Qt::EditRole == role) {
|
||||
if (index.column() == 1) {
|
||||
return QString("%1").arg(item->value());
|
||||
}
|
||||
}
|
||||
@@ -244,17 +204,14 @@ QVariant QJsonModel::data(const QModelIndex &index, int role) const
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool QJsonModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
bool QJsonModel::setData(const QModelIndex &index, const QVariant &value, int role) {
|
||||
int col = index.column();
|
||||
|
||||
if (Qt::EditRole == role)
|
||||
{
|
||||
if (col == 1)
|
||||
{
|
||||
if (Qt::EditRole == role) {
|
||||
if (col == 1) {
|
||||
QJsonTreeItem *item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
||||
item->setValue(value.toString());
|
||||
emit dataChanged(index, index, { Qt::EditRole });
|
||||
emit dataChanged(index, index, {Qt::EditRole});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -262,21 +219,17 @@ bool QJsonModel::setData(const QModelIndex &index, const QVariant &value, int ro
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const {
|
||||
if (role != Qt::DisplayRole)
|
||||
return QVariant();
|
||||
|
||||
if (orientation == Qt::Horizontal)
|
||||
{
|
||||
if (orientation == Qt::Horizontal) {
|
||||
return mHeaders.value(section);
|
||||
}
|
||||
else
|
||||
} else
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const {
|
||||
if (!hasIndex(row, column, parent))
|
||||
return QModelIndex();
|
||||
|
||||
@@ -295,8 +248,7 @@ QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) co
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex QJsonModel::parent(const QModelIndex &index) const
|
||||
{
|
||||
QModelIndex QJsonModel::parent(const QModelIndex &index) const {
|
||||
if (!index.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
@@ -309,8 +261,7 @@ QModelIndex QJsonModel::parent(const QModelIndex &index) const
|
||||
return createIndex(parentItem->row(), 0, parentItem);
|
||||
}
|
||||
|
||||
int QJsonModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
int QJsonModel::rowCount(const QModelIndex &parent) const {
|
||||
QJsonTreeItem *parentItem;
|
||||
|
||||
if (parent.column() > 0)
|
||||
@@ -324,78 +275,61 @@ int QJsonModel::rowCount(const QModelIndex &parent) const
|
||||
return parentItem->childCount();
|
||||
}
|
||||
|
||||
int QJsonModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
int QJsonModel::columnCount(const QModelIndex &parent) const {
|
||||
Q_UNUSED(parent)
|
||||
return 2;
|
||||
}
|
||||
|
||||
Qt::ItemFlags QJsonModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
Qt::ItemFlags QJsonModel::flags(const QModelIndex &index) const {
|
||||
int col = index.column();
|
||||
auto item = static_cast<QJsonTreeItem *>(index.internalPointer());
|
||||
auto isArray = QJsonValue::Array == item->type();
|
||||
auto isObject = QJsonValue::Object == item->type();
|
||||
|
||||
if ((col == 1) && !(isArray || isObject))
|
||||
{
|
||||
if ((col == 1) && !(isArray || isObject)) {
|
||||
return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return QAbstractItemModel::flags(index);
|
||||
}
|
||||
}
|
||||
|
||||
QJsonDocument QJsonModel::json() const
|
||||
{
|
||||
QJsonDocument QJsonModel::json() const {
|
||||
auto v = genJson(mRootItem);
|
||||
QJsonDocument doc;
|
||||
|
||||
if (v.isObject())
|
||||
{
|
||||
if (v.isObject()) {
|
||||
doc = QJsonDocument(v.toObject());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
doc = QJsonDocument(v.toArray());
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
QJsonValue QJsonModel::genJson(QJsonTreeItem *item) const
|
||||
{
|
||||
QJsonValue QJsonModel::genJson(QJsonTreeItem *item) const {
|
||||
auto type = item->type();
|
||||
int nchild = item->childCount();
|
||||
|
||||
if (QJsonValue::Object == type)
|
||||
{
|
||||
if (QJsonValue::Object == type) {
|
||||
QJsonObject jo;
|
||||
|
||||
for (int i = 0; i < nchild; ++i)
|
||||
{
|
||||
for (int i = 0; i < nchild; ++i) {
|
||||
auto ch = item->child(i);
|
||||
auto key = ch->key();
|
||||
jo.insert(key, genJson(ch));
|
||||
}
|
||||
|
||||
return jo;
|
||||
}
|
||||
else if (QJsonValue::Array == type)
|
||||
{
|
||||
} else if (QJsonValue::Array == type) {
|
||||
QJsonArray arr;
|
||||
|
||||
for (int i = 0; i < nchild; ++i)
|
||||
{
|
||||
for (int i = 0; i < nchild; ++i) {
|
||||
auto ch = item->child(i);
|
||||
arr.append(genJson(ch));
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
QJsonValue va(item->value());
|
||||
return va;
|
||||
}
|
||||
|
||||
@@ -34,9 +34,8 @@
|
||||
class QJsonModel;
|
||||
class QJsonItem;
|
||||
|
||||
class QJsonTreeItem
|
||||
{
|
||||
public:
|
||||
class QJsonTreeItem {
|
||||
public:
|
||||
QJsonTreeItem(QJsonTreeItem *parent = nullptr);
|
||||
~QJsonTreeItem();
|
||||
void appendChild(QJsonTreeItem *item);
|
||||
@@ -53,8 +52,8 @@ class QJsonTreeItem
|
||||
|
||||
static QJsonTreeItem *load(const QJsonValue &value, QJsonTreeItem *parent = 0);
|
||||
|
||||
protected:
|
||||
private:
|
||||
protected:
|
||||
private:
|
||||
QString mKey;
|
||||
QString mValue;
|
||||
QJsonValue::Type mType;
|
||||
@@ -64,10 +63,9 @@ class QJsonTreeItem
|
||||
|
||||
//---------------------------------------------------
|
||||
|
||||
class QJsonModel : public QAbstractItemModel
|
||||
{
|
||||
class QJsonModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
public:
|
||||
explicit QJsonModel(QObject *parent = nullptr);
|
||||
QJsonModel(const QString &fileName, QObject *parent = nullptr);
|
||||
QJsonModel(QIODevice *device, QObject *parent = nullptr);
|
||||
@@ -86,7 +84,7 @@ class QJsonModel : public QAbstractItemModel
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
|
||||
QJsonDocument json() const;
|
||||
|
||||
private:
|
||||
private:
|
||||
QJsonValue genJson(QJsonTreeItem *) const;
|
||||
|
||||
QJsonTreeItem *mRootItem;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "main/NekoRay.hpp"
|
||||
|
||||
JsonEditor::JsonEditor(const QJsonObject& rootObject, QWidget *parent) : QDialog(parent) {
|
||||
JsonEditor::JsonEditor(const QJsonObject& rootObject, QWidget* parent) : QDialog(parent) {
|
||||
setupUi(this);
|
||||
// QvMessageBusConnect(JsonEditor);
|
||||
// QvMessageBusConnect(JsonEditor);
|
||||
//
|
||||
original = rootObject;
|
||||
final = rootObject;
|
||||
@@ -23,17 +23,17 @@ JsonEditor::JsonEditor(const QJsonObject& rootObject, QWidget *parent) : QDialog
|
||||
jsonTree->resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
//QvMessageBusSlotImpl(JsonEditor)
|
||||
// {
|
||||
// switch (msg)
|
||||
// {
|
||||
// MBShowDefaultImpl;
|
||||
// MBHideDefaultImpl;
|
||||
// MBRetranslateDefaultImpl;
|
||||
// case UPDATE_COLORSCHEME:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// QvMessageBusSlotImpl(JsonEditor)
|
||||
// {
|
||||
// switch (msg)
|
||||
// {
|
||||
// MBShowDefaultImpl;
|
||||
// MBHideDefaultImpl;
|
||||
// MBRetranslateDefaultImpl;
|
||||
// case UPDATE_COLORSCHEME:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
QJsonObject JsonEditor::OpenEditor() {
|
||||
int resultCode = this->exec();
|
||||
|
||||
@@ -4,28 +4,26 @@
|
||||
#include "qv2ray/v2/ui/widgets/common/QJsonModel.hpp"
|
||||
#include "ui_w_JsonEditor.h"
|
||||
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class JsonEditor
|
||||
: public QDialog
|
||||
, private Ui::JsonEditor
|
||||
{
|
||||
: public QDialog,
|
||||
private Ui::JsonEditor {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit JsonEditor(const QJsonObject& rootObject, QWidget *parent = nullptr);
|
||||
public:
|
||||
explicit JsonEditor(const QJsonObject& rootObject, QWidget* parent = nullptr);
|
||||
~JsonEditor();
|
||||
QJsonObject OpenEditor();
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void on_jsonEditor_textChanged();
|
||||
|
||||
void on_formatJsonBtn_clicked();
|
||||
|
||||
void on_removeCommentsBtn_clicked();
|
||||
|
||||
private:
|
||||
private:
|
||||
QJsonModel model;
|
||||
QJsonObject original;
|
||||
QJsonObject final;
|
||||
|
||||
@@ -14,11 +14,12 @@ namespace Qv2ray::common::network {
|
||||
};
|
||||
|
||||
class NetworkRequestHelper : QObject {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
explicit NetworkRequestHelper(QObject *parent) : QObject(parent) {};
|
||||
explicit NetworkRequestHelper(QObject *parent) : QObject(parent){};
|
||||
|
||||
~NetworkRequestHelper() override = default;;
|
||||
~NetworkRequestHelper() override = default;
|
||||
;
|
||||
|
||||
public:
|
||||
static NekoHTTPResponse HttpGet(const QUrl &url);
|
||||
|
||||
@@ -39,4 +39,4 @@ namespace Qv2ray::components::GeositeReader {
|
||||
GeositeEntries[filepath] = list;
|
||||
return list;
|
||||
}
|
||||
} // namespace Qv2ray::components::geosite
|
||||
} // namespace Qv2ray::components::GeositeReader
|
||||
|
||||
@@ -15,18 +15,15 @@
|
||||
|
||||
#include "picoproto.hpp"
|
||||
|
||||
namespace picoproto
|
||||
{
|
||||
namespace picoproto {
|
||||
|
||||
namespace
|
||||
{
|
||||
namespace {
|
||||
|
||||
// To keep the dependencies down, here's a local copy of the widespread bit_cast
|
||||
// operator. This is necessary because in practice weird things can happen if
|
||||
// you just try to use reinterpret_cast.
|
||||
template<class Dest, class Source>
|
||||
inline Dest bit_cast(const Source &source)
|
||||
{
|
||||
inline Dest bit_cast(const Source &source) {
|
||||
static_assert(sizeof(Dest) == sizeof(Source), "Sizes do not match");
|
||||
Dest dest;
|
||||
memcpy(&dest, &source, sizeof(dest));
|
||||
@@ -35,8 +32,7 @@ namespace picoproto
|
||||
|
||||
// These are defined in:
|
||||
// https://developers.google.com/protocol-buffers/docs/encoding
|
||||
enum WireType
|
||||
{
|
||||
enum WireType {
|
||||
WIRETYPE_VARINT = 0,
|
||||
WIRETYPE_64BIT = 1,
|
||||
WIRETYPE_LENGTH_DELIMITED = 2,
|
||||
@@ -46,10 +42,8 @@ namespace picoproto
|
||||
};
|
||||
|
||||
// Pull bytes from the stream, updating the state.
|
||||
bool ConsumeBytes(uint8_t **current, size_t how_many, size_t *remaining)
|
||||
{
|
||||
if (how_many > *remaining)
|
||||
{
|
||||
bool ConsumeBytes(uint8_t **current, size_t how_many, size_t *remaining) {
|
||||
if (how_many > *remaining) {
|
||||
PP_LOG(ERROR) << "ReadBytes overrun!";
|
||||
return false;
|
||||
}
|
||||
@@ -60,30 +54,26 @@ namespace picoproto
|
||||
|
||||
// Grabs a particular type from the byte stream.
|
||||
template<class T>
|
||||
T ReadFromBytes(uint8_t **current, size_t *remaining)
|
||||
{
|
||||
T ReadFromBytes(uint8_t **current, size_t *remaining) {
|
||||
PP_CHECK(ConsumeBytes(current, sizeof(T), remaining));
|
||||
const T result = *(bit_cast<T *>(*current - sizeof(T)));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64_t ReadVarInt(uint8_t **current, size_t *remaining)
|
||||
{
|
||||
uint64_t ReadVarInt(uint8_t **current, size_t *remaining) {
|
||||
uint64_t result = 0;
|
||||
bool keep_going;
|
||||
int shift = 0;
|
||||
do
|
||||
{
|
||||
do {
|
||||
const uint8_t next_number = ReadFromBytes<uint8_t>(current, remaining);
|
||||
keep_going = (next_number >= 128);
|
||||
result += (uint64_t)(next_number & 0x7f) << shift;
|
||||
result += (uint64_t) (next_number & 0x7f) << shift;
|
||||
shift += 7;
|
||||
} while (keep_going);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ReadWireTypeAndFieldNumber(uint8_t **current, size_t *remaining, uint8_t *wire_type, uint32_t *field_number)
|
||||
{
|
||||
void ReadWireTypeAndFieldNumber(uint8_t **current, size_t *remaining, uint8_t *wire_type, uint32_t *field_number) {
|
||||
uint64_t wire_type_and_field_number = ReadVarInt(current, remaining);
|
||||
*wire_type = wire_type_and_field_number & 0x07;
|
||||
*field_number = wire_type_and_field_number >> 3;
|
||||
@@ -91,123 +81,106 @@ namespace picoproto
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string FieldTypeDebugString(enum FieldType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case FIELD_UNSET: return "UNSET"; break;
|
||||
case FIELD_UINT32: return "UINT32"; break;
|
||||
case FIELD_UINT64: return "UINT64"; break;
|
||||
case FIELD_BYTES: return "BYTES"; break;
|
||||
default: return "Unknown field type"; break;
|
||||
std::string FieldTypeDebugString(enum FieldType type) {
|
||||
switch (type) {
|
||||
case FIELD_UNSET:
|
||||
return "UNSET";
|
||||
break;
|
||||
case FIELD_UINT32:
|
||||
return "UINT32";
|
||||
break;
|
||||
case FIELD_UINT64:
|
||||
return "UINT64";
|
||||
break;
|
||||
case FIELD_BYTES:
|
||||
return "BYTES";
|
||||
break;
|
||||
default:
|
||||
return "Unknown field type";
|
||||
break;
|
||||
}
|
||||
return "Should never get here";
|
||||
}
|
||||
|
||||
Field::Field(FieldType type, bool owns_data) : type(type), owns_data(owns_data)
|
||||
{
|
||||
Field::Field(FieldType type, bool owns_data) : type(type), owns_data(owns_data) {
|
||||
cached_messages = nullptr;
|
||||
switch (type)
|
||||
{
|
||||
case FIELD_UINT32:
|
||||
{
|
||||
switch (type) {
|
||||
case FIELD_UINT32: {
|
||||
value.v_uint32 = new std::vector<uint32_t>();
|
||||
}
|
||||
break;
|
||||
case FIELD_UINT64:
|
||||
{
|
||||
} break;
|
||||
case FIELD_UINT64: {
|
||||
value.v_uint64 = new std::vector<uint64_t>();
|
||||
}
|
||||
break;
|
||||
case FIELD_BYTES:
|
||||
{
|
||||
} break;
|
||||
case FIELD_BYTES: {
|
||||
value.v_bytes = new std::vector<std::pair<uint8_t *, size_t>>();
|
||||
cached_messages = new std::vector<Message *>();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
} break;
|
||||
default: {
|
||||
PP_LOG(ERROR) << "Bad field type when constructing field: " << type;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
Field::Field(const Field &other) : type(other.type), owns_data(other.owns_data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case FIELD_UINT32:
|
||||
{
|
||||
Field::Field(const Field &other) : type(other.type), owns_data(other.owns_data) {
|
||||
switch (type) {
|
||||
case FIELD_UINT32: {
|
||||
value.v_uint32 = new std::vector<uint32_t>(*other.value.v_uint32);
|
||||
}
|
||||
break;
|
||||
case FIELD_UINT64:
|
||||
{
|
||||
} break;
|
||||
case FIELD_UINT64: {
|
||||
value.v_uint64 = new std::vector<uint64_t>(*other.value.v_uint64);
|
||||
}
|
||||
break;
|
||||
case FIELD_BYTES:
|
||||
{
|
||||
if (owns_data)
|
||||
{
|
||||
} break;
|
||||
case FIELD_BYTES: {
|
||||
if (owns_data) {
|
||||
value.v_bytes = new std::vector<std::pair<uint8_t *, size_t>>();
|
||||
for (std::pair<uint8_t *, size_t> data_info : *other.value.v_bytes)
|
||||
{
|
||||
for (std::pair<uint8_t *, size_t> data_info: *other.value.v_bytes) {
|
||||
uint8_t *new_data = new uint8_t[data_info.second];
|
||||
std::copy_n(data_info.first, data_info.second, new_data);
|
||||
value.v_bytes->push_back({ new_data, data_info.second });
|
||||
value.v_bytes->push_back({new_data, data_info.second});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
value.v_bytes = new std::vector<std::pair<uint8_t *, size_t>>(*other.value.v_bytes);
|
||||
}
|
||||
cached_messages = new std::vector<Message *>();
|
||||
cached_messages->reserve(other.cached_messages->size());
|
||||
for (Message *other_cached_message : *other.cached_messages)
|
||||
{
|
||||
for (Message *other_cached_message: *other.cached_messages) {
|
||||
Message *cached_message;
|
||||
if (other_cached_message)
|
||||
{
|
||||
if (other_cached_message) {
|
||||
cached_message = new Message(*other_cached_message);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
cached_message = nullptr;
|
||||
}
|
||||
cached_messages->push_back(cached_message);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
} break;
|
||||
default: {
|
||||
PP_LOG(ERROR) << "Bad field type when constructing field: " << type;
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
Field::~Field()
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case FIELD_UINT32: delete value.v_uint32; break;
|
||||
case FIELD_UINT64: delete value.v_uint64; break;
|
||||
case FIELD_BYTES:
|
||||
{
|
||||
Field::~Field() {
|
||||
switch (type) {
|
||||
case FIELD_UINT32:
|
||||
delete value.v_uint32;
|
||||
break;
|
||||
case FIELD_UINT64:
|
||||
delete value.v_uint64;
|
||||
break;
|
||||
case FIELD_BYTES: {
|
||||
if (owns_data)
|
||||
for (std::pair<uint8_t *, size_t> data_info : *value.v_bytes)
|
||||
for (std::pair<uint8_t *, size_t> data_info: *value.v_bytes)
|
||||
delete[] data_info.first;
|
||||
delete value.v_bytes;
|
||||
|
||||
for (Message *cached_message : *cached_messages)
|
||||
for (Message *cached_message: *cached_messages)
|
||||
if (cached_message)
|
||||
delete cached_message;
|
||||
delete cached_messages;
|
||||
break;
|
||||
}
|
||||
default: PP_LOG(ERROR) << "Bad field type when destroying field: " << type; break;
|
||||
default:
|
||||
PP_LOG(ERROR) << "Bad field type when destroying field: " << type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -219,74 +192,61 @@ namespace picoproto
|
||||
|
||||
Message::~Message(){};
|
||||
|
||||
bool Message::ParseFromBytes(uint8_t *bytes, size_t bytes_size)
|
||||
{
|
||||
bool Message::ParseFromBytes(uint8_t *bytes, size_t bytes_size) {
|
||||
uint8_t *current = bytes;
|
||||
size_t remaining = bytes_size;
|
||||
while (remaining > 0)
|
||||
{
|
||||
while (remaining > 0) {
|
||||
uint8_t wire_type;
|
||||
uint32_t field_number;
|
||||
ReadWireTypeAndFieldNumber(¤t, &remaining, &wire_type, &field_number);
|
||||
switch (wire_type)
|
||||
{
|
||||
case WIRETYPE_VARINT:
|
||||
{
|
||||
switch (wire_type) {
|
||||
case WIRETYPE_VARINT: {
|
||||
Field *field = AddField(field_number, FIELD_UINT64);
|
||||
const uint64_t varint = ReadVarInt(¤t, &remaining);
|
||||
field->value.v_uint64->push_back(varint);
|
||||
break;
|
||||
}
|
||||
case WIRETYPE_64BIT:
|
||||
{
|
||||
case WIRETYPE_64BIT: {
|
||||
Field *field = AddField(field_number, FIELD_UINT64);
|
||||
const uint64_t value = ReadFromBytes<uint64_t>(¤t, &remaining);
|
||||
field->value.v_uint64->push_back(value);
|
||||
break;
|
||||
}
|
||||
case WIRETYPE_LENGTH_DELIMITED:
|
||||
{
|
||||
case WIRETYPE_LENGTH_DELIMITED: {
|
||||
Field *field = AddField(field_number, FIELD_BYTES);
|
||||
const uint64_t size = ReadVarInt(¤t, &remaining);
|
||||
uint8_t *data;
|
||||
if (copy_arrays)
|
||||
{
|
||||
if (copy_arrays) {
|
||||
data = new uint8_t[size];
|
||||
std::copy_n(current, size, data);
|
||||
field->owns_data = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
data = current;
|
||||
field->owns_data = false;
|
||||
}
|
||||
field->value.v_bytes->push_back({ data, size });
|
||||
field->value.v_bytes->push_back({data, size});
|
||||
field->cached_messages->push_back(nullptr);
|
||||
current += size;
|
||||
remaining -= size;
|
||||
break;
|
||||
}
|
||||
case WIRETYPE_GROUP_START:
|
||||
{
|
||||
case WIRETYPE_GROUP_START: {
|
||||
PP_LOG(INFO) << field_number << ": GROUPSTART" << std::endl;
|
||||
PP_LOG(ERROR) << "Unhandled wire type encountered";
|
||||
break;
|
||||
}
|
||||
case WIRETYPE_GROUP_END:
|
||||
{
|
||||
case WIRETYPE_GROUP_END: {
|
||||
PP_LOG(INFO) << field_number << ": GROUPEND" << std::endl;
|
||||
PP_LOG(ERROR) << "Unhandled wire type encountered";
|
||||
break;
|
||||
}
|
||||
case WIRETYPE_32BIT:
|
||||
{
|
||||
case WIRETYPE_32BIT: {
|
||||
Field *field = AddField(field_number, FIELD_UINT32);
|
||||
const uint32_t value = ReadFromBytes<uint32_t>(¤t, &remaining);
|
||||
field->value.v_uint32->push_back(value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
default: {
|
||||
PP_LOG(ERROR) << "Unknown wire type encountered: " << static_cast<int>(wire_type) << " at offset" << (bytes_size - remaining);
|
||||
return false;
|
||||
break;
|
||||
@@ -296,122 +256,107 @@ namespace picoproto
|
||||
return true;
|
||||
}
|
||||
|
||||
Field *Message::AddField(int32_t number, enum FieldType type)
|
||||
{
|
||||
Field *Message::AddField(int32_t number, enum FieldType type) {
|
||||
Field *field = GetField(number);
|
||||
if (!field)
|
||||
{
|
||||
if (!field) {
|
||||
fields.push_back(Field(type, copy_arrays));
|
||||
field = &fields.back();
|
||||
field_map.insert({ number, fields.size() - 1 });
|
||||
field_map.insert({number, fields.size() - 1});
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
Field *Message::GetField(int32_t number)
|
||||
{
|
||||
Field *Message::GetField(int32_t number) {
|
||||
if (field_map.count(number) == 0)
|
||||
return nullptr;
|
||||
return &(fields[field_map[number]]);
|
||||
}
|
||||
|
||||
Field *Message::GetFieldAndCheckType(int32_t number, enum FieldType type)
|
||||
{
|
||||
Field *Message::GetFieldAndCheckType(int32_t number, enum FieldType type) {
|
||||
Field *field = GetField(number);
|
||||
PP_CHECK(field) << "No field for " << number;
|
||||
PP_CHECK(field->type == type) << "For field " << number << " wanted type " << FieldTypeDebugString(type) << " but found " << FieldTypeDebugString(field->type);
|
||||
return field;
|
||||
}
|
||||
|
||||
int32_t Message::GetInt32(int32_t number)
|
||||
{
|
||||
int32_t Message::GetInt32(int32_t number) {
|
||||
Field *field = GetFieldAndCheckType(number, FIELD_UINT32);
|
||||
uint32_t first_value = (*(field->value.v_uint32))[0];
|
||||
int32_t zig_zag_decoded = static_cast<int32_t>((first_value >> 1) ^ (-(first_value & 1)));
|
||||
return zig_zag_decoded;
|
||||
}
|
||||
|
||||
int64_t Message::GetInt64(int32_t number)
|
||||
{
|
||||
int64_t Message::GetInt64(int32_t number) {
|
||||
Field *field = GetFieldAndCheckType(number, FIELD_UINT64);
|
||||
uint64_t first_value = (*(field->value.v_uint64))[0];
|
||||
int64_t zig_zag_decoded = static_cast<int64_t>((first_value >> 1) ^ (-(first_value & 1)));
|
||||
return zig_zag_decoded;
|
||||
}
|
||||
|
||||
uint32_t Message::GetUInt32(int32_t number)
|
||||
{
|
||||
uint32_t Message::GetUInt32(int32_t number) {
|
||||
Field *field = GetFieldAndCheckType(number, FIELD_UINT32);
|
||||
uint32_t first_value = (*(field->value.v_uint32))[0];
|
||||
return first_value;
|
||||
}
|
||||
|
||||
uint64_t Message::GetUInt64(int32_t number)
|
||||
{
|
||||
uint64_t Message::GetUInt64(int32_t number) {
|
||||
Field *field = GetFieldAndCheckType(number, FIELD_UINT64);
|
||||
uint64_t first_value = (*(field->value.v_uint64))[0];
|
||||
return first_value;
|
||||
}
|
||||
|
||||
int64_t Message::GetInt(int32_t number)
|
||||
{
|
||||
int64_t Message::GetInt(int32_t number) {
|
||||
Field *field = GetField(number);
|
||||
PP_CHECK(field) << "No field for " << number;
|
||||
PP_CHECK((field->type == FIELD_UINT32) || (field->type == FIELD_UINT64))
|
||||
<< "For field " << number << " wanted integer type but found " << FieldTypeDebugString(field->type);
|
||||
switch (field->type)
|
||||
{
|
||||
case FIELD_UINT32: return GetInt32(number); break;
|
||||
case FIELD_UINT64: return GetInt64(number); break;
|
||||
default:
|
||||
{
|
||||
switch (field->type) {
|
||||
case FIELD_UINT32:
|
||||
return GetInt32(number);
|
||||
break;
|
||||
case FIELD_UINT64:
|
||||
return GetInt64(number);
|
||||
break;
|
||||
default: {
|
||||
// Should never get here.
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
}
|
||||
// Should never get here.
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Message::GetBool(int32_t number)
|
||||
{
|
||||
bool Message::GetBool(int32_t number) {
|
||||
return (GetInt(number) != 0);
|
||||
}
|
||||
|
||||
float Message::GetFloat(int32_t number)
|
||||
{
|
||||
float Message::GetFloat(int32_t number) {
|
||||
uint32_t int_value = GetUInt32(number);
|
||||
float float_value = *(bit_cast<float *>(&int_value));
|
||||
return float_value;
|
||||
}
|
||||
|
||||
double Message::GetDouble(int32_t number)
|
||||
{
|
||||
double Message::GetDouble(int32_t number) {
|
||||
uint64_t int_value = GetUInt64(number);
|
||||
return *(bit_cast<double *>(&int_value));
|
||||
}
|
||||
|
||||
std::pair<uint8_t *, size_t> Message::GetBytes(int32_t number)
|
||||
{
|
||||
std::pair<uint8_t *, size_t> Message::GetBytes(int32_t number) {
|
||||
Field *field = GetFieldAndCheckType(number, FIELD_BYTES);
|
||||
std::pair<uint8_t *, size_t> first_value = (*(field->value.v_bytes))[0];
|
||||
return first_value;
|
||||
}
|
||||
|
||||
std::string Message::GetString(int32_t number)
|
||||
{
|
||||
std::string Message::GetString(int32_t number) {
|
||||
Field *field = GetFieldAndCheckType(number, FIELD_BYTES);
|
||||
std::pair<uint8_t *, size_t> first_value = (*(field->value.v_bytes))[0];
|
||||
std::string result(first_value.first, first_value.first + first_value.second);
|
||||
return result;
|
||||
}
|
||||
|
||||
Message *Message::GetMessage(int32_t number)
|
||||
{
|
||||
Message *Message::GetMessage(int32_t number) {
|
||||
Field *field = GetFieldAndCheckType(number, FIELD_BYTES);
|
||||
Message *cached_message = field->cached_messages->at(0);
|
||||
if (!cached_message)
|
||||
{
|
||||
if (!cached_message) {
|
||||
std::pair<uint8_t *, size_t> first_value = (*(field->value.v_bytes))[0];
|
||||
cached_message = new Message(copy_arrays);
|
||||
cached_message->ParseFromBytes(first_value.first, first_value.second);
|
||||
@@ -420,232 +365,176 @@ namespace picoproto
|
||||
return cached_message;
|
||||
}
|
||||
|
||||
std::vector<int32_t> Message::GetInt32Array(int32_t number)
|
||||
{
|
||||
std::vector<int32_t> Message::GetInt32Array(int32_t number) {
|
||||
std::vector<uint64_t> raw_array = GetUInt64Array(number);
|
||||
std::vector<int32_t> result;
|
||||
result.reserve(raw_array.size());
|
||||
for (uint64_t raw_value : raw_array)
|
||||
{
|
||||
for (uint64_t raw_value: raw_array) {
|
||||
int32_t zig_zag_decoded = static_cast<int32_t>((raw_value >> 1) ^ (-(raw_value & 1)));
|
||||
result.push_back(zig_zag_decoded);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<int64_t> Message::GetInt64Array(int32_t number)
|
||||
{
|
||||
std::vector<int64_t> Message::GetInt64Array(int32_t number) {
|
||||
std::vector<uint64_t> raw_array = GetUInt64Array(number);
|
||||
std::vector<int64_t> result;
|
||||
result.reserve(raw_array.size());
|
||||
for (uint64_t raw_value : raw_array)
|
||||
{
|
||||
for (uint64_t raw_value: raw_array) {
|
||||
int64_t zig_zag_decoded = static_cast<int64_t>((raw_value >> 1) ^ (-(raw_value & 1)));
|
||||
result.push_back(zig_zag_decoded);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> Message::GetUInt32Array(int32_t number)
|
||||
{
|
||||
std::vector<uint32_t> Message::GetUInt32Array(int32_t number) {
|
||||
std::vector<uint64_t> raw_array = GetUInt64Array(number);
|
||||
std::vector<uint32_t> result;
|
||||
result.reserve(raw_array.size());
|
||||
for (uint64_t raw_value : raw_array)
|
||||
{
|
||||
for (uint64_t raw_value: raw_array) {
|
||||
result.push_back(static_cast<uint32_t>(raw_value));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<uint64_t> Message::GetUInt64Array(int32_t number)
|
||||
{
|
||||
std::vector<uint64_t> Message::GetUInt64Array(int32_t number) {
|
||||
std::vector<uint64_t> result;
|
||||
Field *field = GetField(number);
|
||||
if (!field)
|
||||
{
|
||||
if (!field) {
|
||||
return result;
|
||||
}
|
||||
if (field->type == FIELD_UINT64)
|
||||
{
|
||||
if (field->type == FIELD_UINT64) {
|
||||
result.reserve(field->value.v_uint64->size());
|
||||
for (uint64_t value : *field->value.v_uint64)
|
||||
{
|
||||
for (uint64_t value: *field->value.v_uint64) {
|
||||
result.push_back(static_cast<uint64_t>(value));
|
||||
}
|
||||
}
|
||||
else if (field->type == FIELD_UINT32)
|
||||
{
|
||||
} else if (field->type == FIELD_UINT32) {
|
||||
result.reserve(field->value.v_uint32->size());
|
||||
for (uint32_t value : *field->value.v_uint32)
|
||||
{
|
||||
for (uint32_t value: *field->value.v_uint32) {
|
||||
result.push_back(static_cast<uint64_t>(value));
|
||||
}
|
||||
}
|
||||
else if (field->type == FIELD_BYTES)
|
||||
{
|
||||
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
|
||||
{
|
||||
} else if (field->type == FIELD_BYTES) {
|
||||
for (std::pair<uint8_t *, size_t> data_info: *field->value.v_bytes) {
|
||||
uint8_t *current = data_info.first;
|
||||
size_t remaining = data_info.second;
|
||||
while (remaining > 0)
|
||||
{
|
||||
while (remaining > 0) {
|
||||
const uint64_t varint = ReadVarInt(¤t, &remaining);
|
||||
result.push_back(static_cast<int64_t>(varint));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
PP_LOG(ERROR) << "Expected field type UINT32, UINT64, or BYTES but got " << FieldTypeDebugString(field->type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<bool> Message::GetBoolArray(int32_t number)
|
||||
{
|
||||
std::vector<bool> Message::GetBoolArray(int32_t number) {
|
||||
std::vector<uint64_t> raw_array = GetUInt64Array(number);
|
||||
std::vector<bool> result;
|
||||
result.reserve(raw_array.size());
|
||||
for (uint64_t raw_value : raw_array)
|
||||
{
|
||||
for (uint64_t raw_value: raw_array) {
|
||||
result.push_back(raw_value != 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<float> Message::GetFloatArray(int32_t number)
|
||||
{
|
||||
std::vector<float> Message::GetFloatArray(int32_t number) {
|
||||
std::vector<float> result;
|
||||
Field *field = GetField(number);
|
||||
if (!field)
|
||||
{
|
||||
if (!field) {
|
||||
return result;
|
||||
}
|
||||
if (field->type == FIELD_UINT32)
|
||||
{
|
||||
if (field->type == FIELD_UINT32) {
|
||||
result.reserve(field->value.v_uint32->size());
|
||||
for (uint32_t value : *field->value.v_uint32)
|
||||
{
|
||||
for (uint32_t value: *field->value.v_uint32) {
|
||||
result.push_back(bit_cast<float>(value));
|
||||
}
|
||||
}
|
||||
else if (field->type == FIELD_BYTES)
|
||||
{
|
||||
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
|
||||
{
|
||||
} else if (field->type == FIELD_BYTES) {
|
||||
for (std::pair<uint8_t *, size_t> data_info: *field->value.v_bytes) {
|
||||
uint8_t *current = data_info.first;
|
||||
size_t remaining = data_info.second;
|
||||
while (remaining > 0)
|
||||
{
|
||||
while (remaining > 0) {
|
||||
const uint64_t varint = ReadVarInt(¤t, &remaining);
|
||||
const uint32_t varint32 = static_cast<uint32_t>(varint & 0xffffffff);
|
||||
result.push_back(bit_cast<float>(varint32));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
PP_LOG(ERROR) << "Expected field type UINT32 or BYTES but got " << FieldTypeDebugString(field->type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<double> Message::GetDoubleArray(int32_t number)
|
||||
{
|
||||
std::vector<double> Message::GetDoubleArray(int32_t number) {
|
||||
std::vector<double> result;
|
||||
Field *field = GetField(number);
|
||||
if (!field)
|
||||
{
|
||||
if (!field) {
|
||||
return result;
|
||||
}
|
||||
if (field->type == FIELD_UINT64)
|
||||
{
|
||||
if (field->type == FIELD_UINT64) {
|
||||
result.reserve(field->value.v_uint64->size());
|
||||
for (uint64_t value : *field->value.v_uint64)
|
||||
{
|
||||
for (uint64_t value: *field->value.v_uint64) {
|
||||
result.push_back(bit_cast<double>(value));
|
||||
}
|
||||
}
|
||||
else if (field->type == FIELD_BYTES)
|
||||
{
|
||||
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
|
||||
{
|
||||
} else if (field->type == FIELD_BYTES) {
|
||||
for (std::pair<uint8_t *, size_t> data_info: *field->value.v_bytes) {
|
||||
uint8_t *current = data_info.first;
|
||||
size_t remaining = data_info.second;
|
||||
while (remaining > 0)
|
||||
{
|
||||
while (remaining > 0) {
|
||||
const uint64_t varint = ReadVarInt(¤t, &remaining);
|
||||
result.push_back(bit_cast<double>(varint));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
PP_LOG(ERROR) << "Expected field type UINT64 or BYTES but got " << FieldTypeDebugString(field->type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::pair<uint8_t *, size_t>> Message::GetByteArray(int32_t number)
|
||||
{
|
||||
std::vector<std::pair<uint8_t *, size_t>> Message::GetByteArray(int32_t number) {
|
||||
std::vector<std::pair<uint8_t *, size_t>> result;
|
||||
Field *field = GetField(number);
|
||||
if (!field)
|
||||
{
|
||||
if (!field) {
|
||||
return result;
|
||||
}
|
||||
if (field->type == FIELD_BYTES)
|
||||
{
|
||||
if (field->type == FIELD_BYTES) {
|
||||
result.reserve(field->value.v_bytes->size());
|
||||
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
|
||||
{
|
||||
for (std::pair<uint8_t *, size_t> data_info: *field->value.v_bytes) {
|
||||
result.push_back(data_info);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> Message::GetStringArray(int32_t number)
|
||||
{
|
||||
std::vector<std::string> Message::GetStringArray(int32_t number) {
|
||||
std::vector<std::string> result;
|
||||
Field *field = GetField(number);
|
||||
if (!field)
|
||||
return result;
|
||||
if (field->type == FIELD_BYTES)
|
||||
{
|
||||
if (field->type == FIELD_BYTES) {
|
||||
result.reserve(field->value.v_bytes->size());
|
||||
for (std::pair<uint8_t *, size_t> data_info : *field->value.v_bytes)
|
||||
{
|
||||
for (std::pair<uint8_t *, size_t> data_info: *field->value.v_bytes) {
|
||||
result.push_back(std::string(data_info.first, data_info.first + data_info.second));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<Message *> Message::GetMessageArray(int32_t number)
|
||||
{
|
||||
std::vector<Message *> Message::GetMessageArray(int32_t number) {
|
||||
std::vector<Message *> result;
|
||||
Field *field = GetField(number);
|
||||
if (!field)
|
||||
return result;
|
||||
|
||||
if (field->type == FIELD_BYTES)
|
||||
{
|
||||
if (field->type == FIELD_BYTES) {
|
||||
result.reserve(field->value.v_bytes->size());
|
||||
for (size_t i = 0; i < field->value.v_bytes->size(); ++i)
|
||||
{
|
||||
for (size_t i = 0; i < field->value.v_bytes->size(); ++i) {
|
||||
Message *cached_message = field->cached_messages->at(i);
|
||||
if (!cached_message)
|
||||
{
|
||||
if (!cached_message) {
|
||||
std::pair<uint8_t *, size_t> value = field->value.v_bytes->at(i);
|
||||
cached_message = new Message(copy_arrays);
|
||||
cached_message->ParseFromBytes(value.first, value.second);
|
||||
@@ -653,9 +542,7 @@ namespace picoproto
|
||||
}
|
||||
result.push_back(cached_message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
PP_LOG(ERROR) << "Expected field type BYTES but got " << FieldTypeDebugString(field->type);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -70,20 +70,18 @@
|
||||
#define PP_LOG_INFO std::cerr << __FILE__ << ":" << __LINE__ << " - INFO: "
|
||||
#define PP_LOG_WARN std::cerr << __FILE__ << ":" << __LINE__ << " - WARN: "
|
||||
#define PP_LOG_ERROR std::cerr << __FILE__ << ":" << __LINE__ << " - ERROR: "
|
||||
#define PP_CHECK(X) \
|
||||
if (!(X)) \
|
||||
#define PP_CHECK(X) \
|
||||
if (!(X)) \
|
||||
PP_LOG(ERROR) << "PP_CHECK(" << #X << ") failed. "
|
||||
|
||||
namespace picoproto
|
||||
{
|
||||
namespace picoproto {
|
||||
|
||||
// These roughly correspond to the wire types used to save data in protobuf
|
||||
// files. The best reference to understand the full format is:
|
||||
// https://developers.google.com/protocol-buffers/docs/encoding
|
||||
// Because we don't know the bit-depth of VarInts, they're always stored as
|
||||
// uint64 values, which is why there's no specific type for them.
|
||||
enum FieldType
|
||||
{
|
||||
enum FieldType {
|
||||
FIELD_UNSET,
|
||||
FIELD_UINT32,
|
||||
FIELD_UINT64,
|
||||
@@ -100,9 +98,8 @@ namespace picoproto
|
||||
// data member, and handle all the allocation and deallocation of storage.
|
||||
// It's unlikely you'll want to access this class directly, since you'll
|
||||
// normally want to use Message below to pull typed values.
|
||||
class Field
|
||||
{
|
||||
public:
|
||||
class Field {
|
||||
public:
|
||||
// You need to specify the type of a Field on creation, so that the right
|
||||
// storage can be set up for the values. You also need to indicate whether the
|
||||
// underlying memory will be around for the lifetime of the message (in which
|
||||
@@ -117,8 +114,7 @@ namespace picoproto
|
||||
// and deciding how to initialize and access the data based on that persuaded
|
||||
// me this was the best approach. The `value` member contains whatever data
|
||||
// the field should be holding.
|
||||
union
|
||||
{
|
||||
union {
|
||||
std::vector<uint32_t> *v_uint32;
|
||||
std::vector<uint64_t> *v_uint64;
|
||||
std::vector<std::pair<uint8_t *, size_t>> *v_bytes;
|
||||
@@ -138,9 +134,8 @@ namespace picoproto
|
||||
};
|
||||
|
||||
// The main interface for loading and accessing serialized protobuf data.
|
||||
class Message
|
||||
{
|
||||
public:
|
||||
class Message {
|
||||
public:
|
||||
// If you're not sure about the lifetime of any binary data you're reading
|
||||
// from, just call this default constructor.
|
||||
Message();
|
||||
@@ -195,7 +190,7 @@ namespace picoproto
|
||||
// hatch in case you do have to manipulate them more directly.
|
||||
Field *GetField(int32_t number);
|
||||
|
||||
private:
|
||||
private:
|
||||
// Inserts a new field, updating all the internal data structures.
|
||||
Field *AddField(int32_t number, enum FieldType type);
|
||||
|
||||
|
||||
@@ -9,11 +9,11 @@
|
||||
namespace Qv2ray::base {
|
||||
template<typename... T>
|
||||
inline void log_internal(T... v) {}
|
||||
}
|
||||
} // namespace Qv2ray::base
|
||||
|
||||
#define JsonToString(a) QJsonObject2QString(a,false)
|
||||
#define JsonToString(a) QJsonObject2QString(a, false)
|
||||
#define JsonFromString(a) QString2QJsonObject(a)
|
||||
#define QvMessageBoxWarn(a, b, c) MessageBoxWarning(b,c)
|
||||
#define QvMessageBoxWarn(a, b, c) MessageBoxWarning(b, c)
|
||||
|
||||
inline QString VerifyJsonString(const QString &source) {
|
||||
QJsonParseError error{};
|
||||
@@ -23,16 +23,16 @@ inline QString VerifyJsonString(const QString &source) {
|
||||
if (error.error == QJsonParseError::NoError) {
|
||||
return "";
|
||||
} else {
|
||||
//LOG("WARNING: Json parse returns: " + error.errorString());
|
||||
// LOG("WARNING: Json parse returns: " + error.errorString());
|
||||
return error.errorString();
|
||||
}
|
||||
}
|
||||
|
||||
#define RED(obj) \
|
||||
{ \
|
||||
auto _temp = obj->palette(); \
|
||||
_temp.setColor(QPalette::Text, Qt::red); \
|
||||
obj->setPalette(_temp); \
|
||||
#define RED(obj) \
|
||||
{ \
|
||||
auto _temp = obj->palette(); \
|
||||
_temp.setColor(QPalette::Text, Qt::red); \
|
||||
obj->setPalette(_temp); \
|
||||
}
|
||||
|
||||
#define BLACK(obj) obj->setPalette(QWidget::palette());
|
||||
|
||||
32
rpc/gRPC.cpp
32
rpc/gRPC.cpp
@@ -34,13 +34,13 @@ namespace QtGrpc {
|
||||
|
||||
// TODO WTF
|
||||
// https://github.com/semlanik/qtprotobuf/issues/116
|
||||
// setCachingEnabled: 5 bytesDownloaded
|
||||
// QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written
|
||||
// setCachingEnabled: 5 bytesDownloaded
|
||||
// QNetworkReplyImpl: backend error: caching was enabled after some bytes had been written
|
||||
|
||||
// async
|
||||
QNetworkReply *post(const QString &method, const QString &service, const QByteArray &args) {
|
||||
QUrl callUrl = url_base + "/" + service + "/" + method;
|
||||
// qDebug() << "Service call url: " << callUrl;
|
||||
// qDebug() << "Service call url: " << callUrl;
|
||||
|
||||
QNetworkRequest request(callUrl);
|
||||
request.setAttribute(QNetworkRequest::CacheSaveControlAttribute, false);
|
||||
@@ -144,15 +144,17 @@ namespace QtGrpc {
|
||||
QMutex lock;
|
||||
lock.lock();
|
||||
|
||||
runOnUiThread([&] {
|
||||
err = call(methodName, serviceName, requestArray, responseArray, timeout_ms);
|
||||
lock.unlock();
|
||||
}, nm);
|
||||
runOnUiThread(
|
||||
[&] {
|
||||
err = call(methodName, serviceName, requestArray, responseArray, timeout_ms);
|
||||
lock.unlock();
|
||||
},
|
||||
nm);
|
||||
|
||||
lock.lock();
|
||||
lock.unlock();
|
||||
// qDebug() << "rsp err" << err;
|
||||
// qDebug() << "rsp array" << responseArray;
|
||||
// qDebug() << "rsp err" << err;
|
||||
// qDebug() << "rsp array" << responseArray;
|
||||
|
||||
if (err != QNetworkReply::NetworkError::NoError) {
|
||||
return err;
|
||||
@@ -162,9 +164,8 @@ namespace QtGrpc {
|
||||
}
|
||||
return QNetworkReply::NetworkError::NoError;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
} // namespace QtGrpc
|
||||
|
||||
namespace NekoRay::rpc {
|
||||
Client::Client(std::function<void(const QString &)> onError, const QString &target, const QString &token) {
|
||||
@@ -172,10 +173,9 @@ namespace NekoRay::rpc {
|
||||
this->onError = std::move(onError);
|
||||
}
|
||||
|
||||
#define NOT_OK *rpcOK = false; \
|
||||
onError( \
|
||||
QString("QNetworkReply::NetworkError code: %1\n").arg(status) \
|
||||
);
|
||||
#define NOT_OK \
|
||||
*rpcOK = false; \
|
||||
onError(QString("QNetworkReply::NetworkError code: %1\n").arg(status));
|
||||
|
||||
void Client::Exit() {
|
||||
libcore::EmptyReq request;
|
||||
@@ -276,6 +276,6 @@ namespace NekoRay::rpc {
|
||||
return reply;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace NekoRay::rpc
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,5 @@ namespace NekoRay::rpc {
|
||||
};
|
||||
|
||||
inline Client *defaultClient;
|
||||
}
|
||||
} // namespace NekoRay::rpc
|
||||
#endif
|
||||
|
||||
|
||||
@@ -33,15 +33,14 @@ namespace NekoRay::sub {
|
||||
stream->security = "tls";
|
||||
}
|
||||
// 2. TLS SNI: v2rayN config builder generate sni like this, so set sni here for their format.
|
||||
if (stream->security == "tls" && IsIpAddress(ent->bean->serverAddress)
|
||||
&& (!stream->host.isEmpty()) && stream->sni.isEmpty()) {
|
||||
stream->sni = stream->host;;
|
||||
if (stream->security == "tls" && IsIpAddress(ent->bean->serverAddress) && (!stream->host.isEmpty()) && stream->sni.isEmpty()) {
|
||||
stream->sni = stream->host;
|
||||
}
|
||||
}
|
||||
|
||||
void RawUpdater::update(const QString &str) {
|
||||
// Base64 encoded subscription
|
||||
if (auto str2 = DecodeB64IfValid(str);!str2.isEmpty()) {
|
||||
if (auto str2 = DecodeB64IfValid(str); !str2.isEmpty()) {
|
||||
update(str2);
|
||||
return;
|
||||
}
|
||||
@@ -202,7 +201,7 @@ namespace NekoRay::sub {
|
||||
|
||||
#endif
|
||||
|
||||
// https://github.com/Dreamacro/clash/wiki/configuration
|
||||
// https://github.com/Dreamacro/clash/wiki/configuration
|
||||
void RawUpdater::updateClash(const QString &str) {
|
||||
#ifndef NKR_NO_EXTERNAL
|
||||
try {
|
||||
@@ -364,8 +363,7 @@ namespace NekoRay::sub {
|
||||
|
||||
auto resp = NetworkRequestHelper::HttpGet(content);
|
||||
if (!resp.error.isEmpty()) {
|
||||
MW_show_log("<<<<<<<< " + QObject::tr("Requesting subscription %1 error: %2")
|
||||
.arg(groupName, resp.error + "\n" + resp.data));
|
||||
MW_show_log("<<<<<<<< " + QObject::tr("Requesting subscription %1 error: %2").arg(groupName, resp.error + "\n" + resp.data));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -373,11 +371,11 @@ namespace NekoRay::sub {
|
||||
sub_user_info = NetworkRequestHelper::GetHeader(resp.header, "Subscription-UserInfo");
|
||||
}
|
||||
|
||||
QList<QSharedPointer<ProxyEntity>> in; // 更新前
|
||||
QList<QSharedPointer<ProxyEntity>> out_all; // 更新前 + 更新后
|
||||
QList<QSharedPointer<ProxyEntity>> out; // 更新后
|
||||
QList<QSharedPointer<ProxyEntity>> only_in; // 只在更新前有的
|
||||
QList<QSharedPointer<ProxyEntity>> only_out; // 只在更新后有的
|
||||
QList<QSharedPointer<ProxyEntity>> in; // 更新前
|
||||
QList<QSharedPointer<ProxyEntity>> out_all; // 更新前 + 更新后
|
||||
QList<QSharedPointer<ProxyEntity>> out; // 更新后
|
||||
QList<QSharedPointer<ProxyEntity>> only_in; // 只在更新前有的
|
||||
QList<QSharedPointer<ProxyEntity>> only_out; // 只在更新后有的
|
||||
QList<QSharedPointer<ProxyEntity>> update_del; // 更新前后都有的,删除更新后多余的
|
||||
|
||||
// 订阅解析前
|
||||
@@ -423,8 +421,10 @@ namespace NekoRay::sub {
|
||||
}
|
||||
|
||||
auto change = "\n" + QObject::tr("Added %1 profiles:\n%2\nDeleted %3 Profiles:\n%4")
|
||||
.arg(only_out.length()).arg(notice_added)
|
||||
.arg(only_in.length()).arg(notice_deleted);
|
||||
.arg(only_out.length())
|
||||
.arg(notice_added)
|
||||
.arg(only_in.length())
|
||||
.arg(notice_deleted);
|
||||
if (only_out.length() + only_in.length() == 0) change = QObject::tr("Nothing");
|
||||
MW_show_log("<<<<<<<< " + QObject::tr("Change of %1:").arg(group->name) + " " + change);
|
||||
MW_dialog_message("SubUpdater", "finish-dingyue");
|
||||
@@ -433,4 +433,4 @@ namespace NekoRay::sub {
|
||||
MW_dialog_message("SubUpdater", "finish");
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace NekoRay::sub
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace NekoRay::sub {
|
||||
};
|
||||
|
||||
class GroupUpdater : public QObject {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
void AsyncUpdate(const QString &str, int _sub_gid = -1, const std::function<void()> &finish = nullptr);
|
||||
@@ -28,5 +28,4 @@ namespace NekoRay::sub {
|
||||
};
|
||||
|
||||
extern GroupUpdater *groupUpdater;
|
||||
}
|
||||
|
||||
} // namespace NekoRay::sub
|
||||
|
||||
@@ -27,8 +27,7 @@ void AutoRun_SetEnabled(bool enable) {
|
||||
QFileInfo fInfo(appPath);
|
||||
QString name = fInfo.baseName();
|
||||
|
||||
QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
|
||||
QSettings::NativeFormat);
|
||||
QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
||||
|
||||
if (enable) {
|
||||
settings.setValue(name, Windows_GenAutoRunString());
|
||||
@@ -38,8 +37,7 @@ void AutoRun_SetEnabled(bool enable) {
|
||||
}
|
||||
|
||||
bool AutoRun_IsEnabled() {
|
||||
QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
|
||||
QSettings::NativeFormat);
|
||||
QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", QSettings::NativeFormat);
|
||||
|
||||
//以程序名称作为注册表中的键
|
||||
//根据键获取对应的值(程序路径)
|
||||
@@ -50,7 +48,6 @@ bool AutoRun_IsEnabled() {
|
||||
return settings.value(name).toString() == Windows_GenAutoRunString();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
@@ -66,7 +63,7 @@ void AutoRun_SetEnabled(bool enable) {
|
||||
if (loginItems && enable) {
|
||||
// Insert an item to the list.
|
||||
LSSharedFileListItemRef item =
|
||||
LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, 0, 0, urlRef, 0, 0);
|
||||
LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemLast, 0, 0, urlRef, 0, 0);
|
||||
|
||||
if (item) CFRelease(item);
|
||||
|
||||
@@ -194,13 +191,13 @@ void AutoRun_SetEnabled(bool enable) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
ts.setCodec("UTF-8");
|
||||
#endif
|
||||
ts << QLatin1String("[Desktop Entry]") << NEWLINE //
|
||||
<< QLatin1String("Name=") << appName << NEWLINE //
|
||||
<< QLatin1String("Exec=") << appCmdList.join(" ") << NEWLINE //
|
||||
<< QLatin1String("Terminal=") << "false" << NEWLINE //
|
||||
<< QLatin1String("Categories=") << "Network" << NEWLINE //
|
||||
<< QLatin1String("Type=") << "Application" << NEWLINE //
|
||||
<< QLatin1String("StartupNotify=") << "false" << NEWLINE //
|
||||
ts << QLatin1String("[Desktop Entry]") << NEWLINE
|
||||
<< QLatin1String("Name=") << appName << NEWLINE
|
||||
<< QLatin1String("Exec=") << appCmdList.join(" ") << NEWLINE
|
||||
<< QLatin1String("Terminal=") << "false" << NEWLINE
|
||||
<< QLatin1String("Categories=") << "Network" << NEWLINE
|
||||
<< QLatin1String("Type=") << "Application" << NEWLINE
|
||||
<< QLatin1String("StartupNotify=") << "false" << NEWLINE
|
||||
<< QLatin1String("X-GNOME-Autostart-enabled=") << "true" << NEWLINE;
|
||||
ts.flush();
|
||||
iniFile.close();
|
||||
|
||||
@@ -95,17 +95,21 @@ namespace NekoRay::sys {
|
||||
MW_show_log("[Error] core exited, restarting.\n");
|
||||
|
||||
// Restart
|
||||
setTimeout([=] {
|
||||
Kill();
|
||||
ExternalProcess::started = false;
|
||||
Start();
|
||||
}, this, 1000);
|
||||
setTimeout(
|
||||
[=] {
|
||||
Kill();
|
||||
ExternalProcess::started = false;
|
||||
Start();
|
||||
},
|
||||
this, 1000);
|
||||
} else if (state == QProcess::Running && restart_id >= 0) {
|
||||
// Restart profile
|
||||
setTimeout([=] {
|
||||
MW_dialog_message("ExternalProcess", "CoreRestarted," + Int2String(restart_id));
|
||||
restart_id = -1;
|
||||
}, this, 1000);
|
||||
setTimeout(
|
||||
[=] {
|
||||
MW_dialog_message("ExternalProcess", "CoreRestarted," + Int2String(restart_id));
|
||||
restart_id = -1;
|
||||
},
|
||||
this, 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -122,4 +126,4 @@ namespace NekoRay::sys {
|
||||
write((dataStore->core_token + "\n").toUtf8());
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace NekoRay::sys
|
||||
|
||||
@@ -43,4 +43,4 @@ namespace NekoRay::sys {
|
||||
|
||||
// start & kill change this list
|
||||
inline QList<ExternalProcess *> running_ext;
|
||||
}
|
||||
} // namespace NekoRay::sys
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
#include <QDateTime>
|
||||
#include <QMessageBox>
|
||||
|
||||
typedef BOOL( WINAPI *MINIDUMPWRITEDUMP )(
|
||||
HANDLE hProcess,
|
||||
DWORD dwPid,
|
||||
HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
typedef BOOL(WINAPI *MINIDUMPWRITEDUMP)(
|
||||
HANDLE hProcess,
|
||||
DWORD dwPid,
|
||||
HANDLE hFile,
|
||||
MINIDUMP_TYPE DumpType,
|
||||
CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||
CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
|
||||
CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam);
|
||||
|
||||
LONG CreateCrashHandler(EXCEPTION_POINTERS *pException) {
|
||||
QDir::setCurrent(QApplication::applicationDirPath());
|
||||
@@ -30,7 +30,7 @@ LONG CreateCrashHandler(EXCEPTION_POINTERS *pException) {
|
||||
//创建 Dump 文件
|
||||
QDateTime CurDTime = QDateTime::currentDateTime();
|
||||
QString current_date = CurDTime.toString("yyyy_MM_dd_hh_mm_ss");
|
||||
//dmp文件的命名
|
||||
// dmp文件的命名
|
||||
QString dumpText = "Dump_" + current_date + ".dmp";
|
||||
EXCEPTION_RECORD *record = pException->ExceptionRecord;
|
||||
QString errCode(QString::number(record->ExceptionCode, 16));
|
||||
@@ -46,7 +46,7 @@ LONG CreateCrashHandler(EXCEPTION_POINTERS *pException) {
|
||||
dumpInfo.ClientPointers = TRUE;
|
||||
//将dump信息写入dmp文件
|
||||
Dump(GetCurrentProcess(), GetCurrentProcessId(), DumpHandle, MiniDumpNormal, &dumpInfo,
|
||||
NULL, NULL);
|
||||
NULL, NULL);
|
||||
CloseHandle(DumpHandle);
|
||||
} else {
|
||||
dumpText = "";
|
||||
@@ -54,12 +54,16 @@ LONG CreateCrashHandler(EXCEPTION_POINTERS *pException) {
|
||||
//创建消息提示
|
||||
QMessageBox::warning(NULL, "Application crashed",
|
||||
QString("ErrorCode: %1 ErrorAddr:%2 ErrorFlag: %3 ErrorPara: %4\nVersion: %5\nDump file at %6")
|
||||
.arg(errCode).arg(errAddr).arg(errFlag).arg(errPara)
|
||||
.arg(NKR_VERSION).arg(dumpText),
|
||||
.arg(errCode)
|
||||
.arg(errAddr)
|
||||
.arg(errFlag)
|
||||
.arg(errPara)
|
||||
.arg(NKR_VERSION)
|
||||
.arg(dumpText),
|
||||
QMessageBox::Ok);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
}
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
void Windows_SetCrashHandler() {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#ifdef __MINGW32__
|
||||
|
||||
void Windows_SetCrashHandler(){}
|
||||
void Windows_SetCrashHandler() {}
|
||||
|
||||
#else
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ namespace NekoRay {
|
||||
|
||||
struct GroupSortAction {
|
||||
GroupSortMethod::GroupSortMethod method = GroupSortMethod::Raw;
|
||||
bool save_sort = false; //保存到文件
|
||||
bool save_sort = false; //保存到文件
|
||||
bool descending = false; //默认升序,开这个就是降序
|
||||
bool scroll_to_started = false;
|
||||
};
|
||||
}
|
||||
} // namespace NekoRay
|
||||
|
||||
@@ -36,12 +36,12 @@ QIcon TrayIcon::GetIcon(TrayIcon::TrayIconStatus status) {
|
||||
p.setBrush(QBrush(Qt::red));
|
||||
}
|
||||
p.drawRoundedRect(
|
||||
QRect(side - d - margin,
|
||||
side - d - margin,
|
||||
d,
|
||||
d),
|
||||
radius,
|
||||
radius);
|
||||
QRect(side - d - margin,
|
||||
side - d - margin,
|
||||
d,
|
||||
d),
|
||||
radius,
|
||||
radius);
|
||||
p.end();
|
||||
|
||||
return pixmap;
|
||||
|
||||
@@ -13,4 +13,4 @@ namespace TrayIcon {
|
||||
|
||||
QIcon GetIcon(TrayIconStatus status);
|
||||
|
||||
}
|
||||
} // namespace TrayIcon
|
||||
|
||||
@@ -22,7 +22,7 @@ public:
|
||||
|
||||
explicit ExtraCoreWidget(QJsonObject *extraCore, const QString &coreName_,
|
||||
QWidget *parent = nullptr)
|
||||
: QWidget(parent) {
|
||||
: QWidget(parent) {
|
||||
coreName = coreName_;
|
||||
label_name = new QLabel;
|
||||
label_name->setText(coreName);
|
||||
@@ -51,7 +51,7 @@ public:
|
||||
};
|
||||
|
||||
DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::DialogBasicSettings) {
|
||||
: QDialog(parent), ui(new Ui::DialogBasicSettings) {
|
||||
ui->setupUi(this);
|
||||
|
||||
// Common
|
||||
@@ -85,10 +85,8 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
auto str = QInputDialog::getItem(this, ui->sys_proxy_format->text() + " (Windows)",
|
||||
tr("Advanced system proxy settings. Please select a format."),
|
||||
Preset::Windows::system_proxy_format,
|
||||
Preset::Windows::system_proxy_format.indexOf(
|
||||
NekoRay::dataStore->system_proxy_format),
|
||||
false, &ok
|
||||
);
|
||||
Preset::Windows::system_proxy_format.indexOf(NekoRay::dataStore->system_proxy_format),
|
||||
false, &ok);
|
||||
if (ok) NekoRay::dataStore->system_proxy_format = str;
|
||||
});
|
||||
#else
|
||||
@@ -174,7 +172,8 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
bool ok;
|
||||
auto s = QInputDialog::getText(nullptr, tr("Add"),
|
||||
tr("Please input the core name."),
|
||||
QLineEdit::Normal, "", &ok).trimmed();
|
||||
QLineEdit::Normal, "", &ok)
|
||||
.trimmed();
|
||||
if (s.isEmpty() || !ok) return;
|
||||
if (CACHE.extraCore.contains(s)) return;
|
||||
extra_core_layout->addWidget(new ExtraCoreWidget(&CACHE.extraCore, s));
|
||||
@@ -212,8 +211,7 @@ DialogBasicSettings::DialogBasicSettings(QWidget *parent)
|
||||
QString core_name_new = dynamic_cast<QRadioButton *>(sender())->text();
|
||||
if (QMessageBox::question(this, tr("Confirmation"),
|
||||
tr("Switching the core to %1, click \"Yes\" to complete the switch and the program will restart. This feature may be unstable, please do not switch frequently.")
|
||||
.arg(core_name_new)
|
||||
) == QMessageBox::StandardButton::Yes) {
|
||||
.arg(core_name_new)) == QMessageBox::StandardButton::Yes) {
|
||||
QFile file;
|
||||
file.setFileName("groups/coreType");
|
||||
file.open(QIODevice::ReadWrite | QIODevice::Truncate);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Ui {
|
||||
}
|
||||
|
||||
class DialogBasicSettings : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogBasicSettings(QWidget *parent = nullptr);
|
||||
@@ -32,7 +32,6 @@ private:
|
||||
private slots:
|
||||
|
||||
void on_set_custom_icon_clicked();
|
||||
|
||||
};
|
||||
|
||||
#endif // DIALOG_BASIC_SETTINGS_H
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#include "ui/mainwindow_interface.h"
|
||||
|
||||
DialogHotkey::DialogHotkey(QWidget *parent) :
|
||||
QDialog(parent), ui(new Ui::DialogHotkey) {
|
||||
DialogHotkey::DialogHotkey(QWidget *parent) : QDialog(parent), ui(new Ui::DialogHotkey) {
|
||||
ui->setupUi(this);
|
||||
ui->show_mainwindow->setKeySequence(NekoRay::dataStore->hotkey_mainwindow);
|
||||
ui->show_groups->setKeySequence(NekoRay::dataStore->hotkey_group);
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
#include "main/NekoRay.hpp"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class DialogHotkey; }
|
||||
namespace Ui {
|
||||
class DialogHotkey;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DialogHotkey : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogHotkey(QWidget *parent = nullptr);
|
||||
|
||||
@@ -11,18 +11,17 @@
|
||||
#include <QListWidgetItem>
|
||||
#include <QMessageBox>
|
||||
|
||||
#define AddGroupToListIfExist(_id) \
|
||||
auto __ent = NekoRay::profileManager->GetGroup(_id); \
|
||||
if (__ent != nullptr) { \
|
||||
auto wI = new QListWidgetItem(); \
|
||||
auto w = new GroupItem(this, __ent, wI); \
|
||||
wI->setData(114514, _id); \
|
||||
ui->listWidget->addItem(wI); \
|
||||
ui->listWidget->setItemWidget(wI, w); \
|
||||
}
|
||||
#define AddGroupToListIfExist(_id) \
|
||||
auto __ent = NekoRay::profileManager->GetGroup(_id); \
|
||||
if (__ent != nullptr) { \
|
||||
auto wI = new QListWidgetItem(); \
|
||||
auto w = new GroupItem(this, __ent, wI); \
|
||||
wI->setData(114514, _id); \
|
||||
ui->listWidget->addItem(wI); \
|
||||
ui->listWidget->setItemWidget(wI, w); \
|
||||
}
|
||||
|
||||
DialogManageGroups::DialogManageGroups(QWidget *parent) :
|
||||
QDialog(parent), ui(new Ui::DialogManageGroups) {
|
||||
DialogManageGroups::DialogManageGroups(QWidget *parent) : QDialog(parent), ui(new Ui::DialogManageGroups) {
|
||||
ui->setupUi(this);
|
||||
|
||||
for (auto id: NekoRay::profileManager->_groups) {
|
||||
@@ -47,14 +46,13 @@ void DialogManageGroups::on_add_clicked() {
|
||||
|
||||
if (ret == QDialog::Accepted) {
|
||||
NekoRay::profileManager->AddGroup(ent);
|
||||
AddGroupToListIfExist(ent->id)
|
||||
AddGroupToListIfExist(ent->id);
|
||||
MW_dialog_message(Dialog_DialogManageGroups, "refresh-1");
|
||||
}
|
||||
}
|
||||
|
||||
void DialogManageGroups::on_update_all_clicked() {
|
||||
if (QMessageBox::question(this, tr("Confirmation"), tr("Update all subscriptions?"))
|
||||
== QMessageBox::StandardButton::Yes) {
|
||||
if (QMessageBox::question(this, tr("Confirmation"), tr("Update all subscriptions?")) == QMessageBox::StandardButton::Yes) {
|
||||
for (const auto &gid: NekoRay::profileManager->_groups) {
|
||||
auto group = NekoRay::profileManager->GetGroup(gid);
|
||||
if (group == nullptr || group->url.isEmpty()) continue;
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
#include "db/Group.hpp"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class DialogManageGroups; }
|
||||
namespace Ui {
|
||||
class DialogManageGroups;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DialogManageGroups : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogManageGroups(QWidget *parent = nullptr);
|
||||
|
||||
@@ -9,23 +9,22 @@
|
||||
#include <QMessageBox>
|
||||
#include <QListWidget>
|
||||
|
||||
#define REFRESH_ACTIVE_ROUTING(a, r) \
|
||||
active_routing = a; \
|
||||
ui->active_routing->setText("[" + active_routing + "]"); \
|
||||
setWindowTitle(title_base + " [" + a + "]"); \
|
||||
SetRouteConfig(*r);
|
||||
#define REFRESH_ACTIVE_ROUTING(a, r) \
|
||||
active_routing = a; \
|
||||
ui->active_routing->setText("[" + active_routing + "]"); \
|
||||
setWindowTitle(title_base + " [" + a + "]"); \
|
||||
SetRouteConfig(*r);
|
||||
|
||||
#define SAVE_TO_ROUTING(r) \
|
||||
r->direct_ip = directIPTxt->toPlainText(); \
|
||||
r->direct_domain = directDomainTxt->toPlainText(); \
|
||||
r->proxy_ip = proxyIPTxt->toPlainText(); \
|
||||
r->proxy_domain = proxyDomainTxt->toPlainText(); \
|
||||
r->block_ip = blockIPTxt->toPlainText(); \
|
||||
r->block_domain = blockDomainTxt->toPlainText(); \
|
||||
r->custom = CACHE.custom_route;
|
||||
#define SAVE_TO_ROUTING(r) \
|
||||
r->direct_ip = directIPTxt->toPlainText(); \
|
||||
r->direct_domain = directDomainTxt->toPlainText(); \
|
||||
r->proxy_ip = proxyIPTxt->toPlainText(); \
|
||||
r->proxy_domain = proxyDomainTxt->toPlainText(); \
|
||||
r->block_ip = blockIPTxt->toPlainText(); \
|
||||
r->block_domain = blockDomainTxt->toPlainText(); \
|
||||
r->custom = CACHE.custom_route;
|
||||
|
||||
DialogManageRoutes::DialogManageRoutes(QWidget *parent) :
|
||||
QDialog(parent), ui(new Ui::DialogManageRoutes) {
|
||||
DialogManageRoutes::DialogManageRoutes(QWidget *parent) : QDialog(parent), ui(new Ui::DialogManageRoutes) {
|
||||
ui->setupUi(this);
|
||||
title_base = windowTitle();
|
||||
|
||||
@@ -171,9 +170,7 @@ void DialogManageRoutes::on_load_save_clicked() {
|
||||
r->load_control_force = true;
|
||||
r->fn = ROUTES_PREFIX + fn;
|
||||
if (r->Load()) {
|
||||
auto btn = QMessageBox::question(nullptr,
|
||||
software_name, tr("Load routing: %1").arg(fn) + "\n" + r->toString());
|
||||
if (btn == QMessageBox::Yes) {
|
||||
if (QMessageBox::question(nullptr, software_name, tr("Load routing: %1").arg(fn) + "\n" + r->toString()) == QMessageBox::Yes) {
|
||||
REFRESH_ACTIVE_ROUTING(fn, r)
|
||||
w->accept();
|
||||
}
|
||||
@@ -186,9 +183,7 @@ void DialogManageRoutes::on_load_save_clicked() {
|
||||
auto r = std::make_unique<NekoRay::Routing>();
|
||||
SAVE_TO_ROUTING(r)
|
||||
r->fn = ROUTES_PREFIX + fn;
|
||||
auto btn = QMessageBox::question(nullptr, software_name,
|
||||
tr("Save routing: %1").arg(fn) + "\n" + r->toString());
|
||||
if (btn == QMessageBox::Yes) {
|
||||
if (QMessageBox::question(nullptr, software_name, tr("Save routing: %1").arg(fn) + "\n" + r->toString()) == QMessageBox::Yes) {
|
||||
r->Save();
|
||||
REFRESH_ACTIVE_ROUTING(fn, r)
|
||||
w->accept();
|
||||
@@ -198,8 +193,7 @@ void DialogManageRoutes::on_load_save_clicked() {
|
||||
connect(remove, &QPushButton::clicked, w, [=] {
|
||||
auto fn = lineEdit->text();
|
||||
if (!fn.isEmpty() && NekoRay::Routing::List().length() > 1) {
|
||||
auto btn = QMessageBox::question(nullptr, software_name, tr("Remove routing: %1").arg(fn));
|
||||
if (btn == QMessageBox::Yes) {
|
||||
if (QMessageBox::question(nullptr, software_name, tr("Remove routing: %1").arg(fn)) == QMessageBox::Yes) {
|
||||
QFile f(ROUTES_PREFIX + fn);
|
||||
f.remove();
|
||||
if (NekoRay::dataStore->active_routing == fn) {
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#include "main/NekoRay.hpp"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class DialogManageRoutes; }
|
||||
namespace Ui {
|
||||
class DialogManageRoutes;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DialogManageRoutes : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogManageRoutes(QWidget *parent = nullptr);
|
||||
@@ -53,5 +55,3 @@ public slots:
|
||||
|
||||
void on_load_save_clicked();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@
|
||||
#include "main/GuiUtils.hpp"
|
||||
#include "main/NekoRay.hpp"
|
||||
|
||||
DialogVPNSettings::DialogVPNSettings(QWidget *parent) :
|
||||
QDialog(parent), ui(new Ui::DialogVPNSettings) {
|
||||
DialogVPNSettings::DialogVPNSettings(QWidget *parent) : QDialog(parent), ui(new Ui::DialogVPNSettings) {
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->fake_dns->setVisible(!IS_NEKO_BOX);
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class DialogVPNSettings; }
|
||||
namespace Ui {
|
||||
class DialogVPNSettings;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DialogVPNSettings : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogVPNSettings(QWidget *parent = nullptr);
|
||||
@@ -22,8 +23,6 @@ private:
|
||||
public slots:
|
||||
|
||||
void accept() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //NEKORAY_DIALOG_VPN_SETTINGS_H
|
||||
#endif // NEKORAY_DIALOG_VPN_SETTINGS_H
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
#include <QClipboard>
|
||||
|
||||
DialogEditGroup::DialogEditGroup(const QSharedPointer<NekoRay::Group> &ent, QWidget *parent) :
|
||||
QDialog(parent), ui(new Ui::DialogEditGroup) {
|
||||
DialogEditGroup::DialogEditGroup(const QSharedPointer<NekoRay::Group> &ent, QWidget *parent)
|
||||
: QDialog(parent), ui(new Ui::DialogEditGroup) {
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->type, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index) {
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
#include "db/Group.hpp"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class DialogEditGroup; }
|
||||
namespace Ui {
|
||||
class DialogEditGroup;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DialogEditGroup : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogEditGroup(const QSharedPointer<NekoRay::Group> &ent, QWidget *parent = nullptr);
|
||||
@@ -18,5 +20,3 @@ public:
|
||||
private:
|
||||
Ui::DialogEditGroup *ui;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@
|
||||
#define LOAD_TYPE(a) ui->type->addItem(NekoRay::ProfileManager::NewProxyEntity(a)->bean->DisplayType(), a);
|
||||
|
||||
DialogEditProfile::DialogEditProfile(const QString &_type, int profileOrGroupId, QWidget *parent)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::DialogEditProfile) {
|
||||
: QDialog(parent), ui(new Ui::DialogEditProfile) {
|
||||
// setup UI
|
||||
ui->setupUi(this);
|
||||
ui->dialog_layout->setAlignment(ui->left, Qt::AlignTop);
|
||||
@@ -244,7 +243,7 @@ void DialogEditProfile::typeSelected(const QString &newType) {
|
||||
ui->name->setText(ent->bean->name);
|
||||
ui->address->setText(ent->bean->serverAddress);
|
||||
ui->port->setText(Int2String(ent->bean->serverPort));
|
||||
ui->port->setValidator(QRegExpValidator_Number, this));
|
||||
ui->port->setValidator(QRegExpValidator_Number);
|
||||
|
||||
// 星号
|
||||
for (auto label: findChildren<QLabel *>()) {
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Ui {
|
||||
}
|
||||
|
||||
class DialogEditProfile : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DialogEditProfile(const QString &_type, int profileOrGroupId, QWidget *parent = nullptr);
|
||||
|
||||
@@ -4,11 +4,13 @@
|
||||
#include "profile_editor.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class EditChain; }
|
||||
namespace Ui {
|
||||
class EditChain;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class EditChain : public QWidget, public ProfileEditor {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditChain(QWidget *parent = nullptr);
|
||||
|
||||
@@ -5,16 +5,15 @@
|
||||
#include "fmt/CustomBean.hpp"
|
||||
#include "fmt/Preset.hpp"
|
||||
|
||||
EditCustom::EditCustom(QWidget *parent) :
|
||||
QWidget(parent), ui(new Ui::EditCustom) {
|
||||
EditCustom::EditCustom(QWidget *parent) : QWidget(parent), ui(new Ui::EditCustom) {
|
||||
ui->setupUi(this);
|
||||
ui->config_simple->setPlaceholderText("example:\n"
|
||||
" server-address: \"127.0.0.1:%mapping_port%\"\n"
|
||||
" listen-address: \"127.0.0.1\"\n"
|
||||
" listen-port: %socks_port%\n"
|
||||
" host: your-domain.com\n"
|
||||
" sni: your-domain.com\n"
|
||||
);
|
||||
ui->config_simple->setPlaceholderText(
|
||||
"example:\n"
|
||||
" server-address: \"127.0.0.1:%mapping_port%\"\n"
|
||||
" listen-address: \"127.0.0.1\"\n"
|
||||
" listen-port: %socks_port%\n"
|
||||
" host: your-domain.com\n"
|
||||
" sni: your-domain.com\n");
|
||||
}
|
||||
|
||||
EditCustom::~EditCustom() {
|
||||
@@ -36,14 +35,14 @@ void EditCustom::onStart(QSharedPointer<NekoRay::ProxyEntity> _ent) {
|
||||
preset_config = Preset::Hysteria::config;
|
||||
ui->config_simple->setPlaceholderText("");
|
||||
ui->core->hide();
|
||||
ui->core_l->setText(
|
||||
tr("Please read the documentation. If you don't understand, use a share link instead."));
|
||||
ui->core_l->setText(tr("Please read the documentation. If you don't understand, use a share link instead."));
|
||||
} else if (preset_core == "internal") {
|
||||
preset_command = preset_config = "";
|
||||
ui->config_simple->setPlaceholderText("{\n"
|
||||
" \"type\": \"socks\",\n"
|
||||
" // ...\n"
|
||||
"}");
|
||||
ui->config_simple->setPlaceholderText(
|
||||
"{\n"
|
||||
" \"type\": \"socks\",\n"
|
||||
" // ...\n"
|
||||
"}");
|
||||
}
|
||||
|
||||
// load core ui
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
#include <QWidget>
|
||||
#include "profile_editor.h"
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class EditCustom; }
|
||||
namespace Ui {
|
||||
class EditCustom;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class EditCustom : public QWidget, public ProfileEditor {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QString preset_core;
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
|
||||
#include <QInputDialog>
|
||||
|
||||
EditNaive::EditNaive(QWidget *parent) :
|
||||
QWidget(parent), ui(new Ui::EditNaive) {
|
||||
EditNaive::EditNaive(QWidget *parent) : QWidget(parent), ui(new Ui::EditNaive) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
@@ -43,8 +42,8 @@ bool EditNaive::onEnd() {
|
||||
|
||||
QList<QPair<QPushButton *, QString>> EditNaive::get_editor_cached() {
|
||||
return {
|
||||
{ui->certificate, CACHE.certificate},
|
||||
{ui->extra_headers, CACHE.extra_headers},
|
||||
{ui->certificate, CACHE.certificate},
|
||||
{ui->extra_headers, CACHE.extra_headers},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
#include <QWidget>
|
||||
#include "profile_editor.h"
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class EditNaive; }
|
||||
namespace Ui {
|
||||
class EditNaive;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class EditNaive : public QWidget, public ProfileEditor {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditNaive(QWidget *parent = nullptr);
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Ui {
|
||||
}
|
||||
|
||||
class EditShadowSocks : public QWidget, public ProfileEditor {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditShadowSocks(QWidget *parent = nullptr);
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Ui {
|
||||
}
|
||||
|
||||
class EditSocksHttp : public QWidget, public ProfileEditor {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditSocksHttp(QWidget *parent = nullptr);
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#include "fmt/TrojanVLESSBean.hpp"
|
||||
|
||||
EditTrojanVLESS::EditTrojanVLESS(QWidget *parent) :
|
||||
QWidget(parent), ui(new Ui::EditTrojanVLESS) {
|
||||
EditTrojanVLESS::EditTrojanVLESS(QWidget *parent) : QWidget(parent), ui(new Ui::EditTrojanVLESS) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
#include <QWidget>
|
||||
#include "profile_editor.h"
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class EditTrojanVLESS; }
|
||||
namespace Ui {
|
||||
class EditTrojanVLESS;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class EditTrojanVLESS : public QWidget, public ProfileEditor {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditTrojanVLESS(QWidget *parent = nullptr);
|
||||
@@ -24,5 +25,3 @@ private:
|
||||
Ui::EditTrojanVLESS *ui;
|
||||
QSharedPointer<NekoRay::ProxyEntity> ent;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
|
||||
#include "fmt/VMessBean.hpp"
|
||||
|
||||
EditVMess::EditVMess(QWidget *parent) :
|
||||
QWidget(parent), ui(new Ui::EditVMess) {
|
||||
EditVMess::EditVMess(QWidget *parent) : QWidget(parent), ui(new Ui::EditVMess) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
#include <QWidget>
|
||||
#include "profile_editor.h"
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class EditVMess; }
|
||||
namespace Ui {
|
||||
class EditVMess;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class EditVMess : public QWidget, public ProfileEditor {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit EditVMess(QWidget *parent = nullptr);
|
||||
@@ -24,5 +25,3 @@ private:
|
||||
Ui::EditVMess *ui;
|
||||
QSharedPointer<NekoRay::ProxyEntity> ent;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -55,13 +55,10 @@ void UI_InitMainWindow() {
|
||||
mainwindow = new MainWindow;
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent), ui(new Ui::MainWindow) {
|
||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
|
||||
mainwindow = this;
|
||||
MW_dialog_message = [=](const QString &a, const QString &b) {
|
||||
runOnUiThread([=] {
|
||||
dialog_message_impl(a, b);
|
||||
});
|
||||
runOnUiThread([=] { dialog_message_impl(a, b); });
|
||||
};
|
||||
|
||||
// Load Manager
|
||||
@@ -111,10 +108,8 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
ui->toolButton_preferences->setMenu(ui->menu_preferences);
|
||||
ui->toolButton_server->setMenu(ui->menu_server);
|
||||
ui->menubar->setVisible(false);
|
||||
connect(ui->toolButton_document, &QToolButton::clicked, this,
|
||||
[=] { QDesktopServices::openUrl(QUrl("https://matsuridayo.github.io/")); });
|
||||
connect(ui->toolButton_ads, &QToolButton::clicked, this,
|
||||
[=] { QDesktopServices::openUrl(QUrl("https://matsuricom.github.io/")); });
|
||||
connect(ui->toolButton_document, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://matsuridayo.github.io/")); });
|
||||
connect(ui->toolButton_ads, &QToolButton::clicked, this, [=] { QDesktopServices::openUrl(QUrl("https://matsuricom.github.io/")); });
|
||||
connect(ui->toolButton_update, &QToolButton::clicked, this, [=] { runOnNewThread([=] { CheckUpdate(); }); });
|
||||
|
||||
// Setup log UI
|
||||
@@ -142,19 +137,13 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
bar->setValue(bar->maximum());
|
||||
});
|
||||
MW_show_log = [=](const QString &log) {
|
||||
runOnUiThread([=] {
|
||||
show_log_impl(log);
|
||||
});
|
||||
runOnUiThread([=] { show_log_impl(log); });
|
||||
};
|
||||
MW_show_log_ext = [=](const QString &tag, const QString &log) {
|
||||
runOnUiThread([=] {
|
||||
show_log_impl("[" + tag + "] " + log);
|
||||
});
|
||||
runOnUiThread([=] { show_log_impl("[" + tag + "] " + log); });
|
||||
};
|
||||
MW_show_log_ext_vt100 = [=](const QString &log) {
|
||||
runOnUiThread([=] {
|
||||
show_log_impl(cleanVT100String(log));
|
||||
});
|
||||
runOnUiThread([=] { show_log_impl(cleanVT100String(log)); });
|
||||
};
|
||||
|
||||
// table UI
|
||||
@@ -163,33 +152,32 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
group->order = ui->proxyListTable->order;
|
||||
group->Save();
|
||||
};
|
||||
connect(ui->proxyListTable->horizontalHeader(), &QHeaderView::sectionClicked, this,
|
||||
[=](int logicalIndex) {
|
||||
NekoRay::GroupSortAction action;
|
||||
// 不正确的descending实现
|
||||
if (proxy_last_order == logicalIndex) {
|
||||
action.descending = true;
|
||||
proxy_last_order = -1;
|
||||
} else {
|
||||
proxy_last_order = logicalIndex;
|
||||
}
|
||||
action.save_sort = true;
|
||||
// 表头
|
||||
if (logicalIndex == 1) {
|
||||
action.method = NekoRay::GroupSortMethod::ByType;
|
||||
} else if (logicalIndex == 2) {
|
||||
action.method = NekoRay::GroupSortMethod::ByAddress;
|
||||
} else if (logicalIndex == 3) {
|
||||
action.method = NekoRay::GroupSortMethod::ByName;
|
||||
} else if (logicalIndex == 4) {
|
||||
action.method = NekoRay::GroupSortMethod::ByLatency;
|
||||
} else if (logicalIndex == 0) {
|
||||
action.method = NekoRay::GroupSortMethod::ById;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
refresh_proxy_list_impl(-1, action);
|
||||
});
|
||||
connect(ui->proxyListTable->horizontalHeader(), &QHeaderView::sectionClicked, this, [=](int logicalIndex) {
|
||||
NekoRay::GroupSortAction action;
|
||||
// 不正确的descending实现
|
||||
if (proxy_last_order == logicalIndex) {
|
||||
action.descending = true;
|
||||
proxy_last_order = -1;
|
||||
} else {
|
||||
proxy_last_order = logicalIndex;
|
||||
}
|
||||
action.save_sort = true;
|
||||
// 表头
|
||||
if (logicalIndex == 1) {
|
||||
action.method = NekoRay::GroupSortMethod::ByType;
|
||||
} else if (logicalIndex == 2) {
|
||||
action.method = NekoRay::GroupSortMethod::ByAddress;
|
||||
} else if (logicalIndex == 3) {
|
||||
action.method = NekoRay::GroupSortMethod::ByName;
|
||||
} else if (logicalIndex == 4) {
|
||||
action.method = NekoRay::GroupSortMethod::ByLatency;
|
||||
} else if (logicalIndex == 0) {
|
||||
action.method = NekoRay::GroupSortMethod::ById;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
refresh_proxy_list_impl(-1, action);
|
||||
});
|
||||
ui->proxyListTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
|
||||
ui->proxyListTable->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
||||
ui->proxyListTable->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
|
||||
@@ -238,26 +226,25 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
this->refresh_groups();
|
||||
|
||||
// Setup Tray
|
||||
tray = new QSystemTrayIcon(this);//初始化托盘对象tray
|
||||
tray = new QSystemTrayIcon(this); //初始化托盘对象tray
|
||||
tray->setIcon(TrayIcon::GetIcon(TrayIcon::NONE));
|
||||
tray->setContextMenu(ui->menu_program);//创建托盘菜单
|
||||
tray->show();//让托盘图标显示在系统托盘上
|
||||
connect(tray, &QSystemTrayIcon::activated, this,
|
||||
[=](QSystemTrayIcon::ActivationReason reason) {
|
||||
switch (reason) {
|
||||
case QSystemTrayIcon::Trigger:
|
||||
if (this->isVisible()) {
|
||||
hide();
|
||||
} else {
|
||||
this->showNormal();
|
||||
this->raise();
|
||||
this->activateWindow();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
tray->setContextMenu(ui->menu_program); //创建托盘菜单
|
||||
tray->show(); //让托盘图标显示在系统托盘上
|
||||
connect(tray, &QSystemTrayIcon::activated, this, [=](QSystemTrayIcon::ActivationReason reason) {
|
||||
switch (reason) {
|
||||
case QSystemTrayIcon::Trigger:
|
||||
if (this->isVisible()) {
|
||||
hide();
|
||||
} else {
|
||||
this->showNormal();
|
||||
this->raise();
|
||||
this->activateWindow();
|
||||
}
|
||||
});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
//
|
||||
ui->menu_program_preference->addActions(ui->menu_preferences->actions());
|
||||
connect(ui->menu_add_from_clipboard2, &QAction::triggered, ui->menu_add_from_clipboard, &QAction::trigger);
|
||||
@@ -310,9 +297,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
r.load_control_force = true;
|
||||
r.fn = ROUTES_PREFIX + fn;
|
||||
if (r.Load()) {
|
||||
auto btn = QMessageBox::question(GetMessageBoxParent(), software_name,
|
||||
tr("Load routing and apply: %1").arg(fn) + "\n" + r.toString());
|
||||
if (btn == QMessageBox::Yes) {
|
||||
if (QMessageBox::question(GetMessageBoxParent(), software_name, tr("Load routing and apply: %1").arg(fn) + "\n" + r.toString()) == QMessageBox::Yes) {
|
||||
NekoRay::Routing::SetToActive(fn);
|
||||
if (NekoRay::dataStore->started_id >= 0) {
|
||||
neko_start(NekoRay::dataStore->started_id);
|
||||
@@ -343,16 +328,12 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
});
|
||||
connect(ui->menu_spmode, &QMenu::aboutToShow, this, [=]() {
|
||||
ui->menu_spmode_disabled->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::DISABLE);
|
||||
ui->menu_spmode_system_proxy->setChecked(
|
||||
NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY);
|
||||
ui->menu_spmode_system_proxy->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::SYSTEM_PROXY);
|
||||
ui->menu_spmode_vpn->setChecked(NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN);
|
||||
});
|
||||
connect(ui->menu_spmode_system_proxy, &QAction::triggered, this,
|
||||
[=]() { neko_set_spmode(NekoRay::SystemProxyMode::SYSTEM_PROXY); });
|
||||
connect(ui->menu_spmode_vpn, &QAction::triggered, this,
|
||||
[=]() { neko_set_spmode(NekoRay::SystemProxyMode::VPN); });
|
||||
connect(ui->menu_spmode_disabled, &QAction::triggered, this,
|
||||
[=]() { neko_set_spmode(NekoRay::SystemProxyMode::DISABLE); });
|
||||
connect(ui->menu_spmode_system_proxy, &QAction::triggered, this, [=]() { neko_set_spmode(NekoRay::SystemProxyMode::SYSTEM_PROXY); });
|
||||
connect(ui->menu_spmode_vpn, &QAction::triggered, this, [=]() { neko_set_spmode(NekoRay::SystemProxyMode::VPN); });
|
||||
connect(ui->menu_spmode_disabled, &QAction::triggered, this, [=]() { neko_set_spmode(NekoRay::SystemProxyMode::DISABLE); });
|
||||
connect(ui->menu_qr, &QAction::triggered, this, [=]() { display_qr_link(false); });
|
||||
connect(ui->menu_tcp_ping, &QAction::triggered, this, [=]() { speedtest_current_group(0); });
|
||||
connect(ui->menu_url_test, &QAction::triggered, this, [=]() { speedtest_current_group(1); });
|
||||
@@ -410,7 +391,7 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event) {
|
||||
if (tray->isVisible()) {
|
||||
hide(); //隐藏窗口
|
||||
hide(); //隐藏窗口
|
||||
event->ignore(); //忽略事件
|
||||
}
|
||||
}
|
||||
@@ -471,8 +452,7 @@ void MainWindow::dialog_message_impl(const QString &sender, const QString &info)
|
||||
if (info.contains("VPNChanged") && NekoRay::dataStore->running_spmode == NekoRay::SystemProxyMode::VPN) {
|
||||
MessageBoxWarning(tr("VPN settings changed"), tr("Restart VPN to take effect."));
|
||||
} else if (changed && NekoRay::dataStore->started_id >= 0 &&
|
||||
QMessageBox::question(GetMessageBoxParent(), tr("Confirmation"),
|
||||
tr("Settings changed, restart proxy?")) == QMessageBox::StandardButton::Yes) {
|
||||
QMessageBox::question(GetMessageBoxParent(), tr("Confirmation"), tr("Settings changed, restart proxy?")) == QMessageBox::StandardButton::Yes) {
|
||||
neko_start(NekoRay::dataStore->started_id);
|
||||
}
|
||||
refresh_status();
|
||||
@@ -509,12 +489,13 @@ void MainWindow::dialog_message_impl(const QString &sender, const QString &info)
|
||||
|
||||
inline bool dialog_is_using = false;
|
||||
|
||||
#define USE_DIALOG(a) if (dialog_is_using) return; \
|
||||
dialog_is_using = true; \
|
||||
auto dialog = new a(this); \
|
||||
dialog->exec(); \
|
||||
dialog->deleteLater(); \
|
||||
dialog_is_using = false;
|
||||
#define USE_DIALOG(a) \
|
||||
if (dialog_is_using) return; \
|
||||
dialog_is_using = true; \
|
||||
auto dialog = new a(this); \
|
||||
dialog->exec(); \
|
||||
dialog->deleteLater(); \
|
||||
dialog_is_using = false;
|
||||
|
||||
void MainWindow::on_menu_basic_settings_triggered() {
|
||||
USE_DIALOG(DialogBasicSettings)
|
||||
@@ -578,7 +559,9 @@ void MainWindow::on_menu_exit_triggered() {
|
||||
QCoreApplication::quit();
|
||||
}
|
||||
|
||||
#define neko_set_spmode_FAILED refresh_status(); return;
|
||||
#define neko_set_spmode_FAILED \
|
||||
refresh_status(); \
|
||||
return;
|
||||
|
||||
void MainWindow::neko_set_spmode(int mode, bool save) {
|
||||
if (mode != NekoRay::dataStore->running_spmode) {
|
||||
@@ -907,11 +890,11 @@ void MainWindow::on_proxyListTable_itemDoubleClicked(QTableWidgetItem *item) {
|
||||
connect(dialog, &QDialog::finished, dialog, &QDialog::deleteLater);
|
||||
}
|
||||
|
||||
#define NO_ADD_TO_SUBSCRIPTION_GROUP \
|
||||
if (!NekoRay::profileManager->CurrentGroup()->url.isEmpty()) { \
|
||||
MessageBoxWarning(software_name, MainWindow::tr("Manual addition of profiles is not allowed in subscription groupings.")); \
|
||||
return; \
|
||||
}
|
||||
#define NO_ADD_TO_SUBSCRIPTION_GROUP \
|
||||
if (!NekoRay::profileManager->CurrentGroup()->url.isEmpty()) { \
|
||||
MessageBoxWarning(software_name, MainWindow::tr("Manual addition of profiles is not allowed in subscription groupings.")); \
|
||||
return; \
|
||||
}
|
||||
|
||||
void MainWindow::on_menu_add_from_input_triggered() {
|
||||
NO_ADD_TO_SUBSCRIPTION_GROUP
|
||||
@@ -977,10 +960,7 @@ void MainWindow::on_menu_delete_triggered() {
|
||||
void MainWindow::on_menu_reset_traffic_triggered() {
|
||||
auto ents = get_now_selected();
|
||||
if (ents.count() == 0) return;
|
||||
if (QMessageBox::question(this,
|
||||
tr("Confirmation"),
|
||||
QString(tr("Reset traffic of %1 item(s) ?")).arg(ents.count()))
|
||||
== QMessageBox::StandardButton::Yes) {
|
||||
if (QMessageBox::question(this, tr("Confirmation"), QString(tr("Reset traffic of %1 item(s) ?")).arg(ents.count())) == QMessageBox::StandardButton::Yes) {
|
||||
for (const auto &ent: ents) {
|
||||
ent->traffic_data->Reset();
|
||||
ent->Save();
|
||||
@@ -994,9 +974,7 @@ void MainWindow::on_menu_profile_debug_info_triggered() {
|
||||
if (ents.count() != 1) return;
|
||||
auto btn = QMessageBox::information(this, software_name, ents.first()->ToJsonBytes(), "OK", "Edit", "Reload", 0, 0);
|
||||
if (btn == 1) {
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(
|
||||
QFileInfo(QString("profiles/%1.json").arg(ents.first()->id)).absoluteFilePath()
|
||||
));
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(QFileInfo(QString("profiles/%1.json").arg(ents.first()->id)).absoluteFilePath()));
|
||||
} else if (btn == 2) {
|
||||
ents.first()->Load();
|
||||
refresh_proxy_list();
|
||||
@@ -1144,9 +1122,9 @@ void MainWindow::on_menu_scan_qr_triggered() {
|
||||
show();
|
||||
|
||||
auto hints = DecodeHints()
|
||||
.setFormats(BarcodeFormat::QRCode)
|
||||
.setTryRotate(false)
|
||||
.setBinarizer(Binarizer::FixedThreshold);
|
||||
.setFormats(BarcodeFormat::QRCode)
|
||||
.setTryRotate(false)
|
||||
.setBinarizer(Binarizer::FixedThreshold);
|
||||
|
||||
auto result = ReadBarcode(qpx.toImage(), hints);
|
||||
const auto &text = result.text();
|
||||
@@ -1194,11 +1172,7 @@ void MainWindow::on_menu_delete_repeat_triggered() {
|
||||
}
|
||||
|
||||
if (out_del.length() > 0 &&
|
||||
QMessageBox::question(this,
|
||||
tr("Confirmation"),
|
||||
tr("Remove %1 item(s) ?").arg(out_del.length()) + "\n" + remove_display
|
||||
) == QMessageBox::StandardButton::Yes) {
|
||||
|
||||
QMessageBox::question(this, tr("Confirmation"), tr("Remove %1 item(s) ?").arg(out_del.length()) + "\n" + remove_display) == QMessageBox::StandardButton::Yes) {
|
||||
for (const auto &ent: out_del) {
|
||||
NekoRay::profileManager->DeleteProfile(ent->id);
|
||||
}
|
||||
@@ -1229,11 +1203,7 @@ void MainWindow::on_menu_remove_unavailable_triggered() {
|
||||
remove_display += ent->bean->DisplayTypeAndName() + "\n";
|
||||
}
|
||||
if (out_del.length() > 0 &&
|
||||
QMessageBox::question(this,
|
||||
tr("Confirmation"),
|
||||
tr("Remove %1 item(s) ?").arg(out_del.length()) + "\n" + remove_display
|
||||
) == QMessageBox::StandardButton::Yes) {
|
||||
|
||||
QMessageBox::question(this, tr("Confirmation"), tr("Remove %1 item(s) ?").arg(out_del.length()) + "\n" + remove_display) == QMessageBox::StandardButton::Yes) {
|
||||
for (const auto &ent: out_del) {
|
||||
NekoRay::profileManager->DeleteProfile(ent->id);
|
||||
}
|
||||
@@ -1244,8 +1214,7 @@ void MainWindow::on_menu_remove_unavailable_triggered() {
|
||||
void MainWindow::on_menu_resolve_domain_triggered() {
|
||||
if (QMessageBox::question(this,
|
||||
tr("Confirmation"),
|
||||
tr("Resolving current group domain to IP, if support.")
|
||||
) != QMessageBox::StandardButton::Yes) {
|
||||
tr("Resolving current group domain to IP, if support.")) != QMessageBox::StandardButton::Yes) {
|
||||
return;
|
||||
}
|
||||
if (mw_sub_updating) return;
|
||||
@@ -1401,10 +1370,7 @@ void MainWindow::refresh_connection_list(const QJsonArray &arr) {
|
||||
} else {
|
||||
f->setText(tr("Active"));
|
||||
}
|
||||
f->setToolTip(tr("Start: %1\nEnd: %2").arg(
|
||||
DisplayTime(start_t),
|
||||
end_t > 0 ? DisplayTime(end_t) : ""
|
||||
));
|
||||
f->setToolTip(tr("Start: %1\nEnd: %2").arg(DisplayTime(start_t), end_t > 0 ? DisplayTime(end_t) : ""));
|
||||
ui->tableWidget_conn->setItem(row, 0, f);
|
||||
|
||||
// C1: Outbound
|
||||
@@ -1425,7 +1391,6 @@ void MainWindow::refresh_connection_list(const QJsonArray &arr) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Hotkey
|
||||
|
||||
#ifndef NKR_NO_EXTERNAL
|
||||
@@ -1498,16 +1463,13 @@ bool MainWindow::StartVPNProcess() {
|
||||
//
|
||||
#ifdef Q_OS_WIN
|
||||
runOnNewThread([=] {
|
||||
vpn_pid = 1; //TODO get pid?
|
||||
vpn_pid = 1; // TODO get pid?
|
||||
WinCommander::runProcessElevated(QApplication::applicationDirPath() + "/nekobox_core.exe",
|
||||
{"--disable-color", "run", "-c", configPath},
|
||||
"",
|
||||
NekoRay::dataStore->vpn_hide_console
|
||||
); // blocking
|
||||
NekoRay::dataStore->vpn_hide_console); // blocking
|
||||
vpn_pid = 0;
|
||||
runOnUiThread([=] {
|
||||
neko_set_spmode(NekoRay::SystemProxyMode::DISABLE);
|
||||
});
|
||||
runOnUiThread([=] { neko_set_spmode(NekoRay::SystemProxyMode::DISABLE); });
|
||||
});
|
||||
#else
|
||||
QFile::remove(protectPath);
|
||||
@@ -1528,7 +1490,7 @@ bool MainWindow::StartVPNProcess() {
|
||||
vpn_process->setProcessChannelMode(QProcess::ForwardedChannels);
|
||||
#ifdef Q_OS_MACOS
|
||||
vpn_process->start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges")
|
||||
.arg("bash " + scriptPath)});
|
||||
.arg("bash " + scriptPath)});
|
||||
#else
|
||||
vpn_process->start("pkexec", {"bash", scriptPath});
|
||||
#endif
|
||||
@@ -1551,7 +1513,7 @@ bool MainWindow::StopVPNProcess() {
|
||||
QProcess p;
|
||||
#ifdef Q_OS_MACOS
|
||||
p.start("osascript", {"-e", QString("do shell script \"%1\" with administrator privileges")
|
||||
.arg("pkill -2 -U 0 nekobox_core")});
|
||||
.arg("pkill -2 -U 0 nekobox_core")});
|
||||
#else
|
||||
p.start("pkexec", {"pkill", "-2", "-P", Int2String(vpn_pid)});
|
||||
#endif
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
|
||||
#endif
|
||||
|
||||
namespace NekoRay::sys { class CoreProcess; }
|
||||
namespace NekoRay::sys {
|
||||
class CoreProcess;
|
||||
}
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
@@ -29,7 +31,7 @@ namespace Ui {
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
@@ -166,7 +168,6 @@ private:
|
||||
|
||||
bool StopVPNProcess();
|
||||
|
||||
|
||||
// grpc and ...
|
||||
|
||||
static void ExitNekorayCore();
|
||||
|
||||
@@ -20,9 +20,11 @@ using namespace NekoRay::rpc;
|
||||
void MainWindow::setup_grpc() {
|
||||
#ifndef NKR_NO_GRPC
|
||||
// Setup Connection
|
||||
defaultClient = new Client([=](const QString &errStr) {
|
||||
MW_show_log("[Error] gRPC: " + errStr);
|
||||
}, "127.0.0.1:" + Int2String(NekoRay::dataStore->core_port), NekoRay::dataStore->core_token);
|
||||
defaultClient = new Client(
|
||||
[=](const QString &errStr) {
|
||||
MW_show_log("[Error] gRPC: " + errStr);
|
||||
},
|
||||
"127.0.0.1:" + Int2String(NekoRay::dataStore->core_port), NekoRay::dataStore->core_token);
|
||||
auto t = new QTimer();
|
||||
connect(t, &QTimer::timeout, this, [=]() {
|
||||
bool ok = defaultClient->KeepAlive();
|
||||
@@ -38,9 +40,7 @@ void MainWindow::setup_grpc() {
|
||||
auto tt = new QThread;
|
||||
tt->start();
|
||||
t->moveToThread(tt);
|
||||
runOnUiThread([=] {
|
||||
t->start(2000);
|
||||
}, t);
|
||||
runOnUiThread([=] { t->start(2000); }, t);
|
||||
|
||||
// Looper
|
||||
runOnNewThread([=] { NekoRay::traffic::trafficLooper->loop(); });
|
||||
@@ -74,7 +74,7 @@ void MainWindow::speedtest_current_group(int mode) {
|
||||
runOnNewThread([=]() {
|
||||
auto group = NekoRay::profileManager->CurrentGroup();
|
||||
if (group->archive) return;
|
||||
auto order = ui->proxyListTable->order;//copy
|
||||
auto order = ui->proxyListTable->order; // copy
|
||||
|
||||
QMutex lock_write;
|
||||
QMutex lock_return;
|
||||
@@ -152,9 +152,7 @@ void MainWindow::speedtest_current_group(int mode) {
|
||||
|
||||
runOnUiThread([=] {
|
||||
if (!result.error().empty()) {
|
||||
show_log_impl(
|
||||
tr("[%1] test error: %2").arg(profile->bean->DisplayTypeAndName(),
|
||||
result.error().c_str()));
|
||||
show_log_impl(tr("[%1] test error: %2").arg(profile->bean->DisplayTypeAndName(), result.error().c_str()));
|
||||
}
|
||||
refresh_proxy_list(profile->id);
|
||||
});
|
||||
@@ -325,8 +323,8 @@ void MainWindow::CheckUpdate() {
|
||||
runOnUiThread([=] {
|
||||
auto note_pre_release = response.is_pre_release() ? " (Pre-release)" : "";
|
||||
QMessageBox box(QMessageBox::Question, QObject::tr("Update") + note_pre_release,
|
||||
QObject::tr("Update found: %1\nRelease note:\n%2")
|
||||
.arg(response.assets_name().c_str(), response.release_note().c_str()));
|
||||
QObject::tr("Update found: %1\nRelease note:\n%2").arg(response.assets_name().c_str(), response.release_note().c_str()));
|
||||
//
|
||||
QAbstractButton *btn1 = nullptr;
|
||||
if (!NekoRay::dataStore->flag_use_appdata) {
|
||||
btn1 = box.addButton(QObject::tr("Update"), QMessageBox::AcceptRole);
|
||||
@@ -334,7 +332,7 @@ void MainWindow::CheckUpdate() {
|
||||
QAbstractButton *btn2 = box.addButton(QObject::tr("Open in browser"), QMessageBox::AcceptRole);
|
||||
box.addButton(QObject::tr("Close"), QMessageBox::RejectRole);
|
||||
box.exec();
|
||||
|
||||
//
|
||||
if (btn1 == box.clickedButton()) {
|
||||
// Download Update
|
||||
runOnNewThread([=] {
|
||||
|
||||
@@ -16,7 +16,6 @@ QString ParseSubInfo(const QString &info) {
|
||||
long long total = 0;
|
||||
long long expire = 0;
|
||||
|
||||
|
||||
auto re0m = QRegularExpression("total=([0-9]+)").match(info);
|
||||
if (re0m.lastCapturedIndex() >= 1) {
|
||||
total = re0m.captured(1).toLongLong();
|
||||
@@ -37,13 +36,12 @@ QString ParseSubInfo(const QString &info) {
|
||||
}
|
||||
|
||||
result = QObject::tr("Used: %1 Remain: %2 Expire: %3")
|
||||
.arg(ReadableSize(used), ReadableSize(total - used), DisplayTime(expire, QLocale::ShortFormat));
|
||||
.arg(ReadableSize(used), ReadableSize(total - used), DisplayTime(expire, QLocale::ShortFormat));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GroupItem::GroupItem(QWidget *parent, const QSharedPointer<NekoRay::Group> &ent, QListWidgetItem *item) :
|
||||
QWidget(parent), ui(new Ui::GroupItem) {
|
||||
GroupItem::GroupItem(QWidget *parent, const QSharedPointer<NekoRay::Group> &ent, QListWidgetItem *item) : QWidget(parent), ui(new Ui::GroupItem) {
|
||||
ui->setupUi(this);
|
||||
|
||||
this->ent = ent;
|
||||
@@ -51,8 +49,7 @@ GroupItem::GroupItem(QWidget *parent, const QSharedPointer<NekoRay::Group> &ent,
|
||||
if (ent == nullptr) return;
|
||||
|
||||
connect(this, &GroupItem::edit_clicked, this, &GroupItem::on_edit_clicked);
|
||||
connect(NekoRay::sub::groupUpdater, &NekoRay::sub::GroupUpdater::asyncUpdateCallback,
|
||||
this, [=](int gid) { if (gid == this->ent->id) refresh_data(); });
|
||||
connect(NekoRay::sub::groupUpdater, &NekoRay::sub::GroupUpdater::asyncUpdateCallback, this, [=](int gid) { if (gid == this->ent->id) refresh_data(); });
|
||||
|
||||
refresh_data();
|
||||
}
|
||||
@@ -90,11 +87,13 @@ void GroupItem::refresh_data() {
|
||||
ui->subinfo->setText(info.join(" | "));
|
||||
}
|
||||
}
|
||||
runOnUiThread([=] {
|
||||
adjustSize();
|
||||
item->setSizeHint(sizeHint());
|
||||
dynamic_cast<QWidget *>(parent())->adjustSize();
|
||||
}, this);
|
||||
runOnUiThread(
|
||||
[=] {
|
||||
adjustSize();
|
||||
item->setSizeHint(sizeHint());
|
||||
dynamic_cast<QWidget *>(parent())->adjustSize();
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
void GroupItem::on_update_sub_clicked() {
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
#include "db/Database.hpp"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class GroupItem; }
|
||||
namespace Ui {
|
||||
class GroupItem;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class GroupItem : public QWidget {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GroupItem(QWidget *parent, const QSharedPointer<NekoRay::Group> &ent, QListWidgetItem *item);
|
||||
|
||||
@@ -10,12 +10,12 @@ class MyTableWidget : public QTableWidget {
|
||||
public:
|
||||
explicit MyTableWidget(QWidget *parent = nullptr) : QTableWidget(parent) {
|
||||
// 拖拽设置
|
||||
this->setDragDropMode(QAbstractItemView::InternalMove); // 内部移动
|
||||
this->setDropIndicatorShown(true); // drop位置 提示
|
||||
this->setDragDropMode(QAbstractItemView::InternalMove); // 内部移动
|
||||
this->setDropIndicatorShown(true); // drop位置 提示
|
||||
this->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
};
|
||||
|
||||
// takes and returns the whole row
|
||||
// takes and returns the whole row
|
||||
QList<QTableWidgetItem *> takeRow(int row) {
|
||||
QList<QTableWidgetItem *> rowItems;
|
||||
for (int col = 0; col < columnCount(); ++col) {
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
return rowItems;
|
||||
}
|
||||
|
||||
// sets the whole row
|
||||
// sets the whole row
|
||||
void setRow(int row, const QList<QTableWidgetItem *> &rowItems) {
|
||||
for (int col = 0; col < columnCount(); ++col) {
|
||||
setItem(row, col, rowItems.at(col));
|
||||
@@ -88,36 +88,35 @@ public:
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
* 2021.7.6 by gy
|
||||
* 拖拽 继承QTableWidget overwrite dropEvent事件
|
||||
* 功能:拖动一行到鼠标落下的位置
|
||||
* 注意:DragDropMode相关参数的设置
|
||||
*/
|
||||
/*
|
||||
* 2021.7.6 by gy
|
||||
* 拖拽 继承QTableWidget overwrite dropEvent事件
|
||||
* 功能:拖动一行到鼠标落下的位置
|
||||
* 注意:DragDropMode相关参数的设置
|
||||
*/
|
||||
void dropEvent(QDropEvent *event) override {
|
||||
// 原行号与目标行号的确定
|
||||
int row_src, row_dst;
|
||||
row_src = this->currentRow();// 原行号 可加if
|
||||
QTableWidgetItem *item = this->itemAt(event->pos());// 获取落点的item
|
||||
row_src = this->currentRow(); // 原行号 可加if
|
||||
QTableWidgetItem *item = this->itemAt(event->pos()); // 获取落点的item
|
||||
if (item != nullptr) {
|
||||
// 判断是否为空
|
||||
row_dst = item->row();// 不为空 获取其行号
|
||||
row_dst = item->row(); // 不为空 获取其行号
|
||||
// 保证鼠标落下的位置 就是拖拽的一行最后所移动到的位置(考虑插入新行 移除原行的上下变化)
|
||||
row_src = (row_src > row_dst ? row_src + 1 : row_src);// 如果src在dst的下方(行号大),后续插入dst会影响src的行号
|
||||
row_dst = (row_src < row_dst ? row_dst + 1 : row_dst);// 如果src在dst的上方(行号小),后续移除src会影响dst的行号
|
||||
this->insertRow(row_dst);// 插入一行
|
||||
row_src = (row_src > row_dst ? row_src + 1 : row_src); // 如果src在dst的下方(行号大),后续插入dst会影响src的行号
|
||||
row_dst = (row_src < row_dst ? row_dst + 1 : row_dst); // 如果src在dst的上方(行号小),后续移除src会影响dst的行号
|
||||
this->insertRow(row_dst); // 插入一行
|
||||
} else {
|
||||
// 落点没有item 说明拖动到了最下面
|
||||
row_dst = this->rowCount();// 获取行总数
|
||||
this->insertRow(row_dst);// 在最后新增一行
|
||||
row_dst = this->rowCount(); // 获取行总数
|
||||
this->insertRow(row_dst); // 在最后新增一行
|
||||
}
|
||||
// 执行移动 并移除原行
|
||||
for (int i = 0; i < this->columnCount(); i++) {
|
||||
// 遍历列
|
||||
this->setItem(row_dst, i, this->takeItem(row_src, i));// 每一列item的移动
|
||||
this->setItem(row_dst, i, this->takeItem(row_src, i)); // 每一列item的移动
|
||||
}
|
||||
this->removeRow(row_src);// 删除原行
|
||||
this->removeRow(row_src); // 删除原行
|
||||
|
||||
// Then save the order
|
||||
_save_order(true);
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
ProxyItem::ProxyItem(QWidget *parent, const QSharedPointer<NekoRay::ProxyEntity> &ent, QListWidgetItem *item) :
|
||||
QWidget(parent), ui(new Ui::ProxyItem) {
|
||||
ProxyItem::ProxyItem(QWidget *parent, const QSharedPointer<NekoRay::ProxyEntity> &ent, QListWidgetItem *item)
|
||||
: QWidget(parent), ui(new Ui::ProxyItem) {
|
||||
ui->setupUi(this);
|
||||
this->item = item;
|
||||
this->ent = ent;
|
||||
@@ -24,17 +24,18 @@ void ProxyItem::refresh_data() {
|
||||
ui->traffic->setText(ent->traffic_data->DisplayTraffic());
|
||||
ui->test_result->setText(ent->DisplayLatency());
|
||||
|
||||
runOnUiThread([=] {
|
||||
adjustSize();
|
||||
item->setSizeHint(sizeHint());
|
||||
dynamic_cast<QWidget *>(parent())->adjustSize();
|
||||
}, this);
|
||||
runOnUiThread(
|
||||
[=] {
|
||||
adjustSize();
|
||||
item->setSizeHint(sizeHint());
|
||||
dynamic_cast<QWidget *>(parent())->adjustSize();
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
void ProxyItem::on_remove_clicked() {
|
||||
if (!this->remove_confirm ||
|
||||
QMessageBox::question(this, tr("Confirmation"), tr("Remove %1?").arg(ent->bean->DisplayName()))
|
||||
== QMessageBox::StandardButton::Yes) {
|
||||
QMessageBox::question(this, tr("Confirmation"), tr("Remove %1?").arg(ent->bean->DisplayName())) == QMessageBox::StandardButton::Yes) {
|
||||
// TODO do remove (or not) -> callback
|
||||
delete item;
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
#include "db/ProxyEntity.hpp"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class ProxyItem; }
|
||||
namespace Ui {
|
||||
class ProxyItem;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class ProxyItem : public QWidget {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ProxyItem(QWidget *parent, const QSharedPointer<NekoRay::ProxyEntity> &ent, QListWidgetItem *item);
|
||||
|
||||
Reference in New Issue
Block a user