diff --git a/ppf.py b/ppf.py index dddb66e..98d1f1c 100644 --- a/ppf.py +++ b/ppf.py @@ -14,6 +14,7 @@ import sys from soup_parser import set_nobs import threading import random +import os # Global profiler for signal handler access _profiler = None @@ -32,6 +33,68 @@ signal.signal(signal.SIGTERM, sigterm_handler) config = Config() +def reset_state(): + """Clear all proxy and session state for a fresh start. + + Clears: + - proxylist table (all proxies) + - session_state table (test counters) + - stats_history table (historical stats) + - scraper_state.json (engine backoffs) + - mitm_certs.json (MITM cert tracking) + """ + db_path = config.watchd.database + data_dir = os.path.dirname(db_path) or 'data' + + # Clear database tables + try: + db = mysqlite.mysqlite(db_path, str) + dbs.create_table_if_not_exists(db, 'proxylist') + + db.execute('DELETE FROM proxylist') + db.commit() + _log('cleared proxylist table', 'reset') + + # Clear session_state if exists + try: + db.execute('DELETE FROM session_state') + db.commit() + _log('cleared session_state table', 'reset') + except Exception: + pass + + # Clear stats_history if exists + try: + db.execute('DELETE FROM stats_history') + db.commit() + _log('cleared stats_history table', 'reset') + except Exception: + pass + + db.execute('VACUUM') + db.commit() + db.close() + except Exception as e: + _log('database reset failed: %s' % e, 'error') + return False + + # Remove state files + state_files = [ + os.path.join(data_dir, 'scraper_state.json'), + os.path.join(data_dir, 'mitm_certs.json'), + ] + for f in state_files: + if os.path.exists(f): + try: + os.remove(f) + _log('removed %s' % f, 'reset') + except Exception as e: + _log('failed to remove %s: %s' % (f, e), 'error') + + _log('state reset complete', 'reset') + return True + + def format_duration(seconds): """Format seconds into compact human-readable duration.""" if seconds < 60: @@ -208,6 +271,14 @@ def main(): """Main entry point.""" global config + # Handle --reset flag before connecting to databases + if len(sys.argv) == 2 and sys.argv[1] == "--reset": + if reset_state(): + _log('use without --reset to start fresh', 'reset') + sys.exit(0) + else: + sys.exit(1) + proxydb = mysqlite.mysqlite(config.watchd.database, str) dbs.create_table_if_not_exists(proxydb, 'proxylist') fetch.init_known_proxies(proxydb)