- Add from __future__ import division for correct percentages
- Remove start_time restoration so uptime reflects current session
- Remove success_rate threshold for scaling (scale on queue depth only)
- Add DEAD_PROXY=-1 constant for permanently dead proxies
- Mark proxy dead when: failed >= max_fail*2, or max_fail with fatal error
- Fatal errors: refused, unreachable, auth (proxy definitely not working)
- Dead proxies excluded from testing (failed >= 0 query)
- Cleanup_stale also removes old dead proxies
- Dashboard shows separate dead vs failing counts
Major features:
- gevent monkey-patching for cooperative concurrency
- Stats class with latency percentiles, histograms, geo tracking
- session state persistence across restarts
- JudgeStats with cooldown for blocked/rate-limited judges
- ThreadScaler for dynamic greenlet pool sizing
- SIGHUP handler for config hot-reload
- SSL/TLS tracking with MITM detection
- anonymity detection (transparent/anonymous/elite)
Bug fixes:
- rwip(): fix string comparison (b[0] == '0' not == 0)
- rwip(): fix strip logic (b[1:] not b[:1])
- use string.ascii_letters for Py2/3 compatibility
- Stats class with failure category tracking
- Configurable stats_interval for periodic reports
- Optional httpd server startup when enabled
- cleanup_stale() for removing dead proxies
needs a new entry in proxies.sqlite
sqlite3 proxies.sqlite "alter table proxylist add consecutive_success int"
sqlite3 proxies.sqlite "update proxylist set consecutive_success=0"
Exception in thread Thread-9:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "proxywatchd.py", line 200, in workloop
job.run()
File "proxywatchd.py", line 123, in run
sock, proto, duration, tor, srv, failinc = self.connect_socket()
ValueError: need more than 5 values to unpack
Exception in thread Thread-8:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "proxywatchd.py", line 191, in workloop
job.run()
File "proxywatchd.py", line 114, in run
sock, proto, duration, tor, srv, failinc = self.connect_socket()
File "proxywatchd.py", line 76, in connect_socket
sock.send('%s\n' % random.choice(['NICK', 'USER', 'JOIN', 'MODE', 'PART', 'INVITE', 'KNOCK', 'WHOIS', 'WHO', 'NOTICE', 'PRIVMSG', 'PING', 'QUIT']))
File "rocksock.py", line 279, in send
return self.sock.sendall(buf)
File "/usr/lib/python2.7/ssl.py", line 741, in sendall
v = self.send(data[count:])
File "/usr/lib/python2.7/ssl.py", line 707, in send
v = self._sslobj.write(data)
error: [Errno 32] Broken pipe