namespace ServiceLib.Manager; public sealed class AppManager { #region Property private static readonly Lazy _instance = new(() => new()); private Config _config; private int? _statePort; private int? _statePort2; public static AppManager Instance => _instance.Value; public Config Config => _config; public int StatePort { get { _statePort ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api)); return _statePort.Value; } } public int StatePort2 { get { _statePort2 ??= Utils.GetFreePort(GetLocalPort(EInboundProtocol.api2)); return _statePort2.Value + (_config.TunModeItem.EnableTun ? 1 : 0); } } public string LinuxSudoPwd { get; set; } public bool ShowInTaskbar { get; set; } public ECoreType RunningCoreType { get; set; } public bool IsRunningCore(ECoreType type) { switch (type) { case ECoreType.Xray when RunningCoreType is ECoreType.Xray or ECoreType.v2fly or ECoreType.v2fly_v5: case ECoreType.sing_box when RunningCoreType is ECoreType.sing_box or ECoreType.mihomo: return true; default: return false; } } #endregion Property #region App public bool InitApp() { if (Utils.HasWritePermission() == false) { Environment.SetEnvironmentVariable(Global.LocalAppData, "1", EnvironmentVariableTarget.Process); } Logging.Setup(); var config = ConfigHandler.LoadConfig(); if (config == null) { return false; } _config = config; Thread.CurrentThread.CurrentUICulture = new(_config.UiItem.CurrentLanguage); //Under Win10 if (Utils.IsWindows() && Environment.OSVersion.Version.Major < 10) { Environment.SetEnvironmentVariable("DOTNET_EnableWriteXorExecute", "0", EnvironmentVariableTarget.User); } SQLiteHelper.Instance.CreateTable(); SQLiteHelper.Instance.CreateTable(); SQLiteHelper.Instance.CreateTable(); SQLiteHelper.Instance.CreateTable(); SQLiteHelper.Instance.CreateTable(); SQLiteHelper.Instance.CreateTable(); SQLiteHelper.Instance.CreateTable(); SQLiteHelper.Instance.CreateTable(); return true; } public bool InitComponents() { Logging.SaveLog($"v2rayN start up | {Utils.GetRuntimeInfo()}"); Logging.LoggingEnabled(_config.GuiItem.EnableLog); //First determine the port value _ = StatePort; _ = StatePort2; return true; } public bool Reset() { _statePort = null; _statePort2 = null; return true; } public async Task AppExitAsync(bool needShutdown) { try { Logging.SaveLog("AppExitAsync Begin"); await SysProxyHandler.UpdateSysProxy(_config, true); AppEvents.AppExitRequested.Publish(); await Task.Delay(50); //Wait for AppExitRequested to be processed await ConfigHandler.SaveConfig(_config); await ProfileExManager.Instance.SaveTo(); await StatisticsManager.Instance.SaveTo(); await CoreManager.Instance.CoreStop(); StatisticsManager.Instance.Close(); Logging.SaveLog("AppExitAsync End"); } catch { } finally { if (needShutdown) { Shutdown(false); } } } public void Shutdown(bool byUser) { AppEvents.ShutdownRequested.Publish(byUser); } public async Task RebootAsAdmin() { ProcUtils.RebootAsAdmin(); await AppManager.Instance.AppExitAsync(true); } #endregion App #region Config public int GetLocalPort(EInboundProtocol protocol) { var localPort = _config.Inbound.FirstOrDefault(t => t.Protocol == nameof(EInboundProtocol.socks))?.LocalPort ?? 10808; return localPort + (int)protocol; } #endregion Config #region SqliteHelper public async Task?> SubItems() { return await SQLiteHelper.Instance.TableAsync().OrderBy(t => t.Sort).ToListAsync(); } public async Task GetSubItem(string? subid) { return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(t => t.Id == subid); } public async Task?> ProfileItems(string subid) { if (subid.IsNullOrEmpty()) { return await SQLiteHelper.Instance.TableAsync().ToListAsync(); } else { return await SQLiteHelper.Instance.TableAsync().Where(t => t.Subid == subid).ToListAsync(); } } public async Task?> ProfileItemIndexes(string subid) { return (await ProfileItems(subid))?.Select(t => t.IndexId)?.ToList(); } public async Task?> ProfileItems(string subid, string filter) { var sql = @$"select a.* ,b.remarks subRemarks from ProfileItem a left join SubItem b on a.subid = b.id where 1=1 "; if (subid.IsNotEmpty()) { sql += $" and a.subid = '{subid}'"; } if (filter.IsNotEmpty()) { if (filter.Contains('\'')) { filter = filter.Replace("'", ""); } sql += string.Format(" and (a.remarks like '%{0}%' or a.address like '%{0}%') ", filter); } return await SQLiteHelper.Instance.QueryAsync(sql); } public async Task GetProfileItem(string indexId) { if (indexId.IsNullOrEmpty()) { return null; } return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.IndexId == indexId); } public async Task GetProfileItemViaRemarks(string? remarks) { if (remarks.IsNullOrEmpty()) { return null; } return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.Remarks == remarks); } public async Task GetProfileGroupItem(string indexId) { if (indexId.IsNullOrEmpty()) { return null; } return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.IndexId == indexId); } public async Task?> RoutingItems() { return await SQLiteHelper.Instance.TableAsync().OrderBy(t => t.Sort).ToListAsync(); } public async Task GetRoutingItem(string id) { return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.Id == id); } public async Task?> DNSItems() { return await SQLiteHelper.Instance.TableAsync().ToListAsync(); } public async Task GetDNSItem(ECoreType eCoreType) { return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); } public async Task?> FullConfigTemplateItem() { return await SQLiteHelper.Instance.TableAsync().ToListAsync(); } public async Task GetFullConfigTemplateItem(ECoreType eCoreType) { return await SQLiteHelper.Instance.TableAsync().FirstOrDefaultAsync(it => it.CoreType == eCoreType); } #endregion SqliteHelper #region Core Type public List GetShadowsocksSecurities(ProfileItem profileItem) { var coreType = GetCoreType(profileItem, EConfigType.Shadowsocks); switch (coreType) { case ECoreType.v2fly: return Global.SsSecurities; case ECoreType.Xray: return Global.SsSecuritiesInXray; case ECoreType.sing_box: return Global.SsSecuritiesInSingbox; } return Global.SsSecuritiesInSingbox; } public ECoreType GetCoreType(ProfileItem profileItem, EConfigType eConfigType) { if (profileItem?.CoreType != null) { return (ECoreType)profileItem.CoreType; } var item = _config.CoreTypeItem?.FirstOrDefault(it => it.ConfigType == eConfigType); return item?.CoreType ?? ECoreType.Xray; } #endregion Core Type }