mirror of
https://github.com/2dust/v2rayN.git
synced 2026-11-08 21:45:01 +03:00
feat: support Xray XDRIVE object storage relay transport (#10546)
This commit is contained in:
@@ -824,4 +824,135 @@ public class CoreConfigV2rayServiceTests
|
|||||||
await proxyOutbound.Should().NotBeNull();
|
await proxyOutbound.Should().NotBeNull();
|
||||||
await proxyOutbound!.protocol.Should().BeEqualTo("shadowsocks");
|
await proxyOutbound!.protocol.Should().BeEqualTo("shadowsocks");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GenerateClientConfigContent_XdriveGoogleDrive_ShouldGenerateValidOutbound()
|
||||||
|
{
|
||||||
|
var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray);
|
||||||
|
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||||
|
|
||||||
|
var node = new ProfileItem
|
||||||
|
{
|
||||||
|
IndexId = "node-xdrive-gdrive",
|
||||||
|
ConfigType = EConfigType.VLESS,
|
||||||
|
CoreType = ECoreType.Xray,
|
||||||
|
Remarks = "xdrive-gdrive",
|
||||||
|
Address = "example.com",
|
||||||
|
Port = 443,
|
||||||
|
Password = Guid.NewGuid().ToString(),
|
||||||
|
Network = nameof(ETransport.xdrive),
|
||||||
|
MuxEnabled = false,
|
||||||
|
};
|
||||||
|
node.SetProtocolExtra(new ProtocolExtraItem { VlessEncryption = Global.None });
|
||||||
|
node.SetTransportExtra(new TransportExtraItem
|
||||||
|
{
|
||||||
|
XdriveService = "google-drive",
|
||||||
|
XdriveRemoteFolder = "folder-123",
|
||||||
|
XdriveSecrets = "id,secret,token",
|
||||||
|
});
|
||||||
|
|
||||||
|
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.Xray);
|
||||||
|
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
|
||||||
|
|
||||||
|
await result.Success.Should().BeTrue();
|
||||||
|
var generatedConfig = JsonNode.Parse(result.Data!.ToString()!)!;
|
||||||
|
var proxy = generatedConfig["outbounds"]!.AsArray()
|
||||||
|
.First(outbound => outbound!["tag"]!.GetValue<string>() == Global.ProxyTag)!;
|
||||||
|
|
||||||
|
var streamSettings = proxy["streamSettings"]!;
|
||||||
|
await streamSettings["network"]!.GetValue<string>().Should().BeEqualTo("xdrive");
|
||||||
|
|
||||||
|
var xdriveSettings = streamSettings["xdriveSettings"]!;
|
||||||
|
await xdriveSettings["service"]!.GetValue<string>().Should().BeEqualTo("google-drive");
|
||||||
|
await xdriveSettings["remoteFolder"]!.GetValue<string>().Should().BeEqualTo("folder-123");
|
||||||
|
|
||||||
|
var secrets = xdriveSettings["secrets"]!.AsArray();
|
||||||
|
await secrets.Count.Should().BeEqualTo(3);
|
||||||
|
await secrets[0]!.GetValue<string>().Should().BeEqualTo("id");
|
||||||
|
await secrets[1]!.GetValue<string>().Should().BeEqualTo("secret");
|
||||||
|
await secrets[2]!.GetValue<string>().Should().BeEqualTo("token");
|
||||||
|
|
||||||
|
await proxy["mux"]!["enabled"]!.GetValue<bool>().Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GenerateClientConfigContent_XdriveS3_ShouldGenerateValidOutbound()
|
||||||
|
{
|
||||||
|
var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray);
|
||||||
|
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||||
|
|
||||||
|
var node = new ProfileItem
|
||||||
|
{
|
||||||
|
IndexId = "node-xdrive-s3",
|
||||||
|
ConfigType = EConfigType.VLESS,
|
||||||
|
CoreType = ECoreType.Xray,
|
||||||
|
Remarks = "xdrive-s3",
|
||||||
|
Address = "example.com",
|
||||||
|
Port = 443,
|
||||||
|
Password = Guid.NewGuid().ToString(),
|
||||||
|
Network = nameof(ETransport.xdrive),
|
||||||
|
};
|
||||||
|
node.SetProtocolExtra(new ProtocolExtraItem { VlessEncryption = Global.None });
|
||||||
|
node.SetTransportExtra(new TransportExtraItem
|
||||||
|
{
|
||||||
|
XdriveService = "s3",
|
||||||
|
XdriveS3Endpoint = "https://s3.amazonaws.com",
|
||||||
|
XdriveS3Bucket = "mybucket",
|
||||||
|
XdriveS3PathStyle = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.Xray);
|
||||||
|
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
|
||||||
|
|
||||||
|
await result.Success.Should().BeTrue();
|
||||||
|
var generatedConfig = JsonNode.Parse(result.Data!.ToString()!)!;
|
||||||
|
var proxy = generatedConfig["outbounds"]!.AsArray()
|
||||||
|
.First(outbound => outbound!["tag"]!.GetValue<string>() == Global.ProxyTag)!;
|
||||||
|
|
||||||
|
var s3 = proxy["streamSettings"]!["xdriveSettings"]!["s3"]!;
|
||||||
|
await s3["endpoint"]!.GetValue<string>().Should().BeEqualTo("https://s3.amazonaws.com");
|
||||||
|
await s3["bucket"]!.GetValue<string>().Should().BeEqualTo("mybucket");
|
||||||
|
await s3["pathStyle"]!.GetValue<bool>().Should().BeFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task GenerateClientConfigContent_XdriveExtra_ShouldPopulateParameters()
|
||||||
|
{
|
||||||
|
var config = CoreConfigTestFactory.CreateConfig(ECoreType.Xray);
|
||||||
|
CoreConfigTestFactory.BindAppManagerConfig(config);
|
||||||
|
|
||||||
|
var node = new ProfileItem
|
||||||
|
{
|
||||||
|
IndexId = "node-xdrive-extra",
|
||||||
|
ConfigType = EConfigType.VLESS,
|
||||||
|
CoreType = ECoreType.Xray,
|
||||||
|
Remarks = "xdrive-extra",
|
||||||
|
Address = "example.com",
|
||||||
|
Port = 443,
|
||||||
|
Password = Guid.NewGuid().ToString(),
|
||||||
|
Network = nameof(ETransport.xdrive),
|
||||||
|
};
|
||||||
|
node.SetProtocolExtra(new ProtocolExtraItem { VlessEncryption = Global.None });
|
||||||
|
node.SetTransportExtra(new TransportExtraItem
|
||||||
|
{
|
||||||
|
XdriveService = "onedrive",
|
||||||
|
XdriveExtra = """{"segmentBytes":1048576,"flushIntervalMs":500,"pollIntervalMs":200,"maxPollIntervalMs":2000,"eagerWindowMs":1000,"concurrency":4}""",
|
||||||
|
});
|
||||||
|
|
||||||
|
var context = CoreConfigTestFactory.CreateContext(config, node, ECoreType.Xray);
|
||||||
|
var result = new CoreConfigV2rayService(context).GenerateClientConfigContent();
|
||||||
|
|
||||||
|
await result.Success.Should().BeTrue();
|
||||||
|
var generatedConfig = JsonNode.Parse(result.Data!.ToString()!)!;
|
||||||
|
var proxy = generatedConfig["outbounds"]!.AsArray()
|
||||||
|
.First(outbound => outbound!["tag"]!.GetValue<string>() == Global.ProxyTag)!;
|
||||||
|
|
||||||
|
var xdriveSettings = proxy["streamSettings"]!["xdriveSettings"]!;
|
||||||
|
await xdriveSettings["segmentBytes"]!.GetValue<int>().Should().BeEqualTo(1048576);
|
||||||
|
await xdriveSettings["flushIntervalMs"]!.GetValue<int>().Should().BeEqualTo(500);
|
||||||
|
await xdriveSettings["pollIntervalMs"]!.GetValue<int>().Should().BeEqualTo(200);
|
||||||
|
await xdriveSettings["maxPollIntervalMs"]!.GetValue<int>().Should().BeEqualTo(2000);
|
||||||
|
await xdriveSettings["eagerWindowMs"]!.GetValue<int>().Should().BeEqualTo(1000);
|
||||||
|
await xdriveSettings["concurrency"]!.GetValue<int>().Should().BeEqualTo(4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,164 @@
|
|||||||
|
using System.Reflection;
|
||||||
|
using ReactiveUI.Builder;
|
||||||
|
using ServiceLib.Enums;
|
||||||
|
using ServiceLib.Models.Entities;
|
||||||
|
using ServiceLib.Resx;
|
||||||
|
using ServiceLib.Tests.CoreConfig;
|
||||||
|
using ServiceLib.ViewModels;
|
||||||
|
|
||||||
|
namespace ServiceLib.Tests.ViewModels;
|
||||||
|
|
||||||
|
[NotInParallel]
|
||||||
|
public class AddServerViewModelTests
|
||||||
|
{
|
||||||
|
static AddServerViewModelTests()
|
||||||
|
{
|
||||||
|
RxAppBuilder.CreateReactiveUIBuilder().WithCoreServices().BuildApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task XdriveServices_ShouldContainExpectedServices()
|
||||||
|
{
|
||||||
|
await Global.XdriveServices.Count.Should().BeEqualTo(3);
|
||||||
|
await Global.XdriveServices[0].Should().BeEqualTo("google-drive");
|
||||||
|
await Global.XdriveServices[1].Should().BeEqualTo("s3");
|
||||||
|
await Global.XdriveServices[2].Should().BeEqualTo("local");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task AddServerViewModel_ShouldBindXdrivePropertiesFromTransportExtra()
|
||||||
|
{
|
||||||
|
CoreConfigTestFactory.BindAppManagerConfig(CoreConfigTestFactory.CreateConfig());
|
||||||
|
|
||||||
|
var profile = new ProfileItem
|
||||||
|
{
|
||||||
|
IndexId = "test-node",
|
||||||
|
ConfigType = EConfigType.VLESS,
|
||||||
|
Address = "example.com",
|
||||||
|
Port = 443,
|
||||||
|
Network = nameof(ETransport.xdrive),
|
||||||
|
};
|
||||||
|
profile.SetTransportExtra(new TransportExtraItem
|
||||||
|
{
|
||||||
|
XdriveService = "s3",
|
||||||
|
XdriveRemoteFolder = "/remote/path",
|
||||||
|
XdriveSecrets = "sec1,sec2",
|
||||||
|
XdriveS3Endpoint = "s3.example.com",
|
||||||
|
XdriveS3Region = "us-west-2",
|
||||||
|
XdriveS3Bucket = "my-bucket",
|
||||||
|
XdriveS3PathStyle = true,
|
||||||
|
XdriveExtra = "{\"concurrency\":4}",
|
||||||
|
});
|
||||||
|
|
||||||
|
var vm = new AddServerViewModel(profile);
|
||||||
|
|
||||||
|
await vm.XdriveService.Should().BeEqualTo("s3");
|
||||||
|
await vm.XdriveRemoteFolder.Should().BeEqualTo("/remote/path");
|
||||||
|
await vm.XdriveSecrets.Should().BeEqualTo("sec1,sec2");
|
||||||
|
await vm.XdriveS3Endpoint.Should().BeEqualTo("s3.example.com");
|
||||||
|
await vm.XdriveS3Region.Should().BeEqualTo("us-west-2");
|
||||||
|
await vm.XdriveS3Bucket.Should().BeEqualTo("my-bucket");
|
||||||
|
await vm.XdriveS3PathStyle.Should().BeEqualTo(true);
|
||||||
|
await vm.XdriveExtra.Should().BeEqualTo("{\"concurrency\":4}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task AddServerViewModel_TransportFriendlyProperties_ShouldAdaptToXdrive()
|
||||||
|
{
|
||||||
|
CoreConfigTestFactory.BindAppManagerConfig(CoreConfigTestFactory.CreateConfig());
|
||||||
|
|
||||||
|
var profile = new ProfileItem
|
||||||
|
{
|
||||||
|
IndexId = "test-node",
|
||||||
|
ConfigType = EConfigType.VLESS,
|
||||||
|
Address = "example.com",
|
||||||
|
Port = 443,
|
||||||
|
Network = nameof(ETransport.xdrive),
|
||||||
|
};
|
||||||
|
profile.SetTransportExtra(new TransportExtraItem
|
||||||
|
{
|
||||||
|
XdriveService = "s3",
|
||||||
|
XdriveRemoteFolder = "/folder",
|
||||||
|
XdriveS3Endpoint = "s3.custom.endpoint",
|
||||||
|
XdriveExtra = "{\"segmentBytes\":1024}",
|
||||||
|
});
|
||||||
|
|
||||||
|
var vm = new AddServerViewModel(profile);
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
await vm.TransportHeaderType.Should().BeEqualTo("s3");
|
||||||
|
await vm.TransportHost.Should().BeEqualTo("s3.custom.endpoint");
|
||||||
|
await vm.TransportPath.Should().BeEqualTo("/folder");
|
||||||
|
await vm.TransportExtraText.Should().BeEqualTo("{\"segmentBytes\":1024}");
|
||||||
|
|
||||||
|
// Setters
|
||||||
|
vm.TransportHeaderType = "google-drive";
|
||||||
|
await vm.XdriveService.Should().BeEqualTo("google-drive");
|
||||||
|
await vm.TransportHeaderType.Should().BeEqualTo("google-drive");
|
||||||
|
|
||||||
|
vm.TransportHost = "s3.new.endpoint";
|
||||||
|
await vm.XdriveS3Endpoint.Should().BeEqualTo("s3.new.endpoint");
|
||||||
|
await vm.TransportHost.Should().BeEqualTo("s3.new.endpoint");
|
||||||
|
|
||||||
|
vm.TransportPath = "/new/folder";
|
||||||
|
await vm.XdriveRemoteFolder.Should().BeEqualTo("/new/folder");
|
||||||
|
await vm.TransportPath.Should().BeEqualTo("/new/folder");
|
||||||
|
|
||||||
|
vm.TransportExtraText = "{\"flushIntervalMs\":500}";
|
||||||
|
await vm.XdriveExtra.Should().BeEqualTo("{\"flushIntervalMs\":500}");
|
||||||
|
await vm.TransportExtraText.Should().BeEqualTo("{\"flushIntervalMs\":500}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task AddServerViewModel_SaveServerAsync_ShouldPersistXdriveFields()
|
||||||
|
{
|
||||||
|
CoreConfigTestFactory.BindAppManagerConfig(CoreConfigTestFactory.CreateConfig());
|
||||||
|
|
||||||
|
var profile = new ProfileItem
|
||||||
|
{
|
||||||
|
IndexId = "test-node",
|
||||||
|
Remarks = "test remarks",
|
||||||
|
ConfigType = EConfigType.VLESS,
|
||||||
|
Address = "example.com",
|
||||||
|
Port = 443,
|
||||||
|
Password = Guid.NewGuid().ToString(),
|
||||||
|
Network = nameof(ETransport.xdrive),
|
||||||
|
};
|
||||||
|
|
||||||
|
var vm = new AddServerViewModel(profile);
|
||||||
|
vm.XdriveService = "s3";
|
||||||
|
vm.XdriveRemoteFolder = "/backup";
|
||||||
|
vm.XdriveSecrets = "key,secret";
|
||||||
|
vm.XdriveS3Endpoint = "s3.amazonaws.com";
|
||||||
|
vm.XdriveS3Region = "eu-central-1";
|
||||||
|
vm.XdriveS3Bucket = "bucket-1";
|
||||||
|
vm.XdriveS3PathStyle = false;
|
||||||
|
vm.XdriveExtra = "{\"concurrency\":8}";
|
||||||
|
|
||||||
|
var saveMethod = typeof(AddServerViewModel).GetMethod("SaveServerAsync", BindingFlags.Instance | BindingFlags.NonPublic)!;
|
||||||
|
await (Task)saveMethod.Invoke(vm, null)!;
|
||||||
|
|
||||||
|
var extra = vm.SelectedSource.GetTransportExtra();
|
||||||
|
await extra.XdriveService.Should().BeEqualTo("s3");
|
||||||
|
await extra.XdriveRemoteFolder.Should().BeEqualTo("/backup");
|
||||||
|
await extra.XdriveSecrets.Should().BeEqualTo("key,secret");
|
||||||
|
await extra.XdriveS3Endpoint.Should().BeEqualTo("s3.amazonaws.com");
|
||||||
|
await extra.XdriveS3Region.Should().BeEqualTo("eu-central-1");
|
||||||
|
await extra.XdriveS3Bucket.Should().BeEqualTo("bucket-1");
|
||||||
|
await extra.XdriveS3PathStyle.Should().BeEqualTo(false);
|
||||||
|
await extra.XdriveExtra.Should().BeEqualTo("{\"concurrency\":8}");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task Localization_ShouldProvideXdriveStrings()
|
||||||
|
{
|
||||||
|
await ResUI.XdriveService.IsNotEmpty().Should().BeTrue();
|
||||||
|
await ResUI.XdriveRemoteFolder.IsNotEmpty().Should().BeTrue();
|
||||||
|
await ResUI.XdriveSecrets.IsNotEmpty().Should().BeTrue();
|
||||||
|
await ResUI.XdriveS3Endpoint.IsNotEmpty().Should().BeTrue();
|
||||||
|
await ResUI.XdriveS3Region.IsNotEmpty().Should().BeTrue();
|
||||||
|
await ResUI.XdriveS3Bucket.IsNotEmpty().Should().BeTrue();
|
||||||
|
await ResUI.XdriveS3PathStyle.IsNotEmpty().Should().BeTrue();
|
||||||
|
await ResUI.XdriveExtra.IsNotEmpty().Should().BeTrue();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,5 +10,6 @@ public enum ETransport
|
|||||||
h2,
|
h2,
|
||||||
http,
|
http,
|
||||||
quic,
|
quic,
|
||||||
grpc
|
grpc,
|
||||||
|
xdrive
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -337,7 +337,8 @@ public class Global
|
|||||||
"kcp",
|
"kcp",
|
||||||
"grpc",
|
"grpc",
|
||||||
"ws",
|
"ws",
|
||||||
"httpupgrade"
|
"httpupgrade",
|
||||||
|
"xdrive"
|
||||||
];
|
];
|
||||||
|
|
||||||
public static readonly List<string> KcpHeaderTypes =
|
public static readonly List<string> KcpHeaderTypes =
|
||||||
@@ -455,6 +456,18 @@ public class Global
|
|||||||
"stream-one"
|
"stream-one"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public static readonly List<string> XdriveServices = ["google-drive", "s3", "local"];
|
||||||
|
|
||||||
|
public static readonly List<string> XdriveProviders =
|
||||||
|
[
|
||||||
|
"Cloudflare R2",
|
||||||
|
"Google Drive",
|
||||||
|
"AWS S3 (Global)",
|
||||||
|
"Yandex Cloud S3",
|
||||||
|
"ArvanCloud S3",
|
||||||
|
"Custom S3"
|
||||||
|
];
|
||||||
|
|
||||||
public static readonly List<string> DomainStrategy =
|
public static readonly List<string> DomainStrategy =
|
||||||
[
|
[
|
||||||
"AsIs",
|
"AsIs",
|
||||||
|
|||||||
@@ -321,6 +321,7 @@ public class StreamSettings4Ray
|
|||||||
public HysteriaSettings4Ray? hysteriaSettings { get; set; }
|
public HysteriaSettings4Ray? hysteriaSettings { get; set; }
|
||||||
|
|
||||||
public MasqueSettings4Ray? masqueSettings { get; set; }
|
public MasqueSettings4Ray? masqueSettings { get; set; }
|
||||||
|
public XdriveSettings4Ray? xdriveSettings { get; set; }
|
||||||
|
|
||||||
public JsonObject? finalmask { get; set; }
|
public JsonObject? finalmask { get; set; }
|
||||||
|
|
||||||
@@ -462,6 +463,28 @@ public class MasqueWarpSettings4Ray
|
|||||||
public List<string>? address { get; set; }
|
public List<string>? address { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class XdriveSettings4Ray
|
||||||
|
{
|
||||||
|
public string? service { get; set; }
|
||||||
|
public string? remoteFolder { get; set; }
|
||||||
|
public List<string>? secrets { get; set; }
|
||||||
|
public S3Settings4Ray? s3 { get; set; }
|
||||||
|
public int? segmentBytes { get; set; }
|
||||||
|
public int? flushIntervalMs { get; set; }
|
||||||
|
public int? pollIntervalMs { get; set; }
|
||||||
|
public int? maxPollIntervalMs { get; set; }
|
||||||
|
public int? eagerWindowMs { get; set; }
|
||||||
|
public int? concurrency { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class S3Settings4Ray
|
||||||
|
{
|
||||||
|
public string? endpoint { get; set; }
|
||||||
|
public string? region { get; set; }
|
||||||
|
public string? bucket { get; set; }
|
||||||
|
public bool? pathStyle { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
public class Finalmask4Ray
|
public class Finalmask4Ray
|
||||||
{
|
{
|
||||||
public List<Mask4Ray>? tcp { get; set; }
|
public List<Mask4Ray>? tcp { get; set; }
|
||||||
|
|||||||
@@ -16,4 +16,13 @@ public record TransportExtraItem
|
|||||||
public string? KcpHeaderType { get; init; }
|
public string? KcpHeaderType { get; init; }
|
||||||
public string? KcpSeed { get; init; }
|
public string? KcpSeed { get; init; }
|
||||||
public int? KcpMtu { get; init; }
|
public int? KcpMtu { get; init; }
|
||||||
|
|
||||||
|
public string? XdriveService { get; init; }
|
||||||
|
public string? XdriveRemoteFolder { get; init; }
|
||||||
|
public string? XdriveSecrets { get; init; }
|
||||||
|
public string? XdriveS3Endpoint { get; init; }
|
||||||
|
public string? XdriveS3Region { get; init; }
|
||||||
|
public string? XdriveS3Bucket { get; init; }
|
||||||
|
public bool? XdriveS3PathStyle { get; init; }
|
||||||
|
public string? XdriveExtra { get; init; }
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+118
-46
@@ -996,6 +996,15 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Columns 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string menuColumns {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("menuColumns", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Close Connection 的本地化字符串。
|
/// 查找类似 Close Connection 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1032,15 +1041,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Currently frozen first {0} column(s) 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuCurrentlyFrozenColumns {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuCurrentlyFrozenColumns", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Latency Test 的本地化字符串。
|
/// 查找类似 Latency Test 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1185,15 +1185,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Freeze up to this column 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuFreezeToThisColumn {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuFreezeToThisColumn", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Full Config Template Setting 的本地化字符串。
|
/// 查找类似 Full Config Template Setting 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1239,15 +1230,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Hide this column 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuHideThisColumn {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuHideThisColumn", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Import Rules From Clipboard 的本地化字符串。
|
/// 查找类似 Import Rules From Clipboard 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -1824,15 +1806,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Show columns 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuShowColumns {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuShowColumns", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 Show or hide the main window 的本地化字符串。
|
/// 查找类似 Show or hide the main window 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -2022,15 +1995,6 @@ namespace ServiceLib.Resx {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找类似 Unfreeze all columns 的本地化字符串。
|
|
||||||
/// </summary>
|
|
||||||
public static string menuUnfreezeAllColumns {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("menuUnfreezeAllColumns", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 {0} Website 的本地化字符串。
|
/// 查找类似 {0} Website 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -4949,7 +4913,7 @@ namespace ServiceLib.Resx {
|
|||||||
return ResourceManager.GetString("TbSettingsTunAutoRoute", resourceCulture);
|
return ResourceManager.GetString("TbSettingsTunAutoRoute", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 DNS mode 的本地化字符串。
|
/// 查找类似 DNS mode 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -5516,5 +5480,113 @@ namespace ServiceLib.Resx {
|
|||||||
return ResourceManager.GetString("UpgradeAppNotExistTip", resourceCulture);
|
return ResourceManager.GetString("UpgradeAppNotExistTip", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Preset Provider 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveProvider {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveProvider", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 XDRIVE service 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveService {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveService", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Remote folder 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveRemoteFolder {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveRemoteFolder", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Secrets (comma separated) 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveSecrets {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveSecrets", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 S3 Endpoint 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveS3Endpoint {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveS3Endpoint", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 S3 Region 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveS3Region {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveS3Region", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 S3 Bucket 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveS3Bucket {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveS3Bucket", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 S3 Force Path Style 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveS3PathStyle {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveS3PathStyle", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 XDRIVE Extra 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveExtra {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveExtra", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Raw JSON, format: { XdriveObject } 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string XdriveExtraTip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("XdriveExtraTip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 XDRIVE service 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TransportHeaderType6 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TransportHeaderType6", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 XDRIVE remote folder 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
public static string TransportPathTip6 {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("TransportPathTip6", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1902,4 +1902,40 @@ Təyin edildikdə sertifikat sabitlənəcək və "Təhlükəsiz olmayan əlaqəy
|
|||||||
<data name="TbSortingProcess" xml:space="preserve">
|
<data name="TbSortingProcess" xml:space="preserve">
|
||||||
<value>Proses</value>
|
<value>Proses</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
|
<value>Təyin olunmuş təchizatçı</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveService" xml:space="preserve">
|
||||||
|
<value>Saxlama xidməti (service)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
|
<value>Uzaqdakı qovluq (remoteFolder)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
|
<value>Giriş açarları (AK,SK / OAuth)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>S3 son nöqtəsi (Endpoint)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>S3 regionu (Region)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>S3 səbəti (Bucket)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>S3 ünvanlama rejimi (PathStyle)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>XDRIVE əlavə parametrləri</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>Emal edilməmiş JSON, format: { Xdrive obyekti }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>XDRIVE xidməti</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>XDRIVE uzaqdakı qovluq</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1776,4 +1776,40 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<data name="menuNewUpdate" xml:space="preserve">
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
<value>New Update</value>
|
<value>New Update</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
|
<value>ارائهدهنده پیشفرض</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveService" xml:space="preserve">
|
||||||
|
<value>سرویس ذخیرهسازی (service)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
|
<value>پوشه ریموت (remoteFolder)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
|
<value>کلیدهای دسترسی (AK,SK / OAuth)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>آدرس اندپوینت S3</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>منطقه S3 (region)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>باکت S3 (bucket)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>آدرسدهی مستقیم S3 (PathStyle)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>تنظیمات پیشرفته XDRIVE</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>فرمت JSON خام: { XdriveObject }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>سرویس XDRIVE</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>پوشه ریموت XDRIVE</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -1770,4 +1770,40 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<data name="menuNewUpdate" xml:space="preserve">
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
<value>Nouvelle MAJ</value>
|
<value>Nouvelle MAJ</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
|
<value>Fournisseur prédéfini</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveService" xml:space="preserve">
|
||||||
|
<value>Service de stockage (service)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
|
<value>Dossier distant (remoteFolder)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
|
<value>Clés d'accès (AK,SK / OAuth)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>Point de terminaison S3 (Endpoint)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>Région S3 (Region)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>Bucket S3</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>Mode d'adressage S3 (PathStyle)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>XDRIVE Extra</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>JSON brut, format : { XdriveObject }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>Service XDRIVE</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>Dossier distant XDRIVE</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -1773,4 +1773,40 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<data name="menuNewUpdate" xml:space="preserve">
|
<data name="menuNewUpdate" xml:space="preserve">
|
||||||
<value>New Update</value>
|
<value>New Update</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
|
<value>Előre beállított szolgáltató</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveService" xml:space="preserve">
|
||||||
|
<value>Tárhelyszolgáltatás (service)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
|
<value>Távoli mappa (remoteFolder)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
|
<value>Hozzáférési kulcsok (AK,SK / OAuth)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>S3 végpont (Endpoint)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>S3 régió (Region)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>S3 tárhely (Bucket)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>S3 elérési út stílus (PathStyle)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>XDRIVE Extra</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>Raw JSON, formátum: { XdriveObject }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>XDRIVE szolgáltatás</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>XDRIVE távoli mappa</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -1797,4 +1797,40 @@ Tindakan "Ambil sertifikat" mungkin gagal jika sertifikat self-signed digunakan
|
|||||||
<data name="TbEnableFinalFragmentTip" xml:space="preserve">
|
<data name="TbEnableFinalFragmentTip" xml:space="preserve">
|
||||||
<value>Memecah bagian akhir paket menjadi fragmen yang lebih kecil. Hal ini dapat memengaruhi throughput dan latensi.</value>
|
<value>Memecah bagian akhir paket menjadi fragmen yang lebih kecil. Hal ini dapat memengaruhi throughput dan latensi.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
|
<value>Penyedia Preset</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveService" xml:space="preserve">
|
||||||
|
<value>Layanan Penyimpanan (service)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
|
<value>Folder Jarak Jauh (remoteFolder)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
|
<value>Kredensial Akses (AK,SK / OAuth)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>Endpoint S3</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>Wilayah S3 (Region)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>Bucket S3</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>Gaya Jalur S3 (PathStyle)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>XDRIVE Ekstra</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>JSON mentah, format: { XdriveObject }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>Layanan XDRIVE</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>Folder jarak jauh XDRIVE</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -1917,8 +1917,8 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
||||||
<value>Enter a valid IPv6 CIDR range with at least two addresses, for example fc00::/18.</value>
|
<value>Enter a valid IPv6 CIDR range with at least two addresses, for example fc00::/18.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShowColumns" xml:space="preserve">
|
<data name="menuColumns" xml:space="preserve">
|
||||||
<value>Show columns</value>
|
<value>Columns</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbWarp" xml:space="preserve">
|
<data name="TbWarp" xml:space="preserve">
|
||||||
<value>Warp</value>
|
<value>Warp</value>
|
||||||
@@ -1926,16 +1926,40 @@ The "Get Certificate" action may fail if a self-signed certificate is used or if
|
|||||||
<data name="LvPreResolve" xml:space="preserve">
|
<data name="LvPreResolve" xml:space="preserve">
|
||||||
<value>Pre-resolve server domains</value>
|
<value>Pre-resolve server domains</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuFreezeToThisColumn" xml:space="preserve">
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
<value>Freeze up to this column</value>
|
<value>Preset Provider</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuUnfreezeAllColumns" xml:space="preserve">
|
<data name="XdriveService" xml:space="preserve">
|
||||||
<value>Unfreeze all columns</value>
|
<value>Storage service (service)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCurrentlyFrozenColumns" xml:space="preserve">
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
<value>Currently frozen first {0} column(s)</value>
|
<value>Remote folder (remoteFolder)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuHideThisColumn" xml:space="preserve">
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
<value>Hide this column</value>
|
<value>Secrets (AK,SK / OAuth)</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>S3 Endpoint</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>S3 Region</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>S3 Bucket</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>S3 Force Path Style</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>XDRIVE Extra</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>Raw JSON, format: { XdriveObject }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>XDRIVE service</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>XDRIVE remote folder</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
|
|||||||
@@ -1908,4 +1908,40 @@
|
|||||||
<data name="menuAddMasqueServer" xml:space="preserve">
|
<data name="menuAddMasqueServer" xml:space="preserve">
|
||||||
<value>Добавить сервер [MASQUE]</value>
|
<value>Добавить сервер [MASQUE]</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
|
<value>Шаблон провайдера</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveService" xml:space="preserve">
|
||||||
|
<value>Облачный сервис (service)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
|
<value>Удаленная папка (remoteFolder)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
|
<value>Ключи доступа (AK,SK / OAuth)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>Эндпоинт S3 (Endpoint)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>Регион S3 (Region)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>Бакет S3 (Bucket)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>Режим адресации S3 (PathStyle)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>Дополнительные параметры XDRIVE (Extra)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>Сырой JSON, формат: { XdriveObject }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>XDRIVE-сервис</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>Удаленная папка XDRIVE</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -1909,8 +1909,8 @@
|
|||||||
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
||||||
<value>请输入至少包含两个地址的有效 IPv6 网段,例如 fc00::/18。</value>
|
<value>请输入至少包含两个地址的有效 IPv6 网段,例如 fc00::/18。</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuShowColumns" xml:space="preserve">
|
<data name="menuColumns" xml:space="preserve">
|
||||||
<value>显示列</value>
|
<value>列</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="TbWarp" xml:space="preserve">
|
<data name="TbWarp" xml:space="preserve">
|
||||||
<value>Warp</value>
|
<value>Warp</value>
|
||||||
@@ -1918,16 +1918,40 @@
|
|||||||
<data name="LvPreResolve" xml:space="preserve">
|
<data name="LvPreResolve" xml:space="preserve">
|
||||||
<value>预解析节点域名</value>
|
<value>预解析节点域名</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuFreezeToThisColumn" xml:space="preserve">
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
<value>冻结至此列</value>
|
<value>预设服务商</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuUnfreezeAllColumns" xml:space="preserve">
|
<data name="XdriveService" xml:space="preserve">
|
||||||
<value>取消所有冻结</value>
|
<value>存储服务 (service)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuCurrentlyFrozenColumns" xml:space="preserve">
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
<value>当前已冻结前 {0} 列</value>
|
<value>远程目录 (remoteFolder)</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="menuHideThisColumn" xml:space="preserve">
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
<value>隐藏此列</value>
|
<value>访问凭证 Secrets (AK,SK / OAuth)</value>
|
||||||
</data>
|
</data>
|
||||||
</root>
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>S3 终端节点</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>S3 区域</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>S3 存储桶</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>S3 强制路径样式 (PathStyle)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>XDRIVE 额外配置</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>原始 JSON,格式: { XdriveObject }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>XDRIVE 服务</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>XDRIVE 远端目录</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
||||||
|
|||||||
@@ -1927,4 +1927,40 @@
|
|||||||
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
<data name="FillCorrectFakeIPv6Range" xml:space="preserve">
|
||||||
<value>請輸入至少包含兩個位址的有效 IPv6 網段,例如 fc00::/18。</value>
|
<value>請輸入至少包含兩個位址的有效 IPv6 網段,例如 fc00::/18。</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="XdriveProvider" xml:space="preserve">
|
||||||
|
<value>預設服務商</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveService" xml:space="preserve">
|
||||||
|
<value>存儲服務 (service)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveRemoteFolder" xml:space="preserve">
|
||||||
|
<value>遠端目錄 (remoteFolder)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveSecrets" xml:space="preserve">
|
||||||
|
<value>存取憑證 Secrets (AK,SK / OAuth)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Endpoint" xml:space="preserve">
|
||||||
|
<value>S3 終端節點</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Region" xml:space="preserve">
|
||||||
|
<value>S3 區域</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3Bucket" xml:space="preserve">
|
||||||
|
<value>S3 儲存桶</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveS3PathStyle" xml:space="preserve">
|
||||||
|
<value>S3 強制路徑樣式 (PathStyle)</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtra" xml:space="preserve">
|
||||||
|
<value>XDRIVE 額外配置</value>
|
||||||
|
</data>
|
||||||
|
<data name="XdriveExtraTip" xml:space="preserve">
|
||||||
|
<value>原始 JSON,格式: { XdriveObject }</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportHeaderType6" xml:space="preserve">
|
||||||
|
<value>XDRIVE 服務</value>
|
||||||
|
</data>
|
||||||
|
<data name="TransportPathTip6" xml:space="preserve">
|
||||||
|
<value>XDRIVE 遠端目錄</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|||||||
@@ -506,6 +506,81 @@ public partial class CoreConfigV2rayService
|
|||||||
streamSettings.grpcSettings = grpcSettings;
|
streamSettings.grpcSettings = grpcSettings;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.xdrive):
|
||||||
|
streamSettings.network = nameof(ETransport.xdrive);
|
||||||
|
var xdriveSettings = new XdriveSettings4Ray
|
||||||
|
{
|
||||||
|
service = transport.XdriveService,
|
||||||
|
remoteFolder = transport.XdriveRemoteFolder,
|
||||||
|
secrets = transport.XdriveSecrets.IsNotEmpty() ? Utils.String2List(transport.XdriveSecrets) : null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (string.Equals(transport.XdriveService, "s3", StringComparison.OrdinalIgnoreCase)
|
||||||
|
|| transport.XdriveS3Endpoint.IsNotEmpty()
|
||||||
|
|| transport.XdriveS3Bucket.IsNotEmpty())
|
||||||
|
{
|
||||||
|
xdriveSettings.s3 = new S3Settings4Ray
|
||||||
|
{
|
||||||
|
endpoint = transport.XdriveS3Endpoint,
|
||||||
|
region = transport.XdriveS3Region,
|
||||||
|
bucket = transport.XdriveS3Bucket,
|
||||||
|
pathStyle = transport.XdriveS3PathStyle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transport.XdriveExtra.IsNotEmpty())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var extraNode = JsonUtils.ParseJson(transport.XdriveExtra);
|
||||||
|
if (extraNode is JsonObject extraObj)
|
||||||
|
{
|
||||||
|
if (int.TryParse(extraObj["segmentBytes"]?.ToString(), out var segmentBytes))
|
||||||
|
{
|
||||||
|
xdriveSettings.segmentBytes = segmentBytes;
|
||||||
|
}
|
||||||
|
if (int.TryParse(extraObj["flushIntervalMs"]?.ToString(), out var flushIntervalMs))
|
||||||
|
{
|
||||||
|
xdriveSettings.flushIntervalMs = flushIntervalMs;
|
||||||
|
}
|
||||||
|
if (int.TryParse(extraObj["pollIntervalMs"]?.ToString(), out var pollIntervalMs))
|
||||||
|
{
|
||||||
|
xdriveSettings.pollIntervalMs = pollIntervalMs;
|
||||||
|
}
|
||||||
|
if (int.TryParse(extraObj["maxPollIntervalMs"]?.ToString(), out var maxPollIntervalMs))
|
||||||
|
{
|
||||||
|
xdriveSettings.maxPollIntervalMs = maxPollIntervalMs;
|
||||||
|
}
|
||||||
|
if (int.TryParse(extraObj["eagerWindowMs"]?.ToString(), out var eagerWindowMs))
|
||||||
|
{
|
||||||
|
xdriveSettings.eagerWindowMs = eagerWindowMs;
|
||||||
|
}
|
||||||
|
if (int.TryParse(extraObj["concurrency"]?.ToString(), out var concurrency))
|
||||||
|
{
|
||||||
|
xdriveSettings.concurrency = concurrency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignore extra json parse errors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(transport.XdriveService, "google-drive", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
xdriveSettings.segmentBytes ??= 524288;
|
||||||
|
xdriveSettings.flushIntervalMs ??= 10;
|
||||||
|
xdriveSettings.pollIntervalMs ??= 50;
|
||||||
|
xdriveSettings.maxPollIntervalMs ??= 200;
|
||||||
|
xdriveSettings.eagerWindowMs ??= 10000;
|
||||||
|
xdriveSettings.concurrency ??= 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
streamSettings.xdriveSettings = xdriveSettings;
|
||||||
|
FillOutboundMux(outbound, true, true);
|
||||||
|
break;
|
||||||
|
|
||||||
case "hysteria":
|
case "hysteria":
|
||||||
var ports = protocolExtra?.Ports;
|
var ports = protocolExtra?.Ports;
|
||||||
int? upMbps = protocolExtra?.UpMbps is { } su and >= 0
|
int? upMbps = protocolExtra?.UpMbps is { } su and >= 0
|
||||||
|
|||||||
@@ -148,6 +148,33 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
[Reactive]
|
[Reactive]
|
||||||
public partial int? KcpMtu { get; set; }
|
public partial int? KcpMtu { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial string XdriveProvider { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial string XdriveService { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial string XdriveRemoteFolder { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial string XdriveSecrets { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial string XdriveS3Endpoint { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial string XdriveS3Region { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial string XdriveS3Bucket { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial bool? XdriveS3PathStyle { get; set; }
|
||||||
|
|
||||||
|
[Reactive]
|
||||||
|
public partial string XdriveExtra { get; set; }
|
||||||
|
|
||||||
public string TransportHeaderType
|
public string TransportHeaderType
|
||||||
{
|
{
|
||||||
get => SelectedSource.GetNetwork() switch
|
get => SelectedSource.GetNetwork() switch
|
||||||
@@ -156,6 +183,7 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
nameof(ETransport.kcp) => KcpHeaderType,
|
nameof(ETransport.kcp) => KcpHeaderType,
|
||||||
nameof(ETransport.xhttp) => XhttpMode,
|
nameof(ETransport.xhttp) => XhttpMode,
|
||||||
nameof(ETransport.grpc) => GrpcMode,
|
nameof(ETransport.grpc) => GrpcMode,
|
||||||
|
nameof(ETransport.xdrive) => XdriveService,
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
set
|
set
|
||||||
@@ -177,6 +205,10 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
case nameof(ETransport.grpc):
|
case nameof(ETransport.grpc):
|
||||||
GrpcMode = value;
|
GrpcMode = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.xdrive):
|
||||||
|
XdriveService = value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.RaisePropertyChanged();
|
this.RaisePropertyChanged();
|
||||||
}
|
}
|
||||||
@@ -191,6 +223,7 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
nameof(ETransport.httpupgrade) => Host,
|
nameof(ETransport.httpupgrade) => Host,
|
||||||
nameof(ETransport.xhttp) => Host,
|
nameof(ETransport.xhttp) => Host,
|
||||||
nameof(ETransport.grpc) => GrpcAuthority,
|
nameof(ETransport.grpc) => GrpcAuthority,
|
||||||
|
nameof(ETransport.xdrive) => XdriveS3Endpoint,
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
set
|
set
|
||||||
@@ -207,6 +240,10 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
case nameof(ETransport.grpc):
|
case nameof(ETransport.grpc):
|
||||||
GrpcAuthority = value;
|
GrpcAuthority = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.xdrive):
|
||||||
|
XdriveS3Endpoint = value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.RaisePropertyChanged();
|
this.RaisePropertyChanged();
|
||||||
}
|
}
|
||||||
@@ -221,6 +258,7 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
nameof(ETransport.httpupgrade) => Path,
|
nameof(ETransport.httpupgrade) => Path,
|
||||||
nameof(ETransport.xhttp) => Path,
|
nameof(ETransport.xhttp) => Path,
|
||||||
nameof(ETransport.grpc) => GrpcServiceName,
|
nameof(ETransport.grpc) => GrpcServiceName,
|
||||||
|
nameof(ETransport.xdrive) => XdriveRemoteFolder,
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
set
|
set
|
||||||
@@ -240,6 +278,10 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
case nameof(ETransport.grpc):
|
case nameof(ETransport.grpc):
|
||||||
GrpcServiceName = value;
|
GrpcServiceName = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.xdrive):
|
||||||
|
XdriveRemoteFolder = value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.RaisePropertyChanged();
|
this.RaisePropertyChanged();
|
||||||
}
|
}
|
||||||
@@ -247,14 +289,23 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
|
|
||||||
public string TransportExtraText
|
public string TransportExtraText
|
||||||
{
|
{
|
||||||
get => SelectedSource.GetNetwork() == nameof(ETransport.xhttp)
|
get => SelectedSource.GetNetwork() switch
|
||||||
? XhttpExtra
|
{
|
||||||
: string.Empty;
|
nameof(ETransport.xhttp) => XhttpExtra,
|
||||||
|
nameof(ETransport.xdrive) => XdriveExtra,
|
||||||
|
_ => string.Empty,
|
||||||
|
};
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (SelectedSource.GetNetwork() == nameof(ETransport.xhttp))
|
switch (SelectedSource.GetNetwork())
|
||||||
{
|
{
|
||||||
XhttpExtra = value;
|
case nameof(ETransport.xhttp):
|
||||||
|
XhttpExtra = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.xdrive):
|
||||||
|
XdriveExtra = value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
this.RaisePropertyChanged();
|
this.RaisePropertyChanged();
|
||||||
}
|
}
|
||||||
@@ -287,8 +338,16 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
.Subscribe(_ => UpdateCertTip());
|
.Subscribe(_ => UpdateCertTip());
|
||||||
|
|
||||||
this.WhenAnyValue(x => x.Network)
|
this.WhenAnyValue(x => x.Network)
|
||||||
.Subscribe(_ =>
|
.Subscribe(network =>
|
||||||
{
|
{
|
||||||
|
if (SelectedSource != null && !network.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
SelectedSource.Network = network;
|
||||||
|
}
|
||||||
|
if (network == nameof(ETransport.xdrive))
|
||||||
|
{
|
||||||
|
MuxEnabled = true;
|
||||||
|
}
|
||||||
this.RaisePropertyChanged(nameof(TransportHeaderType));
|
this.RaisePropertyChanged(nameof(TransportHeaderType));
|
||||||
this.RaisePropertyChanged(nameof(TransportHost));
|
this.RaisePropertyChanged(nameof(TransportHost));
|
||||||
this.RaisePropertyChanged(nameof(TransportPath));
|
this.RaisePropertyChanged(nameof(TransportPath));
|
||||||
@@ -298,6 +357,13 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
this.WhenAnyValue(x => x.Cert)
|
this.WhenAnyValue(x => x.Cert)
|
||||||
.Subscribe(_ => UpdateCertSha());
|
.Subscribe(_ => UpdateCertSha());
|
||||||
|
|
||||||
|
this.WhenAnyValue(x => x.XdriveProvider)
|
||||||
|
.Where(p => p.IsNotEmpty())
|
||||||
|
.Subscribe(provider =>
|
||||||
|
{
|
||||||
|
ApplyXdriveProviderPreset(provider);
|
||||||
|
});
|
||||||
|
|
||||||
if (profileItem.IndexId.IsNullOrEmpty())
|
if (profileItem.IndexId.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
profileItem.Network = Global.DefaultNetwork;
|
profileItem.Network = Global.DefaultNetwork;
|
||||||
@@ -358,6 +424,48 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
KcpHeaderType = transport.KcpHeaderType.IsNullOrEmpty() ? Global.None : transport.KcpHeaderType;
|
KcpHeaderType = transport.KcpHeaderType.IsNullOrEmpty() ? Global.None : transport.KcpHeaderType;
|
||||||
KcpSeed = transport.KcpSeed ?? string.Empty;
|
KcpSeed = transport.KcpSeed ?? string.Empty;
|
||||||
KcpMtu = transport.KcpMtu;
|
KcpMtu = transport.KcpMtu;
|
||||||
|
XdriveService = transport.XdriveService.IsNullOrEmpty() ? (Global.XdriveServices.FirstOrDefault() ?? "google-drive") : transport.XdriveService;
|
||||||
|
XdriveRemoteFolder = transport.XdriveRemoteFolder ?? string.Empty;
|
||||||
|
XdriveSecrets = transport.XdriveSecrets ?? string.Empty;
|
||||||
|
XdriveS3Endpoint = transport.XdriveS3Endpoint ?? string.Empty;
|
||||||
|
XdriveS3Region = transport.XdriveS3Region ?? string.Empty;
|
||||||
|
XdriveS3Bucket = transport.XdriveS3Bucket ?? string.Empty;
|
||||||
|
XdriveS3PathStyle = transport.XdriveS3PathStyle;
|
||||||
|
XdriveExtra = transport.XdriveExtra ?? string.Empty;
|
||||||
|
|
||||||
|
if (transport.XdriveService == "google-drive")
|
||||||
|
{
|
||||||
|
XdriveProvider = "Google Drive";
|
||||||
|
}
|
||||||
|
else if (transport.XdriveS3Endpoint?.Contains("r2.cloudflarestorage.com") == true)
|
||||||
|
{
|
||||||
|
XdriveProvider = "Cloudflare R2";
|
||||||
|
}
|
||||||
|
else if (transport.XdriveS3Endpoint?.Contains("amazonaws.com") == true)
|
||||||
|
{
|
||||||
|
XdriveProvider = "AWS S3 (Global)";
|
||||||
|
}
|
||||||
|
else if (transport.XdriveS3Endpoint?.Contains("yandexcloud.net") == true)
|
||||||
|
{
|
||||||
|
XdriveProvider = "Yandex Cloud S3";
|
||||||
|
}
|
||||||
|
else if (transport.XdriveS3Endpoint?.Contains("arvanstorage.ir") == true)
|
||||||
|
{
|
||||||
|
XdriveProvider = "ArvanCloud S3";
|
||||||
|
}
|
||||||
|
else if (SelectedSource.Remarks?.Contains("Cloudflare", StringComparison.OrdinalIgnoreCase) == true
|
||||||
|
|| (transport.XdriveS3PathStyle == true && transport.XdriveS3Region == "auto"))
|
||||||
|
{
|
||||||
|
XdriveProvider = "Cloudflare R2";
|
||||||
|
}
|
||||||
|
else if (transport.XdriveService == "s3" || transport.XdriveS3Endpoint.IsNotEmpty())
|
||||||
|
{
|
||||||
|
XdriveProvider = "Custom S3";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
XdriveProvider = "Cloudflare R2";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveServerAsync()
|
private async Task SaveServerAsync()
|
||||||
@@ -440,6 +548,14 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
KcpHeaderType = KcpHeaderType.NullIfEmpty(),
|
KcpHeaderType = KcpHeaderType.NullIfEmpty(),
|
||||||
KcpSeed = KcpSeed.NullIfEmpty(),
|
KcpSeed = KcpSeed.NullIfEmpty(),
|
||||||
KcpMtu = KcpMtu > 0 ? KcpMtu : null,
|
KcpMtu = KcpMtu > 0 ? KcpMtu : null,
|
||||||
|
XdriveService = XdriveService.NullIfEmpty(),
|
||||||
|
XdriveRemoteFolder = XdriveRemoteFolder.NullIfEmpty(),
|
||||||
|
XdriveSecrets = XdriveSecrets.NullIfEmpty(),
|
||||||
|
XdriveS3Endpoint = XdriveS3Endpoint.NullIfEmpty(),
|
||||||
|
XdriveS3Region = XdriveS3Region.NullIfEmpty(),
|
||||||
|
XdriveS3Bucket = XdriveS3Bucket.NullIfEmpty(),
|
||||||
|
XdriveS3PathStyle = XdriveS3PathStyle,
|
||||||
|
XdriveExtra = XdriveExtra.NullIfEmpty(),
|
||||||
};
|
};
|
||||||
|
|
||||||
SelectedSource.SetProtocolExtra(SelectedSource.GetProtocolExtra() with
|
SelectedSource.SetProtocolExtra(SelectedSource.GetProtocolExtra() with
|
||||||
@@ -494,6 +610,44 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
: errorMessage;
|
: errorMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ApplyXdriveProviderPreset(string provider)
|
||||||
|
{
|
||||||
|
switch (provider)
|
||||||
|
{
|
||||||
|
case "Cloudflare R2":
|
||||||
|
XdriveService = "s3";
|
||||||
|
if (XdriveS3Region.IsNullOrEmpty()) XdriveS3Region = "auto";
|
||||||
|
XdriveS3PathStyle = true;
|
||||||
|
break;
|
||||||
|
case "Google Drive":
|
||||||
|
XdriveService = "google-drive";
|
||||||
|
SelectedSource.StreamSecurity = Global.StreamSecurity;
|
||||||
|
if (SelectedSource.Sni.IsNullOrEmpty()) SelectedSource.Sni = "www.google.com";
|
||||||
|
if (SelectedSource.Alpn.IsNullOrEmpty()) SelectedSource.Alpn = "h2";
|
||||||
|
if (SelectedSource.Address.IsNullOrEmpty()) SelectedSource.Address = "www.google.com";
|
||||||
|
if (SelectedSource.Port <= 0) SelectedSource.Port = 443;
|
||||||
|
break;
|
||||||
|
case "AWS S3 (Global)":
|
||||||
|
XdriveService = "s3";
|
||||||
|
if (XdriveS3Region.IsNullOrEmpty()) XdriveS3Region = "ap-northeast-1";
|
||||||
|
XdriveS3PathStyle = false;
|
||||||
|
break;
|
||||||
|
case "Yandex Cloud S3":
|
||||||
|
XdriveService = "s3";
|
||||||
|
if (XdriveS3Region.IsNullOrEmpty()) XdriveS3Region = "ru-central1";
|
||||||
|
XdriveS3PathStyle = true;
|
||||||
|
break;
|
||||||
|
case "ArvanCloud S3":
|
||||||
|
XdriveService = "s3";
|
||||||
|
if (XdriveS3Region.IsNullOrEmpty()) XdriveS3Region = "ir-tbz-sh1";
|
||||||
|
XdriveS3PathStyle = true;
|
||||||
|
break;
|
||||||
|
case "Custom S3":
|
||||||
|
XdriveService = "s3";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateCertSha()
|
private void UpdateCertSha()
|
||||||
{
|
{
|
||||||
if (Cert.IsNullOrEmpty())
|
if (Cert.IsNullOrEmpty())
|
||||||
@@ -582,6 +736,7 @@ public partial class AddServerViewModel : MyReactiveObject, ICloseable
|
|||||||
nameof(ETransport.httpupgrade) => Host,
|
nameof(ETransport.httpupgrade) => Host,
|
||||||
nameof(ETransport.xhttp) => Host,
|
nameof(ETransport.xhttp) => Host,
|
||||||
nameof(ETransport.grpc) => GrpcAuthority,
|
nameof(ETransport.grpc) => GrpcAuthority,
|
||||||
|
nameof(ETransport.xdrive) => XdriveS3Endpoint,
|
||||||
_ => string.Empty,
|
_ => string.Empty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1050,6 +1050,125 @@
|
|||||||
</Expander>
|
</Expander>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
x:Name="gridTransportXdrive"
|
||||||
|
ColumnDefinitions="300,Auto"
|
||||||
|
IsVisible="False"
|
||||||
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto">
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveProvider}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbProviderXdrive"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="250"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveService}" />
|
||||||
|
<ComboBox
|
||||||
|
x:Name="cmbServiceXdrive"
|
||||||
|
Grid.Row="1"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="200"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveRemoteFolder}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtRemoteFolderXdrive"
|
||||||
|
Grid.Row="2"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveSecrets}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtSecretsXdrive"
|
||||||
|
Grid.Row="3"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveS3Endpoint}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtEndpointXdrive"
|
||||||
|
Grid.Row="4"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="5"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveS3Bucket}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtBucketXdrive"
|
||||||
|
Grid.Row="5"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="6"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveS3Region}" />
|
||||||
|
<TextBox
|
||||||
|
x:Name="txtRegionXdrive"
|
||||||
|
Grid.Row="6"
|
||||||
|
Grid.Column="1"
|
||||||
|
Width="400"
|
||||||
|
Margin="{StaticResource Margin4}" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveS3PathStyle}" />
|
||||||
|
<ToggleSwitch
|
||||||
|
x:Name="togPathStyleXdrive"
|
||||||
|
Grid.Row="7"
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
HorizontalAlignment="Left" />
|
||||||
|
<TextBlock
|
||||||
|
Grid.Row="8"
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="{StaticResource Margin4}"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Text="{x:Static resx:ResUI.XdriveExtra}"
|
||||||
|
TextWrapping="Wrap" />
|
||||||
|
<Expander
|
||||||
|
Grid.Row="8"
|
||||||
|
Grid.Column="1"
|
||||||
|
IsExpanded="False">
|
||||||
|
<Expander.Header>
|
||||||
|
<TextBlock FontWeight="Normal" Text="{x:Static resx:ResUI.XdriveExtraTip}" />
|
||||||
|
</Expander.Header>
|
||||||
|
<views:JsonEditor x:Name="txtExtraXdrive" HorizontalAlignment="Stretch" />
|
||||||
|
</Expander>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
x:Name="gridTransportKcp"
|
x:Name="gridTransportKcp"
|
||||||
ColumnDefinitions="300,Auto"
|
ColumnDefinitions="300,Auto"
|
||||||
|
|||||||
@@ -179,6 +179,19 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
this.Bind(ViewModel, vm => vm.GrpcAuthority, v => v.txtRequestHostGrpc.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.GrpcAuthority, v => v.txtRequestHostGrpc.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.GrpcServiceName, v => v.txtPathGrpc.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.GrpcServiceName, v => v.txtPathGrpc.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
|
cmbProviderXdrive.ItemsSource = Global.XdriveProviders;
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveProvider, v => v.cmbProviderXdrive.SelectedValue).DisposeWith(disposables);
|
||||||
|
|
||||||
|
cmbServiceXdrive.ItemsSource = Global.XdriveServices;
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveService, v => v.cmbServiceXdrive.SelectedValue).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveRemoteFolder, v => v.txtRemoteFolderXdrive.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveSecrets, v => v.txtSecretsXdrive.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveS3Endpoint, v => v.txtEndpointXdrive.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveS3Bucket, v => v.txtBucketXdrive.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveS3Region, v => v.txtRegionXdrive.Text).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveS3PathStyle, v => v.togPathStyleXdrive.IsChecked).DisposeWith(disposables);
|
||||||
|
this.Bind(ViewModel, vm => vm.XdriveExtra, v => v.txtExtraXdrive.Text).DisposeWith(disposables);
|
||||||
|
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.SelectedValue).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.StreamSecurity, v => v.cmbStreamSecurity.SelectedValue).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.SelectedSource.Sni, v => v.txtSNI.Text).DisposeWith(disposables);
|
||||||
this.Bind(ViewModel, vm => vm.AllowInsecure, v => v.togAllowInsecure.IsChecked).DisposeWith(disposables);
|
this.Bind(ViewModel, vm => vm.AllowInsecure, v => v.togAllowInsecure.IsChecked).DisposeWith(disposables);
|
||||||
@@ -359,6 +372,7 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
gridTransportHttpupgrade.IsVisible = false;
|
gridTransportHttpupgrade.IsVisible = false;
|
||||||
gridTransportXhttp.IsVisible = false;
|
gridTransportXhttp.IsVisible = false;
|
||||||
gridTransportGrpc.IsVisible = false;
|
gridTransportGrpc.IsVisible = false;
|
||||||
|
gridTransportXdrive.IsVisible = false;
|
||||||
|
|
||||||
switch (network)
|
switch (network)
|
||||||
{
|
{
|
||||||
@@ -386,6 +400,10 @@ public partial class AddServerWindow : WindowBase<AddServerViewModel>
|
|||||||
gridTransportGrpc.IsVisible = true;
|
gridTransportGrpc.IsVisible = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case nameof(ETransport.xdrive):
|
||||||
|
gridTransportXdrive.IsVisible = true;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
gridTransportRaw.IsVisible = true;
|
gridTransportRaw.IsVisible = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user