Voxxium commited on
Commit
ffa51e6
·
verified ·
1 Parent(s): 9a19bb3

Create proxy_pool.py

Browse files
Files changed (1) hide show
  1. proxy_pool.py +158 -0
proxy_pool.py ADDED
@@ -0,0 +1,158 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Proxy Pool
3
+ """
4
+
5
+ import random
6
+ import threading
7
+ import time
8
+ from collections import defaultdict
9
+
10
+
11
+ class ProxyEntry:
12
+ __slots__ = (
13
+ 'proxy', 'protocol', 'proxy_url', 'latency',
14
+ 'proxy_ip', 'verified', 'fail_count', 'total_used',
15
+ )
16
+
17
+ def __init__(self, proxy, protocol, proxy_url,
18
+ latency, proxy_ip, verified):
19
+ self.proxy = proxy
20
+ self.protocol = protocol
21
+ self.proxy_url = proxy_url
22
+ self.latency = latency
23
+ self.proxy_ip = proxy_ip
24
+ self.verified = verified
25
+ self.fail_count = 0
26
+ self.total_used = 0
27
+
28
+ def to_dict(self):
29
+ return {
30
+ "proxy": self.proxy,
31
+ "protocol": self.protocol,
32
+ "proxy_url": self.proxy_url,
33
+ "latency": self.latency,
34
+ "proxy_ip": self.proxy_ip,
35
+ "verified": self.verified,
36
+ "total_used": self.total_used,
37
+ }
38
+
39
+
40
+ class ProxyPool:
41
+ def __init__(self):
42
+ self._px = []
43
+ self._um = {}
44
+ self._lk = threading.Lock()
45
+ self._rr = defaultdict(int)
46
+ self._lr = 0.0
47
+ self._rc = 0
48
+
49
+ def refresh(self, new_proxies):
50
+ with self._lk:
51
+ old = dict(self._um)
52
+ fresh, um = [], {}
53
+ for px in new_proxies:
54
+ e = ProxyEntry(
55
+ px["proxy"], px["protocol"],
56
+ px["proxy_url"], px["latency"],
57
+ px.get("proxy_ip", ""),
58
+ px.get("verified", False),
59
+ )
60
+ o = old.get(e.proxy_url)
61
+ if o:
62
+ e.total_used = o.total_used
63
+ e.fail_count = max(0, o.fail_count - 1)
64
+ fresh.append(e)
65
+ um[e.proxy_url] = e
66
+ fresh.sort(key=lambda x: x.latency)
67
+ self._px = fresh
68
+ self._um = um
69
+ self._lr = time.time()
70
+ self._rc += 1
71
+
72
+ def clear(self):
73
+ with self._lk:
74
+ self._px = []
75
+ self._um = {}
76
+
77
+ @property
78
+ def size(self):
79
+ return len(self._px)
80
+
81
+ def _alive(self, protocol=None, verified=False):
82
+ r = [p for p in self._px if p.fail_count < 3]
83
+ if protocol:
84
+ r = [p for p in r if p.protocol == protocol]
85
+ if verified:
86
+ r = [p for p in r if p.verified]
87
+ return r
88
+
89
+ def get_round_robin(self, protocol=None, verified=False):
90
+ with self._lk:
91
+ a = self._alive(protocol, verified)
92
+ if not a:
93
+ return None
94
+ k = f"{protocol}_{verified}"
95
+ i = self._rr[k] % len(a)
96
+ self._rr[k] = i + 1
97
+ a[i].total_used += 1
98
+ return a[i]
99
+
100
+ def get_random(self, protocol=None, verified=False):
101
+ with self._lk:
102
+ a = self._alive(protocol, verified)
103
+ if not a:
104
+ return None
105
+ p = random.choice(a)
106
+ p.total_used += 1
107
+ return p
108
+
109
+ def get_fastest(self, protocol=None, verified=False):
110
+ with self._lk:
111
+ a = self._alive(protocol, verified)
112
+ if not a:
113
+ return None
114
+ a[0].total_used += 1
115
+ return a[0]
116
+
117
+ def get_least_used(self, protocol=None, verified=False):
118
+ with self._lk:
119
+ a = self._alive(protocol, verified)
120
+ if not a:
121
+ return None
122
+ p = min(a, key=lambda x: x.total_used)
123
+ p.total_used += 1
124
+ return p
125
+
126
+ def report_failure(self, url):
127
+ with self._lk:
128
+ p = self._um.get(url)
129
+ if p:
130
+ p.fail_count += 1
131
+
132
+ def report_success(self, url):
133
+ with self._lk:
134
+ p = self._um.get(url)
135
+ if p:
136
+ p.fail_count = 0
137
+
138
+ def get_all(self, protocol=None, verified=False, limit=500):
139
+ with self._lk:
140
+ return [p.to_dict() for p in self._alive(protocol, verified)[:limit]]
141
+
142
+ def get_stats(self):
143
+ with self._lk:
144
+ bp = defaultdict(lambda: {"total": 0, "alive": 0})
145
+ for p in self._px:
146
+ bp[p.protocol]["total"] += 1
147
+ if p.fail_count < 3:
148
+ bp[p.protocol]["alive"] += 1
149
+ alive = sum(d["alive"] for d in bp.values())
150
+ return {
151
+ "total": len(self._px),
152
+ "alive": alive,
153
+ "by_protocol": dict(bp),
154
+ "refresh_count": self._rc,
155
+ "last_refresh_ago": round(
156
+ time.time() - self._lr, 1
157
+ ) if self._lr else None,
158
+ }