chore: re-format code

This commit is contained in:
arm64v8a
2022-11-18 14:20:30 +09:00
parent deab99af73
commit 62c236f0d5
97 changed files with 1129 additions and 1331 deletions

10
.clang-format Normal file
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -51,4 +51,4 @@ namespace NekoRay {
};
extern ProfileManager *profileManager;
}
} // namespace NekoRay

View File

@@ -22,4 +22,4 @@ namespace NekoRay {
// 按 显示 顺序
[[nodiscard]] QList<QSharedPointer<ProxyEntity>> ProfilesWithOrder() const;
};
}
} // namespace NekoRay

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -37,4 +37,4 @@ namespace NekoRay::traffic {
return QString("%1↑ %2↓").arg(ReadableSize(uplink), ReadableSize(downlink));
}
};
}
} // namespace NekoRay::traffic

View File

@@ -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

View File

@@ -28,4 +28,4 @@ namespace NekoRay::traffic {
};
extern TrafficLooper *trafficLooper;
}
} // namespace NekoRay::traffic

View File

@@ -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

View File

@@ -60,7 +60,6 @@ namespace NekoRay::fmt {
virtual QString InsecureHint() { return {}; };
QString DisplayInsecureHint();
};
}
} // namespace NekoRay::fmt

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -15,4 +15,4 @@ namespace NekoRay::fmt {
QString DisplayAddress() override { return ""; };
};
}
} // namespace NekoRay::fmt

View File

@@ -47,4 +47,4 @@ namespace NekoRay::fmt {
CoreObjOutboundBuildResult BuildCoreObjV2Ray() override;
};
}
} // namespace NekoRay::fmt

View File

@@ -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

View File

@@ -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

View File

@@ -35,4 +35,4 @@ namespace NekoRay::fmt {
QString ToShareLink() override;
};
}
} // namespace NekoRay::fmt

View File

@@ -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

View File

@@ -33,4 +33,4 @@ namespace NekoRay::fmt {
QString InsecureHint() override;
};
}
} // namespace NekoRay::fmt

View File

@@ -38,4 +38,4 @@ namespace NekoRay::fmt {
QString InsecureHint() override;
};
}
} // namespace NekoRay::fmt

View File

@@ -34,4 +34,4 @@ namespace NekoRay::fmt {
QString InsecureHint() override;
};
}
} // namespace NekoRay::fmt

View File

@@ -56,4 +56,4 @@ namespace NekoRay::fmt {
}
return nullptr;
}
}
} // namespace NekoRay::fmt

View File

@@ -33,5 +33,4 @@ namespace NekoRay::fmt {
QString InsecureHint() override;
};
}
} // namespace NekoRay::fmt

2
libs/format_cpp.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
git ls-files | grep -E "\.cpp|\.h" | grep -v "3rdparty" | xargs -n1 clang-format -i

View File

@@ -30,5 +30,4 @@ namespace NekoRay {
SING_BOX,
};
}
}
} // namespace NekoRay

View File

@@ -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();

View File

@@ -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

View File

@@ -60,4 +60,4 @@ namespace NekoRay {
bool Load();
};
}
} // namespace NekoRay

View File

@@ -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 + "/")

View File

@@ -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)

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -57,7 +57,7 @@
namespace Qv2ray::ui {
class SyntaxHighlighter : public QSyntaxHighlighter {
Q_OBJECT
Q_OBJECT
public:
explicit SyntaxHighlighter(bool darkMode, QTextDocument *parent = nullptr);

View File

@@ -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));
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);

View File

@@ -39,4 +39,4 @@ namespace Qv2ray::components::GeositeReader {
GeositeEntries[filepath] = list;
return list;
}
} // namespace Qv2ray::components::geosite
} // namespace Qv2ray::components::GeositeReader

View File

@@ -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(&current, &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(&current, &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>(&current, &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(&current, &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>(&current, &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(&current, &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(&current, &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(&current, &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;

View File

@@ -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);

View File

@@ -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());

View File

@@ -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

View File

@@ -42,6 +42,5 @@ namespace NekoRay::rpc {
};
inline Client *defaultClient;
}
} // namespace NekoRay::rpc
#endif

View File

@@ -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

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -43,4 +43,4 @@ namespace NekoRay::sys {
// start & kill change this list
inline QList<ExternalProcess *> running_ext;
}
} // namespace NekoRay::sys

View File

@@ -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() {

View File

@@ -2,7 +2,7 @@
#ifdef __MINGW32__
void Windows_SetCrashHandler(){}
void Windows_SetCrashHandler() {}
#else

View File

@@ -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

View File

@@ -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;

View File

@@ -13,4 +13,4 @@ namespace TrayIcon {
QIcon GetIcon(TrayIconStatus status);
}
} // namespace TrayIcon

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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();
};

View File

@@ -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);

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;
};

View File

@@ -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 *>()) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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},
};
}

View File

@@ -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);

View File

@@ -9,7 +9,7 @@ namespace Ui {
}
class EditShadowSocks : public QWidget, public ProfileEditor {
Q_OBJECT
Q_OBJECT
public:
explicit EditShadowSocks(QWidget *parent = nullptr);

View File

@@ -8,7 +8,7 @@ namespace Ui {
}
class EditSocksHttp : public QWidget, public ProfileEditor {
Q_OBJECT
Q_OBJECT
public:
explicit EditSocksHttp(QWidget *parent = nullptr);

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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);
}

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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();

View File

@@ -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([=] {

View File

@@ -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() {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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);