Compare commits

...

14 Commits

Author SHA1 Message Date
2dust
8d1853e991 up 7.10.2 2025-03-04 15:11:05 +08:00
DHR60
859299c712 Add kcp DNS masquerade support (#6852)
* Add kcp DNS masquerade support

* Update V2rayConfig.cs

* Update CoreConfigV2rayService.cs

---------

Co-authored-by: 2dust <31833384+2dust@users.noreply.github.com>
2025-03-04 10:32:07 +08:00
2dust
7fbb0013b0 Optimizing Task Code 2025-03-03 16:57:55 +08:00
2dust
837cfbd03b Optimize UI prompts 2025-03-03 14:36:30 +08:00
2dust
cdc5d72cfa Update CoreConfigSingboxService.cs 2025-03-03 14:36:01 +08:00
DHR60
8dcf5c5b90 Add Hy2 Port hopping URI support (#6848) 2025-03-03 14:11:53 +08:00
2dust
67fe6ac3d8 Optimizing Task Code, add unified processing of scheduled tasks 2025-03-03 12:20:58 +08:00
2dust
438eaba4d5 up 7.10.1 2025-03-02 10:30:08 +08:00
2dust
3c8baa99d5 Update Directory.Packages.props 2025-03-02 10:29:43 +08:00
2dust
e70658f311 Add Hy2 Port hopping for sing-box 1.11+
https://github.com/2dust/v2rayN/issues/6772
2025-03-01 21:13:37 +08:00
2dust
2dd10cf5a1 Optimize QrcodeView 2025-03-01 19:56:52 +08:00
2dust
96781a784b git submodule update --remote 2025-03-01 15:29:54 +08:00
2dust
9748fbb076 If the update fails during the upgrade, the update will be retried. 2025-03-01 14:23:43 +08:00
2dust
aa5e4378ab Update AutoStartupHandler.cs 2025-03-01 14:14:07 +08:00
37 changed files with 400 additions and 225 deletions

View File

@@ -1,29 +1,39 @@
namespace AmazTool namespace AmazTool
{ {
internal static class Program internal static class Program
{ {
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread] [STAThread]
private static void Main(string[] args) private static void Main(string[] args)
{ {
if (args.Length == 0) if (args.Length == 0)
{ {
Console.WriteLine(Resx.Resource.Guidelines); Utils.WriteLine(Resx.Resource.Guidelines);
Thread.Sleep(5000); Utils.Waiting(5);
return; return;
} }
var argData = Uri.UnescapeDataString(string.Join(" ", args)); var argData = Uri.UnescapeDataString(string.Join(" ", args));
if (argData.Equals("rebootas")) if (argData.Equals("rebootas"))
{ {
Thread.Sleep(1000); Utils.Waiting(1);
Utils.StartV2RayN(); Utils.StartV2RayN();
return; return;
} }
UpgradeApp.Upgrade(argData); var tryTimes = 0;
UpgradeApp.Init();
while (tryTimes++ < 3)
{
if (!UpgradeApp.Upgrade(argData))
{
continue;
}
Utils.WriteLine(Resx.Resource.Restartv2rayN);
Utils.Waiting(3);
Utils.StartV2RayN();
break;
}
} }
} }
} }

View File

@@ -6,19 +6,99 @@ namespace AmazTool
{ {
internal class UpgradeApp internal class UpgradeApp
{ {
public static void Upgrade(string fileName) public static bool Upgrade(string fileName)
{ {
Console.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}"); Utils.WriteLine($"{Resx.Resource.StartUnzipping}\n{fileName}");
Utils.Waiting(5);
if (!File.Exists(fileName)) if (!File.Exists(fileName))
{ {
Console.WriteLine(Resx.Resource.UpgradeFileNotFound); Utils.WriteLine(Resx.Resource.UpgradeFileNotFound);
return; return false;
} }
Console.WriteLine(Resx.Resource.TryTerminateProcess); Utils.Waiting(5);
KillV2rayN();
Utils.WriteLine(Resx.Resource.StartUnzipping);
StringBuilder sb = new();
try
{
var splitKey = "/";
using var archive = ZipFile.OpenRead(fileName);
foreach (var entry in archive.Entries)
{
try
{
if (entry.Length == 0)
{
continue;
}
Utils.WriteLine(entry.FullName);
var lst = entry.FullName.Split(splitKey);
if (lst.Length == 1)
{
continue;
}
var fullName = string.Join(splitKey, lst[1..lst.Length]);
var entryOutputPath = Utils.GetPath(fullName);
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
//In the bin folder, if the file already exists, it will be skipped
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
{
continue;
}
entry.ExtractToFile(entryOutputPath, true);
Utils.WriteLine(entryOutputPath);
}
catch (Exception ex)
{
sb.Append(ex.Message);
sb.Append(ex.StackTrace);
}
}
}
catch (Exception ex)
{
sb.Append(Resx.Resource.FailedUpgrade + ex.StackTrace);
}
if (sb.Length <= 0)
{
return true;
}
Utils.WriteLine(sb.ToString());
Utils.WriteLine(Resx.Resource.FailedUpgrade);
return false;
}
public static bool Init()
{
//Process temporary files generated by the last update
var files = Directory.GetFiles(Utils.GetPath(""), "*.tmp");
foreach (var file in files)
{
if (file.Contains(Utils.AmazTool))
{
File.Delete(file);
}
}
var destFileName = $"{Utils.GetExePath()}{Guid.NewGuid().ToString("N")[..8]}.tmp";
File.Move(Utils.GetExePath(), destFileName);
return true;
}
private static bool KillV2rayN()
{
Utils.WriteLine(Resx.Resource.TryTerminateProcess);
try try
{ {
var existing = Process.GetProcessesByName(Utils.V2rayN); var existing = Process.GetProcessesByName(Utils.V2rayN);
@@ -35,71 +115,10 @@ namespace AmazTool
catch (Exception ex) catch (Exception ex)
{ {
// Access may be denied without admin right. The user may not be an administrator. // Access may be denied without admin right. The user may not be an administrator.
Console.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace); Utils.WriteLine(Resx.Resource.FailedTerminateProcess + ex.StackTrace);
} }
Console.WriteLine(Resx.Resource.StartUnzipping); return true;
StringBuilder sb = new();
try
{
var thisAppOldFile = $"{Utils.GetExePath()}.tmp";
File.Delete(thisAppOldFile);
var splitKey = "/";
using var archive = ZipFile.OpenRead(fileName);
foreach (var entry in archive.Entries)
{
try
{
if (entry.Length == 0)
{
continue;
}
Console.WriteLine(entry.FullName);
var lst = entry.FullName.Split(splitKey);
if (lst.Length == 1)
continue;
var fullName = string.Join(splitKey, lst[1..lst.Length]);
if (string.Equals(Utils.GetExePath(), Utils.GetPath(fullName), StringComparison.OrdinalIgnoreCase))
{
File.Move(Utils.GetExePath(), thisAppOldFile);
}
var entryOutputPath = Utils.GetPath(fullName);
Directory.CreateDirectory(Path.GetDirectoryName(entryOutputPath)!);
//In the bin folder, if the file already exists, it will be skipped
if (fullName.StartsWith("bin") && File.Exists(entryOutputPath))
{
continue;
}
entry.ExtractToFile(entryOutputPath, true);
Console.WriteLine(entryOutputPath);
}
catch (Exception ex)
{
sb.Append(ex.StackTrace);
}
}
}
catch (Exception ex)
{
Console.WriteLine(Resx.Resource.FailedUpgrade + ex.StackTrace);
//return;
}
if (sb.Length > 0)
{
Console.WriteLine(Resx.Resource.FailedUpgrade + sb.ToString());
//return;
}
Console.WriteLine(Resx.Resource.Restartv2rayN);
Utils.Waiting(2);
Utils.StartV2RayN();
} }
} }
} }

View File

@@ -1,4 +1,4 @@
using System.Diagnostics; using System.Diagnostics;
namespace AmazTool namespace AmazTool
{ {
@@ -14,9 +14,9 @@ namespace AmazTool
return AppDomain.CurrentDomain.BaseDirectory; return AppDomain.CurrentDomain.BaseDirectory;
} }
public static string GetPath(string fileName) public static string GetPath(string? fileName)
{ {
string startupPath = StartupPath(); var startupPath = StartupPath();
if (string.IsNullOrEmpty(fileName)) if (string.IsNullOrEmpty(fileName))
{ {
return startupPath; return startupPath;
@@ -25,6 +25,7 @@ namespace AmazTool
} }
public static string V2rayN => "v2rayN"; public static string V2rayN => "v2rayN";
public static string AmazTool => "AmazTool";
public static void StartV2RayN() public static void StartV2RayN()
{ {
@@ -44,9 +45,14 @@ namespace AmazTool
{ {
for (var i = second; i > 0; i--) for (var i = second; i > 0; i--)
{ {
Console.WriteLine(i); Utils.WriteLine(i);
Thread.Sleep(1000); Thread.Sleep(1000);
} }
} }
public static void WriteLine(object obj)
{
Console.WriteLine(obj);
}
} }
} }

View File

@@ -1,7 +1,7 @@
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<Version>7.10.0</Version> <Version>7.10.2</Version>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>

View File

@@ -5,21 +5,21 @@
<CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled> <CentralPackageVersionOverrideEnabled>false</CentralPackageVersionOverrideEnabled>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.4" /> <PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.2.5" />
<PackageVersion Include="Avalonia.Desktop" Version="11.2.4" /> <PackageVersion Include="Avalonia.Desktop" Version="11.2.5" />
<PackageVersion Include="Avalonia.Diagnostics" Version="11.2.4" /> <PackageVersion Include="Avalonia.Diagnostics" Version="11.2.5" />
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.4" /> <PackageVersion Include="Avalonia.ReactiveUI" Version="11.2.5" />
<PackageVersion Include="CliWrap" Version="3.8.1" /> <PackageVersion Include="CliWrap" Version="3.8.1" />
<PackageVersion Include="Downloader" Version="3.3.3" /> <PackageVersion Include="Downloader" Version="3.3.3" />
<PackageVersion Include="H.NotifyIcon.Wpf" Version="2.2.0" /> <PackageVersion Include="H.NotifyIcon.Wpf" Version="2.3.0" />
<PackageVersion Include="MaterialDesignThemes" Version="5.2.1" /> <PackageVersion Include="MaterialDesignThemes" Version="5.2.1" />
<PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" /> <PackageVersion Include="MessageBox.Avalonia" Version="3.2.0" />
<PackageVersion Include="QRCoder" Version="1.6.0" /> <PackageVersion Include="QRCoder" Version="1.6.0" />
<PackageVersion Include="ReactiveUI" Version="20.1.63" /> <PackageVersion Include="ReactiveUI" Version="20.1.63" />
<PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" /> <PackageVersion Include="ReactiveUI.Fody" Version="19.5.41" />
<PackageVersion Include="ReactiveUI.WPF" Version="20.1.63" /> <PackageVersion Include="ReactiveUI.WPF" Version="20.1.63" />
<PackageVersion Include="Semi.Avalonia" Version="11.2.1.4" /> <PackageVersion Include="Semi.Avalonia" Version="11.2.1.5" />
<PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.4" /> <PackageVersion Include="Semi.Avalonia.DataGrid" Version="11.2.1.5" />
<PackageVersion Include="Splat.NLog" Version="15.3.1" /> <PackageVersion Include="Splat.NLog" Version="15.3.1" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" /> <PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="TaskScheduler" Version="2.12.0" /> <PackageVersion Include="TaskScheduler" Version="2.12.0" />

View File

@@ -265,7 +265,8 @@ namespace ServiceLib
"utp", "utp",
"wechat-video", "wechat-video",
"dtls", "dtls",
"wireguard" "wireguard",
"dns"
]; ];
public static readonly List<string> CoreTypes = public static readonly List<string> CoreTypes =

View File

@@ -80,8 +80,6 @@ namespace ServiceLib.Handler
Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}"); Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}");
Logging.LoggingEnabled(_config.GuiItem.EnableLog); Logging.LoggingEnabled(_config.GuiItem.EnableLog);
ClearExpiredFiles();
return true; return true;
} }
@@ -92,16 +90,6 @@ namespace ServiceLib.Handler
return true; return true;
} }
private void ClearExpiredFiles()
{
Task.Run(() =>
{
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
});
}
#endregion Init #endregion Init
#region Config #region Config

View File

@@ -109,7 +109,7 @@ namespace ServiceLib.Handler
task.Settings.RunOnlyIfIdle = false; task.Settings.RunOnlyIfIdle = false;
task.Settings.IdleSettings.StopOnIdleEnd = false; task.Settings.IdleSettings.StopOnIdleEnd = false;
task.Settings.ExecutionTimeLimit = TimeSpan.Zero; task.Settings.ExecutionTimeLimit = TimeSpan.Zero;
task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(10) }); task.Triggers.Add(new Microsoft.Win32.TaskScheduler.LogonTrigger { UserId = logonUser, Delay = TimeSpan.FromSeconds(30) });
task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest; task.Principal.RunLevel = Microsoft.Win32.TaskScheduler.TaskRunLevel.Highest;
task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName))); task.Actions.Add(new Microsoft.Win32.TaskScheduler.ExecAction(fileName.AppendQuotes(), null, Path.GetDirectoryName(fileName)));

View File

@@ -7,9 +7,9 @@ namespace ServiceLib.Handler
private static readonly Lazy<ClashApiHandler> instance = new(() => new()); private static readonly Lazy<ClashApiHandler> instance = new(() => new());
public static ClashApiHandler Instance => instance.Value; public static ClashApiHandler Instance => instance.Value;
private static readonly string _tag = "ClashApiHandler";
private Dictionary<string, ProxiesItem>? _proxies; private Dictionary<string, ProxiesItem>? _proxies;
public Dictionary<string, object> ProfileContent { get; set; } public Dictionary<string, object> ProfileContent { get; set; }
private static readonly string _tag = "ClashApiHandler";
public async Task<Tuple<ClashProxies, ClashProviders>?> GetClashProxiesAsync(Config config) public async Task<Tuple<ClashProxies, ClashProviders>?> GetClashProxiesAsync(Config config)
{ {
@@ -54,7 +54,7 @@ namespace ServiceLib.Handler
return; return;
} }
lstProxy = new List<ClashProxyModel>(); lstProxy = new List<ClashProxyModel>();
foreach (KeyValuePair<string, ProxiesItem> kv in _proxies) foreach (var kv in _proxies)
{ {
if (Global.notAllowTestType.Contains(kv.Value.type.ToLower())) if (Global.notAllowTestType.Contains(kv.Value.type.ToLower()))
{ {

View File

@@ -217,6 +217,7 @@ namespace ServiceLib.Handler
item.Remarks = profileItem.Remarks; item.Remarks = profileItem.Remarks;
item.Address = profileItem.Address; item.Address = profileItem.Address;
item.Port = profileItem.Port; item.Port = profileItem.Port;
item.Ports = profileItem.Ports;
item.Id = profileItem.Id; item.Id = profileItem.Id;
item.AlterId = profileItem.AlterId; item.AlterId = profileItem.AlterId;

View File

@@ -24,6 +24,8 @@ namespace ServiceLib.Handler.Fmt
item.Path = Utils.UrlDecode(query["obfs-password"] ?? ""); item.Path = Utils.UrlDecode(query["obfs-password"] ?? "");
item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false"; item.AllowInsecure = (query["insecure"] ?? "") == "1" ? "true" : "false";
item.Ports = Utils.UrlDecode(query["mport"] ?? "").Replace('-', ':');
return item; return item;
} }
@@ -53,6 +55,10 @@ namespace ServiceLib.Handler.Fmt
dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path)); dicQuery.Add("obfs-password", Utils.UrlEncode(item.Path));
} }
dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0"); dicQuery.Add("insecure", item.AllowInsecure.ToLower() == "true" ? "1" : "0");
if (Utils.IsNotEmpty(item.Ports))
{
dicQuery.Add("mport", Utils.UrlEncode(item.Ports.Replace(':', '-')));
}
return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark); return ToUri(EConfigType.Hysteria2, item.Address, item.Port, item.Id, dicQuery, remark);
} }

View File

@@ -20,14 +20,6 @@ namespace ServiceLib.Handler
public async Task Init() public async Task Init()
{ {
await InitData(); await InitData();
_ = Task.Run(async () =>
{
while (true)
{
await Task.Delay(1000 * 600);
await SaveQueueIndexIds();
}
});
} }
public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs() public async Task<ConcurrentBag<ProfileExItem>> GetProfileExs()

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Handler namespace ServiceLib.Handler
{ {
public class TaskHandler public class TaskHandler
{ {
@@ -7,65 +7,91 @@
public void RegUpdateTask(Config config, Action<bool, string> updateFunc) public void RegUpdateTask(Config config, Action<bool, string> updateFunc)
{ {
Task.Run(() => UpdateTaskRunSubscription(config, updateFunc)); Task.Run(() => ScheduledTasks(config, updateFunc));
Task.Run(() => UpdateTaskRunGeo(config, updateFunc)); }
private async Task ScheduledTasks(Config config, Action<bool, string> updateFunc)
{
Logging.SaveLog("Setup Scheduled Tasks");
var numOfExecuted = 1;
while (true)
{
//1 minute
await Task.Delay(1000 * 60);
//Execute once 1 minute
await UpdateTaskRunSubscription(config, updateFunc);
//Execute once 20 minute
if (numOfExecuted % 20 == 0)
{
//Logging.SaveLog("Execute save config");
await ConfigHandler.SaveConfig(config);
await ProfileExHandler.Instance.SaveTo();
}
//Execute once 1 hour
if (numOfExecuted % 60 == 0)
{
//Logging.SaveLog("Execute delete expired files");
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
FileManager.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
FileManager.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
//Check once 1 hour
await UpdateTaskRunGeo(config, numOfExecuted / 60, updateFunc);
}
numOfExecuted++;
}
} }
private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> updateFunc) private async Task UpdateTaskRunSubscription(Config config, Action<bool, string> updateFunc)
{ {
await Task.Delay(60000); var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds();
Logging.SaveLog("UpdateTaskRunSubscription"); var lstSubs = (await AppHandler.Instance.SubItems())?
.Where(t => t.AutoUpdateInterval > 0)
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
.ToList();
var updateHandle = new UpdateService(); if (lstSubs is not { Count: > 0 })
while (true)
{ {
var updateTime = ((DateTimeOffset)DateTime.Now).ToUnixTimeSeconds(); return;
var lstSubs = (await AppHandler.Instance.SubItems()) }
.Where(t => t.AutoUpdateInterval > 0)
.Where(t => updateTime - t.UpdateTime >= t.AutoUpdateInterval * 60)
.ToList();
foreach (var item in lstSubs) Logging.SaveLog("Execute update subscription");
var updateHandle = new UpdateService();
foreach (var item in lstSubs)
{
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) =>
{ {
await updateHandle.UpdateSubscriptionProcess(config, item.Id, true, (bool success, string msg) => updateFunc?.Invoke(success, msg);
{ if (success)
updateFunc?.Invoke(success, msg); {
if (success) Logging.SaveLog($"Update subscription end. {msg}");
Logging.SaveLog("subscription" + msg); }
}); });
item.UpdateTime = updateTime; item.UpdateTime = updateTime;
await ConfigHandler.AddSubItem(config, item); await ConfigHandler.AddSubItem(config, item);
await Task.Delay(1000);
await Task.Delay(5000);
}
await Task.Delay(60000);
} }
} }
private async Task UpdateTaskRunGeo(Config config, Action<bool, string> updateFunc) private async Task UpdateTaskRunGeo(Config config, int hours, Action<bool, string> updateFunc)
{ {
var autoUpdateGeoTime = DateTime.Now; if (config.GuiItem.AutoUpdateInterval > 0 && hours > 0 && hours % config.GuiItem.AutoUpdateInterval == 0)
//await Task.Delay(1000 * 120);
Logging.SaveLog("UpdateTaskRunGeo");
var updateHandle = new UpdateService();
while (true)
{ {
await Task.Delay(1000 * 3600); Logging.SaveLog("Execute update geo files");
var dtNow = DateTime.Now; var updateHandle = new UpdateService();
if (config.GuiItem.AutoUpdateInterval > 0) await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{ {
if ((dtNow - autoUpdateGeoTime).Hours % config.GuiItem.AutoUpdateInterval == 0) updateFunc?.Invoke(false, msg);
{ });
await updateHandle.UpdateGeoFileAll(config, (bool success, string msg) =>
{
updateFunc?.Invoke(false, msg);
});
autoUpdateGeoTime = dtNow;
}
}
} }
} }
} }

View File

@@ -197,6 +197,7 @@ namespace ServiceLib.Models
{ {
public int UpMbps { get; set; } public int UpMbps { get; set; }
public int DownMbps { get; set; } public int DownMbps { get; set; }
public int HopInterval { get; set; } = 30;
} }
[Serializable] [Serializable]

View File

@@ -1,4 +1,4 @@
using SQLite; using SQLite;
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
@@ -64,11 +64,11 @@ namespace ServiceLib.Models
[PrimaryKey] [PrimaryKey]
public string IndexId { get; set; } public string IndexId { get; set; }
public EConfigType ConfigType { get; set; } public EConfigType ConfigType { get; set; }
public int ConfigVersion { get; set; } public int ConfigVersion { get; set; }
public string Address { get; set; } public string Address { get; set; }
public int Port { get; set; } public int Port { get; set; }
public string Ports { get; set; }
public string Id { get; set; } public string Id { get; set; }
public int AlterId { get; set; } public int AlterId { get; set; }
public string Security { get; set; } public string Security { get; set; }

View File

@@ -1,4 +1,4 @@
namespace ServiceLib.Models namespace ServiceLib.Models
{ {
public class SingboxConfig public class SingboxConfig
{ {
@@ -101,21 +101,23 @@
public string tag { get; set; } public string tag { get; set; }
public string? server { get; set; } public string? server { get; set; }
public int? server_port { get; set; } public int? server_port { get; set; }
public string uuid { get; set; } public List<string>? server_ports { get; set; }
public string security { get; set; } public string? uuid { get; set; }
public string? security { get; set; }
public int? alter_id { get; set; } public int? alter_id { get; set; }
public string flow { get; set; } public string? flow { get; set; }
public string? hop_interval { get; set; }
public int? up_mbps { get; set; } public int? up_mbps { get; set; }
public int? down_mbps { get; set; } public int? down_mbps { get; set; }
public string auth_str { get; set; } public string? auth_str { get; set; }
public int? recv_window_conn { get; set; } public int? recv_window_conn { get; set; }
public int? recv_window { get; set; } public int? recv_window { get; set; }
public bool? disable_mtu_discovery { get; set; } public bool? disable_mtu_discovery { get; set; }
public string? detour { get; set; } public string? detour { get; set; }
public string method { get; set; } public string? method { get; set; }
public string username { get; set; } public string? username { get; set; }
public string password { get; set; } public string? password { get; set; }
public string congestion_control { get; set; } public string? congestion_control { get; set; }
public string? version { get; set; } public string? version { get; set; }
public string? network { get; set; } public string? network { get; set; }
public string? packet_encoding { get; set; } public string? packet_encoding { get; set; }

View File

@@ -291,6 +291,8 @@ namespace ServiceLib.Models
public object request { get; set; } public object request { get; set; }
public object response { get; set; } public object response { get; set; }
public string? domain { get; set; }
} }
public class KcpSettings4Ray public class KcpSettings4Ray

View File

@@ -2483,7 +2483,7 @@ namespace ServiceLib.Resx {
} }
/// <summary> /// <summary>
/// 查找类似 Address(Ip,Ipv6) 的本地化字符串。 /// 查找类似 Address(Ipv4,Ipv6) 的本地化字符串。
/// </summary> /// </summary>
public static string TbLocalAddress { public static string TbLocalAddress {
get { get {
@@ -2536,6 +2536,24 @@ namespace ServiceLib.Resx {
} }
} }
/// <summary>
/// 查找类似 Server port range 的本地化字符串。
/// </summary>
public static string TbPorts7 {
get {
return ResourceManager.GetString("TbPorts7", resourceCulture);
}
}
/// <summary>
/// 查找类似 Will cover the port, separate with commas (,) 的本地化字符串。
/// </summary>
public static string TbPorts7Tips {
get {
return ResourceManager.GetString("TbPorts7Tips", resourceCulture);
}
}
/// <summary> /// <summary>
/// 查找类似 Socks port 的本地化字符串。 /// 查找类似 Socks port 的本地化字符串。
/// </summary> /// </summary>

View File

@@ -1319,7 +1319,7 @@
<value>Previous proxy remarks</value> <value>Previous proxy remarks</value>
</data> </data>
<data name="TbLocalAddress" xml:space="preserve"> <data name="TbLocalAddress" xml:space="preserve">
<value>آدرس (IP, IPv6)</value> <value>آدرس (IPv4, IPv6)</value>
</data> </data>
<data name="TbReserved" xml:space="preserve"> <data name="TbReserved" xml:space="preserve">
<value>Reserved(2,3,4)</value> <value>Reserved(2,3,4)</value>
@@ -1396,4 +1396,10 @@
<data name="RemoveInvalidServerResultTip" xml:space="preserve"> <data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>Removed {0} invalid test results.</value> <value>Removed {0} invalid test results.</value>
</data> </data>
<data name="TbPorts7" xml:space="preserve">
<value>Server port range</value>
</data>
<data name="TbPorts7Tips" xml:space="preserve">
<value>Will cover the port, separate with commas (,)</value>
</data>
</root> </root>

View File

@@ -1100,7 +1100,7 @@
<value>Fenntartva (2,3,4)</value> <value>Fenntartva (2,3,4)</value>
</data> </data>
<data name="TbLocalAddress" xml:space="preserve"> <data name="TbLocalAddress" xml:space="preserve">
<value>Cím (Ip,Ipv6)</value> <value>Cím (Ipv4,Ipv6)</value>
</data> </data>
<data name="TbPath7" xml:space="preserve"> <data name="TbPath7" xml:space="preserve">
<value>obfs jelszó</value> <value>obfs jelszó</value>
@@ -1396,4 +1396,10 @@
<data name="RemoveInvalidServerResultTip" xml:space="preserve"> <data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>Removed {0} invalid test results.</value> <value>Removed {0} invalid test results.</value>
</data> </data>
<data name="TbPorts7" xml:space="preserve">
<value>Server port range</value>
</data>
<data name="TbPorts7Tips" xml:space="preserve">
<value>Will cover the port, separate with commas (,)</value>
</data>
</root> </root>

View File

@@ -1100,7 +1100,7 @@
<value>Reserved(2,3,4)</value> <value>Reserved(2,3,4)</value>
</data> </data>
<data name="TbLocalAddress" xml:space="preserve"> <data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value> <value>Address(Ipv4,Ipv6)</value>
</data> </data>
<data name="TbPath7" xml:space="preserve"> <data name="TbPath7" xml:space="preserve">
<value>obfs password</value> <value>obfs password</value>
@@ -1396,4 +1396,10 @@
<data name="RemoveInvalidServerResultTip" xml:space="preserve"> <data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>Removed {0} invalid test results.</value> <value>Removed {0} invalid test results.</value>
</data> </data>
<data name="TbPorts7" xml:space="preserve">
<value>Server port range</value>
</data>
<data name="TbPorts7Tips" xml:space="preserve">
<value>Will cover the port, separate with commas (,)</value>
</data>
</root> </root>

View File

@@ -1052,7 +1052,7 @@
<value>obfs password</value> <value>obfs password</value>
</data> </data>
<data name="TbLocalAddress" xml:space="preserve"> <data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value> <value>Address(Ipv4,Ipv6)</value>
</data> </data>
<data name="TbSettingsDomainStrategy4Out" xml:space="preserve"> <data name="TbSettingsDomainStrategy4Out" xml:space="preserve">
<value>Default domain strategy for outbound</value> <value>Default domain strategy for outbound</value>
@@ -1396,4 +1396,10 @@
<data name="RemoveInvalidServerResultTip" xml:space="preserve"> <data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>Removed {0} invalid test results.</value> <value>Removed {0} invalid test results.</value>
</data> </data>
<data name="TbPorts7" xml:space="preserve">
<value>Server port range</value>
</data>
<data name="TbPorts7Tips" xml:space="preserve">
<value>Will cover the port, separate with commas (,)</value>
</data>
</root> </root>

View File

@@ -1097,7 +1097,7 @@
<value>Reserved(2,3,4)</value> <value>Reserved(2,3,4)</value>
</data> </data>
<data name="TbLocalAddress" xml:space="preserve"> <data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value> <value>Address(Ipv4,Ipv6)</value>
</data> </data>
<data name="TbPath7" xml:space="preserve"> <data name="TbPath7" xml:space="preserve">
<value>混淆密码(obfs password)</value> <value>混淆密码(obfs password)</value>
@@ -1393,4 +1393,10 @@
<data name="RemoveInvalidServerResultTip" xml:space="preserve"> <data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>移除无效测试结果 {0} 个。</value> <value>移除无效测试结果 {0} 个。</value>
</data> </data>
<data name="TbPorts7" xml:space="preserve">
<value>跳跃端口范围</value>
</data>
<data name="TbPorts7Tips" xml:space="preserve">
<value>会覆盖端口,多组时用逗号(,)隔开</value>
</data>
</root> </root>

View File

@@ -1326,7 +1326,7 @@
<value>Reserved(2,3,4)</value> <value>Reserved(2,3,4)</value>
</data> </data>
<data name="TbLocalAddress" xml:space="preserve"> <data name="TbLocalAddress" xml:space="preserve">
<value>Address(Ip,Ipv6)</value> <value>Address(Ipv4,Ipv6)</value>
</data> </data>
<data name="TbSettingsUseSystemHosts" xml:space="preserve"> <data name="TbSettingsUseSystemHosts" xml:space="preserve">
<value>使用系統hosts</value> <value>使用系統hosts</value>
@@ -1394,4 +1394,10 @@
<data name="RemoveInvalidServerResultTip" xml:space="preserve"> <data name="RemoveInvalidServerResultTip" xml:space="preserve">
<value>移除無效測試結果 {0} 個。</value> <value>移除無效測試結果 {0} 個。</value>
</data> </data>
<data name="TbPorts7" xml:space="preserve">
<value>跳躍端口範圍</value>
</data>
<data name="TbPorts7Tips" xml:space="preserve">
<value>會覆蓋端口,多組時用逗號(,)隔開</value>
</data>
</root> </root>

View File

@@ -730,6 +730,16 @@ namespace ServiceLib.Services.CoreConfig
outbound.up_mbps = _config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null; outbound.up_mbps = _config.HysteriaItem.UpMbps > 0 ? _config.HysteriaItem.UpMbps : null;
outbound.down_mbps = _config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null; outbound.down_mbps = _config.HysteriaItem.DownMbps > 0 ? _config.HysteriaItem.DownMbps : null;
if (node.Ports.IsNotEmpty())
{
outbound.server_port = null;
outbound.server_ports = node.Ports.Split(',')
.Where(p => p.Trim().IsNotEmpty())
.Select(p => p.Replace('-', ':'))
.ToList();
outbound.hop_interval = _config.HysteriaItem.HopInterval > 0 ? $"{_config.HysteriaItem.HopInterval}s" : null;
}
break; break;
} }
case EConfigType.TUIC: case EConfigType.TUIC:

View File

@@ -915,7 +915,8 @@ namespace ServiceLib.Services.CoreConfig
kcpSettings.writeBufferSize = _config.KcpItem.WriteBufferSize; kcpSettings.writeBufferSize = _config.KcpItem.WriteBufferSize;
kcpSettings.header = new Header4Ray kcpSettings.header = new Header4Ray
{ {
type = node.HeaderType type = node.HeaderType,
domain = host.IsNullOrEmpty() ? null : host
}; };
if (Utils.IsNotEmpty(path)) if (Utils.IsNotEmpty(path))
{ {

View File

@@ -25,8 +25,6 @@ namespace ServiceLib.Services
await RunAsync(actionType, selecteds); await RunAsync(actionType, selecteds);
await ProfileExHandler.Instance.SaveTo(); await ProfileExHandler.Instance.SaveTo();
UpdateFunc("", ResUI.SpeedtestingCompleted); UpdateFunc("", ResUI.SpeedtestingCompleted);
FileManager.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
}); });
} }

View File

@@ -53,26 +53,31 @@ namespace ServiceLib.ViewModels
private async Task Init() private async Task Init()
{ {
var lastTime = DateTime.Now; Task.Run(async () =>
{
var numOfExecuted = 1;
while (true)
{
await Task.Delay(1000 * 5);
numOfExecuted++;
if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box)))
{
continue;
}
if (_config.ClashUIItem.ConnectionsRefreshInterval <= 0)
{
continue;
}
if (numOfExecuted % _config.ClashUIItem.ConnectionsRefreshInterval != 0)
{
continue;
}
await GetClashConnections();
}
});
Observable.Interval(TimeSpan.FromSeconds(5))
.Subscribe(async x =>
{
if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box)))
{
return;
}
var dtNow = DateTime.Now;
if (_config.ClashUIItem.ConnectionsRefreshInterval > 0)
{
if ((dtNow - lastTime).Minutes % _config.ClashUIItem.ConnectionsRefreshInterval == 0)
{
await GetClashConnections();
lastTime = dtNow;
}
Task.Delay(1000).Wait();
}
});
await Task.CompletedTask; await Task.CompletedTask;
} }

View File

@@ -95,8 +95,8 @@ namespace ServiceLib.ViewModels
private async Task Init() private async Task Init()
{ {
await ProxiesReload();
_ = DelayTestTask(); _ = DelayTestTask();
await ProxiesReload();
} }
private async Task DoRulemodeSelected(bool c) private async Task DoRulemodeSelected(bool c)
@@ -383,8 +383,6 @@ namespace ServiceLib.ViewModels
private async Task ProxiesDelayTest(bool blAll) private async Task ProxiesDelayTest(bool blAll)
{ {
//UpdateHandler(false, "Clash Proxies Latency Test");
ClashApiHandler.Instance.ClashProxiesDelayTest(blAll, _proxyDetails.ToList(), async (item, result) => ClashApiHandler.Instance.ClashProxiesDelayTest(blAll, _proxyDetails.ToList(), async (item, result) =>
{ {
if (item == null) if (item == null)
@@ -434,13 +432,13 @@ namespace ServiceLib.ViewModels
public async Task DelayTestTask() public async Task DelayTestTask()
{ {
var lastTime = DateTime.Now; Task.Run(async () =>
_ = Task.Run(async () =>
{ {
var numOfExecuted = 1;
while (true) while (true)
{ {
await Task.Delay(1000 * 60); await Task.Delay(1000 * 60);
numOfExecuted++;
if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box))) if (!(AutoRefresh && _config.UiItem.ShowInTaskbar && _config.IsRunningCore(ECoreType.sing_box)))
{ {
continue; continue;
@@ -449,13 +447,11 @@ namespace ServiceLib.ViewModels
{ {
continue; continue;
} }
var dtNow = DateTime.Now; if (numOfExecuted % _config.ClashUIItem.ProxiesAutoDelayTestInterval != 0)
if ((dtNow - lastTime).Minutes % _config.ClashUIItem.ProxiesAutoDelayTestInterval != 0)
{ {
continue; continue;
} }
await ProxiesDelayTest(); await ProxiesDelayTest();
lastTime = dtNow;
} }
}); });
await Task.CompletedTask; await Task.CompletedTask;

View File

@@ -49,7 +49,7 @@ namespace v2rayN.Desktop.Handler
} }
var vKey = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode); var vKey = KeyInterop.VirtualKeyFromKey((Key)item.KeyCode);
var modifiers = Modifiers.NoRepeat; var modifiers = Modifiers.None;
if (item.Control) if (item.Control)
{ {
modifiers |= Modifiers.Control; modifiers |= Modifiers.Control;

View File

@@ -308,7 +308,7 @@
<Grid <Grid
x:Name="gridHysteria2" x:Name="gridHysteria2"
Grid.Row="2" Grid.Row="2"
ColumnDefinitions="180,Auto" ColumnDefinitions="180,Auto,Auto"
IsVisible="False" IsVisible="False"
RowDefinitions="Auto,Auto,Auto,Auto"> RowDefinitions="Auto,Auto,Auto,Auto">
@@ -337,6 +337,26 @@
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource Margin4}" /> Margin="{StaticResource Margin4}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbPorts7}" />
<TextBox
x:Name="txtPorts7"
Grid.Row="3"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
Watermark="1000:2000,3000:4000" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Text="{x:Static resx:ResUI.TbPorts7Tips}" />
</Grid> </Grid>
<Grid <Grid
x:Name="gridTuic" x:Name="gridTuic"
@@ -429,7 +449,8 @@
Grid.Row="3" Grid.Row="3"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource Margin4}" /> Margin="{StaticResource Margin4}"
Watermark="2,3,4" />
<TextBlock <TextBlock
Grid.Row="4" Grid.Row="4"
@@ -442,7 +463,8 @@
Grid.Row="4" Grid.Row="4"
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource Margin4}" /> Margin="{StaticResource Margin4}"
Watermark="Ipv4,Ipv6" />
<TextBlock <TextBlock
Grid.Row="5" Grid.Row="5"
@@ -456,7 +478,8 @@
Grid.Column="1" Grid.Column="1"
Width="200" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" /> HorizontalAlignment="Left"
Watermark="1500" />
</Grid> </Grid>
<Separator <Separator

View File

@@ -178,6 +178,7 @@ namespace v2rayN.Desktop.Views
case EConfigType.Hysteria2: case EConfigType.Hysteria2:
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Ports, v => v.txtPorts7.Text).DisposeWith(disposables);
break; break;
case EConfigType.TUIC: case EConfigType.TUIC:

View File

@@ -17,10 +17,11 @@
x:Name="txtContent" x:Name="txtContent"
Grid.Row="1" Grid.Row="1"
Width="300" Width="300"
MaxHeight="100"
Margin="{StaticResource MarginTb8}" Margin="{StaticResource MarginTb8}"
VerticalAlignment="Center" VerticalAlignment="Center"
IsReadOnly="True" IsReadOnly="True"
MaxLines="1" /> TextWrapping="WrapWithOverflow" />
</Grid> </Grid>
</UserControl> </UserControl>

View File

@@ -1,5 +1,6 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Threading;
namespace v2rayN.Desktop.Views namespace v2rayN.Desktop.Views
{ {
@@ -17,7 +18,7 @@ namespace v2rayN.Desktop.Views
txtContent.Text = url; txtContent.Text = url;
imgQrcode.Source = GetQRCode(url); imgQrcode.Source = GetQRCode(url);
// btnCancel.Click += (s, e) => this.Close(); txtContent.GotFocus += (_, _) => Dispatcher.UIThread.Post(() => { txtContent.SelectAll(); });
} }
private Bitmap? GetQRCode(string? url) private Bitmap? GetQRCode(string? url)
@@ -29,7 +30,9 @@ namespace v2rayN.Desktop.Views
private Bitmap? ByteToBitmap(byte[]? bytes) private Bitmap? ByteToBitmap(byte[]? bytes)
{ {
if (bytes is null) if (bytes is null)
{
return null; return null;
}
using var ms = new MemoryStream(bytes); using var ms = new MemoryStream(bytes);
return new Bitmap(ms); return new Bitmap(ms);

View File

@@ -1,4 +1,4 @@
<reactiveui:ReactiveWindow <reactiveui:ReactiveWindow
x:Class="v2rayN.Views.AddServerWindow" x:Class="v2rayN.Views.AddServerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -432,6 +432,7 @@
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="180" /> <ColumnDefinition Width="180" />
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock <TextBlock
@@ -463,6 +464,30 @@
Width="400" Width="400"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="0"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPorts7}" />
<TextBox
x:Name="txtPorts7"
Grid.Row="3"
Grid.Column="1"
Width="400"
Margin="{StaticResource Margin4}"
HorizontalAlignment="Left"
materialDesign:HintAssist.Hint="1000:2000,3000:4000"
Style="{StaticResource DefTextBox}" />
<TextBlock
Grid.Row="3"
Grid.Column="2"
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Style="{StaticResource ToolbarTextBlock}"
Text="{x:Static resx:ResUI.TbPorts7Tips}" />
</Grid> </Grid>
<Grid <Grid
x:Name="gridTuic" x:Name="gridTuic"
@@ -585,6 +610,7 @@
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
materialDesign:HintAssist.Hint="2,3,4"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
@@ -600,6 +626,7 @@
Grid.Column="1" Grid.Column="1"
Width="400" Width="400"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
materialDesign:HintAssist.Hint="Ipv4,Ipv6"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
<TextBlock <TextBlock
@@ -616,6 +643,7 @@
Width="200" Width="200"
Margin="{StaticResource Margin4}" Margin="{StaticResource Margin4}"
HorizontalAlignment="Left" HorizontalAlignment="Left"
materialDesign:HintAssist.Hint="1500"
Style="{StaticResource DefTextBox}" /> Style="{StaticResource DefTextBox}" />
</Grid> </Grid>

View File

@@ -172,6 +172,7 @@ namespace v2rayN.Views
case EConfigType.Hysteria2: case EConfigType.Hysteria2:
this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Id, v => v.txtId7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSource.Path, v => v.txtPath7.Text).DisposeWith(disposables);
this.Bind(ViewModel, vm => vm.SelectedSource.Ports, v => v.txtPorts7.Text).DisposeWith(disposables);
break; break;
case EConfigType.TUIC: case EConfigType.TUIC: