using System; using System.Collections.Generic; using System.Linq; using System.Threading; namespace RuriLib.Models { /// /// Class that manages a pool of proxies. /// public class ProxyPool { private static Random rng = new Random(); /// The full list of proxies in the pool. public List Proxies { get; } = new List(); /// The list of Alive proxies (AVAILABLE or BUSY). public List Alive { get { return Proxies.Where(p => p.Status == Status.AVAILABLE || p.Status == Status.BUSY).ToList(); } } /// The list of Available proxies. public List Available { get { return Proxies.Where(p => p.Status == Status.AVAILABLE).ToList(); } } /// The list of Banned proxies. public List Banned { get { return Proxies.Where(p => p.Status == Status.BANNED).ToList(); } } /// The list of Bad proxies. public List Bad { get { return Proxies.Where(p => p.Status == Status.BAD).ToList(); } } /// /// Whether the proxy list is locked or not. /// It prevents multiple bots from choosing the same proxy simultaneously, regardless of the fact that concurrent usage may be disabled. /// private bool Locked { get; set; } = false; /// /// Initializes the proxy pool given a collection of string to be parsed as proxies and their type. /// /// The collection of strings to parse the proxies from /// The type of the proxies /// Whether to shuffle the proxy list public ProxyPool(IEnumerable proxies, Extreme.Net.ProxyType type, bool shuffle) { Proxies = proxies.Select(p => new CProxy(p, type)).ToList(); if (shuffle) Shuffle(Proxies); } /// /// Initializes the proxy pool given a collection of CProxy objects. /// The proxies will be first cloned and then stored in the list. /// They will also be unbanned to make sure there are no leftovers from previous checks. /// /// The list of CProxy objects to be cloned and added to the list /// Whether to shuffle the proxy list public ProxyPool(List proxies, bool shuffle = false) { // We clone the list, since we don't want to target to the same objects that are in the Proxy Manager // If we don't do this, a ban on a runner instance would cause a ban on all the other instances as well! Proxies = IOManager.CloneProxies(proxies); // Now that the list is cloned, we make sure that no proxy is already banned UnbanAll(); // Shuffle it if necessary if (shuffle) Shuffle(Proxies); } /// /// Clears the Clearance and Cfduid cookies set by Cloudflare. /// public void ClearCF() { foreach (var proxy in Proxies) { proxy.Clearance = ""; proxy.Cfduid = ""; } } /// /// Sets all the BANNED and BAD proxies status to AVAILABLE and resets their Uses. It also clears the Cloudflare cookies. /// public void UnbanAll() { foreach (var proxy in Proxies) { if (proxy.Status == Status.BANNED || proxy.Status == Status.BAD) { proxy.Status = Status.AVAILABLE; proxy.Hooked = 0; proxy.Uses = 0; } } ClearCF(); } /// /// Tries to return the first available proxy from the list. /// /// Whether to include proxies that are being used by other bots /// The maximum uses of a proxy, after which it will be banned (0 for infinite) /// Whether a proxy can ever be banned /// The first available proxy respecting the conditions or null public CProxy GetProxy(bool evenBusy, int maxUses, bool neverBan = false) { while (Locked) Thread.Sleep(10); CProxy proxy; Locked = true; if (evenBusy) { if (maxUses == 0) proxy = Alive.FirstOrDefault(); else proxy = Alive.Where(p => p.Uses < maxUses).FirstOrDefault(); } else { if (maxUses == 0) proxy = Available.FirstOrDefault(); else proxy = Available.Where(p => p.Uses < maxUses).FirstOrDefault(); } if (proxy != null) { if (maxUses > 0 && proxy.Uses > maxUses && !neverBan) { proxy.Status = Status.BANNED; Locked = false; return null; } else { proxy.Status = Status.BUSY; proxy.Hooked++; } } Locked = false; return proxy; } private static void Shuffle(IList list) { int n = list.Count; while (n > 1) { n--; int k = rng.Next(n + 1); T value = list[k]; list[k] = list[n]; list[n] = value; } } } }