diff --git a/v2rayN/ServiceLib/Common/FileManager.cs b/v2rayN/ServiceLib/Common/FileUtils.cs similarity index 99% rename from v2rayN/ServiceLib/Common/FileManager.cs rename to v2rayN/ServiceLib/Common/FileUtils.cs index 44a9fe82..2f86b60a 100644 --- a/v2rayN/ServiceLib/Common/FileManager.cs +++ b/v2rayN/ServiceLib/Common/FileUtils.cs @@ -3,7 +3,7 @@ using System.IO.Compression; namespace ServiceLib.Common; -public static class FileManager +public static class FileUtils { private static readonly string _tag = "FileManager"; diff --git a/v2rayN/ServiceLib/Common/WindowsJob.cs b/v2rayN/ServiceLib/Common/WindowsJob.cs deleted file mode 100644 index dacf8586..00000000 --- a/v2rayN/ServiceLib/Common/WindowsJob.cs +++ /dev/null @@ -1,177 +0,0 @@ -namespace ServiceLib.Common; - /* - * See: - * http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net - */ - - public sealed class WindowsJob : IDisposable - { - private IntPtr handle = IntPtr.Zero; - - public WindowsJob() - { - handle = CreateJobObject(IntPtr.Zero, null); - var extendedInfoPtr = IntPtr.Zero; - var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION - { - LimitFlags = 0x2000 - }; - - var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION - { - BasicLimitInformation = info - }; - - try - { - var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); - extendedInfoPtr = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); - - if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, - (uint)length)) - { - throw new Exception(string.Format("Unable to set information. Error: {0}", - Marshal.GetLastWin32Error())); - } - } - finally - { - if (extendedInfoPtr != IntPtr.Zero) - { - Marshal.FreeHGlobal(extendedInfoPtr); - } - } - } - - public bool AddProcess(IntPtr processHandle) - { - var succ = AssignProcessToJobObject(handle, processHandle); - - if (!succ) - { - Logging.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); - } - - return succ; - } - - public bool AddProcess(int processId) - { - return AddProcess(Process.GetProcessById(processId).Handle); - } - - #region IDisposable - - private bool disposed; - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - private void Dispose(bool disposing) - { - if (disposed) - { - return; - } - disposed = true; - - if (disposing) - { - // no managed objects to free - } - - if (handle != IntPtr.Zero) - { - CloseHandle(handle); - handle = IntPtr.Zero; - } - } - - ~WindowsJob() - { - Dispose(false); - } - - #endregion IDisposable - - #region Interop - - [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] - private static extern IntPtr CreateJobObject(IntPtr a, string? lpName); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool SetInformationJobObject(IntPtr hJob, JobObjectInfoType infoType, IntPtr lpJobObjectInfo, uint cbJobObjectInfoLength); - - [DllImport("kernel32.dll", SetLastError = true)] - private static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process); - - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool CloseHandle(IntPtr hObject); - - #endregion Interop - } - - #region Helper classes - - [StructLayout(LayoutKind.Sequential)] - internal struct IO_COUNTERS - { - public ulong ReadOperationCount; - public ulong WriteOperationCount; - public ulong OtherOperationCount; - public ulong ReadTransferCount; - public ulong WriteTransferCount; - public ulong OtherTransferCount; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION - { - public long PerProcessUserTimeLimit; - public long PerJobUserTimeLimit; - public uint LimitFlags; - public UIntPtr MinimumWorkingSetSize; - public UIntPtr MaximumWorkingSetSize; - public uint ActiveProcessLimit; - public UIntPtr Affinity; - public uint PriorityClass; - public uint SchedulingClass; - } - - [StructLayout(LayoutKind.Sequential)] - public struct SECURITY_ATTRIBUTES - { - public uint nLength; - public IntPtr lpSecurityDescriptor; - public int bInheritHandle; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION - { - public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; - public IO_COUNTERS IoInfo; - public UIntPtr ProcessMemoryLimit; - public UIntPtr JobMemoryLimit; - public UIntPtr PeakProcessMemoryUsed; - public UIntPtr PeakJobMemoryUsed; - } - - public enum JobObjectInfoType - { - AssociateCompletionPortInformation = 7, - BasicLimitInformation = 2, - BasicUIRestrictions = 4, - EndOfJobTimeInformation = 6, - ExtendedLimitInformation = 9, - SecurityLimitInformation = 5, - GroupInformation = 11 - } - - #endregion Helper classes - diff --git a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs index 828c2102..9cac0018 100644 --- a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs +++ b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingLinux.cs @@ -18,7 +18,7 @@ public static class ProxySettingLinux private static async Task ExecCmd(List args) { - var fileName = await FileManager.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName), false); + var fileName = await FileUtils.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName), false); await Utils.GetCliWrapOutput(fileName, args); } diff --git a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs index 85d9b821..88baa5a6 100644 --- a/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs +++ b/v2rayN/ServiceLib/Handler/SysProxy/ProxySettingOSX.cs @@ -23,7 +23,7 @@ public static class ProxySettingOSX private static async Task ExecCmd(List args) { - var fileName = await FileManager.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName), false); + var fileName = await FileUtils.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName), false); await Utils.GetCliWrapOutput(fileName, args); } diff --git a/v2rayN/ServiceLib/Manager/CoreAdminManager.cs b/v2rayN/ServiceLib/Manager/CoreAdminManager.cs index dbd19d38..6c54e1e1 100644 --- a/v2rayN/ServiceLib/Manager/CoreAdminManager.cs +++ b/v2rayN/ServiceLib/Manager/CoreAdminManager.cs @@ -35,7 +35,7 @@ public class CoreAdminManager sb.AppendLine("#!/bin/bash"); var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}"; sb.AppendLine($"exec sudo -S -- {cmdLine}"); - var shFilePath = await FileManager.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true); + var shFilePath = await FileUtils.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true); var procService = new ProcessService( fileName: shFilePath, @@ -68,7 +68,7 @@ public class CoreAdminManager try { var shellFileName = Utils.IsOSX() ? Global.KillAsSudoOSXShellFileName : Global.KillAsSudoLinuxShellFileName; - var shFilePath = await FileManager.CreateLinuxShellFile("kill_as_sudo.sh", EmbedUtils.GetEmbedText(shellFileName), true); + var shFilePath = await FileUtils.CreateLinuxShellFile("kill_as_sudo.sh", EmbedUtils.GetEmbedText(shellFileName), true); if (shFilePath.Contains(' ')) { shFilePath = shFilePath.AppendQuotes(); diff --git a/v2rayN/ServiceLib/Manager/CoreManager.cs b/v2rayN/ServiceLib/Manager/CoreManager.cs index bd01fe5b..8dbff9e2 100644 --- a/v2rayN/ServiceLib/Manager/CoreManager.cs +++ b/v2rayN/ServiceLib/Manager/CoreManager.cs @@ -8,7 +8,7 @@ public class CoreManager private static readonly Lazy _instance = new(() => new()); public static CoreManager Instance => _instance.Value; private Config _config; - private WindowsJob? _processJob; + private WindowsJobService? _processJob; private ProcessService? _processService; private ProcessService? _processPreService; private bool _linuxSudo = false; @@ -27,7 +27,7 @@ public class CoreManager var toPath = Utils.GetBinPath(""); if (fromPath != toPath) { - FileManager.CopyDirectory(fromPath, toPath, true, false); + FileUtils.CopyDirectory(fromPath, toPath, true, false); } } diff --git a/v2rayN/ServiceLib/Manager/TaskManager.cs b/v2rayN/ServiceLib/Manager/TaskManager.cs index 862afe44..d1c73157 100644 --- a/v2rayN/ServiceLib/Manager/TaskManager.cs +++ b/v2rayN/ServiceLib/Manager/TaskManager.cs @@ -56,9 +56,9 @@ public class TaskManager { //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)); + FileUtils.DeleteExpiredFiles(Utils.GetBinConfigPath(), DateTime.Now.AddHours(-1)); + FileUtils.DeleteExpiredFiles(Utils.GetLogPath(), DateTime.Now.AddMonths(-1)); + FileUtils.DeleteExpiredFiles(Utils.GetTempPath(), DateTime.Now.AddMonths(-1)); try { diff --git a/v2rayN/ServiceLib/Common/SemanticVersion.cs b/v2rayN/ServiceLib/Models/SemanticVersion.cs similarity index 99% rename from v2rayN/ServiceLib/Common/SemanticVersion.cs rename to v2rayN/ServiceLib/Models/SemanticVersion.cs index 64167084..78463434 100644 --- a/v2rayN/ServiceLib/Common/SemanticVersion.cs +++ b/v2rayN/ServiceLib/Models/SemanticVersion.cs @@ -1,4 +1,4 @@ -namespace ServiceLib.Common; +namespace ServiceLib.Models; public class SemanticVersion { diff --git a/v2rayN/ServiceLib/Services/WindowsJobService.cs b/v2rayN/ServiceLib/Services/WindowsJobService.cs new file mode 100644 index 00000000..ffd4a36a --- /dev/null +++ b/v2rayN/ServiceLib/Services/WindowsJobService.cs @@ -0,0 +1,171 @@ +namespace ServiceLib.Services; + +/// +/// http://stackoverflow.com/questions/6266820/working-example-of-createjobobject-setinformationjobobject-pinvoke-in-net +/// +public sealed class WindowsJobService : IDisposable +{ + private nint handle = nint.Zero; + + public WindowsJobService() + { + handle = CreateJobObject(nint.Zero, null); + var extendedInfoPtr = nint.Zero; + var info = new JOBOBJECT_BASIC_LIMIT_INFORMATION + { + LimitFlags = 0x2000 + }; + + var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION + { + BasicLimitInformation = info + }; + + try + { + var length = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION)); + extendedInfoPtr = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false); + + if (!SetInformationJobObject(handle, JobObjectInfoType.ExtendedLimitInformation, extendedInfoPtr, + (uint)length)) + { + throw new Exception(string.Format("Unable to set information. Error: {0}", + Marshal.GetLastWin32Error())); + } + } + finally + { + if (extendedInfoPtr != nint.Zero) + { + Marshal.FreeHGlobal(extendedInfoPtr); + } + } + } + + public bool AddProcess(nint processHandle) + { + var succ = AssignProcessToJobObject(handle, processHandle); + + if (!succ) + { + Logging.SaveLog("Failed to call AssignProcessToJobObject! GetLastError=" + Marshal.GetLastWin32Error()); + } + + return succ; + } + + public bool AddProcess(int processId) + { + return AddProcess(Process.GetProcessById(processId).Handle); + } + + #region IDisposable + + private bool disposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (disposed) + { + return; + } + disposed = true; + + if (disposing) + { + // no managed objects to free + } + + if (handle != nint.Zero) + { + CloseHandle(handle); + handle = nint.Zero; + } + } + + ~WindowsJobService() + { + Dispose(false); + } + + #endregion IDisposable + + #region Interop + + [DllImport("kernel32.dll", CharSet = CharSet.Unicode)] + private static extern nint CreateJobObject(nint a, string? lpName); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool SetInformationJobObject(nint hJob, JobObjectInfoType infoType, nint lpJobObjectInfo, uint cbJobObjectInfoLength); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool AssignProcessToJobObject(nint job, nint process); + + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool CloseHandle(nint hObject); + + #endregion Interop +} + +[StructLayout(LayoutKind.Sequential)] +internal struct IO_COUNTERS +{ + public ulong ReadOperationCount; + public ulong WriteOperationCount; + public ulong OtherOperationCount; + public ulong ReadTransferCount; + public ulong WriteTransferCount; + public ulong OtherTransferCount; +} + +[StructLayout(LayoutKind.Sequential)] +internal struct JOBOBJECT_BASIC_LIMIT_INFORMATION +{ + public long PerProcessUserTimeLimit; + public long PerJobUserTimeLimit; + public uint LimitFlags; + public nuint MinimumWorkingSetSize; + public nuint MaximumWorkingSetSize; + public uint ActiveProcessLimit; + public nuint Affinity; + public uint PriorityClass; + public uint SchedulingClass; +} + +[StructLayout(LayoutKind.Sequential)] +public struct SECURITY_ATTRIBUTES +{ + public uint nLength; + public nint lpSecurityDescriptor; + public int bInheritHandle; +} + +[StructLayout(LayoutKind.Sequential)] +internal struct JOBOBJECT_EXTENDED_LIMIT_INFORMATION +{ + public JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation; + public IO_COUNTERS IoInfo; + public nuint ProcessMemoryLimit; + public nuint JobMemoryLimit; + public nuint PeakProcessMemoryUsed; + public nuint PeakJobMemoryUsed; +} + +public enum JobObjectInfoType +{ + AssociateCompletionPortInformation = 7, + BasicLimitInformation = 2, + BasicUIRestrictions = 4, + EndOfJobTimeInformation = 6, + ExtendedLimitInformation = 9, + SecurityLimitInformation = 5, + GroupInformation = 11 +} diff --git a/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs b/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs index c0eae75f..dbe3b24d 100644 --- a/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/BackupAndRestoreViewModel.cs @@ -119,7 +119,7 @@ public class BackupAndRestoreViewModel : MyReactiveObject return; } //check - var lstFiles = FileManager.GetFilesFromZip(fileName); + var lstFiles = FileUtils.GetFilesFromZip(fileName); if (lstFiles is null || !lstFiles.Any(t => t.Contains(_guiConfigs))) { DisplayOperationMsg(ResUI.LocalRestoreInvalidZipTips); @@ -135,7 +135,7 @@ public class BackupAndRestoreViewModel : MyReactiveObject await SQLiteHelper.Instance.DisposeDbConnectionAsync(); var toPath = Utils.GetConfigPath(); - FileManager.ZipExtractToFile(fileName, toPath, ""); + FileUtils.ZipExtractToFile(fileName, toPath, ""); if (Utils.IsWindows()) { @@ -167,8 +167,8 @@ public class BackupAndRestoreViewModel : MyReactiveObject var configDirZipTemp = Utils.GetTempPath($"v2rayN_{DateTime.Now:yyyyMMddHHmmss}"); var configDirTemp = Path.Combine(configDirZipTemp, _guiConfigs); - FileManager.CopyDirectory(configDir, configDirTemp, false, true, ""); - var ret = FileManager.CreateFromDirectory(configDirZipTemp, fileName); + FileUtils.CopyDirectory(configDir, configDirTemp, false, true, ""); + var ret = FileUtils.CreateFromDirectory(configDirZipTemp, fileName); Directory.Delete(configDirZipTemp, true); return await Task.FromResult(ret); } diff --git a/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs b/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs index d5a1b0c6..7bcb36ea 100644 --- a/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs +++ b/v2rayN/ServiceLib/ViewModels/CheckUpdateViewModel.cs @@ -271,24 +271,24 @@ public class CheckUpdateViewModel : MyReactiveObject if (fileName.Contains(".tar.gz")) { - FileManager.DecompressTarFile(fileName, toPath); + FileUtils.DecompressTarFile(fileName, toPath); var dir = new DirectoryInfo(toPath); if (dir.Exists) { foreach (var subDir in dir.GetDirectories()) { - FileManager.CopyDirectory(subDir.FullName, toPath, false, true); + FileUtils.CopyDirectory(subDir.FullName, toPath, false, true); subDir.Delete(true); } } } else if (fileName.Contains(".gz")) { - FileManager.DecompressFile(fileName, toPath, item.CoreType); + FileUtils.DecompressFile(fileName, toPath, item.CoreType); } else { - FileManager.ZipExtractToFile(fileName, toPath, "geo"); + FileUtils.ZipExtractToFile(fileName, toPath, "geo"); } if (Utils.IsNonWindows())