allow proxy changes without restart

This commit is contained in:
kaso17
2017-11-17 16:46:58 +01:00
parent 01dec12909
commit 59388a8f80
6 changed files with 177 additions and 94 deletions

View File

@@ -9,10 +9,14 @@ using System.Threading.Tasks;
namespace Jackett.Models.Config namespace Jackett.Models.Config
{ {
public class ServerConfig public class ServerConfig : IObservable<ServerConfig>
{ {
[JsonIgnore]
protected List<IObserver<ServerConfig>> observers;
public ServerConfig(RuntimeSettings runtimeSettings) public ServerConfig(RuntimeSettings runtimeSettings)
{ {
observers = new List<IObserver<ServerConfig>>();
Port = 9117; Port = 9117;
AllowExternal = System.Environment.OSVersion.Platform == PlatformID.Unix; AllowExternal = System.Environment.OSVersion.Platform == PlatformID.Unix;
RuntimeSettings = runtimeSettings; RuntimeSettings = runtimeSettings;
@@ -109,5 +113,42 @@ namespace Jackett.Models.Config
}; };
} }
} }
public IDisposable Subscribe(IObserver<ServerConfig> observer)
{
if (!observers.Contains(observer))
{
observers.Add(observer);
}
return new UnSubscriber(observers, observer);
}
private class UnSubscriber : IDisposable
{
private List<IObserver<ServerConfig>> lstObservers;
private IObserver<ServerConfig> observer;
public UnSubscriber(List<IObserver<ServerConfig>> ObserversCollection, IObserver<ServerConfig> observer)
{
this.lstObservers = ObserversCollection;
this.observer = observer;
}
public void Dispose()
{
if (this.observer != null)
{
lstObservers.Remove(this.observer);
}
}
}
public void ConfigChanged()
{
foreach (var obs in observers)
{
obs.OnNext(this);
}
}
} }
} }

View File

@@ -136,6 +136,7 @@ namespace Jackett.Common.Plumbing
config.InstanceId = StringUtil.GenerateRandom(64); config.InstanceId = StringUtil.GenerateRandom(64);
configService.SaveConfig(config); configService.SaveConfig(config);
} }
config.ConfigChanged();
return config; return config;
} }

View File

@@ -21,32 +21,54 @@ namespace Jackett.Utils.Clients
public class HttpWebClient : WebClient public class HttpWebClient : WebClient
{ {
static protected Dictionary<string, ICollection<string>> trustedCertificates = new Dictionary<string, ICollection<string>>(); static protected Dictionary<string, ICollection<string>> trustedCertificates = new Dictionary<string, ICollection<string>>();
static protected SocksWebProxy socksWebProxy; static protected string webProxyUrl;
static protected IWebProxy webProxy;
static public void InitSocksWebProxy(ServerConfig serverConfig) static public void InitProxy(ServerConfig serverConfig)
{ {
if (socksWebProxy != null) // dispose old SocksWebProxy
if (webProxy != null && webProxy is SocksWebProxy)
{ {
socksWebProxy.Dispose(); ((SocksWebProxy)webProxy).Dispose();
webProxy = null;
} }
if (serverConfig.ProxyType != ProxyType.Http) webProxyUrl = serverConfig.GetProxyUrl();
if (!string.IsNullOrWhiteSpace(webProxyUrl))
{ {
var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result; if (serverConfig.ProxyType != ProxyType.Http)
var socksConfig = new ProxyConfig
{ {
SocksAddress = addresses.FirstOrDefault(), var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result;
Username = serverConfig.ProxyUsername, var socksConfig = new ProxyConfig
Password = serverConfig.ProxyPassword, {
Version = serverConfig.ProxyType == ProxyType.Socks4 ? SocksAddress = addresses.FirstOrDefault(),
ProxyConfig.SocksVersion.Four : Username = serverConfig.ProxyUsername,
ProxyConfig.SocksVersion.Five Password = serverConfig.ProxyPassword,
}; Version = serverConfig.ProxyType == ProxyType.Socks4 ?
if (serverConfig.ProxyPort.HasValue) ProxyConfig.SocksVersion.Four :
{ ProxyConfig.SocksVersion.Five
socksConfig.SocksPort = serverConfig.ProxyPort.Value; };
if (serverConfig.ProxyPort.HasValue)
{
socksConfig.SocksPort = serverConfig.ProxyPort.Value;
}
webProxy = new SocksWebProxy(socksConfig, false);
}
else
{
NetworkCredential creds = null;
if (!serverConfig.ProxyIsAnonymous)
{
var username = serverConfig.ProxyUsername;
var password = serverConfig.ProxyPassword;
creds = new NetworkCredential(username, password);
}
webProxy = new WebProxy(webProxyUrl)
{
BypassProxyOnLocal = false,
Credentials = creds
};
} }
socksWebProxy = new SocksWebProxy(socksConfig, false);
} }
} }
@@ -56,8 +78,16 @@ namespace Jackett.Utils.Clients
c: c, c: c,
sc: sc) sc: sc)
{ {
if (socksWebProxy == null) if (webProxyUrl == null)
InitSocksWebProxy(sc); InitProxy(sc);
}
// Called everytime the ServerConfig changes
public override void OnNext(ServerConfig value)
{
var newProxyUrl = serverConfig.GetProxyUrl();
if (webProxyUrl != newProxyUrl) // if proxy URL changed
InitProxy(serverConfig);
} }
override public void Init() override public void Init()
@@ -112,42 +142,16 @@ namespace Jackett.Utils.Clients
} }
} }
} }
var useProxy = false;
using (ClearanceHandler clearanceHandlr = new ClearanceHandler()) using (ClearanceHandler clearanceHandlr = new ClearanceHandler())
{ {
IWebProxy proxyServer = null;
var proxyUrl = serverConfig.GetProxyUrl();
if (!string.IsNullOrWhiteSpace(proxyUrl))
{
useProxy = true;
if (serverConfig.ProxyType != ProxyType.Http)
{
proxyServer = socksWebProxy;
}
else
{
NetworkCredential creds = null;
if (!serverConfig.ProxyIsAnonymous)
{
var username = serverConfig.ProxyUsername;
var password = serverConfig.ProxyPassword;
creds = new NetworkCredential(username, password);
}
proxyServer = new WebProxy(proxyUrl)
{
BypassProxyOnLocal = false,
Credentials = creds
};
}
}
using (HttpClientHandler clientHandlr = new HttpClientHandler using (HttpClientHandler clientHandlr = new HttpClientHandler
{ {
CookieContainer = cookies, CookieContainer = cookies,
AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more.
UseCookies = true, UseCookies = true,
Proxy = proxyServer, Proxy = webProxy,
UseProxy = useProxy, UseProxy = (webProxy != null),
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
}) })
{ {

View File

@@ -33,54 +33,38 @@ namespace Jackett.Utils.Clients
HttpClient client; HttpClient client;
static protected Dictionary<string, ICollection<string>> trustedCertificates = new Dictionary<string, ICollection<string>>(); static protected Dictionary<string, ICollection<string>> trustedCertificates = new Dictionary<string, ICollection<string>>();
static protected SocksWebProxy socksWebProxy; static protected string webProxyUrl;
static protected IWebProxy webProxy;
static public void InitSocksWebProxy(ServerConfig serverConfig) static public void InitProxy(ServerConfig serverConfig)
{ {
if (socksWebProxy != null) // dispose old SocksWebProxy
if (webProxy != null && webProxy is SocksWebProxy)
{ {
socksWebProxy.Dispose(); ((SocksWebProxy)webProxy).Dispose();
webProxy = null;
} }
if (serverConfig.ProxyType != ProxyType.Http) webProxyUrl = serverConfig.GetProxyUrl();
if (!string.IsNullOrWhiteSpace(webProxyUrl))
{ {
var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result;
var socksConfig = new ProxyConfig
{
SocksAddress = addresses.FirstOrDefault(),
Username = serverConfig.ProxyUsername,
Password = serverConfig.ProxyPassword,
Version = serverConfig.ProxyType == ProxyType.Socks4 ?
ProxyConfig.SocksVersion.Four :
ProxyConfig.SocksVersion.Five
};
if (serverConfig.ProxyPort.HasValue)
{
socksConfig.SocksPort = serverConfig.ProxyPort.Value;
}
socksWebProxy = new SocksWebProxy(socksConfig, false);
}
}
public HttpWebClient2(IProcessService p, Logger l, IConfigurationService c, ServerConfig sc)
: base(p: p,
l: l,
c: c,
sc: sc)
{
if (socksWebProxy == null)
InitSocksWebProxy(sc);
cookies = new CookieContainer();
var useProxy = false;
IWebProxy proxyServer = null;
var proxyUrl = serverConfig.GetProxyUrl();
if (!string.IsNullOrWhiteSpace(proxyUrl))
{
useProxy = true;
if (serverConfig.ProxyType != ProxyType.Http) if (serverConfig.ProxyType != ProxyType.Http)
{ {
proxyServer = socksWebProxy; var addresses = Dns.GetHostAddressesAsync(serverConfig.ProxyUrl).Result;
var socksConfig = new ProxyConfig
{
SocksAddress = addresses.FirstOrDefault(),
Username = serverConfig.ProxyUsername,
Password = serverConfig.ProxyPassword,
Version = serverConfig.ProxyType == ProxyType.Socks4 ?
ProxyConfig.SocksVersion.Four :
ProxyConfig.SocksVersion.Five
};
if (serverConfig.ProxyPort.HasValue)
{
socksConfig.SocksPort = serverConfig.ProxyPort.Value;
}
webProxy = new SocksWebProxy(socksConfig, false);
} }
else else
{ {
@@ -91,22 +75,38 @@ namespace Jackett.Utils.Clients
var password = serverConfig.ProxyPassword; var password = serverConfig.ProxyPassword;
creds = new NetworkCredential(username, password); creds = new NetworkCredential(username, password);
} }
proxyServer = new WebProxy(proxyUrl) webProxy = new WebProxy(webProxyUrl)
{ {
BypassProxyOnLocal = false, BypassProxyOnLocal = false,
Credentials = creds Credentials = creds
}; };
} }
} }
}
public HttpWebClient2(IProcessService p, Logger l, IConfigurationService c, ServerConfig sc)
: base(p: p,
l: l,
c: c,
sc: sc)
{
if (webProxyUrl == null)
InitProxy(sc);
cookies = new CookieContainer();
CreateClient();
}
public void CreateClient()
{
clearanceHandlr = new ClearanceHandler(); clearanceHandlr = new ClearanceHandler();
clientHandlr = new HttpClientHandler clientHandlr = new HttpClientHandler
{ {
CookieContainer = cookies, CookieContainer = cookies,
AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more.
UseCookies = true, UseCookies = true,
Proxy = proxyServer, Proxy = webProxy,
UseProxy = useProxy, UseProxy = (webProxy != null),
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
}; };
@@ -114,6 +114,20 @@ namespace Jackett.Utils.Clients
client = new HttpClient(clearanceHandlr); client = new HttpClient(clearanceHandlr);
} }
// Called everytime the ServerConfig changes
public override void OnNext(ServerConfig value)
{
var newProxyUrl = serverConfig.GetProxyUrl();
if (webProxyUrl != newProxyUrl) // if proxy URL changed
InitProxy(serverConfig);
// recreate client if needed (can't just change the proxy attribute)
if (!ReferenceEquals(clientHandlr.Proxy, webProxy))
{
CreateClient();
}
}
override public void Init() override public void Init()
{ {
if (serverConfig.RuntimeSettings.IgnoreSslErrors == true) if (serverConfig.RuntimeSettings.IgnoreSslErrors == true)

View File

@@ -13,8 +13,9 @@ using Jackett.Models.Config;
namespace Jackett.Utils.Clients namespace Jackett.Utils.Clients
{ {
public abstract class WebClient public abstract class WebClient : IObserver<ServerConfig>
{ {
protected IDisposable ServerConfigUnsubscriber;
protected Logger logger; protected Logger logger;
protected IConfigurationService configService; protected IConfigurationService configService;
protected readonly ServerConfig serverConfig; protected readonly ServerConfig serverConfig;
@@ -32,6 +33,10 @@ namespace Jackett.Utils.Clients
} }
} }
virtual protected void OnConfigChange()
{
}
virtual public void AddTrustedCertificate(string host, string hash) virtual public void AddTrustedCertificate(string host, string hash)
{ {
// not implemented by default // not implemented by default
@@ -44,6 +49,7 @@ namespace Jackett.Utils.Clients
configService = c; configService = c;
serverConfig = sc; serverConfig = sc;
ClientType = GetType().Name; ClientType = GetType().Name;
ServerConfigUnsubscriber = serverConfig.Subscribe(this);
} }
async protected Task DelayRequest(WebRequest request) async protected Task DelayRequest(WebRequest request)
@@ -165,5 +171,20 @@ namespace Jackett.Utils.Clients
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously #pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
abstract public void Init(); abstract public void Init();
public virtual void OnCompleted()
{
throw new NotImplementedException();
}
public virtual void OnError(Exception error)
{
throw new NotImplementedException();
}
public virtual void OnNext(ServerConfig value)
{
// nothing by default
}
} }
} }

View File

@@ -187,6 +187,8 @@ namespace Jackett.Controllers.V20
serverConfig.BlackholeDir = saveDir; serverConfig.BlackholeDir = saveDir;
configService.SaveConfig(serverConfig); configService.SaveConfig(serverConfig);
} }
serverConfig.ConfigChanged();
} }
[HttpGet] [HttpGet]
@@ -195,6 +197,6 @@ namespace Jackett.Controllers.V20
return logCache.Logs; return logCache.Logs;
} }
} }
} }