diff --git a/src/Jackett.Common/Models/Config/ServerConfig.cs b/src/Jackett.Common/Models/Config/ServerConfig.cs index b49a9cd78..31937d1b1 100644 --- a/src/Jackett.Common/Models/Config/ServerConfig.cs +++ b/src/Jackett.Common/Models/Config/ServerConfig.cs @@ -9,10 +9,14 @@ using System.Threading.Tasks; namespace Jackett.Models.Config { - public class ServerConfig + public class ServerConfig : IObservable { + [JsonIgnore] + protected List> observers; + public ServerConfig(RuntimeSettings runtimeSettings) { + observers = new List>(); Port = 9117; AllowExternal = System.Environment.OSVersion.Platform == PlatformID.Unix; RuntimeSettings = runtimeSettings; @@ -109,5 +113,42 @@ namespace Jackett.Models.Config }; } } + + public IDisposable Subscribe(IObserver observer) + { + if (!observers.Contains(observer)) + { + observers.Add(observer); + } + return new UnSubscriber(observers, observer); + } + + private class UnSubscriber : IDisposable + { + private List> lstObservers; + private IObserver observer; + + public UnSubscriber(List> ObserversCollection, IObserver 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); + } + } } } diff --git a/src/Jackett.Common/Plumbing/JackettModule.cs b/src/Jackett.Common/Plumbing/JackettModule.cs index 5ce552485..e12e08411 100644 --- a/src/Jackett.Common/Plumbing/JackettModule.cs +++ b/src/Jackett.Common/Plumbing/JackettModule.cs @@ -136,6 +136,7 @@ namespace Jackett.Common.Plumbing config.InstanceId = StringUtil.GenerateRandom(64); configService.SaveConfig(config); } + config.ConfigChanged(); return config; } diff --git a/src/Jackett.Common/Utils/Clients/HttpWebClient.cs b/src/Jackett.Common/Utils/Clients/HttpWebClient.cs index 36e9efe0b..3bb59ddbe 100644 --- a/src/Jackett.Common/Utils/Clients/HttpWebClient.cs +++ b/src/Jackett.Common/Utils/Clients/HttpWebClient.cs @@ -21,32 +21,54 @@ namespace Jackett.Utils.Clients public class HttpWebClient : WebClient { static protected Dictionary> trustedCertificates = new Dictionary>(); - 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 + if (serverConfig.ProxyType != ProxyType.Http) { - 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; + 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 + { + 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, sc: sc) { - if (socksWebProxy == null) - InitSocksWebProxy(sc); + if (webProxyUrl == null) + 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() @@ -112,42 +142,16 @@ namespace Jackett.Utils.Clients } } } - var useProxy = false; 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 { CookieContainer = cookies, AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. UseCookies = true, - Proxy = proxyServer, - UseProxy = useProxy, + Proxy = webProxy, + UseProxy = (webProxy != null), AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }) { diff --git a/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs b/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs index b6e5e4a3f..a13472209 100644 --- a/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs +++ b/src/Jackett.Common/Utils/Clients/HttpWebClient2.cs @@ -33,54 +33,38 @@ namespace Jackett.Utils.Clients HttpClient client; static protected Dictionary> trustedCertificates = new Dictionary>(); - 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) { - 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 { @@ -91,22 +75,38 @@ namespace Jackett.Utils.Clients var password = serverConfig.ProxyPassword; creds = new NetworkCredential(username, password); } - proxyServer = new WebProxy(proxyUrl) + webProxy = new WebProxy(webProxyUrl) { BypassProxyOnLocal = false, 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(); clientHandlr = new HttpClientHandler { CookieContainer = cookies, AllowAutoRedirect = false, // Do not use this - Bugs ahoy! Lost cookies and more. UseCookies = true, - Proxy = proxyServer, - UseProxy = useProxy, + Proxy = webProxy, + UseProxy = (webProxy != null), AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }; @@ -114,6 +114,20 @@ namespace Jackett.Utils.Clients 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() { if (serverConfig.RuntimeSettings.IgnoreSslErrors == true) diff --git a/src/Jackett.Common/Utils/Clients/WebClient.cs b/src/Jackett.Common/Utils/Clients/WebClient.cs index 06f31e7ba..4cea36927 100644 --- a/src/Jackett.Common/Utils/Clients/WebClient.cs +++ b/src/Jackett.Common/Utils/Clients/WebClient.cs @@ -13,8 +13,9 @@ using Jackett.Models.Config; namespace Jackett.Utils.Clients { - public abstract class WebClient + public abstract class WebClient : IObserver { + protected IDisposable ServerConfigUnsubscriber; protected Logger logger; protected IConfigurationService configService; protected readonly ServerConfig serverConfig; @@ -32,6 +33,10 @@ namespace Jackett.Utils.Clients } } + virtual protected void OnConfigChange() + { + } + virtual public void AddTrustedCertificate(string host, string hash) { // not implemented by default @@ -44,6 +49,7 @@ namespace Jackett.Utils.Clients configService = c; serverConfig = sc; ClientType = GetType().Name; + ServerConfigUnsubscriber = serverConfig.Subscribe(this); } 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 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 + } } } diff --git a/src/Jackett/Controllers/ServerConfigurationController.cs b/src/Jackett/Controllers/ServerConfigurationController.cs index 9f82ed812..b03e9861a 100644 --- a/src/Jackett/Controllers/ServerConfigurationController.cs +++ b/src/Jackett/Controllers/ServerConfigurationController.cs @@ -187,6 +187,8 @@ namespace Jackett.Controllers.V20 serverConfig.BlackholeDir = saveDir; configService.SaveConfig(serverConfig); } + + serverConfig.ConfigChanged(); } [HttpGet] @@ -195,6 +197,6 @@ namespace Jackett.Controllers.V20 return logCache.Logs; } - + } }