mirror of
https://github.com/2dust/v2rayN.git
synced 2026-07-26 18:02:05 +03:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da81101cfd | ||
|
|
3d4f202cd7 | ||
|
|
35fbb137e8 | ||
|
|
1869a95700 | ||
|
|
34359885ab | ||
|
|
93832656dd | ||
|
|
b1a400b393 | ||
|
|
879c736924 | ||
|
|
8147b39723 | ||
|
|
5fed566a32 |
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
|
||||
<PropertyGroup>
|
||||
<Version>7.22.6</Version>
|
||||
<Version>7.22.7</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -118,4 +118,20 @@ public static class Extension
|
||||
destination.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replace all cross-platform newline characters with the specified string
|
||||
/// </summary>
|
||||
public static string ReplaceLineBreaks(this string input, string replacement)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input))
|
||||
{
|
||||
return input;
|
||||
}
|
||||
|
||||
// You must replace \r\n first, and then replace the single characters \r and \n.
|
||||
return input.Replace("\r\n", replacement)
|
||||
.Replace("\r", replacement)
|
||||
.Replace("\n", replacement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@ public static class FileUtils
|
||||
}
|
||||
}
|
||||
|
||||
public static void DeleteExpiredFiles(string sourceDir, DateTime dtLine)
|
||||
public static void DeleteExpiredFiles(string sourceDir, DateTime dtLine, string? contains = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -214,6 +214,10 @@ public static class FileUtils
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (contains.IsNotEmpty() && !file.Name.Contains(contains))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
file.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class Utils
|
||||
|
||||
try
|
||||
{
|
||||
str = str.Replace(Environment.NewLine, string.Empty);
|
||||
str = str.ReplaceLineBreaks(string.Empty);
|
||||
return new List<string>(str.Split(',', StringSplitOptions.RemoveEmptyEntries));
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -114,9 +114,7 @@ public class Utils
|
||||
}
|
||||
|
||||
plainText = plainText.Trim()
|
||||
.Replace(Environment.NewLine, "")
|
||||
.Replace("\n", "")
|
||||
.Replace("\r", "")
|
||||
.ReplaceLineBreaks("")
|
||||
.Replace('_', '/')
|
||||
.Replace('-', '+')
|
||||
.Replace(" ", "");
|
||||
@@ -321,7 +319,9 @@ public class Utils
|
||||
return text;
|
||||
}
|
||||
|
||||
return text.Replace(",", ",").Replace(Environment.NewLine, ",");
|
||||
return text.Replace(",", ",")
|
||||
.Replace(" ", "")
|
||||
.ReplaceLineBreaks(",");
|
||||
}
|
||||
|
||||
public static List<string> GetEnumNames<TEnum>() where TEnum : Enum
|
||||
|
||||
@@ -66,7 +66,9 @@ public class VmessFmt : BaseFmt
|
||||
sni = item.Sni,
|
||||
alpn = item.Alpn,
|
||||
fp = item.Fingerprint,
|
||||
insecure = item.GetAllowInsecure() ? "1" : "0"
|
||||
insecure = item.GetAllowInsecure() ? "1" : "0",
|
||||
vcn = item.VerifyPeerCertByName,
|
||||
pcs = item.CertSha
|
||||
};
|
||||
|
||||
var url = JsonUtils.Serialize(vmessQRCode);
|
||||
@@ -141,6 +143,8 @@ public class VmessFmt : BaseFmt
|
||||
item.Alpn = Utils.ToString(vmessQRCode.alpn);
|
||||
item.Fingerprint = Utils.ToString(vmessQRCode.fp);
|
||||
item.AllowInsecure = vmessQRCode.insecure == "1" ? Global.StringTrue : string.Empty;
|
||||
item.VerifyPeerCertByName = Utils.ToString(vmessQRCode.vcn);
|
||||
item.CertSha = Utils.ToString(vmessQRCode.pcs);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class TaskManager
|
||||
{
|
||||
//Logging.SaveLog("Execute delete expired files");
|
||||
|
||||
FileUtils.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1));
|
||||
FileUtils.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1), "Test");
|
||||
FileUtils.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1));
|
||||
FileUtils.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1));
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public class Stats4Ray
|
||||
|
||||
public class Metrics4Ray
|
||||
{
|
||||
public string tag { get; set; }
|
||||
public string listen { get; set; }
|
||||
}
|
||||
|
||||
public class Policy4Ray
|
||||
|
||||
@@ -40,4 +40,8 @@ public class VmessQRCode
|
||||
public string fp { get; set; } = string.Empty;
|
||||
|
||||
public string insecure { get; set; } = string.Empty;
|
||||
|
||||
public string vcn { get; set; } = string.Empty;
|
||||
|
||||
public string pcs { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
@@ -17,14 +17,6 @@
|
||||
],
|
||||
"routing": {
|
||||
"domainStrategy": "IPIfNonMatch",
|
||||
"rules": [
|
||||
{
|
||||
"inboundTag": [
|
||||
"api"
|
||||
],
|
||||
"outboundTag": "api",
|
||||
"type": "field"
|
||||
}
|
||||
]
|
||||
"rules": []
|
||||
}
|
||||
}
|
||||
@@ -6,45 +6,19 @@ public partial class CoreConfigV2rayService
|
||||
{
|
||||
if (_config.GuiItem.EnableStatistics || _config.GuiItem.DisplayRealTimeSpeed)
|
||||
{
|
||||
const string tag = nameof(EInboundProtocol.api);
|
||||
Metrics4Ray apiObj = new();
|
||||
Metrics4Ray metricsObj = new();
|
||||
Policy4Ray policyObj = new();
|
||||
SystemPolicy4Ray policySystemSetting = new();
|
||||
|
||||
_coreConfig.stats = new Stats4Ray();
|
||||
|
||||
apiObj.tag = tag;
|
||||
_coreConfig.metrics = apiObj;
|
||||
metricsObj.listen = $"{Global.Loopback}:{AppManager.Instance.StatePort}";
|
||||
_coreConfig.metrics = metricsObj;
|
||||
|
||||
policySystemSetting.statsOutboundDownlink = true;
|
||||
policySystemSetting.statsOutboundUplink = true;
|
||||
policyObj.system = policySystemSetting;
|
||||
_coreConfig.policy = policyObj;
|
||||
|
||||
if (!_coreConfig.inbounds.Exists(item => item.tag == tag))
|
||||
{
|
||||
Inbounds4Ray apiInbound = new();
|
||||
Inboundsettings4Ray apiInboundSettings = new();
|
||||
apiInbound.tag = tag;
|
||||
apiInbound.listen = Global.Loopback;
|
||||
apiInbound.port = AppManager.Instance.StatePort;
|
||||
apiInbound.protocol = Global.InboundAPIProtocol;
|
||||
apiInboundSettings.address = Global.Loopback;
|
||||
apiInbound.settings = apiInboundSettings;
|
||||
_coreConfig.inbounds.Add(apiInbound);
|
||||
}
|
||||
|
||||
if (!_coreConfig.routing.rules.Exists(item => item.outboundTag == tag))
|
||||
{
|
||||
RulesItem4Ray apiRoutingRule = new()
|
||||
{
|
||||
inboundTag = new List<string> { tag },
|
||||
outboundTag = tag,
|
||||
type = "field"
|
||||
};
|
||||
|
||||
_coreConfig.routing.rules.Add(apiRoutingRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,8 @@ public partial class App : Application
|
||||
DataContext = StatusBarViewModel.Instance;
|
||||
}
|
||||
|
||||
desktop.Exit += OnExit;
|
||||
desktop.MainWindow = new MainWindow();
|
||||
var mainWindow = new MainWindow();
|
||||
desktop.MainWindow = mainWindow;
|
||||
|
||||
if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
@@ -35,6 +35,8 @@ public partial class App : Application
|
||||
base.OnFrameworkInitializationCompleted();
|
||||
}
|
||||
|
||||
#region MacOS Activation
|
||||
|
||||
private void OnMacOSActivated(object? sender, ActivatedEventArgs args)
|
||||
{
|
||||
if (args.Kind != ActivationKind.Reopen)
|
||||
@@ -42,17 +44,69 @@ public partial class App : Application
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow is not MainWindow mainWindow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var isMiniaturized = MacAppUtils.IsWindowMiniaturized(mainWindow);
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
if (isMiniaturized)
|
||||
{
|
||||
RestoreMacOSAccessoryPolicyAfterMiniaturize(mainWindow);
|
||||
mainWindow.ShowHideWindow(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AppManager.Instance.Config.UiItem.MacOSShowInDock)
|
||||
{
|
||||
MacAppUtils.SetActivationPolicyAccessory();
|
||||
}
|
||||
|
||||
((ApplicationLifetime as IClassicDesktopStyleApplicationLifetime)?.MainWindow as MainWindow)?.ShowHideWindow(true);
|
||||
|
||||
mainWindow.ShowHideWindow(true);
|
||||
});
|
||||
}
|
||||
|
||||
private static void RestoreMacOSAccessoryPolicyAfterMiniaturize(MainWindow mainWindow)
|
||||
{
|
||||
if (AppManager.Instance.Config.UiItem.MacOSShowInDock)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mainWindow
|
||||
.GetObservable(Window.WindowStateProperty)
|
||||
.Skip(1)
|
||||
.Where(state => state != WindowState.Minimized)
|
||||
.Take(1)
|
||||
.ObserveOn(RxSchedulers.MainThreadScheduler)
|
||||
.Subscribe(_ => QueueMacOSAccessoryPolicyRestore(mainWindow));
|
||||
}
|
||||
|
||||
private static void QueueMacOSAccessoryPolicyRestore(MainWindow mainWindow)
|
||||
{
|
||||
// AppKit may keep isMiniaturized set until the Dock restore animation finishes.
|
||||
DispatcherTimer.RunOnce(() => RestoreMacOSAccessoryPolicy(mainWindow), TimeSpan.FromMilliseconds(300));
|
||||
}
|
||||
|
||||
private static void RestoreMacOSAccessoryPolicy(MainWindow mainWindow)
|
||||
{
|
||||
if (AppManager.Instance.Config.UiItem.MacOSShowInDock || MacAppUtils.IsWindowMiniaturized(mainWindow))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MacAppUtils.SetActivationPolicyAccessory();
|
||||
mainWindow.Activate();
|
||||
mainWindow.Focus();
|
||||
}
|
||||
|
||||
#endregion MacOS Activation
|
||||
|
||||
#region App Event
|
||||
|
||||
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
if (e.ExceptionObject != null)
|
||||
@@ -66,10 +120,6 @@ public partial class App : Application
|
||||
Logging.SaveLog("TaskScheduler_UnobservedTaskException", e.Exception);
|
||||
}
|
||||
|
||||
private void OnExit(object? sender, ControlledApplicationLifetimeExitEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
private async void MenuAddServerViaClipboardClick(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
@@ -91,4 +141,6 @@ public partial class App : Application
|
||||
await AppManager.Instance.AppExitAsync(false);
|
||||
AppManager.Instance.Shutdown(true);
|
||||
}
|
||||
|
||||
#endregion App Event
|
||||
}
|
||||
|
||||
@@ -4,7 +4,15 @@ public class WindowBase<TViewModel> : ReactiveWindow<TViewModel> where TViewMode
|
||||
{
|
||||
public WindowBase()
|
||||
{
|
||||
Initialized += OnWindowInitialized;
|
||||
Loaded += OnLoaded;
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
if (Owner != null && !ShowInTaskbar)
|
||||
{
|
||||
CanMinimize = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void ReactiveWindowBase_Closed(object? sender, EventArgs e)
|
||||
@@ -12,30 +20,33 @@ public class WindowBase<TViewModel> : ReactiveWindow<TViewModel> where TViewMode
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected virtual void OnLoaded(object? sender, RoutedEventArgs e)
|
||||
private void OnWindowInitialized(object? sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var sizeItem = ConfigHandler.GetWindowSizeItem(AppManager.Instance.Config, GetType().Name);
|
||||
if (sizeItem == null)
|
||||
if (sizeItem is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Width = sizeItem.Width;
|
||||
Height = sizeItem.Height;
|
||||
if (sizeItem.Width > 0 && !Width.Equals(sizeItem.Width))
|
||||
{
|
||||
Width = sizeItem.Width;
|
||||
}
|
||||
|
||||
var workingArea = (Screens.ScreenFromWindow(this) ?? Screens.Primary).WorkingArea;
|
||||
var scaling = (Utils.IsMacOS() ? null : VisualRoot?.RenderScaling) ?? 1.0;
|
||||
|
||||
var x = workingArea.X + ((workingArea.Width - (Width * scaling)) / 2);
|
||||
var y = workingArea.Y + ((workingArea.Height - (Height * scaling)) / 2);
|
||||
|
||||
Position = new PixelPoint((int)x, (int)y);
|
||||
if (sizeItem.Height > 0 && !Height.Equals(sizeItem.Height))
|
||||
{
|
||||
Height = sizeItem.Height;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
protected virtual void OnLoaded(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
base.OnClosed(e);
|
||||
|
||||
@@ -18,18 +18,18 @@ public static class AppBuilderExtension
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
{
|
||||
AddFontFallback(fallbacks, "Segoe UI Symbol");
|
||||
AddFontFallback(fallbacks, "Segoe UI Emoji");
|
||||
AddFontFallback(fallbacks, "Segoe UI Symbol");
|
||||
}
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
{
|
||||
AddFontFallback(fallbacks, "Apple Symbols");
|
||||
AddFontFallback(fallbacks, "Apple Color Emoji");
|
||||
AddFontFallback(fallbacks, "Apple Symbols");
|
||||
}
|
||||
else if (OperatingSystem.IsLinux())
|
||||
{
|
||||
AddFontFallback(fallbacks, "Noto Sans Symbols");
|
||||
AddFontFallback(fallbacks, "Noto Color Emoji");
|
||||
AddFontFallback(fallbacks, "Noto Sans Symbols");
|
||||
}
|
||||
|
||||
return appBuilder.With(new FontManagerOptions
|
||||
|
||||
@@ -13,6 +13,10 @@ internal static class MacAppUtils
|
||||
sel_registerName("setActivationPolicy:"),
|
||||
ActivationPolicyAccessory);
|
||||
|
||||
public static bool IsWindowMiniaturized(Window window)
|
||||
=> window.TryGetPlatformHandle() is IMacOSTopLevelPlatformHandle { NSWindow: not 0 } handle
|
||||
&& objc_msgSend_bool(handle.NSWindow, sel_registerName("isMiniaturized"));
|
||||
|
||||
[DllImport(LibObjC)]
|
||||
private static extern nint objc_getClass(string name);
|
||||
|
||||
@@ -22,6 +26,10 @@ internal static class MacAppUtils
|
||||
[DllImport(LibObjC, EntryPoint = "objc_msgSend")]
|
||||
private static extern nint objc_msgSend(nint receiver, nint selector);
|
||||
|
||||
[DllImport(LibObjC, EntryPoint = "objc_msgSend")]
|
||||
[return: MarshalAs(UnmanagedType.I1)]
|
||||
private static extern bool objc_msgSend_bool(nint receiver, nint selector);
|
||||
|
||||
[DllImport(LibObjC, EntryPoint = "objc_msgSend")]
|
||||
private static extern void objc_msgSend(nint receiver, nint selector, nint argument);
|
||||
}
|
||||
|
||||
@@ -413,7 +413,7 @@ public partial class MainWindow : WindowBase<MainWindowViewModel>
|
||||
public void ShowHideWindow(bool? blShow)
|
||||
{
|
||||
var bl = blShow ??
|
||||
(Utils.IsLinux()
|
||||
(Utils.IsLinux() || Utils.IsMacOS()
|
||||
? (!AppManager.Instance.ShowInTaskbar ^ (WindowState == WindowState.Minimized))
|
||||
: !AppManager.Instance.ShowInTaskbar);
|
||||
if (bl)
|
||||
|
||||
@@ -18,6 +18,8 @@ public partial class MessageBoxDialog : Window
|
||||
|
||||
btnYes.Click += BtnYes_Click;
|
||||
btnNo.Click += BtnNo_Click;
|
||||
|
||||
CanMinimize = false;
|
||||
}
|
||||
|
||||
private void BtnYes_Click(object? sender, RoutedEventArgs e)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
|
||||
<AssemblyName>v2rayN</AssemblyName>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CETCompat>false</CETCompat>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<ApplicationHighDpiMode>PerMonitorV2</ApplicationHighDpiMode>
|
||||
<SupportedOSPlatformVersion>7.0</SupportedOSPlatformVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CETCompat>false</CETCompat>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user