mirror of
https://github.com/2dust/v2rayN.git
synced 2025-05-13 03:38:50 +00:00
1581 lines
51 KiB
C#
1581 lines
51 KiB
C#
using System.Data;
|
|
using System.IO;
|
|
using System.Text.RegularExpressions;
|
|
using v2rayN.Base;
|
|
using v2rayN.Mode;
|
|
using v2rayN.Tool;
|
|
|
|
namespace v2rayN.Handler
|
|
{
|
|
/// <summary>
|
|
/// 本软件配置文件处理类
|
|
/// </summary>
|
|
class ConfigHandler
|
|
{
|
|
private static string configRes = Global.ConfigFileName;
|
|
private static readonly object objLock = new object();
|
|
|
|
#region ConfigHandler
|
|
|
|
/// <summary>
|
|
/// 载入配置文件
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <returns></returns>
|
|
public static int LoadConfig(ref Config config)
|
|
{
|
|
//载入配置文件
|
|
string result = Utils.LoadResource(Utils.GetConfigPath(configRes));
|
|
if (!Utils.IsNullOrEmpty(result))
|
|
{
|
|
//转成Json
|
|
config = Utils.FromJson<Config>(result);
|
|
}
|
|
else
|
|
{
|
|
if (File.Exists(Utils.GetConfigPath(configRes)))
|
|
{
|
|
Utils.SaveLog("LoadConfig Exception");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (config == null)
|
|
{
|
|
config = new Config
|
|
{
|
|
};
|
|
}
|
|
if (config.coreBasicItem == null)
|
|
{
|
|
config.coreBasicItem = new()
|
|
{
|
|
logEnabled = false,
|
|
loglevel = "warning",
|
|
|
|
muxEnabled = false,
|
|
};
|
|
}
|
|
|
|
//本地监听
|
|
if (config.inbound == null)
|
|
{
|
|
config.inbound = new List<InItem>();
|
|
InItem inItem = new InItem
|
|
{
|
|
protocol = Global.InboundSocks,
|
|
localPort = 10808,
|
|
udpEnabled = true,
|
|
sniffingEnabled = true,
|
|
routeOnly = false,
|
|
};
|
|
|
|
config.inbound.Add(inItem);
|
|
|
|
//inItem = new InItem();
|
|
//inItem.protocol = "http";
|
|
//inItem.localPort = 1081;
|
|
//inItem.udpEnabled = true;
|
|
|
|
//config.inbound.Add(inItem);
|
|
}
|
|
else
|
|
{
|
|
if (config.inbound.Count > 0)
|
|
{
|
|
config.inbound[0].protocol = Global.InboundSocks;
|
|
}
|
|
}
|
|
if (config.routingBasicItem == null)
|
|
{
|
|
config.routingBasicItem = new()
|
|
{
|
|
enableRoutingAdvanced = true
|
|
};
|
|
}
|
|
//路由规则
|
|
if (Utils.IsNullOrEmpty(config.routingBasicItem.domainStrategy))
|
|
{
|
|
config.routingBasicItem.domainStrategy = Global.domainStrategys[0];//"IPIfNonMatch";
|
|
}
|
|
//if (Utils.IsNullOrEmpty(config.domainMatcher))
|
|
//{
|
|
// config.domainMatcher = "linear";
|
|
//}
|
|
|
|
//kcp
|
|
if (config.kcpItem == null)
|
|
{
|
|
config.kcpItem = new KcpItem
|
|
{
|
|
mtu = 1350,
|
|
tti = 50,
|
|
uplinkCapacity = 12,
|
|
downlinkCapacity = 100,
|
|
readBufferSize = 2,
|
|
writeBufferSize = 2,
|
|
congestion = false
|
|
};
|
|
}
|
|
if (config.grpcItem == null)
|
|
{
|
|
config.grpcItem = new GrpcItem
|
|
{
|
|
idle_timeout = 60,
|
|
health_check_timeout = 20,
|
|
permit_without_stream = false,
|
|
initial_windows_size = 0,
|
|
};
|
|
}
|
|
if (config.tunModeItem == null)
|
|
{
|
|
config.tunModeItem = new TunModeItem
|
|
{
|
|
enableTun = false,
|
|
showWindow = true,
|
|
mtu = 9000,
|
|
};
|
|
}
|
|
if (config.guiItem == null)
|
|
{
|
|
config.guiItem = new()
|
|
{
|
|
enableStatistics = false,
|
|
statisticsFreshRate = 1,
|
|
};
|
|
}
|
|
if (config.uiItem == null)
|
|
{
|
|
config.uiItem = new UIItem()
|
|
{
|
|
enableAutoAdjustMainLvColWidth = true
|
|
};
|
|
}
|
|
if (config.uiItem.mainLvColWidth == null)
|
|
{
|
|
config.uiItem.mainLvColWidth = new Dictionary<string, int>();
|
|
}
|
|
if (Utils.IsNullOrEmpty(config.uiItem.currentLanguage))
|
|
{
|
|
config.uiItem.currentLanguage = Global.Languages[0];
|
|
}
|
|
|
|
if (config.constItem == null)
|
|
{
|
|
config.constItem = new ConstItem();
|
|
}
|
|
if (Utils.IsNullOrEmpty(config.constItem.defIEProxyExceptions))
|
|
{
|
|
config.constItem.defIEProxyExceptions = Global.IEProxyExceptions;
|
|
}
|
|
//if (Utils.IsNullOrEmpty(config.remoteDNS))
|
|
//{
|
|
// config.remoteDNS = "1.1.1.1";
|
|
//}
|
|
|
|
if (config.speedTestItem == null)
|
|
{
|
|
config.speedTestItem = new();
|
|
}
|
|
if (config.speedTestItem.speedTestTimeout < 10)
|
|
{
|
|
config.speedTestItem.speedTestTimeout = 10;
|
|
}
|
|
if (Utils.IsNullOrEmpty(config.speedTestItem.speedTestUrl))
|
|
{
|
|
config.speedTestItem.speedTestUrl = Global.SpeedTestUrls[0];
|
|
}
|
|
if (Utils.IsNullOrEmpty(config.speedTestItem.speedPingTestUrl))
|
|
{
|
|
config.speedTestItem.speedPingTestUrl = Global.SpeedPingTestUrl;
|
|
}
|
|
|
|
if (config.guiItem.statisticsFreshRate > 100 || config.guiItem.statisticsFreshRate < 1)
|
|
{
|
|
config.guiItem.statisticsFreshRate = 1;
|
|
}
|
|
|
|
if (config == null)
|
|
{
|
|
Global.reloadCore = false;
|
|
}
|
|
else
|
|
{
|
|
Global.reloadCore = true;
|
|
|
|
}
|
|
|
|
LazyConfig.Instance.SetConfig(ref config);
|
|
return 0;
|
|
}
|
|
/// <summary>
|
|
/// 保参数
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <returns></returns>
|
|
public static int SaveConfig(ref Config config, bool reload = true)
|
|
{
|
|
Global.reloadCore = reload;
|
|
|
|
ToJsonFile(config);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 存储文件
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
private static void ToJsonFile(Config config)
|
|
{
|
|
lock (objLock)
|
|
{
|
|
try
|
|
{
|
|
|
|
//save temp file
|
|
var resPath = Utils.GetConfigPath(configRes);
|
|
var tempPath = $"{resPath}_temp";
|
|
if (Utils.ToJsonFile(config, tempPath) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (File.Exists(resPath))
|
|
{
|
|
File.Delete(resPath);
|
|
}
|
|
//rename
|
|
File.Move(tempPath, resPath);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.SaveLog("ToJsonFile", ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static int ImportOldGuiConfig(ref Config config, string fileName)
|
|
{
|
|
string result = Utils.LoadResource(fileName);
|
|
if (Utils.IsNullOrEmpty(result))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
var configOld = Utils.FromJson<ConfigOld>(result);
|
|
if (configOld == null)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
var subItem = Utils.FromJson<List<SubItem>>(Utils.ToJson(configOld.subItem));
|
|
foreach (var it in subItem)
|
|
{
|
|
if (Utils.IsNullOrEmpty(it.id))
|
|
{
|
|
it.id = Utils.GetGUID(false);
|
|
}
|
|
SqliteHelper.Instance.Replace(it);
|
|
}
|
|
|
|
var profileItems = Utils.FromJson<List<ProfileItem>>(Utils.ToJson(configOld.vmess));
|
|
foreach (var it in profileItems)
|
|
{
|
|
if (Utils.IsNullOrEmpty(it.indexId))
|
|
{
|
|
it.indexId = Utils.GetGUID(false);
|
|
}
|
|
SqliteHelper.Instance.Replace(it);
|
|
}
|
|
|
|
foreach (var it in configOld.routings)
|
|
{
|
|
if (it.locked)
|
|
{
|
|
continue;
|
|
}
|
|
var routing = Utils.FromJson<RoutingItem>(Utils.ToJson(it));
|
|
foreach (var it2 in it.rules)
|
|
{
|
|
it2.id = Utils.GetGUID(false);
|
|
}
|
|
routing.ruleNum = it.rules.Count;
|
|
routing.ruleSet = Utils.ToJson(it.rules, false);
|
|
|
|
if (Utils.IsNullOrEmpty(routing.id))
|
|
{
|
|
routing.id = Utils.GetGUID(false);
|
|
}
|
|
SqliteHelper.Instance.Replace(routing);
|
|
}
|
|
|
|
config = Utils.FromJson<Config>(Utils.ToJson(configOld));
|
|
|
|
if (config.coreBasicItem == null)
|
|
{
|
|
config.coreBasicItem = new()
|
|
{
|
|
logEnabled = configOld.logEnabled,
|
|
loglevel = configOld.loglevel,
|
|
muxEnabled = configOld.muxEnabled,
|
|
};
|
|
}
|
|
|
|
if (config.routingBasicItem == null)
|
|
{
|
|
config.routingBasicItem = new()
|
|
{
|
|
enableRoutingAdvanced = configOld.enableRoutingAdvanced,
|
|
domainStrategy = configOld.domainStrategy
|
|
};
|
|
}
|
|
|
|
if (config.guiItem == null)
|
|
{
|
|
config.guiItem = new()
|
|
{
|
|
enableStatistics = configOld.enableStatistics,
|
|
statisticsFreshRate = configOld.statisticsFreshRate,
|
|
keepOlderDedupl = configOld.keepOlderDedupl,
|
|
ignoreGeoUpdateCore = configOld.ignoreGeoUpdateCore,
|
|
autoUpdateInterval = configOld.autoUpdateInterval,
|
|
checkPreReleaseUpdate = configOld.checkPreReleaseUpdate,
|
|
enableSecurityProtocolTls13 = configOld.enableSecurityProtocolTls13,
|
|
trayMenuServersLimit = configOld.trayMenuServersLimit,
|
|
};
|
|
}
|
|
|
|
GetDefaultServer(ref config);
|
|
GetDefaultRouting(ref config);
|
|
SaveConfig(ref config);
|
|
LoadConfig(ref config);
|
|
|
|
return 0;
|
|
}
|
|
#endregion
|
|
|
|
#region Server
|
|
|
|
/// <summary>
|
|
/// 添加服务器或编辑
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="profileItem"></param>
|
|
/// <returns></returns>
|
|
public static int AddServer(ref Config config, ProfileItem profileItem)
|
|
{
|
|
profileItem.configType = EConfigType.VMess;
|
|
|
|
profileItem.address = profileItem.address.TrimEx();
|
|
profileItem.id = profileItem.id.TrimEx();
|
|
profileItem.security = profileItem.security.TrimEx();
|
|
profileItem.network = profileItem.network.TrimEx();
|
|
profileItem.headerType = profileItem.headerType.TrimEx();
|
|
profileItem.requestHost = profileItem.requestHost.TrimEx();
|
|
profileItem.path = profileItem.path.TrimEx();
|
|
profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
|
|
|
|
if (!Global.vmessSecuritys.Contains(profileItem.security))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
AddServerCommon(ref config, profileItem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移除服务器
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="indexs"></param>
|
|
/// <returns></returns>
|
|
public static int RemoveServer(Config config, List<ProfileItem> indexs)
|
|
{
|
|
foreach (var item in indexs)
|
|
{
|
|
RemoveProfileItem(config, item.indexId);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 克隆服务器
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="index"></param>
|
|
/// <returns></returns>
|
|
public static int CopyServer(ref Config config, List<ProfileItem> indexs)
|
|
{
|
|
foreach (var item in indexs)
|
|
{
|
|
ProfileItem profileItem = Utils.DeepCopy(item);
|
|
profileItem.indexId = string.Empty;
|
|
profileItem.remarks = $"{item.remarks}-clone";
|
|
|
|
if (profileItem.configType == EConfigType.Custom)
|
|
{
|
|
profileItem.address = Utils.GetConfigPath(profileItem.address);
|
|
if (AddCustomServer(ref config, profileItem, false) == 0)
|
|
{
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddServerCommon(ref config, profileItem);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置活动服务器
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="item"></param>
|
|
/// <returns></returns>
|
|
public static int SetDefaultServerIndex(ref Config config, string indexId)
|
|
{
|
|
if (Utils.IsNullOrEmpty(indexId))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
config.indexId = indexId;
|
|
Global.reloadCore = true;
|
|
|
|
ToJsonFile(config);
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static int SetDefaultServer(Config config, List<ProfileItemModel> lstProfile)
|
|
{
|
|
if (lstProfile.Exists(t => t.indexId == config.indexId))
|
|
{
|
|
return 0;
|
|
}
|
|
var allItems = LazyConfig.Instance.ProfileItemIndexs("");
|
|
if (allItems.Where(t => t == config.indexId).Count() > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if (lstProfile.Count > 0)
|
|
{
|
|
return SetDefaultServerIndex(ref config, lstProfile[0].indexId);
|
|
}
|
|
if (allItems.Count() > 0)
|
|
{
|
|
return SetDefaultServerIndex(ref config, allItems.FirstOrDefault());
|
|
}
|
|
return -1;
|
|
}
|
|
public static ProfileItem GetDefaultServer(ref Config config)
|
|
{
|
|
var item = LazyConfig.Instance.GetProfileItem(config.indexId);
|
|
if (item is null)
|
|
{
|
|
var item2 = SqliteHelper.Instance.Table<ProfileItem>().FirstOrDefault();
|
|
SetDefaultServerIndex(ref config, item2?.indexId);
|
|
return item2;
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 移动服务器
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="lstProfile"></param>
|
|
/// <param name="index"></param>
|
|
/// <param name="eMove"></param>
|
|
/// <returns></returns>
|
|
public static int MoveServer(ref Config config, ref List<ProfileItem> lstProfile, int index, EMove eMove, int pos = -1)
|
|
{
|
|
int count = lstProfile.Count;
|
|
if (index < 0 || index > lstProfile.Count - 1)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
for (int i = 0; i < lstProfile.Count; i++)
|
|
{
|
|
ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
|
|
}
|
|
|
|
var sort = 0;
|
|
switch (eMove)
|
|
{
|
|
case EMove.Top:
|
|
{
|
|
if (index == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
sort = ProfileExHandler.Instance.GetSort(lstProfile[0].indexId) - 1;
|
|
|
|
break;
|
|
}
|
|
case EMove.Up:
|
|
{
|
|
if (index == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
sort = ProfileExHandler.Instance.GetSort(lstProfile[index - 1].indexId) - 1;
|
|
|
|
break;
|
|
}
|
|
|
|
case EMove.Down:
|
|
{
|
|
if (index == count - 1)
|
|
{
|
|
return 0;
|
|
}
|
|
sort = ProfileExHandler.Instance.GetSort(lstProfile[index + 1].indexId) + 1;
|
|
|
|
break;
|
|
}
|
|
case EMove.Bottom:
|
|
{
|
|
if (index == count - 1)
|
|
{
|
|
return 0;
|
|
}
|
|
sort = ProfileExHandler.Instance.GetSort(lstProfile[lstProfile.Count - 1].indexId) + 1;
|
|
|
|
break;
|
|
}
|
|
case EMove.Position:
|
|
sort = pos * 10 + 1;
|
|
break;
|
|
}
|
|
|
|
ProfileExHandler.Instance.SetSort(lstProfile[index].indexId, sort);
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加自定义服务器
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="profileItem"></param>
|
|
/// <returns></returns>
|
|
public static int AddCustomServer(ref Config config, ProfileItem profileItem, bool blDelete)
|
|
{
|
|
var fileName = profileItem.address;
|
|
if (!File.Exists(fileName))
|
|
{
|
|
return -1;
|
|
}
|
|
var ext = Path.GetExtension(fileName);
|
|
string newFileName = $"{Utils.GetGUID()}{ext}";
|
|
//newFileName = Path.Combine(Utils.GetTempPath(), newFileName);
|
|
|
|
try
|
|
{
|
|
File.Copy(fileName, Utils.GetConfigPath(newFileName));
|
|
if (blDelete)
|
|
{
|
|
File.Delete(fileName);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.SaveLog(ex.Message, ex);
|
|
return -1;
|
|
}
|
|
|
|
profileItem.address = newFileName;
|
|
profileItem.configType = EConfigType.Custom;
|
|
if (Utils.IsNullOrEmpty(profileItem.remarks))
|
|
{
|
|
profileItem.remarks = $"import custom@{DateTime.Now.ToShortDateString()}";
|
|
}
|
|
|
|
|
|
AddServerCommon(ref config, profileItem);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加服务器或编辑
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="profileItem"></param>
|
|
/// <returns></returns>
|
|
public static int EditCustomServer(ref Config config, ProfileItem profileItem)
|
|
{
|
|
if (SqliteHelper.Instance.Update(profileItem) > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
//ToJsonFile(config);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加服务器或编辑
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="profileItem"></param>
|
|
/// <returns></returns>
|
|
public static int AddShadowsocksServer(ref Config config, ProfileItem profileItem)
|
|
{
|
|
profileItem.configType = EConfigType.Shadowsocks;
|
|
|
|
profileItem.address = profileItem.address.TrimEx();
|
|
profileItem.id = profileItem.id.TrimEx();
|
|
profileItem.security = profileItem.security.TrimEx();
|
|
|
|
if (!LazyConfig.Instance.GetShadowsocksSecuritys(profileItem).Contains(profileItem.security))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
AddServerCommon(ref config, profileItem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加服务器或编辑
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="profileItem"></param>
|
|
/// <returns></returns>
|
|
public static int AddSocksServer(ref Config config, ProfileItem profileItem)
|
|
{
|
|
profileItem.configType = EConfigType.Socks;
|
|
|
|
profileItem.address = profileItem.address.TrimEx();
|
|
|
|
AddServerCommon(ref config, profileItem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加服务器或编辑
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="profileItem"></param>
|
|
/// <returns></returns>
|
|
public static int AddTrojanServer(ref Config config, ProfileItem profileItem)
|
|
{
|
|
profileItem.configType = EConfigType.Trojan;
|
|
|
|
profileItem.address = profileItem.address.TrimEx();
|
|
profileItem.id = profileItem.id.TrimEx();
|
|
if (Utils.IsNullOrEmpty(profileItem.streamSecurity))
|
|
{
|
|
profileItem.streamSecurity = Global.StreamSecurity;
|
|
}
|
|
if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
|
|
{
|
|
profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
|
|
}
|
|
|
|
AddServerCommon(ref config, profileItem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
public static int SortServers(ref Config config, string subId, EServerColName name, bool asc)
|
|
{
|
|
var lstModel = LazyConfig.Instance.ProfileItems(subId, "");
|
|
if (lstModel.Count <= 0)
|
|
{
|
|
return -1;
|
|
}
|
|
var lstProfileExs = ProfileExHandler.Instance.ProfileExs;
|
|
var lstProfile = (from t in lstModel
|
|
join t3 in lstProfileExs on t.indexId equals t3.indexId into t3b
|
|
from t33 in t3b.DefaultIfEmpty()
|
|
select new ProfileItemModel
|
|
{
|
|
indexId = t.indexId,
|
|
configType = t.configType,
|
|
remarks = t.remarks,
|
|
address = t.address,
|
|
port = t.port,
|
|
security = t.security,
|
|
network = t.network,
|
|
streamSecurity = t.streamSecurity,
|
|
delay = t33 == null ? 0 : t33.delay,
|
|
speed = t33 == null ? 0 : t33.speed,
|
|
sort = t33 == null ? 0 : t33.sort
|
|
}).ToList();
|
|
|
|
var propertyName = string.Empty;
|
|
switch (name)
|
|
{
|
|
case EServerColName.configType:
|
|
case EServerColName.remarks:
|
|
case EServerColName.address:
|
|
case EServerColName.port:
|
|
case EServerColName.security:
|
|
case EServerColName.network:
|
|
case EServerColName.streamSecurity:
|
|
case EServerColName.delay:
|
|
case EServerColName.speed:
|
|
propertyName = name.ToString();
|
|
break;
|
|
case EServerColName.subRemarks:
|
|
propertyName = "subid";
|
|
break;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
var items = lstProfile.AsQueryable();
|
|
|
|
if (asc)
|
|
{
|
|
lstProfile = items.OrderBy(propertyName).ToList();
|
|
}
|
|
else
|
|
{
|
|
lstProfile = items.OrderByDescending(propertyName).ToList();
|
|
}
|
|
for (int i = 0; i < lstProfile.Count; i++)
|
|
{
|
|
ProfileExHandler.Instance.SetSort(lstProfile[i].indexId, (i + 1) * 10);
|
|
}
|
|
if (name == EServerColName.delay)
|
|
{
|
|
var maxSort = lstProfile.Max(t => t.sort) + 10;
|
|
foreach (var item in lstProfile)
|
|
{
|
|
if (item.delay <= 0)
|
|
{
|
|
ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
|
|
}
|
|
}
|
|
}
|
|
if (name == EServerColName.speed)
|
|
{
|
|
var maxSort = lstProfile.Max(t => t.sort) + 10;
|
|
foreach (var item in lstProfile)
|
|
{
|
|
if (item.speed <= 0)
|
|
{
|
|
ProfileExHandler.Instance.SetSort(item.indexId, maxSort);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 添加服务器或编辑
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="profileItem"></param>
|
|
/// <returns></returns>
|
|
public static int AddVlessServer(ref Config config, ProfileItem profileItem)
|
|
{
|
|
profileItem.configType = EConfigType.VLESS;
|
|
|
|
profileItem.address = profileItem.address.TrimEx();
|
|
profileItem.id = profileItem.id.TrimEx();
|
|
profileItem.security = profileItem.security.TrimEx();
|
|
profileItem.network = profileItem.network.TrimEx();
|
|
profileItem.headerType = profileItem.headerType.TrimEx();
|
|
profileItem.requestHost = profileItem.requestHost.TrimEx();
|
|
profileItem.path = profileItem.path.TrimEx();
|
|
profileItem.streamSecurity = profileItem.streamSecurity.TrimEx();
|
|
|
|
AddServerCommon(ref config, profileItem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static int DedupServerList(ref Config config, ref List<ProfileItem> lstProfile)
|
|
{
|
|
List<ProfileItem> source = lstProfile;
|
|
bool keepOlder = config.guiItem.keepOlderDedupl;
|
|
|
|
List<ProfileItem> list = new List<ProfileItem>();
|
|
if (!keepOlder) source.Reverse(); // Remove the early items first
|
|
|
|
foreach (ProfileItem item in source)
|
|
{
|
|
if (!list.Exists(i => CompareProfileItem(i, item, false)))
|
|
{
|
|
list.Add(item);
|
|
}
|
|
else
|
|
{
|
|
RemoveProfileItem(config, item.indexId);
|
|
}
|
|
}
|
|
//if (!keepOlder) list.Reverse();
|
|
//config.vmess = list;
|
|
|
|
return list.Count;
|
|
}
|
|
|
|
public static int AddServerCommon(ref Config config, ProfileItem profileItem)
|
|
{
|
|
profileItem.configVersion = 2;
|
|
if (Utils.IsNullOrEmpty(profileItem.allowInsecure))
|
|
{
|
|
profileItem.allowInsecure = config.coreBasicItem.defAllowInsecure.ToString().ToLower();
|
|
}
|
|
if (!Utils.IsNullOrEmpty(profileItem.network) && !Global.networks.Contains(profileItem.network))
|
|
{
|
|
profileItem.network = Global.DefaultNetwork;
|
|
}
|
|
|
|
if (Utils.IsNullOrEmpty(profileItem.indexId))
|
|
{
|
|
profileItem.indexId = Utils.GetGUID(false);
|
|
var maxSort = ProfileExHandler.Instance.GetMaxSort();
|
|
ProfileExHandler.Instance.SetSort(profileItem.indexId, maxSort + 1);
|
|
}
|
|
else if (profileItem.indexId == config.indexId)
|
|
{
|
|
Global.reloadCore = true;
|
|
}
|
|
|
|
if (SqliteHelper.Instance.Replace(profileItem) > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private static bool CompareProfileItem(ProfileItem o, ProfileItem n, bool remarks)
|
|
{
|
|
if (o == null || n == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return o.configVersion == n.configVersion
|
|
&& o.configType == n.configType
|
|
&& o.address == n.address
|
|
&& o.port == n.port
|
|
&& o.id == n.id
|
|
&& o.alterId == n.alterId
|
|
&& o.security == n.security
|
|
&& o.network == n.network
|
|
&& o.headerType == n.headerType
|
|
&& o.requestHost == n.requestHost
|
|
&& o.path == n.path
|
|
&& (o.configType == EConfigType.Trojan || o.streamSecurity == n.streamSecurity)
|
|
&& o.flow == n.flow
|
|
&& o.sni == n.sni
|
|
&& (!remarks || o.remarks == n.remarks);
|
|
}
|
|
|
|
private static int RemoveProfileItem(Config config, string indexId)
|
|
{
|
|
try
|
|
{
|
|
var item = LazyConfig.Instance.GetProfileItem(indexId);
|
|
if (item == null)
|
|
{
|
|
return 0;
|
|
}
|
|
if (item.configType == EConfigType.Custom)
|
|
{
|
|
File.Delete(Utils.GetConfigPath(item.address));
|
|
}
|
|
|
|
SqliteHelper.Instance.Delete(item);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Utils.SaveLog("Remove Item", ex);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endregion
|
|
|
|
#region Batch add servers
|
|
|
|
/// <summary>
|
|
/// 批量添加服务器
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="clipboardData"></param>
|
|
/// <param name="subid"></param>
|
|
/// <returns>成功导入的数量</returns>
|
|
private static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
|
{
|
|
if (Utils.IsNullOrEmpty(clipboardData))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
string subFilter = string.Empty;
|
|
//remove sub items
|
|
if (isSub && !Utils.IsNullOrEmpty(subid))
|
|
{
|
|
RemoveServerViaSubid(ref config, subid, isSub);
|
|
subFilter = LazyConfig.Instance.GetSubItem(subid)?.filter ?? "";
|
|
}
|
|
|
|
int countServers = 0;
|
|
//var maxSort = 0;
|
|
//if (SqliteHelper.Instance.Table<ProfileItem>().Count() > 0)
|
|
//{
|
|
// maxSort = SqliteHelper.Instance.Table<ProfileItem>().Max(t => t.sort);
|
|
//}
|
|
string[] arrData = clipboardData.Split(Environment.NewLine.ToCharArray());
|
|
foreach (string str in arrData)
|
|
{
|
|
//maybe sub
|
|
if (Utils.IsNullOrEmpty(subid) && (str.StartsWith(Global.httpsProtocol) || str.StartsWith(Global.httpProtocol)))
|
|
{
|
|
if (AddSubItem(ref config, str) == 0)
|
|
{
|
|
countServers++;
|
|
}
|
|
continue;
|
|
}
|
|
ProfileItem profileItem = ShareHandler.ImportFromClipboardConfig(str, out string msg);
|
|
if (profileItem == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
//exist sub items
|
|
if (isSub && !Utils.IsNullOrEmpty(subid))
|
|
{
|
|
var existItem = lstOriSub?.FirstOrDefault(t => CompareProfileItem(t, profileItem, true));
|
|
if (existItem != null)
|
|
{
|
|
profileItem = existItem;
|
|
}
|
|
//filter
|
|
if (!Utils.IsNullOrEmpty(subFilter))
|
|
{
|
|
if (!Regex.IsMatch(profileItem.remarks, subFilter))
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
profileItem.subid = subid;
|
|
profileItem.isSub = isSub;
|
|
//profileItem.sort = maxSort + countServers + 1;
|
|
|
|
if (profileItem.configType == EConfigType.VMess)
|
|
{
|
|
if (AddServer(ref config, profileItem) == 0)
|
|
{
|
|
countServers++;
|
|
}
|
|
}
|
|
else if (profileItem.configType == EConfigType.Shadowsocks)
|
|
{
|
|
if (AddShadowsocksServer(ref config, profileItem) == 0)
|
|
{
|
|
countServers++;
|
|
}
|
|
}
|
|
else if (profileItem.configType == EConfigType.Socks)
|
|
{
|
|
if (AddSocksServer(ref config, profileItem) == 0)
|
|
{
|
|
countServers++;
|
|
}
|
|
}
|
|
else if (profileItem.configType == EConfigType.Trojan)
|
|
{
|
|
if (AddTrojanServer(ref config, profileItem) == 0)
|
|
{
|
|
countServers++;
|
|
}
|
|
}
|
|
else if (profileItem.configType == EConfigType.VLESS)
|
|
{
|
|
if (AddVlessServer(ref config, profileItem) == 0)
|
|
{
|
|
countServers++;
|
|
}
|
|
}
|
|
}
|
|
|
|
ToJsonFile(config);
|
|
return countServers;
|
|
}
|
|
|
|
private static int AddBatchServers4Custom(ref Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
|
{
|
|
if (Utils.IsNullOrEmpty(clipboardData))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
//判断str是否包含s的任意一个字符串
|
|
static bool Containss(string str, params string[] s)
|
|
{
|
|
foreach (var item in s)
|
|
{
|
|
if (str.Contains(item, StringComparison.OrdinalIgnoreCase)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
ProfileItem profileItem = new();
|
|
//Is v2ray configuration
|
|
V2rayConfig v2rayConfig = Utils.FromJson<V2rayConfig>(clipboardData);
|
|
if (v2rayConfig != null
|
|
&& v2rayConfig.inbounds != null
|
|
&& v2rayConfig.inbounds.Count > 0
|
|
&& v2rayConfig.outbounds != null
|
|
&& v2rayConfig.outbounds.Count > 0)
|
|
{
|
|
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
|
File.WriteAllText(fileName, clipboardData);
|
|
|
|
profileItem.coreType = ECoreType.Xray;
|
|
profileItem.address = fileName;
|
|
profileItem.remarks = "v2ray_custom";
|
|
}
|
|
//Is Clash configuration
|
|
else if (Containss(clipboardData, "port", "socks-port", "proxies"))
|
|
{
|
|
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.yaml");
|
|
File.WriteAllText(fileName, clipboardData);
|
|
|
|
profileItem.coreType = ECoreType.clash;
|
|
profileItem.address = fileName;
|
|
profileItem.remarks = "clash_custom";
|
|
}
|
|
//Is hysteria configuration
|
|
else if (Containss(clipboardData, "server", "up", "down", "listen", "<html>", "<body>"))
|
|
{
|
|
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
|
File.WriteAllText(fileName, clipboardData);
|
|
|
|
profileItem.coreType = ECoreType.hysteria;
|
|
profileItem.address = fileName;
|
|
profileItem.remarks = "hysteria_custom";
|
|
}
|
|
//Is naiveproxy configuration
|
|
else if (Containss(clipboardData, "listen", "proxy", "<html>", "<body>"))
|
|
{
|
|
var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.json");
|
|
File.WriteAllText(fileName, clipboardData);
|
|
|
|
profileItem.coreType = ECoreType.naiveproxy;
|
|
profileItem.address = fileName;
|
|
profileItem.remarks = "naiveproxy_custom";
|
|
}
|
|
//Is Other configuration
|
|
else
|
|
{
|
|
return -1;
|
|
//var fileName = Utils.GetTempPath($"{Utils.GetGUID(false)}.txt");
|
|
//File.WriteAllText(fileName, clipboardData);
|
|
|
|
//profileItem.address = fileName;
|
|
//profileItem.remarks = "other_custom";
|
|
}
|
|
|
|
if (isSub && !Utils.IsNullOrEmpty(subid))
|
|
{
|
|
RemoveServerViaSubid(ref config, subid, isSub);
|
|
}
|
|
if (isSub && lstOriSub != null && lstOriSub.Count == 1)
|
|
{
|
|
profileItem.indexId = lstOriSub[0].indexId;
|
|
}
|
|
profileItem.subid = subid;
|
|
profileItem.isSub = isSub;
|
|
|
|
if (Utils.IsNullOrEmpty(profileItem.address))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (AddCustomServer(ref config, profileItem, true) == 0)
|
|
{
|
|
return 1;
|
|
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
private static int AddBatchServers4SsSIP008(ref Config config, string clipboardData, string subid, bool isSub, List<ProfileItem> lstOriSub)
|
|
{
|
|
if (Utils.IsNullOrEmpty(clipboardData))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (isSub && !Utils.IsNullOrEmpty(subid))
|
|
{
|
|
RemoveServerViaSubid(ref config, subid, isSub);
|
|
}
|
|
|
|
//SsSIP008
|
|
var lstSsServer = Utils.FromJson<List<SsServer>>(clipboardData);
|
|
if (lstSsServer == null || lstSsServer.Count <= 0)
|
|
{
|
|
var ssSIP008 = Utils.FromJson<SsSIP008>(clipboardData);
|
|
if (ssSIP008?.servers != null && ssSIP008.servers.Count > 0)
|
|
{
|
|
lstSsServer = ssSIP008.servers;
|
|
}
|
|
}
|
|
|
|
if (lstSsServer != null && lstSsServer.Count > 0)
|
|
{
|
|
int counter = 0;
|
|
foreach (var it in lstSsServer)
|
|
{
|
|
var ssItem = new ProfileItem()
|
|
{
|
|
subid = subid,
|
|
remarks = it.remarks,
|
|
security = it.method,
|
|
id = it.password,
|
|
address = it.server,
|
|
port = Utils.ToInt(it.server_port)
|
|
};
|
|
ssItem.subid = subid;
|
|
ssItem.isSub = isSub;
|
|
if (AddShadowsocksServer(ref config, ssItem) == 0)
|
|
{
|
|
counter++;
|
|
}
|
|
}
|
|
ToJsonFile(config);
|
|
return counter;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
public static int AddBatchServers(ref Config config, string clipboardData, string subid, bool isSub)
|
|
{
|
|
List<ProfileItem> lstOriSub = null;
|
|
if (isSub && !Utils.IsNullOrEmpty(subid))
|
|
{
|
|
lstOriSub = LazyConfig.Instance.ProfileItems(subid);
|
|
}
|
|
|
|
int counter = AddBatchServers(ref config, clipboardData, subid, isSub, lstOriSub);
|
|
if (counter < 1)
|
|
{
|
|
counter = AddBatchServers(ref config, Utils.Base64Decode(clipboardData), subid, isSub, lstOriSub);
|
|
}
|
|
|
|
if (counter < 1)
|
|
{
|
|
counter = AddBatchServers4SsSIP008(ref config, clipboardData, subid, isSub, lstOriSub);
|
|
}
|
|
|
|
//maybe other sub
|
|
if (counter < 1)
|
|
{
|
|
counter = AddBatchServers4Custom(ref config, clipboardData, subid, isSub, lstOriSub);
|
|
}
|
|
|
|
return counter;
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
#region Sub & Group
|
|
|
|
/// <summary>
|
|
/// add sub
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="url"></param>
|
|
/// <returns></returns>
|
|
public static int AddSubItem(ref Config config, string url)
|
|
{
|
|
//already exists
|
|
if (SqliteHelper.Instance.Table<SubItem>().Where(e => e.url == url).Count() > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
SubItem subItem = new SubItem
|
|
{
|
|
id = string.Empty,
|
|
remarks = "import_sub",
|
|
url = url
|
|
};
|
|
|
|
return AddSubItem(ref config, subItem);
|
|
}
|
|
|
|
public static int AddSubItem(ref Config config, SubItem subItem)
|
|
{
|
|
if (Utils.IsNullOrEmpty(subItem.id))
|
|
{
|
|
subItem.id = Utils.GetGUID(false);
|
|
|
|
if (subItem.sort <= 0)
|
|
{
|
|
var maxSort = 0;
|
|
if (SqliteHelper.Instance.Table<SubItem>().Count() > 0)
|
|
{
|
|
maxSort = SqliteHelper.Instance.Table<SubItem>().Max(t => t == null ? 0 : t.sort);
|
|
}
|
|
subItem.sort = maxSort + 1;
|
|
}
|
|
}
|
|
if (SqliteHelper.Instance.Replace(subItem) > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 移除服务器
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="subid"></param>
|
|
/// <returns></returns>
|
|
public static int RemoveServerViaSubid(ref Config config, string subid, bool isSub)
|
|
{
|
|
if (Utils.IsNullOrEmpty(subid))
|
|
{
|
|
return -1;
|
|
}
|
|
if (isSub)
|
|
{
|
|
SqliteHelper.Instance.Execute($"delete from ProfileItem where isSub = 1 and subid = '{subid}'");
|
|
}
|
|
else
|
|
{
|
|
SqliteHelper.Instance.Execute($"delete from ProfileItem where subid = '{subid}'");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static int DeleteSubItem(ref Config config, string id)
|
|
{
|
|
var item = LazyConfig.Instance.GetSubItem(id);
|
|
if (item is null)
|
|
{
|
|
return 0;
|
|
}
|
|
SqliteHelper.Instance.Delete(item);
|
|
RemoveServerViaSubid(ref config, id, false);
|
|
|
|
return 0;
|
|
}
|
|
|
|
public static int MoveToGroup(Config config, List<ProfileItem> lstProfile, string subid)
|
|
{
|
|
foreach (var it in lstProfile)
|
|
{
|
|
var item = LazyConfig.Instance.GetProfileItem(it.indexId);
|
|
if (item is null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
item.subid = subid;
|
|
SqliteHelper.Instance.Update(item);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endregion
|
|
|
|
#region UI
|
|
|
|
public static int AddformMainLvColWidth(ref Config config, string name, int width)
|
|
{
|
|
if (config.uiItem.mainLvColWidth == null)
|
|
{
|
|
config.uiItem.mainLvColWidth = new Dictionary<string, int>();
|
|
}
|
|
if (config.uiItem.mainLvColWidth.ContainsKey(name))
|
|
{
|
|
config.uiItem.mainLvColWidth[name] = width;
|
|
}
|
|
else
|
|
{
|
|
config.uiItem.mainLvColWidth.Add(name, width);
|
|
}
|
|
|
|
ToJsonFile(config);
|
|
return 0;
|
|
}
|
|
public static int GetformMainLvColWidth(ref Config config, string name, int width)
|
|
{
|
|
if (config.uiItem.mainLvColWidth == null)
|
|
{
|
|
config.uiItem.mainLvColWidth = new Dictionary<string, int>();
|
|
}
|
|
if (config.uiItem.mainLvColWidth.ContainsKey(name))
|
|
{
|
|
return config.uiItem.mainLvColWidth[name];
|
|
}
|
|
else
|
|
{
|
|
return width;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Routing
|
|
|
|
public static int SaveRoutingItem(ref Config config, RoutingItem item)
|
|
{
|
|
if (Utils.IsNullOrEmpty(item.id))
|
|
{
|
|
item.id = Utils.GetGUID(false);
|
|
}
|
|
|
|
if (SqliteHelper.Instance.Replace(item) > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// AddBatchRoutingRules
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
/// <param name="clipboardData"></param>
|
|
/// <returns></returns>
|
|
public static int AddBatchRoutingRules(ref RoutingItem routingItem, string clipboardData)
|
|
{
|
|
if (Utils.IsNullOrEmpty(clipboardData))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
var lstRules = Utils.FromJson<List<RulesItem>>(clipboardData);
|
|
if (lstRules == null)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
foreach (var item in lstRules)
|
|
{
|
|
item.id = Utils.GetGUID(false);
|
|
}
|
|
routingItem.ruleNum = lstRules.Count;
|
|
routingItem.ruleSet = Utils.ToJson(lstRules, false);
|
|
|
|
if (Utils.IsNullOrEmpty(routingItem.id))
|
|
{
|
|
routingItem.id = Utils.GetGUID(false);
|
|
}
|
|
|
|
if (SqliteHelper.Instance.Replace(routingItem) > 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// MoveRoutingRule
|
|
/// </summary>
|
|
/// <param name="routingItem"></param>
|
|
/// <param name="index"></param>
|
|
/// <param name="eMove"></param>
|
|
/// <returns></returns>
|
|
public static int MoveRoutingRule(List<RulesItem> rules, int index, EMove eMove, int pos = -1)
|
|
{
|
|
int count = rules.Count;
|
|
if (index < 0 || index > rules.Count - 1)
|
|
{
|
|
return -1;
|
|
}
|
|
switch (eMove)
|
|
{
|
|
case EMove.Top:
|
|
{
|
|
if (index == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
var item = Utils.DeepCopy(rules[index]);
|
|
rules.RemoveAt(index);
|
|
rules.Insert(0, item);
|
|
|
|
break;
|
|
}
|
|
case EMove.Up:
|
|
{
|
|
if (index == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
var item = Utils.DeepCopy(rules[index]);
|
|
rules.RemoveAt(index);
|
|
rules.Insert(index - 1, item);
|
|
|
|
break;
|
|
}
|
|
|
|
case EMove.Down:
|
|
{
|
|
if (index == count - 1)
|
|
{
|
|
return 0;
|
|
}
|
|
var item = Utils.DeepCopy(rules[index]);
|
|
rules.RemoveAt(index);
|
|
rules.Insert(index + 1, item);
|
|
|
|
break;
|
|
}
|
|
case EMove.Bottom:
|
|
{
|
|
if (index == count - 1)
|
|
{
|
|
return 0;
|
|
}
|
|
var item = Utils.DeepCopy(rules[index]);
|
|
rules.RemoveAt(index);
|
|
rules.Add(item);
|
|
|
|
break;
|
|
}
|
|
case EMove.Position:
|
|
{
|
|
var removeItem = rules[index];
|
|
var item = Utils.DeepCopy(rules[index]);
|
|
rules.Insert(pos, item);
|
|
rules.Remove(removeItem);
|
|
break;
|
|
}
|
|
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public static int SetDefaultRouting(ref Config config, RoutingItem routingItem)
|
|
{
|
|
if (SqliteHelper.Instance.Table<RoutingItem>().Where(t => t.id == routingItem.id).Count() > 0)
|
|
{
|
|
config.routingBasicItem.routingIndexId = routingItem.id;
|
|
}
|
|
|
|
Global.reloadCore = true;
|
|
|
|
ToJsonFile(config);
|
|
|
|
return 0;
|
|
}
|
|
public static RoutingItem GetDefaultRouting(ref Config config)
|
|
{
|
|
var item = LazyConfig.Instance.GetRoutingItem(config.routingBasicItem.routingIndexId);
|
|
if (item is null)
|
|
{
|
|
var item2 = SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(t => t.locked == false);
|
|
SetDefaultRouting(ref config, item2);
|
|
return item2;
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
public static int InitBuiltinRouting(ref Config config, bool blImportAdvancedRules = false)
|
|
{
|
|
var items = LazyConfig.Instance.RoutingItems();
|
|
if (blImportAdvancedRules || items.Count <= 0)
|
|
{
|
|
var maxSort = items.Count;
|
|
//Bypass the mainland
|
|
var item2 = new RoutingItem()
|
|
{
|
|
remarks = "绕过大陆(Whitelist)",
|
|
url = string.Empty,
|
|
sort = maxSort + 1,
|
|
};
|
|
AddBatchRoutingRules(ref item2, Utils.GetEmbedText(Global.CustomRoutingFileName + "white"));
|
|
|
|
//Blacklist
|
|
var item3 = new RoutingItem()
|
|
{
|
|
remarks = "黑名单(Blacklist)",
|
|
url = string.Empty,
|
|
sort = maxSort + 2,
|
|
};
|
|
AddBatchRoutingRules(ref item3, Utils.GetEmbedText(Global.CustomRoutingFileName + "black"));
|
|
|
|
//Global
|
|
var item1 = new RoutingItem()
|
|
{
|
|
remarks = "全局(Global)",
|
|
url = string.Empty,
|
|
sort = maxSort + 3,
|
|
};
|
|
AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "global"));
|
|
|
|
if (!blImportAdvancedRules)
|
|
{
|
|
SetDefaultRouting(ref config, item2);
|
|
}
|
|
}
|
|
|
|
if (GetLockedRoutingItem(ref config) == null)
|
|
{
|
|
var item1 = new RoutingItem()
|
|
{
|
|
remarks = "locked",
|
|
url = string.Empty,
|
|
locked = true,
|
|
};
|
|
AddBatchRoutingRules(ref item1, Utils.GetEmbedText(Global.CustomRoutingFileName + "locked"));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public static RoutingItem GetLockedRoutingItem(ref Config config)
|
|
{
|
|
return SqliteHelper.Instance.Table<RoutingItem>().FirstOrDefault(it => it.locked == true);
|
|
}
|
|
|
|
public static void RemoveRoutingItem(RoutingItem routingItem)
|
|
{
|
|
SqliteHelper.Instance.Delete(routingItem);
|
|
}
|
|
#endregion
|
|
}
|
|
}
|