348 lines
11 KiB
C#
348 lines
11 KiB
C#
using Microsoft.Extensions.Caching.Memory;
|
|
using Shared.Models.Base;
|
|
using Shared.Models.Proxy;
|
|
using System.Collections.Concurrent;
|
|
using System.Net;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading;
|
|
|
|
namespace Shared.Engine
|
|
{
|
|
public class ProxyManager
|
|
{
|
|
#region static
|
|
static IMemoryCache memoryCache;
|
|
static ConcurrentDictionary<string, ProxyManagerModel> database = new ConcurrentDictionary<string, ProxyManagerModel>();
|
|
|
|
public static void Configure(IMemoryCache mem)
|
|
{
|
|
memoryCache = mem;
|
|
}
|
|
#endregion
|
|
|
|
#region ProxyManager
|
|
string plugin;
|
|
bool refresh;
|
|
Iproxy conf;
|
|
RchClient rch;
|
|
|
|
bool IsKitConf;
|
|
string KitCurrentProxyIp;
|
|
|
|
public string[] proxyKeys;
|
|
|
|
public ProxyManager(string plugin, Iproxy conf, bool refresh = true, bool IsKitConf = false)
|
|
{
|
|
if (conf == null)
|
|
return;
|
|
|
|
this.IsKitConf = IsKitConf;
|
|
this.plugin = plugin;
|
|
this.conf = conf;
|
|
this.refresh = refresh;
|
|
proxyKeys = [plugin, $"{plugin}:conf", $"{plugin}:globalname"];
|
|
}
|
|
|
|
public ProxyManager(BaseSettings conf, bool refresh = true)
|
|
: this(conf, null, refresh) { }
|
|
|
|
public ProxyManager(BaseSettings conf, RchClient rch, bool refresh = true)
|
|
{
|
|
if (conf == null)
|
|
return;
|
|
|
|
this.rch = rch;
|
|
IsKitConf = conf.IsKitConf;
|
|
plugin = !string.IsNullOrEmpty(conf.plugin) ? conf.plugin : conf.host ?? conf.apihost;
|
|
this.conf = conf;
|
|
this.refresh = refresh;
|
|
proxyKeys = [plugin, $"{plugin}:conf", $"{plugin}:globalname"];
|
|
}
|
|
#endregion
|
|
|
|
#region Get / BaseGet
|
|
public WebProxy Get() => BaseGet().proxy;
|
|
|
|
public (WebProxy proxy, (string ip, string username, string password) data) BaseGet()
|
|
{
|
|
if (conf == null)
|
|
return default;
|
|
|
|
if (!conf.useproxy && !conf.useproxystream)
|
|
return default;
|
|
|
|
#region proxy()
|
|
(WebProxy proxy, (string ip, string username, string password) data) proxy(ProxySettings p_orig, string key)
|
|
{
|
|
ProxySettings p = ConfigureProxy(p_orig);
|
|
|
|
if (p?.list == null || p.list.Length == 0)
|
|
return default;
|
|
|
|
if (IsKitConf)
|
|
{
|
|
if (KitCurrentProxyIp == null)
|
|
KitCurrentProxyIp = p.list.OrderBy(a => Guid.NewGuid()).First();
|
|
|
|
return ConfigureWebProxy(p, KitCurrentProxyIp);
|
|
}
|
|
|
|
if (!database.TryGetValue(key, out ProxyManagerModel val) || val.proxyip == null || !p.list.Contains(val.proxyip))
|
|
{
|
|
val = new ProxyManagerModel();
|
|
|
|
if (p.actions != null && p.actions.Count > 0)
|
|
{
|
|
val.proxyip = p.list.First();
|
|
start_action(p, key, val.proxyip);
|
|
}
|
|
else
|
|
{
|
|
val.proxyip = p.list.OrderBy(a => Guid.NewGuid()).First();
|
|
database.AddOrUpdate(key, val, (k, v) => val);
|
|
}
|
|
}
|
|
|
|
return ConfigureWebProxy(p, val.proxyip);
|
|
}
|
|
#endregion
|
|
|
|
if (IsKitConf)
|
|
{
|
|
return proxy(conf.proxy, null);
|
|
}
|
|
else if (conf.proxy?.list != null && conf.proxy.list.Length > 0 || !string.IsNullOrEmpty(conf.proxy?.file) || !string.IsNullOrEmpty(conf.proxy?.url))
|
|
{
|
|
return proxy(conf.proxy, $"{plugin}:conf");
|
|
}
|
|
else
|
|
{
|
|
if (!string.IsNullOrEmpty(conf.globalnameproxy))
|
|
{
|
|
string _globalnameproxy = conf.globalnameproxy;
|
|
return proxy(AppInit.conf.globalproxy.FirstOrDefault(i => i.name == _globalnameproxy), $"{plugin}:globalname");
|
|
}
|
|
else
|
|
{
|
|
return proxy(AppInit.conf.proxy, $"{plugin}:conf");
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Refresh
|
|
public void Refresh()
|
|
{
|
|
if (!refresh || IsKitConf)
|
|
return;
|
|
|
|
if (rch != null && rch.enable)
|
|
return;
|
|
|
|
void update(ProxySettings p, string key)
|
|
{
|
|
if (database.TryGetValue(key, out ProxyManagerModel val))
|
|
{
|
|
int maxRequestError = 2;
|
|
if (p?.maxRequestError > 0)
|
|
maxRequestError = p.maxRequestError;
|
|
|
|
if (val.errors >= maxRequestError)
|
|
{
|
|
if (!string.IsNullOrEmpty(p?.refresh_uri))
|
|
_ = Http.Get(p.refresh_uri, timeoutSeconds: 5).ConfigureAwait(false);
|
|
|
|
if (p?.actions != null && p.actions.Count > 0)
|
|
{
|
|
val.errors = 0;
|
|
start_action(ConfigureProxy(p), key);
|
|
return;
|
|
}
|
|
|
|
val.errors = 0;
|
|
val.proxyip = null;
|
|
database.TryRemove(key, out _);
|
|
}
|
|
else
|
|
{
|
|
val.errors += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
update(AppInit.conf.proxy, plugin);
|
|
|
|
if (conf == null)
|
|
return;
|
|
|
|
update(conf.proxy, $"{plugin}:conf");
|
|
string _globalnameproxy = conf.globalnameproxy;
|
|
update(AppInit.conf.globalproxy.FirstOrDefault(i => i.name == _globalnameproxy), $"{plugin}:globalname");
|
|
}
|
|
#endregion
|
|
|
|
#region Success
|
|
public void Success()
|
|
{
|
|
if (IsKitConf)
|
|
return;
|
|
|
|
if (rch != null && rch.enable)
|
|
return;
|
|
|
|
foreach (string key in proxyKeys)
|
|
{
|
|
if (database.TryGetValue(key, out var val) && val.errors > 0)
|
|
val.errors = 0;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region CurrentProxyIp
|
|
public string CurrentProxyIp
|
|
{
|
|
get
|
|
{
|
|
if (IsKitConf)
|
|
return KitCurrentProxyIp;
|
|
|
|
foreach (string key in proxyKeys)
|
|
{
|
|
if (database.TryGetValue(key, out var val))
|
|
return val.proxyip;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
|
|
|
|
ProxySettings ConfigureProxy(ProxySettings orig)
|
|
{
|
|
if (orig == null)
|
|
return null;
|
|
|
|
ProxySettings p = (ProxySettings)orig.Clone();
|
|
|
|
if (!IsKitConf)
|
|
{
|
|
if (!string.IsNullOrEmpty(p.file) && File.Exists(p.file))
|
|
p.list = File.ReadAllLines(p.file);
|
|
|
|
if (!string.IsNullOrEmpty(p.url))
|
|
{
|
|
string mkey = $"ProxyManager:{p.url}";
|
|
if (!memoryCache.TryGetValue(mkey, out List<string> list))
|
|
{
|
|
list = new List<string>();
|
|
|
|
string txt = Http.Get(p.url, timeoutSeconds: 5).Result;
|
|
if (txt != null)
|
|
{
|
|
foreach (string line in txt.Split("\n"))
|
|
{
|
|
if (line.Contains(":"))
|
|
list.Add(line.Trim());
|
|
}
|
|
}
|
|
|
|
memoryCache.Set(mkey, list, DateTime.Now.AddMinutes(15));
|
|
}
|
|
|
|
p.list = list.ToArray();
|
|
}
|
|
}
|
|
|
|
return p;
|
|
}
|
|
|
|
|
|
public static (WebProxy proxy, (string ip, string username, string password) data) ConfigureWebProxy(ProxySettings p, string proxyip)
|
|
{
|
|
if (p == null)
|
|
return default;
|
|
|
|
NetworkCredential credentials = null;
|
|
|
|
if (proxyip.Contains("@"))
|
|
{
|
|
var g = Regex.Match(proxyip, p.pattern_auth).Groups;
|
|
proxyip = g["sheme"].Value + g["host"].Value;
|
|
credentials = new NetworkCredential(g["username"].Value, g["password"].Value);
|
|
}
|
|
else if (p.useAuth)
|
|
credentials = new NetworkCredential(p.username, p.password);
|
|
|
|
var proxy = new WebProxy(proxyip, p.BypassOnLocal, null, credentials);
|
|
return (proxy, (proxyip, credentials?.UserName, credentials?.Password));
|
|
}
|
|
|
|
|
|
void start_action(ProxySettings p, string key, string current_proxyip = null)
|
|
{
|
|
if (p == null || IsKitConf)
|
|
return;
|
|
|
|
string mkey = $"ProxyManager:start_action:{key}";
|
|
if (memoryCache.TryGetValue(mkey, out _))
|
|
return;
|
|
|
|
memoryCache.Set(mkey, 0, DateTime.Now.AddMinutes(10));
|
|
|
|
ThreadPool.QueueUserWorkItem(async _ =>
|
|
{
|
|
try
|
|
{
|
|
string proxyip = null;
|
|
var list = p.list.OrderBy(a => Guid.NewGuid()).ToList();
|
|
|
|
if (!string.IsNullOrEmpty(current_proxyip))
|
|
{
|
|
if (list.Contains(current_proxyip))
|
|
{
|
|
list.Remove(current_proxyip);
|
|
list.Insert(0, current_proxyip);
|
|
}
|
|
}
|
|
|
|
foreach (string proxy in list.Take(p.actions_attempts))
|
|
{
|
|
bool isok = true;
|
|
proxyip = proxy;
|
|
|
|
foreach (var action in p.actions)
|
|
{
|
|
string result = string.Empty;
|
|
|
|
if (!string.IsNullOrEmpty(action.data))
|
|
result = await Http.Post(action.url, action.data, httpversion: 2, timeoutSeconds: action.timeoutSeconds, proxy: ConfigureWebProxy(p, proxy).proxy);
|
|
else
|
|
result = await Http.Get(action.url, httpversion: 2, timeoutSeconds: action.timeoutSeconds, proxy: ConfigureWebProxy(p, proxy).proxy);
|
|
|
|
if (result == null || !result.Contains(action.contains))
|
|
{
|
|
isok = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (isok)
|
|
break;
|
|
}
|
|
|
|
var val = new ProxyManagerModel();
|
|
val.proxyip = proxyip;
|
|
database.AddOrUpdate(key, val, (k, v) => val);
|
|
}
|
|
catch { }
|
|
finally
|
|
{
|
|
memoryCache.Remove(mkey);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|