|
14 | 14 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
15 | 15 | OTHER DEALINGS IN THE SOFTWARE.
|
16 | 16 | """
|
17 |
| - |
| 17 | +import copy |
18 | 18 | import logging
|
| 19 | +import multiprocessing |
19 | 20 | import random
|
20 | 21 | import threading
|
21 | 22 | import time
|
|
28 | 29 | PROXY_FROM_URL = 'http://free-proxy-list.net/'
|
29 | 30 |
|
30 | 31 |
|
| 32 | +def kill_all_processes(processes_and_times): |
| 33 | + """ |
| 34 | + Kills all processes |
| 35 | + :param processes_and_times: list of (process, time_started) |
| 36 | + :return: |
| 37 | + """ |
| 38 | + for (process_, time_) in processes_and_times: |
| 39 | + if process_ is not None and time_ is not None and process_.is_alive(): |
| 40 | + logging.info('Killing process with PID: ' + str(process_.pid)) |
| 41 | + try: |
| 42 | + process_.kill() |
| 43 | + process_.join() |
| 44 | + except: |
| 45 | + logging.warning('Error killing process with PID: ' + str(process_.pid)) |
| 46 | + |
| 47 | + |
| 48 | +def initialize_chatbot(proxy, config, chatbots_and_proxies_queue): |
| 49 | + """ |
| 50 | + Pops first proxy and tries to initialize chatbot |
| 51 | + :return: |
| 52 | + """ |
| 53 | + try: |
| 54 | + # Get config |
| 55 | + config_ = copy.deepcopy(config) |
| 56 | + config_['proxy'] = proxy |
| 57 | + |
| 58 | + # Initialize chatbot |
| 59 | + chatbot = Chatbot(config=config_) |
| 60 | + |
| 61 | + # Append working chatbot and proxy |
| 62 | + if chatbot is not None: |
| 63 | + chatbots_and_proxies_queue.put((chatbot, proxy)) |
| 64 | + except: |
| 65 | + pass |
| 66 | + |
| 67 | + |
31 | 68 | class Authenticator:
|
32 | 69 | def __init__(self, settings):
|
33 | 70 | self.settings = settings
|
34 | 71 |
|
35 | 72 | self.chatbot = None
|
36 | 73 | self.chatbot_working = False
|
| 74 | + self.chatbots_and_proxies_queue = multiprocessing.Queue(maxsize=int(self.settings['proxy'] |
| 75 | + ['max_number_of_processes']) * 2) |
37 | 76 | self.current_proxy = None
|
38 | 77 | self.conversation_id = None
|
39 | 78 | self.proxy_list = []
|
40 |
| - self.proxy_list_index = 0 |
41 | 79 | self.check_loop_running = False
|
42 | 80 |
|
43 | 81 | def start_check_loop(self):
|
@@ -74,7 +112,6 @@ def proxy_get(self):
|
74 | 112 | """
|
75 | 113 | # Reset proxy list
|
76 | 114 | self.proxy_list = []
|
77 |
| - self.proxy_list_index = 0 |
78 | 115 |
|
79 | 116 | # Try to get proxy
|
80 | 117 | try:
|
@@ -162,70 +199,100 @@ def proxy_checker_loop(self):
|
162 | 199 |
|
163 | 200 | # Check is not successful
|
164 | 201 | else:
|
165 |
| - # Get config |
166 |
| - config = self.get_chatbot_config() |
167 |
| - |
168 | 202 | # Get proxy
|
169 | 203 | if self.settings['proxy']['enabled']:
|
170 |
| - proxy = None |
171 | 204 | # Auto proxy
|
172 | 205 | if self.settings['proxy']['auto']:
|
173 |
| - # Already have proxy_list -> get new proxy from it |
174 |
| - if self.proxy_list_index < len(self.proxy_list) - 1: |
175 |
| - # If half list checked |
176 |
| - if self.proxy_list_index >= len(self.proxy_list) // 2: |
177 |
| - # Try to get new proxies |
178 |
| - logging.info('Trying to update proxy-list...') |
179 |
| - proxy_list_old = self.proxy_list |
180 |
| - proxy_list_index_old = self.proxy_list_index |
181 |
| - self.proxy_get() |
182 |
| - |
183 |
| - # Check if new proxies are identical or empty |
184 |
| - if proxy_list_old == self.proxy_list or len(self.proxy_list) == 0: |
185 |
| - # Restore previous |
186 |
| - logging.info('New proxies are identical or empty. Restoring previous...') |
187 |
| - self.proxy_list = proxy_list_old |
188 |
| - self.proxy_list_index = proxy_list_index_old |
189 |
| - |
190 |
| - # Switch to next proxy |
191 |
| - self.proxy_list_index += 1 |
192 |
| - logging.info('Loading next proxy: ' + str(self.proxy_list_index + 1) + '/' |
193 |
| - + str(len(self.proxy_list))) |
194 |
| - |
195 |
| - # Load proxy |
196 |
| - proxy = self.proxy_list[self.proxy_list_index] |
197 |
| - |
198 |
| - # No proxy or all checked |
199 |
| - else: |
200 |
| - # Get new proxy list |
| 206 | + # Get new proxy list |
| 207 | + if len(self.proxy_list) <= 0: |
201 | 208 | self.proxy_get()
|
202 |
| - |
203 |
| - # Get proxy from list |
204 |
| - if len(self.proxy_list) > 0: |
205 |
| - proxy = self.proxy_list[0] |
206 |
| - |
207 | 209 | # Manual proxy
|
208 | 210 | else:
|
209 |
| - proxy = self.settings['proxy']['manual_proxy'] |
210 |
| - |
211 |
| - # Add proxy to config |
212 |
| - self.current_proxy = proxy |
213 |
| - if proxy is not None: |
214 |
| - logging.info('Using proxy: ' + proxy) |
215 |
| - config['proxy'] = proxy |
| 211 | + self.proxy_list = [self.settings['proxy']['manual_proxy']] |
| 212 | + # Proxy disabled |
| 213 | + else: |
| 214 | + break |
216 | 215 |
|
217 | 216 | # Remove old chatbot
|
218 | 217 | if self.chatbot is not None:
|
219 | 218 | del self.chatbot
|
220 | 219 | self.chatbot = None
|
221 | 220 |
|
222 |
| - # Initialize new chatbot |
223 |
| - logging.info('Initializing new chatbot with config: ' + str(config)) |
224 |
| - try: |
225 |
| - self.chatbot = Chatbot(config=config) |
226 |
| - # Error initializing chatbot |
227 |
| - except Exception as e: |
228 |
| - logging.warning('Error initializing chatbot! ' + str(e)) |
| 221 | + # Create list of processes and start times |
| 222 | + processes_and_times = [] |
| 223 | + |
| 224 | + # Get default config |
| 225 | + default_config = self.get_chatbot_config() |
| 226 | + |
| 227 | + while True: |
| 228 | + # Create and start processes |
| 229 | + while len(self.proxy_list) > 0 \ |
| 230 | + and len(processes_and_times) < int(self.settings['proxy']['max_number_of_processes']): |
| 231 | + proxy = self.proxy_list.pop(0) |
| 232 | + process = multiprocessing.Process(target=initialize_chatbot, |
| 233 | + args=(proxy, |
| 234 | + default_config, |
| 235 | + self.chatbots_and_proxies_queue,)) |
| 236 | + process.start() |
| 237 | + time_started = time.time() |
| 238 | + processes_and_times.append((process, time_started)) |
| 239 | + logging.info('Started new initialization process for proxy: ' + proxy + '. PID: ' |
| 240 | + + str(process.pid) + ' Total: ' + str(len(processes_and_times)) + ' processes') |
| 241 | + |
| 242 | + # Limit connection intervals |
| 243 | + time.sleep(0.5) |
| 244 | + |
| 245 | + # Wait some time each cycle |
| 246 | + time.sleep(0.5) |
| 247 | + |
| 248 | + # No more proxies |
| 249 | + if len(self.proxy_list) == 0: |
| 250 | + # Get new proxy list in auto mode |
| 251 | + if self.settings['proxy']['auto']: |
| 252 | + self.proxy_get() |
| 253 | + |
| 254 | + # Exit if manual mode and no more processes |
| 255 | + elif len(processes_and_times) == 0: |
| 256 | + logging.info('Cannot connect with manual proxy. Exiting loop...') |
| 257 | + kill_all_processes(processes_and_times) |
| 258 | + break |
| 259 | + |
| 260 | + # Check chatbots |
| 261 | + try: |
| 262 | + # Get from queue |
| 263 | + chatbot_, proxy_ = self.chatbots_and_proxies_queue.get(block=False) |
| 264 | + |
| 265 | + # Found initialized one |
| 266 | + if chatbot_ is not None and proxy_ is not None and len(proxy_) > 0: |
| 267 | + self.chatbot = chatbot_ |
| 268 | + self.current_proxy = proxy_ |
| 269 | + except: |
| 270 | + pass |
| 271 | + |
| 272 | + # Kill all processes and exit from loop |
| 273 | + if self.chatbot is not None and self.current_proxy is not None: |
| 274 | + kill_all_processes(processes_and_times) |
| 275 | + logging.info('Found working proxy: ' + self.current_proxy + ' exiting loop...') |
| 276 | + break |
| 277 | + |
| 278 | + # Check timeouts |
| 279 | + for i in range(len(processes_and_times)): |
| 280 | + process_, time_ = processes_and_times[i] |
| 281 | + if process_ is not None and time_ is not None: |
| 282 | + # Kill on timeout or exit |
| 283 | + if time.time() - time_ > int(self.settings['proxy']['initialization_timeout']) \ |
| 284 | + or not process_.is_alive(): |
| 285 | + if process_.is_alive(): |
| 286 | + logging.info('Killing process with PID: ' + str(process_.pid) + ' due to timeout') |
| 287 | + try: |
| 288 | + process_.kill() |
| 289 | + process_.join() |
| 290 | + except: |
| 291 | + logging.warning('Error killing process with PID: ' + str(process_.pid)) |
| 292 | + processes_and_times[i] = (None, None) |
| 293 | + |
| 294 | + # Remove Nones |
| 295 | + processes_and_times = [i for i in processes_and_times if i[0] is not None] |
229 | 296 |
|
230 | 297 | # Sleep 1 second to limit connections interval
|
231 | 298 | time.sleep(1)
|
|
0 commit comments