bibibi12345 commited on
Commit
9426190
·
1 Parent(s): f43abc8

changed proxy pool

Browse files
Files changed (3) hide show
  1. docker-compose.yml +18 -0
  2. freeplay2api.py +39 -26
  3. proxy_pool.py +82 -60
docker-compose.yml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ freeplay2api:
5
+ build: .
6
+ ports:
7
+ - "7860:7860"
8
+ environment:
9
+ - API_KEY=sk-123456
10
+ volumes:
11
+ - ./data:/app/data
12
+ restart: unless-stopped
13
+ healthcheck:
14
+ test: ["CMD", "curl", "-f", "http://localhost:7860/v1/models"]
15
+ interval: 30s
16
+ timeout: 10s
17
+ retries: 3
18
+ start_period: 40s
freeplay2api.py CHANGED
@@ -159,6 +159,22 @@ class FreeplayClient:
159
 
160
  def register(self) -> Optional[Dict]:
161
  logging.info("REGISTER FUNCTION STARTED")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  url = "https://app.freeplay.ai/app_data/auth/signup"
163
  headers = {
164
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
@@ -201,24 +217,14 @@ class FreeplayClient:
201
  continue
202
 
203
  logging.info(f"ABOUT TO MAKE REQUEST WITH PROXY {proxy_info['full'] if proxy_info else 'None'}")
204
- try:
205
- response = requests.post(
206
- url,
207
- data=json.dumps(payload),
208
- headers=headers,
209
- proxies=proxies,
210
- timeout=20,
211
- )
212
- logging.info(f"REQUEST COMPLETED WITH STATUS {response.status_code}")
213
- except requests.exceptions.ProxyError as proxy_err:
214
- logging.warning(f"CAUGHT PROXY ERROR: {proxy_err}")
215
- if self.proxy_pool and proxy_info:
216
- self.proxy_pool.remove_proxy(proxy_info['ip'], proxy_info['port'])
217
- logging.info(f"CONTINUING AFTER INNER PROXY ERROR TO ATTEMPT {attempt + 1}")
218
- continue
219
- except Exception as inner_err:
220
- logging.error(f"CAUGHT OTHER ERROR IN REQUEST: {inner_err}")
221
- raise # Re-raise to be caught by outer handlers
222
 
223
  if response.status_code == 200:
224
  data = response.json()
@@ -237,10 +243,18 @@ class FreeplayClient:
237
  logging.warning(f"Registration attempt {attempt}/50 failed with status {response.status_code}: {response.text}")
238
  logging.info(f"CONTINUING TO NEXT ATTEMPT {attempt + 1}")
239
 
 
 
 
 
 
 
 
 
 
240
  except Exception as e:
241
- logging.error(f"An unexpected error occurred during registration on attempt {attempt}/50: {e}. Retrying...")
242
  logging.info(f"CONTINUING AFTER UNEXPECTED ERROR TO ATTEMPT {attempt + 1}")
243
- # Explicitly continue to next iteration
244
  continue
245
 
246
 
@@ -421,17 +435,16 @@ def initialize_app():
421
  default_config = {
422
  "HOST": "0.0.0.0",
423
  "PORT": 7860,
424
- "ACCOUNTS_FILE": "accounts.json",
425
  "LOW_BALANCE_THRESHOLD": 2.0,
426
  "ACTIVE_KEY_THRESHOLD": 5,
427
  "CHECK_INTERVAL_SECONDS": 5,
428
  "REGISTRATION_CONCURRENCY": 1,
429
  "USE_PROXY_POOL": True,
430
  "PROXY_POOL_CONFIG": {
431
- "target_count": 20,
432
- "min_threshold": 5,
433
- "check_interval": 30,
434
- "proxy_protocol": "https"
435
  }
436
  }
437
  try:
@@ -453,7 +466,7 @@ def initialize_app():
453
  proxy_pool_config = config.get("PROXY_POOL_CONFIG", {})
454
  logging.info(f"Proxy pool config being used: {proxy_pool_config}")
455
  proxy_pool = ProxyPool(proxy_pool_config)
456
- # The initialize method will now run in the background
457
  threading.Thread(target=proxy_pool.initialize, daemon=True).start()
458
  else:
459
  logging.info("Proxy pool is disabled in config.")
 
159
 
160
  def register(self) -> Optional[Dict]:
161
  logging.info("REGISTER FUNCTION STARTED")
162
+
163
+ # Wait for proxy pool to have at least one proxy before starting registration
164
+ if self.proxy_pool:
165
+ logging.info("Waiting for proxy pool to initialize...")
166
+ wait_time = 0
167
+ while self.proxy_pool.get_count() == 0 and wait_time < 60: # Wait up to 60 seconds
168
+ time.sleep(1)
169
+ wait_time += 1
170
+ if wait_time % 10 == 0: # Log every 10 seconds
171
+ logging.info(f"Still waiting for proxies... ({wait_time}s elapsed)")
172
+
173
+ if self.proxy_pool.get_count() > 0:
174
+ logging.info(f"Proxy pool ready with {self.proxy_pool.get_count()} proxies")
175
+ else:
176
+ logging.warning("Proxy pool initialization timed out, proceeding anyway")
177
+
178
  url = "https://app.freeplay.ai/app_data/auth/signup"
179
  headers = {
180
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36",
 
217
  continue
218
 
219
  logging.info(f"ABOUT TO MAKE REQUEST WITH PROXY {proxy_info['full'] if proxy_info else 'None'}")
220
+ response = requests.post(
221
+ url,
222
+ data=json.dumps(payload),
223
+ headers=headers,
224
+ proxies=proxies,
225
+ timeout=20,
226
+ )
227
+ logging.info(f"REQUEST COMPLETED WITH STATUS {response.status_code}")
 
 
 
 
 
 
 
 
 
 
228
 
229
  if response.status_code == 200:
230
  data = response.json()
 
243
  logging.warning(f"Registration attempt {attempt}/50 failed with status {response.status_code}: {response.text}")
244
  logging.info(f"CONTINUING TO NEXT ATTEMPT {attempt + 1}")
245
 
246
+ except requests.exceptions.ProxyError as e:
247
+ logging.warning(f"CAUGHT REQUESTS.EXCEPTIONS.PROXYERROR: {e}")
248
+ if self.proxy_pool and proxy_info:
249
+ logging.info(f"ABOUT TO REMOVE PROXY {proxy_info['ip']}:{proxy_info['port']}")
250
+ self.proxy_pool.remove_proxy(proxy_info['ip'], proxy_info['port'])
251
+ logging.info(f"PROXY REMOVAL COMPLETED")
252
+ logging.info(f"CONTINUING AFTER PROXY ERROR TO ATTEMPT {attempt + 1}")
253
+ continue
254
+
255
  except Exception as e:
256
+ logging.error(f"CAUGHT GENERIC EXCEPTION: {type(e).__name__}: {e}")
257
  logging.info(f"CONTINUING AFTER UNEXPECTED ERROR TO ATTEMPT {attempt + 1}")
 
258
  continue
259
 
260
 
 
435
  default_config = {
436
  "HOST": "0.0.0.0",
437
  "PORT": 7860,
438
+ "ACCOUNTS_FILE": "data/accounts.json",
439
  "LOW_BALANCE_THRESHOLD": 2.0,
440
  "ACTIVE_KEY_THRESHOLD": 5,
441
  "CHECK_INTERVAL_SECONDS": 5,
442
  "REGISTRATION_CONCURRENCY": 1,
443
  "USE_PROXY_POOL": True,
444
  "PROXY_POOL_CONFIG": {
445
+ "target_count": 10,
446
+ "min_threshold": 3,
447
+ "check_interval": 30
 
448
  }
449
  }
450
  try:
 
466
  proxy_pool_config = config.get("PROXY_POOL_CONFIG", {})
467
  logging.info(f"Proxy pool config being used: {proxy_pool_config}")
468
  proxy_pool = ProxyPool(proxy_pool_config)
469
+ # Initialize proxy pool asynchronously to avoid blocking app startup
470
  threading.Thread(target=proxy_pool.initialize, daemon=True).start()
471
  else:
472
  logging.info("Proxy pool is disabled in config.")
proxy_pool.py CHANGED
@@ -3,19 +3,17 @@ import threading
3
  import time
4
  import random
5
  from datetime import datetime, timedelta
 
6
 
7
  class ProxyPool:
8
  def __init__(self, options={}):
9
- self.target_count = options.get('target_count', 20)
10
- self.batch_size = options.get('batch_size', 20)
11
  self.test_timeout = options.get('test_timeout', 5)
12
  self.request_timeout = options.get('request_timeout', 5)
13
  self.target_url = options.get('target_url', 'https://app.freeplay.ai/')
14
- self.concurrent_requests = options.get('concurrent_requests', 10)
15
- self.min_threshold = options.get('min_threshold', 5)
16
  self.check_interval = options.get('check_interval', 30)
17
- self.proxy_protocol = options.get('proxy_protocol', 'http')
18
- self.max_refill_attempts = options.get('max_refill_attempts', 20)
19
  self.retry_delay = options.get('retry_delay', 1)
20
 
21
  self.available_proxies = []
@@ -45,7 +43,10 @@ class ProxyPool:
45
  with self.lock:
46
  if len(self.available_proxies) <= self.min_threshold and not self.is_refilling:
47
  print(f"Available proxies ({len(self.available_proxies)}) below threshold ({self.min_threshold}), starting refill")
48
- self.refill_proxies()
 
 
 
49
  if self.is_initialized:
50
  self.check_timer = threading.Timer(self.check_interval, self.check_and_refill)
51
  self.check_timer.start()
@@ -62,33 +63,26 @@ class ProxyPool:
62
  attempts += 1
63
  print(f"Refill attempt #{attempts}, current available: {len(self.available_proxies)}/{self.target_count}")
64
 
65
- remaining_needed = self.target_count - len(self.available_proxies)
66
- batch_size_needed = max(self.batch_size, remaining_needed * 2)
67
-
68
- proxies = self.get_proxies_from_provider(batch_size_needed)
69
- if not proxies:
70
- print(f"No proxies received, retrying in {self.retry_delay} seconds...")
71
  time.sleep(self.retry_delay)
72
  continue
73
 
74
- new_proxies = self.filter_existing_proxies(proxies)
75
- if not new_proxies:
76
- print("All fetched proxies already exist, getting new ones...")
77
  continue
78
 
79
- threads = []
80
- for proxy in new_proxies:
81
- thread = threading.Thread(target=self.test_and_add_proxy, args=(proxy,))
82
- threads.append(thread)
83
- thread.start()
84
 
85
- for thread in threads:
86
- thread.join()
87
-
88
  if len(self.available_proxies) >= self.target_count:
89
  break
90
- if len(self.available_proxies) < self.target_count:
91
- time.sleep(self.retry_delay)
 
92
  except Exception as e:
93
  print(f"Error during proxy refill: {e}")
94
  finally:
@@ -98,45 +92,65 @@ class ProxyPool:
98
  else:
99
  print(f"Max refill attempts reached, current available: {len(self.available_proxies)}/{self.target_count}")
100
 
101
- def test_and_add_proxy(self, proxy):
102
- if self.test_proxy(proxy):
103
- with self.lock:
104
- if not any(p['full'] == f"{self.proxy_protocol}://{proxy}" for p in self.available_proxies):
105
- ip, port = proxy.split(':')
106
- proxy_obj = {
107
- 'ip': ip,
108
- 'port': port,
109
- 'protocol': self.proxy_protocol,
110
- 'full': f"{self.proxy_protocol}://{proxy}",
111
- 'added_at': datetime.now().isoformat()
112
- }
113
- self.available_proxies.append(proxy_obj)
114
- print(f"Successfully added proxy: {proxy_obj['full']}, current available: {len(self.available_proxies)}/{self.target_count}")
115
-
116
- def filter_existing_proxies(self, proxies):
117
- existing = {f"{p['ip']}:{p['port']}" for p in self.available_proxies}
118
- return [p for p in proxies if p not in existing]
119
-
120
- def get_proxies_from_provider(self, count=None):
121
  try:
122
- request_count = count or self.batch_size
123
- url = f"https://proxy.scdn.io/api/get_proxy.php?protocol={self.proxy_protocol}&count={request_count}"
124
- print(f"Getting proxies from: {url}")
125
  response = requests.get(url, timeout=10)
126
  if response.status_code == 200:
127
- data = response.json()
128
- if data.get('code') == 200:
129
- print(f"Successfully got {data['data']['count']} proxies")
130
- return data['data']['proxies']
131
- print(f"Failed to get proxies. Status: {response.status_code}, Response: {response.text}")
132
- return []
133
  except Exception as e:
134
- print(f"Error getting proxies: {e}")
135
- return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  def test_proxy(self, proxy_url):
138
  try:
139
- proxies = {self.proxy_protocol: f"{self.proxy_protocol}://{proxy_url}"}
140
  headers = {
141
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
142
  }
@@ -145,7 +159,7 @@ class ProxyPool:
145
  if is_valid:
146
  print(f"Proxy {proxy_url} successfully tested, status: {response.status_code}")
147
  else:
148
- print(f"Proxy {proxy_url} failed test, status: {response.status_code}, headers: {response.headers}")
149
  return is_valid
150
  except Exception as e:
151
  print(f"Proxy {proxy_url} request error: {e}")
@@ -172,7 +186,15 @@ class ProxyPool:
172
  print(f"Removed proxy {ip}:{port}, current available: {len(self.available_proxies)}")
173
  else:
174
  print(f"Could not find proxy to remove {ip}:{port}")
175
- self.check_and_refill()
 
 
 
 
 
 
 
 
176
  return removed
177
 
178
  def get_all_proxies(self):
 
3
  import time
4
  import random
5
  from datetime import datetime, timedelta
6
+ from urllib.parse import urlparse
7
 
8
  class ProxyPool:
9
  def __init__(self, options={}):
10
+ self.target_count = options.get('target_count', 10) # Reduced since we get one at a time
 
11
  self.test_timeout = options.get('test_timeout', 5)
12
  self.request_timeout = options.get('request_timeout', 5)
13
  self.target_url = options.get('target_url', 'https://app.freeplay.ai/')
14
+ self.min_threshold = options.get('min_threshold', 3) # Reduced threshold
 
15
  self.check_interval = options.get('check_interval', 30)
16
+ self.max_refill_attempts = options.get('max_refill_attempts', 10)
 
17
  self.retry_delay = options.get('retry_delay', 1)
18
 
19
  self.available_proxies = []
 
43
  with self.lock:
44
  if len(self.available_proxies) <= self.min_threshold and not self.is_refilling:
45
  print(f"Available proxies ({len(self.available_proxies)}) below threshold ({self.min_threshold}), starting refill")
46
+ # Start refill in a separate thread to avoid blocking
47
+ refill_thread = threading.Thread(target=self.refill_proxies)
48
+ refill_thread.daemon = True
49
+ refill_thread.start()
50
  if self.is_initialized:
51
  self.check_timer = threading.Timer(self.check_interval, self.check_and_refill)
52
  self.check_timer.start()
 
63
  attempts += 1
64
  print(f"Refill attempt #{attempts}, current available: {len(self.available_proxies)}/{self.target_count}")
65
 
66
+ proxy_url = self.get_proxy_from_provider()
67
+ if not proxy_url:
68
+ print(f"No proxy received, retrying in {self.retry_delay} seconds...")
 
 
 
69
  time.sleep(self.retry_delay)
70
  continue
71
 
72
+ if self.is_proxy_duplicate(proxy_url):
73
+ print(f"Proxy {proxy_url} already exists, getting new one...")
 
74
  continue
75
 
76
+ if self.test_and_add_proxy(proxy_url):
77
+ print(f"Successfully added proxy, current available: {len(self.available_proxies)}/{self.target_count}")
78
+ else:
79
+ print(f"Proxy {proxy_url} failed test, trying next...")
 
80
 
 
 
 
81
  if len(self.available_proxies) >= self.target_count:
82
  break
83
+
84
+ time.sleep(0.5) # Small delay between requests
85
+
86
  except Exception as e:
87
  print(f"Error during proxy refill: {e}")
88
  finally:
 
92
  else:
93
  print(f"Max refill attempts reached, current available: {len(self.available_proxies)}/{self.target_count}")
94
 
95
+ def get_proxy_from_provider(self):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  try:
97
+ url = "https://proxy.doudouzi.me/random/us?host=us.proxy302.com"
98
+ print(f"Getting proxy from: {url}")
 
99
  response = requests.get(url, timeout=10)
100
  if response.status_code == 200:
101
+ proxy_url = response.text.strip()
102
+ print(f"Successfully got proxy: {proxy_url}")
103
+ return proxy_url
104
+ print(f"Failed to get proxy. Status: {response.status_code}, Response: {response.text}")
105
+ return None
 
106
  except Exception as e:
107
+ print(f"Error getting proxy: {e}")
108
+ return None
109
+
110
+ def parse_proxy_url(self, proxy_url):
111
+ """Parse proxy URL like http://username:password@host:port"""
112
+ try:
113
+ parsed = urlparse(proxy_url)
114
+ return {
115
+ 'protocol': parsed.scheme,
116
+ 'username': parsed.username,
117
+ 'password': parsed.password,
118
+ 'host': parsed.hostname,
119
+ 'port': str(parsed.port),
120
+ 'full': proxy_url
121
+ }
122
+ except Exception as e:
123
+ print(f"Error parsing proxy URL {proxy_url}: {e}")
124
+ return None
125
+
126
+ def is_proxy_duplicate(self, proxy_url):
127
+ """Check if proxy already exists in the pool"""
128
+ # Note: This method assumes the caller already holds self.lock
129
+ return any(p['full'] == proxy_url for p in self.available_proxies)
130
+
131
+ def test_and_add_proxy(self, proxy_url):
132
+ if self.test_proxy(proxy_url):
133
+ with self.lock:
134
+ if not self.is_proxy_duplicate(proxy_url):
135
+ parsed = self.parse_proxy_url(proxy_url)
136
+ if parsed:
137
+ proxy_obj = {
138
+ 'ip': parsed['host'],
139
+ 'port': parsed['port'],
140
+ 'protocol': parsed['protocol'],
141
+ 'username': parsed['username'],
142
+ 'password': parsed['password'],
143
+ 'full': parsed['full'],
144
+ 'added_at': datetime.now().isoformat()
145
+ }
146
+ self.available_proxies.append(proxy_obj)
147
+ print(f"Successfully added proxy: {parsed['host']}:{parsed['port']}")
148
+ return True
149
+ return False
150
 
151
  def test_proxy(self, proxy_url):
152
  try:
153
+ proxies = {'http': proxy_url, 'https': proxy_url}
154
  headers = {
155
  'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
156
  }
 
159
  if is_valid:
160
  print(f"Proxy {proxy_url} successfully tested, status: {response.status_code}")
161
  else:
162
+ print(f"Proxy {proxy_url} failed test, status: {response.status_code}")
163
  return is_valid
164
  except Exception as e:
165
  print(f"Proxy {proxy_url} request error: {e}")
 
186
  print(f"Removed proxy {ip}:{port}, current available: {len(self.available_proxies)}")
187
  else:
188
  print(f"Could not find proxy to remove {ip}:{port}")
189
+
190
+ # Check if we need to refill asynchronously to avoid blocking the caller
191
+ if len(self.available_proxies) <= self.min_threshold and not self.is_refilling:
192
+ print(f"Available proxies ({len(self.available_proxies)}) below threshold ({self.min_threshold}), starting async refill")
193
+ # Start refill in a separate thread to avoid blocking
194
+ refill_thread = threading.Thread(target=self.refill_proxies)
195
+ refill_thread.daemon = True
196
+ refill_thread.start()
197
+
198
  return removed
199
 
200
  def get_all_proxies(self):