atomicshop 2.16.28__py3-none-any.whl → 2.16.29__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of atomicshop might be problematic. Click here for more details.
- atomicshop/__init__.py +1 -1
- atomicshop/archiver/zips.py +5 -6
- atomicshop/basics/strings.py +2 -2
- atomicshop/dns.py +8 -6
- atomicshop/file_io/file_io.py +7 -7
- atomicshop/filesystem.py +6 -7
- atomicshop/http_parse.py +12 -18
- atomicshop/mitm/connection_thread_worker.py +183 -227
- atomicshop/mitm/engines/__parent/parser___parent.py +1 -4
- atomicshop/mitm/engines/__parent/recorder___parent.py +1 -1
- atomicshop/mitm/message.py +0 -17
- atomicshop/mitm/mitm_main.py +29 -27
- atomicshop/print_api.py +13 -53
- atomicshop/system_resource_monitor.py +8 -8
- atomicshop/system_resources.py +8 -8
- atomicshop/web.py +10 -10
- atomicshop/wrappers/loggingw/filters.py +23 -0
- atomicshop/wrappers/loggingw/handlers.py +20 -0
- atomicshop/wrappers/loggingw/loggingw.py +130 -7
- atomicshop/wrappers/playwrightw/engine.py +6 -7
- atomicshop/wrappers/playwrightw/waits.py +9 -7
- atomicshop/wrappers/socketw/dns_server.py +1 -1
- atomicshop/wrappers/socketw/sender.py +36 -27
- atomicshop/wrappers/socketw/socket_client.py +6 -5
- atomicshop/wrappers/socketw/socket_wrapper.py +45 -7
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.29.dist-info}/METADATA +1 -1
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.29.dist-info}/RECORD +30 -30
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.29.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.29.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.29.dist-info}/top_level.txt +0 -0
|
@@ -2,11 +2,13 @@ import logging
|
|
|
2
2
|
import os
|
|
3
3
|
from typing import Literal, Union
|
|
4
4
|
import datetime
|
|
5
|
+
import contextlib
|
|
6
|
+
import threading
|
|
5
7
|
|
|
6
8
|
from . import loggers, handlers
|
|
7
9
|
from ...file_io import csvs
|
|
8
|
-
from ...basics import tracebacks
|
|
9
|
-
from ...
|
|
10
|
+
from ...basics import tracebacks, ansi_escape_codes
|
|
11
|
+
from ...import print_api
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
class LoggingwLoggerAlreadyExistsError(Exception):
|
|
@@ -274,25 +276,146 @@ def is_logger_exists(logger_name: str) -> bool:
|
|
|
274
276
|
return loggers.is_logger_exists(logger_name)
|
|
275
277
|
|
|
276
278
|
|
|
279
|
+
def find_the_parent_logger_with_stream_handler(logger: logging.Logger) -> logging.Logger:
|
|
280
|
+
"""
|
|
281
|
+
Function to find the parent logger with StreamHandler.
|
|
282
|
+
Example:
|
|
283
|
+
logger_name = "parent.child.grandchild"
|
|
284
|
+
'parent' logger has StreamHandler, but 'child' and 'grandchild' don't.
|
|
285
|
+
This function will return the 'parent' logger, since both 'child' and 'grandchild' will inherit the
|
|
286
|
+
StreamHandler from the 'parent' logger.
|
|
287
|
+
|
|
288
|
+
:param logger: Logger to find the parent logger with StreamHandler.
|
|
289
|
+
:return: Parent logger with StreamHandler.
|
|
290
|
+
"""
|
|
291
|
+
|
|
292
|
+
# Start with current logger to see if it has a stream handler.
|
|
293
|
+
current_logger = logger
|
|
294
|
+
found: bool = False
|
|
295
|
+
while current_logger and not current_logger.handlers:
|
|
296
|
+
for handler in current_logger.handlers:
|
|
297
|
+
if isinstance(handler, logging.StreamHandler):
|
|
298
|
+
found = True
|
|
299
|
+
break
|
|
300
|
+
|
|
301
|
+
if not found:
|
|
302
|
+
# If the current logger doesn't have the stream handler, let's move to the parent.
|
|
303
|
+
current_logger = current_logger.parent
|
|
304
|
+
|
|
305
|
+
return current_logger
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
@contextlib.contextmanager
|
|
309
|
+
def _temporary_change_logger_stream_handler_color(logger: logging.Logger, color: str):
|
|
310
|
+
"""
|
|
311
|
+
THIS IS ONLY FOR REFERENCE, for better result use the 'temporary_change_logger_stream_handler_emit_color' function.
|
|
312
|
+
If there are several threads that use this logger, there could be a problem, since unwanted messages
|
|
313
|
+
could be colored with the color of the other thread. 'temporary_change_logger_stream_handler_emit_color' is thread
|
|
314
|
+
safe and will color only the messages from the current thread.
|
|
315
|
+
|
|
316
|
+
Context manager to temporarily change the color of the logger's StreamHandler formatter.
|
|
317
|
+
|
|
318
|
+
Example:
|
|
319
|
+
with temporary_change_logger_stream_handler_color(logger, color):
|
|
320
|
+
# Do something with the temporary color.
|
|
321
|
+
pass
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
# Find the current or the topmost logger's StreamHandler.
|
|
325
|
+
# Could be that it is a child logger inherits its handlers from the parent.
|
|
326
|
+
logger_with_handlers = find_the_parent_logger_with_stream_handler(logger)
|
|
327
|
+
|
|
328
|
+
found_stream_handler = None
|
|
329
|
+
for handler in logger_with_handlers.handlers:
|
|
330
|
+
if isinstance(handler, logging.StreamHandler):
|
|
331
|
+
found_stream_handler = handler
|
|
332
|
+
break
|
|
333
|
+
|
|
334
|
+
# Save the original formatter
|
|
335
|
+
original_formatter = found_stream_handler.formatter
|
|
336
|
+
original_formatter_string = handlers.get_formatter_string(found_stream_handler)
|
|
337
|
+
|
|
338
|
+
# Create a colored formatter for errors
|
|
339
|
+
color_formatter = logging.Formatter(
|
|
340
|
+
ansi_escape_codes.get_colors_basic_dict(color) + original_formatter_string +
|
|
341
|
+
ansi_escape_codes.ColorsBasic.END)
|
|
342
|
+
|
|
343
|
+
# thread_id = threading.get_ident()
|
|
344
|
+
# color_filter = filters.ThreadColorLogFilter(color, thread_id)
|
|
345
|
+
# found_stream_handler.addFilter(color_filter)
|
|
346
|
+
try:
|
|
347
|
+
found_stream_handler.setFormatter(color_formatter)
|
|
348
|
+
yield
|
|
349
|
+
finally:
|
|
350
|
+
found_stream_handler.setFormatter(original_formatter)
|
|
351
|
+
# found_stream_handler.removeFilter(color_filter)
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
# Thread-local storage to store color codes per thread
|
|
355
|
+
thread_local = threading.local()
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
@contextlib.contextmanager
|
|
359
|
+
def temporary_change_logger_stream_handler_emit_color(logger: logging.Logger, color: str):
|
|
360
|
+
"""Context manager to temporarily set the color code for log messages in the current thread."""
|
|
361
|
+
|
|
362
|
+
# Find the current or the topmost logger's StreamHandler.
|
|
363
|
+
# Could be that it is a child logger inherits its handlers from the parent.
|
|
364
|
+
logger_with_handlers = find_the_parent_logger_with_stream_handler(logger)
|
|
365
|
+
|
|
366
|
+
found_stream_handler = None
|
|
367
|
+
for handler in logger_with_handlers.handlers:
|
|
368
|
+
if isinstance(handler, logging.StreamHandler):
|
|
369
|
+
found_stream_handler = handler
|
|
370
|
+
break
|
|
371
|
+
|
|
372
|
+
# Save the original emit method of the stream handler
|
|
373
|
+
original_emit = found_stream_handler.emit
|
|
374
|
+
|
|
375
|
+
def emit_with_color(record):
|
|
376
|
+
original_msg = record.msg
|
|
377
|
+
# Check if the current thread has a color code
|
|
378
|
+
if getattr(thread_local, 'color', None):
|
|
379
|
+
record.msg = (
|
|
380
|
+
ansi_escape_codes.get_colors_basic_dict(color) + original_msg +
|
|
381
|
+
ansi_escape_codes.ColorsBasic.END)
|
|
382
|
+
original_emit(record) # Call the original emit method
|
|
383
|
+
record.msg = original_msg # Restore the original message for other handlers
|
|
384
|
+
|
|
385
|
+
# Replace the emit method with our custom method
|
|
386
|
+
found_stream_handler.emit = emit_with_color
|
|
387
|
+
|
|
388
|
+
# Set the color code in thread-local storage for this thread
|
|
389
|
+
thread_local.color = color
|
|
390
|
+
|
|
391
|
+
try:
|
|
392
|
+
yield
|
|
393
|
+
finally:
|
|
394
|
+
# Restore the original emit method after the context manager is exited
|
|
395
|
+
found_stream_handler.emit = original_emit
|
|
396
|
+
# Clear the color code from thread-local storage
|
|
397
|
+
thread_local.color = None
|
|
398
|
+
|
|
399
|
+
|
|
277
400
|
class ExceptionCsvLogger:
|
|
278
401
|
def __init__(
|
|
279
402
|
self,
|
|
280
403
|
logger_name: str,
|
|
281
|
-
|
|
282
|
-
|
|
404
|
+
directory_path: str = None,
|
|
405
|
+
custom_header: str = None
|
|
283
406
|
):
|
|
284
407
|
"""
|
|
285
408
|
Initialize the ExceptionCsvLogger object.
|
|
286
409
|
|
|
287
410
|
:param logger_name: Name of the logger.
|
|
411
|
+
:param directory_path: Directory path where the log file will be saved.
|
|
412
|
+
You can leave it as None, but if the logger doesn't exist, you will get an exception.
|
|
288
413
|
:param custom_header: Custom header to write to the log file.
|
|
289
414
|
If None, the default header will be used: "timestamp,exception", since that what is written to the log file.
|
|
290
415
|
If you want to add more columns to the csv file, you can provide a custom header:
|
|
291
416
|
"custom1,custom2,custom3".
|
|
292
417
|
These will be added to the default header as:
|
|
293
418
|
"timestamp,custom1,custom2,custom3,exception".
|
|
294
|
-
:param directory_path: Directory path where the log file will be saved.
|
|
295
|
-
You can leave it as None, but if the logger doesn't exist, you will get an exception.
|
|
296
419
|
"""
|
|
297
420
|
|
|
298
421
|
if custom_header:
|
|
@@ -352,7 +475,7 @@ class ExceptionCsvLogger:
|
|
|
352
475
|
self.logger.info(output_csv_line)
|
|
353
476
|
|
|
354
477
|
if stdout:
|
|
355
|
-
print_api('', error_type=True, color="red", traceback_string=True)
|
|
478
|
+
print_api.print_api('', error_type=True, color="red", traceback_string=True)
|
|
356
479
|
|
|
357
480
|
def get_logger(self):
|
|
358
481
|
return self.logger
|
|
@@ -5,11 +5,10 @@ import random
|
|
|
5
5
|
import getpass
|
|
6
6
|
from tempfile import gettempdir
|
|
7
7
|
|
|
8
|
-
from ...print_api import print_api
|
|
9
8
|
from ...keyboard_press import send_alt_tab
|
|
10
|
-
from ... import filesystem
|
|
9
|
+
from ... import filesystem, print_api
|
|
11
10
|
|
|
12
|
-
#
|
|
11
|
+
# noinspection PyPackageRequirements
|
|
13
12
|
from playwright.sync_api import sync_playwright
|
|
14
13
|
# Stealth options for playwright. External.
|
|
15
14
|
from playwright_stealth import stealth_sync
|
|
@@ -242,7 +241,7 @@ class PlaywrightEngine:
|
|
|
242
241
|
for i in range(element_count):
|
|
243
242
|
string_current = string_current + element.nth(i).text_content()
|
|
244
243
|
|
|
245
|
-
print_api(f'Current element text of [{locator_string}]: {string_current}', rtl=True)
|
|
244
|
+
print_api.print_api(f'Current element text of [{locator_string}]: {string_current}', rtl=True)
|
|
246
245
|
|
|
247
246
|
# If text from previous cycle isn't the same as text from current cycle, then put the new value to the
|
|
248
247
|
# previous one and return 'True' since the text really changed.
|
|
@@ -312,7 +311,7 @@ class PlaywrightEngine:
|
|
|
312
311
|
# Nullifying 'string_previous', so new loop will not have the same one as previous loop in case of error.
|
|
313
312
|
self.string_previous = str()
|
|
314
313
|
|
|
315
|
-
print_api('Finished execution Time: ' + str(datetime.datetime.now()), **kwargs)
|
|
316
|
-
print_api('Waiting minutes: ' + str(time_to_sleep_minutes), **kwargs)
|
|
314
|
+
print_api.print_api('Finished execution Time: ' + str(datetime.datetime.now()), **kwargs)
|
|
315
|
+
print_api.print_api('Waiting minutes: ' + str(time_to_sleep_minutes), **kwargs)
|
|
317
316
|
time.sleep(time_to_sleep_minutes * 60)
|
|
318
|
-
print_api('-----------------------------------------', **kwargs)
|
|
317
|
+
print_api.print_api('-----------------------------------------', **kwargs)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
from
|
|
1
|
+
from ... import print_api
|
|
2
2
|
|
|
3
|
+
# noinspection PyPackageRequirements
|
|
3
4
|
from playwright.sync_api import expect
|
|
4
5
|
# This is from official docs: https://playwright.dev/python/docs/api/class-timeouterror
|
|
6
|
+
# noinspection PyPackageRequirements
|
|
5
7
|
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
|
|
6
8
|
|
|
7
9
|
|
|
@@ -124,7 +126,7 @@ def network_fully_idle(page, timeout: int = 2000, print_kwargs: dict = None) ->
|
|
|
124
126
|
# 'page.expect_response' will wait for the response to be received, and then return the response object.
|
|
125
127
|
# When timeout is reached, it will raise a TimeoutError, which will break the while loop.
|
|
126
128
|
with page.expect_response("**/*", timeout=timeout) as response_info:
|
|
127
|
-
print_api(response_info.value, **print_kwargs)
|
|
129
|
+
print_api.print_api(response_info.value, **print_kwargs)
|
|
128
130
|
except PlaywrightTimeoutError:
|
|
129
131
|
break
|
|
130
132
|
|
|
@@ -151,13 +153,13 @@ def maximum_idle(page, print_kwargs: dict = None) -> None:
|
|
|
151
153
|
:return: None
|
|
152
154
|
"""
|
|
153
155
|
|
|
154
|
-
print_api('Before wait_for_load', **print_kwargs)
|
|
156
|
+
print_api.print_api('Before wait_for_load', **print_kwargs)
|
|
155
157
|
load(page)
|
|
156
|
-
print_api('After wait_for_load, Before wait_for_domcontentloaded', **print_kwargs)
|
|
158
|
+
print_api.print_api('After wait_for_load, Before wait_for_domcontentloaded', **print_kwargs)
|
|
157
159
|
domcontentloaded(page)
|
|
158
|
-
print_api('After wait_for_domcontentloaded', **print_kwargs)
|
|
160
|
+
print_api.print_api('After wait_for_domcontentloaded', **print_kwargs)
|
|
159
161
|
# For some reason 'networkidle' can result in timeout errors, so currently this is disabled.
|
|
160
162
|
# networkidle(page)
|
|
161
|
-
print_api('Before wait_for_network_fully_idle', **print_kwargs)
|
|
163
|
+
print_api.print_api('Before wait_for_network_fully_idle', **print_kwargs)
|
|
162
164
|
network_fully_idle(page, print_kwargs=print_kwargs)
|
|
163
|
-
print_api('After wait_for_network_fully_idle', **print_kwargs)
|
|
165
|
+
print_api.print_api('After wait_for_network_fully_idle', **print_kwargs)
|
|
@@ -317,7 +317,7 @@ class DnsServer:
|
|
|
317
317
|
|
|
318
318
|
if self.resolve_to_tcp_server_all_domains:
|
|
319
319
|
message = "Routing all domains to Built-in TCP Server."
|
|
320
|
-
print_api(message, logger=self.logger, color='
|
|
320
|
+
print_api(message, logger=self.logger, color='blue')
|
|
321
321
|
|
|
322
322
|
if self.resolve_regular:
|
|
323
323
|
message = f"Routing all domains to Live DNS Service: {self.forwarding_dns_service_ipv4}"
|
|
@@ -4,6 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
from ...print_api import print_api
|
|
6
6
|
from ..loggingw import loggingw
|
|
7
|
+
from ...basics import tracebacks
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
class Sender:
|
|
@@ -29,18 +30,22 @@ class Sender:
|
|
|
29
30
|
# until other side receives all, so there's no way knowing how much data was sent. Returns "None" on
|
|
30
31
|
# Success though.
|
|
31
32
|
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
|
|
33
|
+
# The error string that will be returned by the function in case of error.
|
|
34
|
+
# If returned None then everything is fine.
|
|
35
|
+
# noinspection PyTypeChecker
|
|
36
|
+
function_result_error: str = None
|
|
35
37
|
# Current amount of bytes sent is 0, since we didn't start yet
|
|
36
38
|
total_sent_bytes = 0
|
|
37
39
|
|
|
40
|
+
# noinspection PyTypeChecker
|
|
41
|
+
error_message: str = None
|
|
38
42
|
try:
|
|
39
43
|
# Getting byte length of current message
|
|
40
44
|
current_message_length = len(self.class_message)
|
|
41
45
|
|
|
42
|
-
self.logger.info(
|
|
43
|
-
|
|
46
|
+
self.logger.info(
|
|
47
|
+
f"Sending message to "
|
|
48
|
+
f"{self.ssl_socket.getpeername()[0]}:{self.ssl_socket.getpeername()[1]}")
|
|
44
49
|
|
|
45
50
|
# Looping through "socket.send()" method while total sent bytes are less than message length
|
|
46
51
|
while total_sent_bytes < current_message_length:
|
|
@@ -48,9 +53,11 @@ class Sender:
|
|
|
48
53
|
sent_bytes = self.ssl_socket.send(self.class_message[total_sent_bytes:])
|
|
49
54
|
# If there were only "0" bytes sent, then connection on the other side was terminated
|
|
50
55
|
if sent_bytes == 0:
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
error_message = (
|
|
57
|
+
f"Sent {sent_bytes} bytes - connection is down... Could send only "
|
|
58
|
+
f"{total_sent_bytes} bytes out of {current_message_length}. Closing socket...")
|
|
59
|
+
self.logger.info(error_message)
|
|
60
|
+
function_result_error = error_message
|
|
54
61
|
break
|
|
55
62
|
|
|
56
63
|
# Adding amount of currently sent bytes to the total amount of bytes sent
|
|
@@ -59,23 +66,25 @@ class Sender:
|
|
|
59
66
|
|
|
60
67
|
# At this point the sending loop finished successfully
|
|
61
68
|
self.logger.info(f"Sent the message to destination.")
|
|
62
|
-
except ConnectionResetError:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
function_result = False
|
|
79
|
-
pass
|
|
69
|
+
except ConnectionResetError as e:
|
|
70
|
+
error_class_type = str(type(e)).replace("<class '", '').replace("'>", '')
|
|
71
|
+
exception_error = tracebacks.get_as_string(one_line=True)
|
|
72
|
+
error_message = (f"Socket Send: Error, Couldn't reach the server - Connection was reset | "
|
|
73
|
+
f"{error_class_type}: {exception_error}")
|
|
74
|
+
except (ssl.SSLEOFError, ssl.SSLZeroReturnError, ssl.SSLWantWriteError, TimeoutError) as e:
|
|
75
|
+
error_class_type = str(type(e)).replace("<class '", '').replace("'>", '')
|
|
76
|
+
exception_error = tracebacks.get_as_string(one_line=True)
|
|
77
|
+
error_message = f"Socket Send: {error_class_type}: {exception_error}"
|
|
78
|
+
except Exception as e:
|
|
79
|
+
error_class_type = str(type(e)).replace("<class '", '').replace("'>", '')
|
|
80
|
+
exception_error = tracebacks.get_as_string(one_line=True)
|
|
81
|
+
if 'ssl' in error_class_type.lower():
|
|
82
|
+
error_message = f"Socket Send: SSL UNDOCUMENTED Exception: {error_class_type}{exception_error}"
|
|
83
|
+
else:
|
|
84
|
+
error_message = f"Socket Send: Error, UNDOCUMENTED Exception: {error_class_type}{exception_error}"
|
|
80
85
|
|
|
81
|
-
|
|
86
|
+
if error_message:
|
|
87
|
+
print_api(error_message, logger=self.logger, logger_method='error')
|
|
88
|
+
function_result_error = error_message
|
|
89
|
+
|
|
90
|
+
return function_result_error
|
|
@@ -5,7 +5,10 @@ from typing import Literal, Union
|
|
|
5
5
|
import logging
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
|
|
8
|
+
# noinspection PyPackageRequirements
|
|
8
9
|
from cryptography import x509
|
|
10
|
+
# noinspection PyPackageRequirements
|
|
11
|
+
import dns.resolver
|
|
9
12
|
|
|
10
13
|
from . import creator
|
|
11
14
|
from .receiver import Receiver
|
|
@@ -16,8 +19,6 @@ from ..loggingw import loggingw
|
|
|
16
19
|
from ...print_api import print_api
|
|
17
20
|
from ...file_io import file_io
|
|
18
21
|
|
|
19
|
-
import dns.resolver
|
|
20
|
-
|
|
21
22
|
|
|
22
23
|
class SocketClient:
|
|
23
24
|
def __init__(
|
|
@@ -221,12 +222,12 @@ class SocketClient:
|
|
|
221
222
|
f"[{self.service_name}] resolves to ip: [{self.connection_ip}]. Pulled IP from the socket.")
|
|
222
223
|
|
|
223
224
|
# Send the data received from the client to the service over socket
|
|
224
|
-
|
|
225
|
+
error_on_send: str = Sender(
|
|
225
226
|
ssl_socket=self.socket_instance, class_message=request_bytes, logger=self.logger).send()
|
|
226
227
|
|
|
227
228
|
# If the socket disconnected on data send
|
|
228
|
-
if
|
|
229
|
-
error_string = "Service socket closed on data send"
|
|
229
|
+
if error_on_send:
|
|
230
|
+
error_string = f"Service socket closed on data send: {error_on_send}"
|
|
230
231
|
|
|
231
232
|
# We'll close the socket and nullify the object
|
|
232
233
|
self.close_socket()
|
|
@@ -2,6 +2,7 @@ import threading
|
|
|
2
2
|
import select
|
|
3
3
|
from typing import Literal, Union
|
|
4
4
|
from pathlib import Path
|
|
5
|
+
import logging
|
|
5
6
|
|
|
6
7
|
from ..psutilw import networks
|
|
7
8
|
from ..certauthw import certauthw
|
|
@@ -63,7 +64,8 @@ class SocketWrapper:
|
|
|
63
64
|
],
|
|
64
65
|
None
|
|
65
66
|
] = None,
|
|
66
|
-
logger=None,
|
|
67
|
+
logger: logging.Logger = None,
|
|
68
|
+
exceptions_logger: loggingw.ExceptionCsvLogger = None,
|
|
67
69
|
statistics_logs_directory: str = None,
|
|
68
70
|
request_domain_from_dns_server_queue: queues.NonBlockQueue = None
|
|
69
71
|
):
|
|
@@ -144,7 +146,11 @@ class SocketWrapper:
|
|
|
144
146
|
:param ssh_pass: string, SSH password that will be used to connect to remote host.
|
|
145
147
|
:param ssh_script_to_execute: string, script that will be executed to get the process name on ssh remote host.
|
|
146
148
|
:param logger: logging.Logger object, logger object that will be used to log messages.
|
|
147
|
-
If not provided, logger will be created with default settings
|
|
149
|
+
If not provided, logger will be created with default settings saving logs to the
|
|
150
|
+
'statistics_logs_directory'.
|
|
151
|
+
:param exceptions_logger: loggingw.ExceptionCsvLogger object, logger object that will be used to log exceptions.
|
|
152
|
+
If not provided, logger will be created with default settings and will save exceptions to the
|
|
153
|
+
'statistics_logs_directory'.
|
|
148
154
|
:param statistics_logs_directory: string, path to directory where daily statistics.csv files will be stored.
|
|
149
155
|
After you initialize the SocketWrapper object, you can get the statistics_writer object from it and use it
|
|
150
156
|
to write statistics to the file in a worker thread.
|
|
@@ -231,6 +237,14 @@ class SocketWrapper:
|
|
|
231
237
|
formatter_filehandler='DEFAULT'
|
|
232
238
|
)
|
|
233
239
|
|
|
240
|
+
if not exceptions_logger:
|
|
241
|
+
self.exceptions_logger = loggingw.ExceptionCsvLogger(
|
|
242
|
+
logger_name='SocketWrapperExceptions',
|
|
243
|
+
directory_path=self.statistics_logs_directory
|
|
244
|
+
)
|
|
245
|
+
else:
|
|
246
|
+
self.exceptions_logger = exceptions_logger
|
|
247
|
+
|
|
234
248
|
self.test_config()
|
|
235
249
|
|
|
236
250
|
def test_config(self):
|
|
@@ -432,7 +446,8 @@ class SocketWrapper:
|
|
|
432
446
|
# Wait from any connection on "accept()".
|
|
433
447
|
# 'client_socket' is socket or ssl socket, 'client_address' is a tuple (ip_address, port).
|
|
434
448
|
client_socket, client_address, accept_error_message = accepter.accept_connection_with_error(
|
|
435
|
-
listening_socket_object, domain_from_dns_server=domain_from_dns_server,
|
|
449
|
+
listening_socket_object, domain_from_dns_server=domain_from_dns_server,
|
|
450
|
+
print_kwargs={'logger': self.logger})
|
|
436
451
|
|
|
437
452
|
# This is the earliest stage to ask for process name.
|
|
438
453
|
# SSH Remote / LOCALHOST script execution to identify process section.
|
|
@@ -521,11 +536,15 @@ class SocketWrapper:
|
|
|
521
536
|
# If 'pass_function_reference_to_thread' was set to 'False', execute the callable passed function
|
|
522
537
|
# as is.
|
|
523
538
|
if not pass_function_reference_to_thread:
|
|
524
|
-
|
|
539
|
+
before_socket_thread_worker(
|
|
540
|
+
callable_function=reference_function_name, thread_args=thread_args,
|
|
541
|
+
exception_logger=self.exceptions_logger)
|
|
525
542
|
# If 'pass_function_reference_to_thread' was set to 'True', execute the callable function reference
|
|
526
543
|
# in a new thread.
|
|
527
544
|
else:
|
|
528
|
-
self._send_accepted_socket_to_thread(
|
|
545
|
+
self._send_accepted_socket_to_thread(
|
|
546
|
+
before_socket_thread_worker,
|
|
547
|
+
reference_args=(reference_function_name, thread_args, self.exceptions_logger))
|
|
529
548
|
# Else, if no client_socket was opened during, accept, then print the error.
|
|
530
549
|
else:
|
|
531
550
|
# Write statistics after accept.
|
|
@@ -547,7 +566,26 @@ class SocketWrapper:
|
|
|
547
566
|
# Append to list of threads, so they can be "joined" later
|
|
548
567
|
self.threads_list.append(thread_current)
|
|
549
568
|
|
|
550
|
-
# 'reference_args[0]' is the client socket.
|
|
551
|
-
client_address = base.get_source_address_from_socket(reference_args[0])
|
|
569
|
+
# 'reference_args[1][0]' is the client socket.
|
|
570
|
+
client_address = base.get_source_address_from_socket(reference_args[1][0])
|
|
552
571
|
|
|
553
572
|
self.logger.info(f"Accepted connection, thread created {client_address}. Continue listening...")
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def before_socket_thread_worker(
|
|
576
|
+
callable_function: callable,
|
|
577
|
+
thread_args: tuple,
|
|
578
|
+
exception_logger: loggingw.ExceptionCsvLogger = None
|
|
579
|
+
):
|
|
580
|
+
"""
|
|
581
|
+
Function that will be executed before the thread is started.
|
|
582
|
+
:param callable_function: callable, function that will be executed in the thread.
|
|
583
|
+
:param thread_args: tuple, arguments that will be passed to the function.
|
|
584
|
+
:param exception_logger: loggingw.ExceptionCsvLogger, logger object that will be used to log exceptions.
|
|
585
|
+
:return:
|
|
586
|
+
"""
|
|
587
|
+
|
|
588
|
+
try:
|
|
589
|
+
callable_function(*thread_args)
|
|
590
|
+
except Exception as e:
|
|
591
|
+
exception_logger.write(e)
|