#include "xrayProtocolConfig.h" #include #include #include "core/utils/protocolEnum.h" #include "core/protocols/protocolUtils.h" #include "core/utils/constants/configKeys.h" #include "core/utils/constants/protocolConstants.h" using namespace amnezia; using namespace ProtocolUtils; namespace amnezia { QJsonObject XrayXPaddingConfig::toJson() const { QJsonObject obj; if (!bytesMin.isEmpty()) obj[configKey::xPaddingBytesMin] = bytesMin; if (!bytesMax.isEmpty()) obj[configKey::xPaddingBytesMax] = bytesMax; obj[configKey::xPaddingObfsMode] = obfsMode; if (!key.isEmpty()) obj[configKey::xPaddingKey] = key; if (!header.isEmpty()) obj[configKey::xPaddingHeader] = header; if (!placement.isEmpty()) obj[configKey::xPaddingPlacement] = placement; if (!method.isEmpty()) obj[configKey::xPaddingMethod] = method; return obj; } XrayXPaddingConfig XrayXPaddingConfig::fromJson(const QJsonObject &json) { XrayXPaddingConfig c; c.bytesMin = json.value(configKey::xPaddingBytesMin).toString(); c.bytesMax = json.value(configKey::xPaddingBytesMax).toString(); c.obfsMode = json.value(configKey::xPaddingObfsMode).toBool(true); c.key = json.value(configKey::xPaddingKey).toString(protocols::xray::defaultSite); c.header = json.value(configKey::xPaddingHeader).toString(); c.placement = json.value(configKey::xPaddingPlacement).toString(protocols::xray::defaultXPaddingPlacement); c.method = json.value(configKey::xPaddingMethod).toString(protocols::xray::defaultXPaddingMethod); return c; } QJsonObject XrayXmuxConfig::toJson() const { QJsonObject obj; obj[configKey::xmuxEnabled] = enabled; if (!maxConcurrencyMin.isEmpty()) obj[configKey::xmuxMaxConcurrencyMin] = maxConcurrencyMin; if (!maxConcurrencyMax.isEmpty()) obj[configKey::xmuxMaxConcurrencyMax] = maxConcurrencyMax; if (!maxConnectionsMin.isEmpty()) obj[configKey::xmuxMaxConnectionsMin] = maxConnectionsMin; if (!maxConnectionsMax.isEmpty()) obj[configKey::xmuxMaxConnectionsMax] = maxConnectionsMax; if (!cMaxReuseTimesMin.isEmpty()) obj[configKey::xmuxCMaxReuseTimesMin] = cMaxReuseTimesMin; if (!cMaxReuseTimesMax.isEmpty()) obj[configKey::xmuxCMaxReuseTimesMax] = cMaxReuseTimesMax; if (!hMaxRequestTimesMin.isEmpty()) obj[configKey::xmuxHMaxRequestTimesMin] = hMaxRequestTimesMin; if (!hMaxRequestTimesMax.isEmpty()) obj[configKey::xmuxHMaxRequestTimesMax] = hMaxRequestTimesMax; if (!hMaxReusableSecsMin.isEmpty()) obj[configKey::xmuxHMaxReusableSecsMin] = hMaxReusableSecsMin; if (!hMaxReusableSecsMax.isEmpty()) obj[configKey::xmuxHMaxReusableSecsMax] = hMaxReusableSecsMax; if (!hKeepAlivePeriod.isEmpty()) obj[configKey::xmuxHKeepAlivePeriod] = hKeepAlivePeriod; return obj; } XrayXmuxConfig XrayXmuxConfig::fromJson(const QJsonObject &json) { XrayXmuxConfig c; c.enabled = json.value(configKey::xmuxEnabled).toBool(true); c.maxConcurrencyMin = json.value(configKey::xmuxMaxConcurrencyMin).toString("0"); c.maxConcurrencyMax = json.value(configKey::xmuxMaxConcurrencyMax).toString("0"); c.maxConnectionsMin = json.value(configKey::xmuxMaxConnectionsMin).toString("0"); c.maxConnectionsMax = json.value(configKey::xmuxMaxConnectionsMax).toString("0"); c.cMaxReuseTimesMin = json.value(configKey::xmuxCMaxReuseTimesMin).toString("0"); c.cMaxReuseTimesMax = json.value(configKey::xmuxCMaxReuseTimesMax).toString("0"); c.hMaxRequestTimesMin = json.value(configKey::xmuxHMaxRequestTimesMin).toString("0"); c.hMaxRequestTimesMax = json.value(configKey::xmuxHMaxRequestTimesMax).toString("0"); c.hMaxReusableSecsMin = json.value(configKey::xmuxHMaxReusableSecsMin).toString("0"); c.hMaxReusableSecsMax = json.value(configKey::xmuxHMaxReusableSecsMax).toString("0"); c.hKeepAlivePeriod = json.value(configKey::xmuxHKeepAlivePeriod).toString(); return c; } QJsonObject XrayXhttpConfig::toJson() const { QJsonObject obj; if (!mode.isEmpty()) obj[configKey::xhttpMode] = mode; if (!host.isEmpty()) obj[configKey::xhttpHost] = host; if (!path.isEmpty()) obj[configKey::xhttpPath] = path; if (!headersTemplate.isEmpty()) obj[configKey::xhttpHeadersTemplate] = headersTemplate; if (!uplinkMethod.isEmpty()) obj[configKey::xhttpUplinkMethod] = uplinkMethod; obj[configKey::xhttpDisableGrpc] = disableGrpc; obj[configKey::xhttpDisableSse] = disableSse; if (!sessionPlacement.isEmpty()) obj[configKey::xhttpSessionPlacement] = sessionPlacement; if (!sessionKey.isEmpty()) obj[configKey::xhttpSessionKey] = sessionKey; if (!seqPlacement.isEmpty()) obj[configKey::xhttpSeqPlacement] = seqPlacement; if (!seqKey.isEmpty()) obj[configKey::xhttpSeqKey] = seqKey; if (!uplinkDataPlacement.isEmpty()) obj[configKey::xhttpUplinkDataPlacement] = uplinkDataPlacement; if (!uplinkDataKey.isEmpty()) obj[configKey::xhttpUplinkDataKey] = uplinkDataKey; if (!uplinkChunkSize.isEmpty()) obj[configKey::xhttpUplinkChunkSize] = uplinkChunkSize; if (!scMaxBufferedPosts.isEmpty()) obj[configKey::xhttpScMaxBufferedPosts] = scMaxBufferedPosts; if (!scMaxEachPostBytesMin.isEmpty()) obj[configKey::xhttpScMaxEachPostBytesMin] = scMaxEachPostBytesMin; if (!scMaxEachPostBytesMax.isEmpty()) obj[configKey::xhttpScMaxEachPostBytesMax] = scMaxEachPostBytesMax; if (!scMinPostsIntervalMsMin.isEmpty()) obj[configKey::xhttpScMinPostsIntervalMsMin] = scMinPostsIntervalMsMin; if (!scMinPostsIntervalMsMax.isEmpty()) obj[configKey::xhttpScMinPostsIntervalMsMax] = scMinPostsIntervalMsMax; if (!scStreamUpServerSecsMin.isEmpty()) obj[configKey::xhttpScStreamUpServerSecsMin] = scStreamUpServerSecsMin; if (!scStreamUpServerSecsMax.isEmpty()) obj[configKey::xhttpScStreamUpServerSecsMax] = scStreamUpServerSecsMax; obj["xPadding"] = xPadding.toJson(); obj["xmux"] = xmux.toJson(); return obj; } namespace { XrayXhttpConfig clearedXhttpConfig() { XrayXhttpConfig c; c.mode = QString(); c.host = QString(); c.path = QString(); c.headersTemplate = QString(); c.uplinkMethod = QString(); c.disableGrpc = false; c.disableSse = false; c.sessionPlacement = QString(); c.sessionKey = QString(); c.seqPlacement = QString(); c.seqKey = QString(); c.uplinkDataPlacement = QString(); c.uplinkDataKey = QString(); c.uplinkChunkSize = QString(); c.scMaxBufferedPosts = QString(); c.scMaxEachPostBytesMin = QString(); c.scMaxEachPostBytesMax = QString(); c.scMinPostsIntervalMsMin = QString(); c.scMinPostsIntervalMsMax = QString(); c.scStreamUpServerSecsMin = QString(); c.scStreamUpServerSecsMax = QString(); return c; } } // namespace XrayXhttpConfig XrayXhttpConfig::fromJson(const QJsonObject &json) { if (json.isEmpty()) { return clearedXhttpConfig(); } XrayXhttpConfig c = clearedXhttpConfig(); if (json.contains(configKey::xhttpMode)) { c.mode = json.value(configKey::xhttpMode).toString(); } if (json.contains(configKey::xhttpHost)) { c.host = json.value(configKey::xhttpHost).toString(); } if (json.contains(configKey::xhttpPath)) { c.path = json.value(configKey::xhttpPath).toString(); } if (json.contains(configKey::xhttpHeadersTemplate)) { c.headersTemplate = json.value(configKey::xhttpHeadersTemplate).toString(); } if (json.contains(configKey::xhttpUplinkMethod)) { c.uplinkMethod = json.value(configKey::xhttpUplinkMethod).toString(); } if (json.contains(configKey::xhttpDisableGrpc)) { c.disableGrpc = json.value(configKey::xhttpDisableGrpc).toBool(); } if (json.contains(configKey::xhttpDisableSse)) { c.disableSse = json.value(configKey::xhttpDisableSse).toBool(); } if (json.contains(configKey::xhttpSessionPlacement)) { c.sessionPlacement = json.value(configKey::xhttpSessionPlacement).toString(); } if (json.contains(configKey::xhttpSessionKey)) { c.sessionKey = json.value(configKey::xhttpSessionKey).toString(); } if (json.contains(configKey::xhttpSeqPlacement)) { c.seqPlacement = json.value(configKey::xhttpSeqPlacement).toString(); } if (json.contains(configKey::xhttpSeqKey)) { c.seqKey = json.value(configKey::xhttpSeqKey).toString(); } if (json.contains(configKey::xhttpUplinkDataPlacement)) { c.uplinkDataPlacement = json.value(configKey::xhttpUplinkDataPlacement).toString(); } if (json.contains(configKey::xhttpUplinkDataKey)) { c.uplinkDataKey = json.value(configKey::xhttpUplinkDataKey).toString(); } if (json.contains(configKey::xhttpUplinkChunkSize)) { c.uplinkChunkSize = json.value(configKey::xhttpUplinkChunkSize).toString(); } if (json.contains(configKey::xhttpScMaxBufferedPosts)) { c.scMaxBufferedPosts = json.value(configKey::xhttpScMaxBufferedPosts).toString(); } if (json.contains(configKey::xhttpScMaxEachPostBytesMin)) { c.scMaxEachPostBytesMin = json.value(configKey::xhttpScMaxEachPostBytesMin).toString(); } if (json.contains(configKey::xhttpScMaxEachPostBytesMax)) { c.scMaxEachPostBytesMax = json.value(configKey::xhttpScMaxEachPostBytesMax).toString(); } if (json.contains(configKey::xhttpScMinPostsIntervalMsMin)) { c.scMinPostsIntervalMsMin = json.value(configKey::xhttpScMinPostsIntervalMsMin).toString(); } if (json.contains(configKey::xhttpScMinPostsIntervalMsMax)) { c.scMinPostsIntervalMsMax = json.value(configKey::xhttpScMinPostsIntervalMsMax).toString(); } if (json.contains(configKey::xhttpScStreamUpServerSecsMin)) { c.scStreamUpServerSecsMin = json.value(configKey::xhttpScStreamUpServerSecsMin).toString(); } if (json.contains(configKey::xhttpScStreamUpServerSecsMax)) { c.scStreamUpServerSecsMax = json.value(configKey::xhttpScStreamUpServerSecsMax).toString(); } if (json.contains(QLatin1String("xPadding"))) { c.xPadding = XrayXPaddingConfig::fromJson(json.value(QLatin1String("xPadding")).toObject()); } if (json.contains(QLatin1String("xmux"))) { c.xmux = XrayXmuxConfig::fromJson(json.value(QLatin1String("xmux")).toObject()); } return c; } QJsonObject XrayMkcpConfig::toJson() const { QJsonObject obj; if (!tti.isEmpty()) obj[configKey::mkcpTti] = tti; if (!uplinkCapacity.isEmpty()) obj[configKey::mkcpUplinkCapacity] = uplinkCapacity; if (!downlinkCapacity.isEmpty()) obj[configKey::mkcpDownlinkCapacity] = downlinkCapacity; if (!readBufferSize.isEmpty()) obj[configKey::mkcpReadBufferSize] = readBufferSize; if (!writeBufferSize.isEmpty()) obj[configKey::mkcpWriteBufferSize] = writeBufferSize; obj[configKey::mkcpCongestion] = congestion; return obj; } XrayMkcpConfig XrayMkcpConfig::fromJson(const QJsonObject &json) { XrayMkcpConfig c; if (json.isEmpty()) { return c; } if (json.contains(configKey::mkcpTti)) { c.tti = json.value(configKey::mkcpTti).toString(); } if (json.contains(configKey::mkcpUplinkCapacity)) { c.uplinkCapacity = json.value(configKey::mkcpUplinkCapacity).toString(); } if (json.contains(configKey::mkcpDownlinkCapacity)) { c.downlinkCapacity = json.value(configKey::mkcpDownlinkCapacity).toString(); } if (json.contains(configKey::mkcpReadBufferSize)) { c.readBufferSize = json.value(configKey::mkcpReadBufferSize).toString(); } if (json.contains(configKey::mkcpWriteBufferSize)) { c.writeBufferSize = json.value(configKey::mkcpWriteBufferSize).toString(); } if (json.contains(configKey::mkcpCongestion)) { c.congestion = json.value(configKey::mkcpCongestion).toBool(); } return c; } QJsonObject XrayServerConfig::toJson() const { QJsonObject obj; // Existing fields if (!port.isEmpty()) { obj[configKey::port] = port; } if (!transportProto.isEmpty()) { obj[configKey::transportProto] = transportProto; } if (!subnetAddress.isEmpty()) { obj[configKey::subnetAddress] = subnetAddress; } if (!site.isEmpty()) { obj[configKey::site] = site; } if (isThirdPartyConfig) { obj[configKey::isThirdPartyConfig] = isThirdPartyConfig; } // New: Security if (!security.isEmpty()) { obj[configKey::xraySecurity] = security; } if (!flow.isEmpty()) { obj[configKey::xrayFlow] = flow; } if (!fingerprint.isEmpty()) { obj[configKey::xrayFingerprint] = fingerprint; } if (!sni.isEmpty()) { obj[configKey::xraySni] = sni; } if (!alpn.isEmpty()) { obj[configKey::xrayAlpn] = alpn; } // New: Transport if (!transport.isEmpty()) { obj[configKey::xrayTransport] = transport; } const QJsonObject xhttpObj = xhttp.toJson(); if (!xhttpObj.isEmpty()) { obj[QStringLiteral("xhttp")] = xhttpObj; } const QJsonObject mkcpObj = mkcp.toJson(); if (!mkcpObj.isEmpty()) { obj[QStringLiteral("mkcp")] = mkcpObj; } return obj; } XrayServerConfig XrayServerConfig::fromJson(const QJsonObject &json) { XrayServerConfig c; // Existing fields c.port = json.value(configKey::port).toString(); c.transportProto = json.value(configKey::transportProto).toString(); c.subnetAddress = json.value(configKey::subnetAddress).toString(); c.site = json.value(configKey::site).toString(); c.isThirdPartyConfig = json.value(configKey::isThirdPartyConfig).toBool(false); if (json.contains(configKey::xraySecurity)) { c.security = json.value(configKey::xraySecurity).toString(); } if (json.contains(configKey::xrayFlow)) { c.flow = json.value(configKey::xrayFlow).toString(); } if (json.contains(configKey::xrayFingerprint)) { c.fingerprint = json.value(configKey::xrayFingerprint).toString(); if (c.fingerprint.contains(QLatin1String("Mozilla/5.0"), Qt::CaseInsensitive)) { c.fingerprint = QString::fromLatin1(protocols::xray::defaultFingerprint); } } if (json.contains(configKey::xraySni)) { c.sni = json.value(configKey::xraySni).toString(); } if (json.contains(configKey::xrayAlpn)) { c.alpn = json.value(configKey::xrayAlpn).toString(); } if (json.contains(configKey::xrayTransport)) { c.transport = json.value(configKey::xrayTransport).toString(); } if (json.contains(QLatin1String("xhttp"))) { const QJsonObject xhttpJson = json.value(QLatin1String("xhttp")).toObject(); if (!xhttpJson.isEmpty()) { c.xhttp = XrayXhttpConfig::fromJson(xhttpJson); } } if (json.contains(QLatin1String("mkcp"))) { const QJsonObject mkcpJson = json.value(QLatin1String("mkcp")).toObject(); if (!mkcpJson.isEmpty()) { c.mkcp = XrayMkcpConfig::fromJson(mkcpJson); } } return c; } bool XrayServerConfig::hasEqualServerSettings(const XrayServerConfig &other) const { return port == other.port && site == other.site && security == other.security && flow == other.flow && transport == other.transport && fingerprint == other.fingerprint && sni == other.sni && alpn == other.alpn && xhttp.toJson() == other.xhttp.toJson() && mkcp.toJson() == other.mkcp.toJson(); } QJsonObject XrayClientConfig::toJson() const { QJsonObject obj; if (!nativeConfig.isEmpty()) obj[configKey::config] = nativeConfig; if (!localPort.isEmpty()) obj[configKey::localPort] = localPort; if (!id.isEmpty()) obj[configKey::clientId] = id; return obj; } XrayClientConfig XrayClientConfig::fromJson(const QJsonObject &json) { XrayClientConfig c; c.nativeConfig = json.value(configKey::config).toString(); c.localPort = json.value(configKey::localPort).toString(); c.id = json.value(configKey::clientId).toString(); if (c.id.isEmpty() && !c.nativeConfig.isEmpty()) { QJsonDocument doc = QJsonDocument::fromJson(c.nativeConfig.toUtf8()); if (!doc.isNull() && doc.isObject()) { QJsonObject configObj = doc.object(); if (configObj.contains(protocols::xray::outbounds)) { QJsonArray outbounds = configObj.value(protocols::xray::outbounds).toArray(); if (!outbounds.isEmpty()) { QJsonObject outbound = outbounds[0].toObject(); if (outbound.contains(protocols::xray::settings)) { QJsonObject settings = outbound[protocols::xray::settings].toObject(); if (settings.contains(protocols::xray::vnext)) { QJsonArray vnext = settings[protocols::xray::vnext].toArray(); if (!vnext.isEmpty()) { QJsonObject vnextObj = vnext[0].toObject(); if (vnextObj.contains(protocols::xray::users)) { QJsonArray users = vnextObj[protocols::xray::users].toArray(); if (!users.isEmpty()) { QJsonObject user = users[0].toObject(); if (user.contains(protocols::xray::id)) { c.id = user[protocols::xray::id].toString(); } } } } } } } } } } return c; } QJsonObject XrayProtocolConfig::toJson() const { QJsonObject obj = serverConfig.toJson(); if (clientConfig.has_value()) { QJsonDocument doc = QJsonDocument::fromJson(clientConfig->nativeConfig.toUtf8()); if (!doc.isNull() && doc.isObject() && doc.object().contains(protocols::xray::outbounds) && !doc.object().contains(configKey::config)) { obj[configKey::lastConfig] = clientConfig->nativeConfig; } else { QJsonObject clientJson = clientConfig->toJson(); obj[configKey::lastConfig] = QString::fromUtf8(QJsonDocument(clientJson).toJson(QJsonDocument::Compact)); } } return obj; } XrayProtocolConfig XrayProtocolConfig::fromJson(const QJsonObject &json) { XrayProtocolConfig c; c.serverConfig = XrayServerConfig::fromJson(json); QString lastConfigStr = json.value(configKey::lastConfig).toString(); if (!lastConfigStr.isEmpty()) { QJsonDocument doc = QJsonDocument::fromJson(lastConfigStr.toUtf8()); if (doc.isObject()) { QJsonObject parsed = doc.object(); if (parsed.contains(protocols::xray::outbounds) && !parsed.contains(configKey::config)) { XrayClientConfig clientCfg; clientCfg.nativeConfig = lastConfigStr; if (parsed.contains(protocols::xray::inbounds)) { QJsonArray inbounds = parsed.value(protocols::xray::inbounds).toArray(); if (!inbounds.isEmpty()) { QJsonObject inbound = inbounds[0].toObject(); if (inbound.contains(protocols::xray::port)) { clientCfg.localPort = QString::number(inbound.value(protocols::xray::port).toInt()); } } } c.clientConfig = clientCfg; } else { c.clientConfig = XrayClientConfig::fromJson(parsed); } } } c.needsClientHydration = c.hasClientConfig() && (!json.contains(configKey::xrayTransport) || c.serverConfig.isThirdPartyConfig); if (c.needsClientHydration) { c.hydrateServerConfigFromClientNative(); } return c; } bool XrayProtocolConfig::hydrateServerConfigFromClientNative() { if (!clientConfig.has_value() || clientConfig->nativeConfig.isEmpty()) { return false; } QJsonDocument doc = QJsonDocument::fromJson(clientConfig->nativeConfig.toUtf8()); if (doc.isNull() || !doc.isObject()) { return false; } const QJsonObject root = doc.object(); const QJsonArray outbounds = root.value(protocols::xray::outbounds).toArray(); if (outbounds.isEmpty()) { return false; } const QJsonObject outbound = outbounds[0].toObject(); const QJsonObject streamSettings = outbound.value(protocols::xray::streamSettings).toObject(); if (streamSettings.isEmpty()) { return false; } XrayServerConfig &srv = serverConfig; const QJsonObject settings = outbound.value(protocols::xray::settings).toObject(); const QJsonArray vnext = settings.value(protocols::xray::vnext).toArray(); if (!vnext.isEmpty()) { const QJsonObject vnextEntry = vnext[0].toObject(); if (vnextEntry.contains(protocols::xray::port)) { srv.port = QString::number(vnextEntry.value(protocols::xray::port).toInt()); } const QJsonArray users = vnextEntry.value(protocols::xray::users).toArray(); if (!users.isEmpty()) { srv.flow = users[0].toObject().value(protocols::xray::flow).toString(); } } const QString networkVal = streamSettings.value(protocols::xray::network).toString(QStringLiteral("tcp")); if (networkVal == QLatin1String("xhttp")) { srv.transport = QStringLiteral("xhttp"); } else if (networkVal == QLatin1String("kcp")) { srv.transport = QStringLiteral("mkcp"); } else { srv.transport = QStringLiteral("raw"); } if (streamSettings.contains(protocols::xray::security)) { srv.security = streamSettings.value(protocols::xray::security).toString(); } if (srv.security == QLatin1String("reality")) { const QJsonObject rs = streamSettings.value(protocols::xray::realitySettings).toObject(); srv.sni = rs.value(protocols::xray::serverName).toString(); srv.site = srv.sni.isEmpty() ? srv.site : srv.sni; const QString fp = rs.value(protocols::xray::fingerprint).toString(); if (!fp.isEmpty()) { srv.fingerprint = fp.contains(QLatin1String("Mozilla/5.0"), Qt::CaseInsensitive) ? QString::fromLatin1(protocols::xray::defaultFingerprint) : fp; } } if (srv.security == QLatin1String("tls")) { const QJsonObject tls = streamSettings.value(QStringLiteral("tlsSettings")).toObject(); srv.sni = tls.value(protocols::xray::serverName).toString(); const QString fp = tls.value(protocols::xray::fingerprint).toString(); if (!fp.isEmpty()) { srv.fingerprint = fp; } QStringList alpnList; for (const QJsonValue &v : tls.value(QStringLiteral("alpn")).toArray()) { alpnList << v.toString(); } if (!alpnList.isEmpty()) { srv.alpn = alpnList.join(QLatin1Char(',')); } } if (srv.transport == QLatin1String("xhttp")) { const QJsonObject xhttpObj = streamSettings.value(QStringLiteral("xhttpSettings")).toObject(); QJsonObject xhttpJson; const QString mode = xhttpObj.value(QStringLiteral("mode")).toString(); if (!mode.isEmpty()) { if (mode == QLatin1String("auto")) { xhttpJson[configKey::xhttpMode] = QStringLiteral("Auto"); } else if (mode == QLatin1String("packet-up")) { xhttpJson[configKey::xhttpMode] = QStringLiteral("Packet-up"); } else if (mode == QLatin1String("stream-up")) { xhttpJson[configKey::xhttpMode] = QStringLiteral("Stream-up"); } else if (mode == QLatin1String("stream-one")) { xhttpJson[configKey::xhttpMode] = QStringLiteral("Stream-one"); } else { xhttpJson[configKey::xhttpMode] = mode; } } if (xhttpObj.contains(QStringLiteral("host"))) { xhttpJson[configKey::xhttpHost] = xhttpObj.value(QStringLiteral("host")).toString(); } if (xhttpObj.contains(QStringLiteral("path"))) { xhttpJson[configKey::xhttpPath] = xhttpObj.value(QStringLiteral("path")).toString(); } if (xhttpObj.contains(QStringLiteral("uplinkHTTPMethod"))) { xhttpJson[configKey::xhttpUplinkMethod] = xhttpObj.value(QStringLiteral("uplinkHTTPMethod")).toString(); } xhttpJson[configKey::xhttpDisableGrpc] = xhttpObj.value(QStringLiteral("noGRPCHeader")).toBool(true); xhttpJson[configKey::xhttpDisableSse] = xhttpObj.value(QStringLiteral("noSSEHeader")).toBool(true); srv.xhttp = XrayXhttpConfig::fromJson(xhttpJson); } if (srv.transport == QLatin1String("mkcp")) { const QJsonObject kcpObj = streamSettings.value(QStringLiteral("kcpSettings")).toObject(); XrayMkcpConfig mk; if (kcpObj.contains(QStringLiteral("tti"))) { mk.tti = QString::number(kcpObj.value(QStringLiteral("tti")).toInt()); } if (kcpObj.contains(QStringLiteral("uplinkCapacity"))) { mk.uplinkCapacity = QString::number(kcpObj.value(QStringLiteral("uplinkCapacity")).toInt()); } if (kcpObj.contains(QStringLiteral("downlinkCapacity"))) { mk.downlinkCapacity = QString::number(kcpObj.value(QStringLiteral("downlinkCapacity")).toInt()); } if (kcpObj.contains(QStringLiteral("readBufferSize"))) { mk.readBufferSize = QString::number(kcpObj.value(QStringLiteral("readBufferSize")).toInt()); } if (kcpObj.contains(QStringLiteral("writeBufferSize"))) { mk.writeBufferSize = QString::number(kcpObj.value(QStringLiteral("writeBufferSize")).toInt()); } if (kcpObj.contains(QStringLiteral("congestion"))) { mk.congestion = kcpObj.value(QStringLiteral("congestion")).toBool(true); } srv.mkcp = mk; } needsClientHydration = false; return true; } bool XrayProtocolConfig::hasClientConfig() const { return clientConfig.has_value(); } void XrayProtocolConfig::setClientConfig(const XrayClientConfig &config) { clientConfig = config; } void XrayProtocolConfig::clearClientConfig() { clientConfig.reset(); } } // namespace amnezia