atomicshop 2.16.28__py3-none-any.whl → 2.16.30__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 +82 -67
- atomicshop/mitm/connection_thread_worker.py +187 -231
- atomicshop/mitm/engines/__parent/parser___parent.py +1 -4
- atomicshop/mitm/engines/__parent/recorder___parent.py +6 -2
- atomicshop/mitm/message.py +29 -20
- atomicshop/mitm/mitm_main.py +36 -32
- 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 +2 -2
- atomicshop/wrappers/socketw/sender.py +56 -28
- atomicshop/wrappers/socketw/sni.py +27 -16
- atomicshop/wrappers/socketw/socket_client.py +6 -5
- atomicshop/wrappers/socketw/socket_wrapper.py +49 -14
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.30.dist-info}/METADATA +1 -1
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.30.dist-info}/RECORD +31 -31
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.30.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.30.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.28.dist-info → atomicshop-2.16.30.dist-info}/top_level.txt +0 -0
atomicshop/mitm/mitm_main.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import logging
|
|
2
1
|
import threading
|
|
3
2
|
import multiprocessing
|
|
4
3
|
import time
|
|
@@ -6,12 +5,11 @@ import datetime
|
|
|
6
5
|
|
|
7
6
|
import atomicshop # Importing atomicshop package to get the version of the package.
|
|
8
7
|
|
|
9
|
-
from .. import filesystem, queues, dns, on_exit
|
|
8
|
+
from .. import filesystem, queues, dns, on_exit, print_api
|
|
10
9
|
from ..permissions import permissions
|
|
11
10
|
from ..python_functions import get_current_python_version_string, check_python_version_compliance
|
|
12
11
|
from ..wrappers.socketw import socket_wrapper, dns_server, base
|
|
13
12
|
from ..wrappers.loggingw import loggingw
|
|
14
|
-
from ..print_api import print_api
|
|
15
13
|
|
|
16
14
|
from .initialize_engines import ModuleCategory
|
|
17
15
|
from .connection_thread_worker import thread_worker_main
|
|
@@ -33,16 +31,18 @@ MITM_ERROR_LOGGER: loggingw.ExceptionCsvLogger = None
|
|
|
33
31
|
def exit_cleanup():
|
|
34
32
|
if permissions.is_admin():
|
|
35
33
|
is_dns_dynamic, current_dns_gateway = dns.get_default_dns_gateway()
|
|
36
|
-
print_api(f'Current DNS Gateway: {current_dns_gateway}')
|
|
34
|
+
print_api.print_api(f'Current DNS Gateway: {current_dns_gateway}')
|
|
37
35
|
|
|
38
36
|
if is_dns_dynamic != NETWORK_INTERFACE_IS_DYNAMIC or \
|
|
39
37
|
(not is_dns_dynamic and current_dns_gateway != NETWORK_INTERFACE_IPV4_ADDRESS_LIST):
|
|
40
38
|
dns.set_connection_dns_gateway_dynamic(use_default_connection=True)
|
|
41
|
-
print_api("Returned default DNS gateway...", color='blue')
|
|
39
|
+
print_api.print_api("Returned default DNS gateway...", color='blue')
|
|
42
40
|
|
|
43
|
-
|
|
44
|
-
RECS_PROCESS_INSTANCE
|
|
45
|
-
|
|
41
|
+
# The process will not be executed if there was an exception in the beginning.
|
|
42
|
+
if RECS_PROCESS_INSTANCE is not None:
|
|
43
|
+
print_api.print_api(RECS_PROCESS_INSTANCE.is_alive())
|
|
44
|
+
RECS_PROCESS_INSTANCE.terminate()
|
|
45
|
+
RECS_PROCESS_INSTANCE.join()
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
def mitm_server(config_file_path: str):
|
|
@@ -59,7 +59,8 @@ def mitm_server(config_file_path: str):
|
|
|
59
59
|
return result
|
|
60
60
|
|
|
61
61
|
global MITM_ERROR_LOGGER
|
|
62
|
-
MITM_ERROR_LOGGER = loggingw.ExceptionCsvLogger(
|
|
62
|
+
MITM_ERROR_LOGGER = loggingw.ExceptionCsvLogger(
|
|
63
|
+
logger_name=EXCEPTIONS_CSV_LOGGER_NAME, directory_path=config_static.LogRec.logs_path)
|
|
63
64
|
|
|
64
65
|
# Create folders.
|
|
65
66
|
filesystem.create_directory(config_static.LogRec.logs_path)
|
|
@@ -159,70 +160,72 @@ def mitm_server(config_file_path: str):
|
|
|
159
160
|
# === EOF Initialize Reference Module ==========================================================================
|
|
160
161
|
# === Engine logging ===========================================================================================
|
|
161
162
|
# Printing the parsers using "start=1" for index to start counting from "1" and not "0"
|
|
162
|
-
print_api(f"[*] Found Engines:", logger=system_logger)
|
|
163
|
+
print_api.print_api(f"[*] Found Engines:", logger=system_logger)
|
|
163
164
|
for index, engine in enumerate(engines_list, start=1):
|
|
164
165
|
message = f"[*] {index}: {engine.engine_name} | {engine.domain_list}"
|
|
165
|
-
print_api(message, logger=system_logger)
|
|
166
|
+
print_api.print_api(message, logger=system_logger)
|
|
166
167
|
|
|
167
168
|
message = (f"[*] Modules: {engine.parser_class_object.__name__}, "
|
|
168
169
|
f"{engine.responder_class_object.__name__}, "
|
|
169
170
|
f"{engine.recorder_class_object.__name__}")
|
|
170
|
-
print_api(message, logger=system_logger)
|
|
171
|
+
print_api.print_api(message, logger=system_logger)
|
|
171
172
|
|
|
172
173
|
if config_static.DNSServer.enable:
|
|
173
|
-
print_api("DNS Server is enabled.", logger=system_logger)
|
|
174
|
+
print_api.print_api("DNS Server is enabled.", logger=system_logger)
|
|
174
175
|
|
|
175
176
|
# If engines were found and dns is set to route by the engine domains.
|
|
176
177
|
if engines_list and config_static.DNSServer.resolve_to_tcp_server_only_engine_domains:
|
|
177
|
-
print_api(
|
|
178
|
+
print_api.print_api(
|
|
179
|
+
"Engine domains will be routed by the DNS server to Built-in TCP Server.", logger=system_logger)
|
|
178
180
|
# If engines were found, but the dns isn't set to route to engines.
|
|
179
181
|
elif engines_list and not config_static.DNSServer.resolve_to_tcp_server_only_engine_domains:
|
|
180
182
|
message = f"[*] Engine domains found, but the DNS routing is set not to use them for routing."
|
|
181
|
-
print_api(message, color="yellow", logger=system_logger)
|
|
183
|
+
print_api.print_api(message, color="yellow", logger=system_logger)
|
|
182
184
|
elif not engines_list and config_static.DNSServer.resolve_to_tcp_server_only_engine_domains:
|
|
183
185
|
error_message = (
|
|
184
186
|
f"No engines were found in: [{config_static.MainConfig.ENGINES_DIRECTORY_PATH}]\n"
|
|
185
187
|
f"But the DNS routing is set to use them for routing.\n"
|
|
186
188
|
f"Please check your DNS configuration in the 'config.ini' file.")
|
|
187
|
-
print_api(error_message, color="red")
|
|
189
|
+
print_api.print_api(error_message, color="red")
|
|
188
190
|
return 1
|
|
189
191
|
|
|
190
192
|
if config_static.DNSServer.resolve_to_tcp_server_all_domains:
|
|
191
|
-
print_api(
|
|
193
|
+
print_api.print_api(
|
|
194
|
+
"All domains will be routed by the DNS server to Built-in TCP Server.", logger=system_logger)
|
|
192
195
|
|
|
193
196
|
if config_static.DNSServer.resolve_regular:
|
|
194
|
-
print_api(
|
|
197
|
+
print_api.print_api(
|
|
195
198
|
"Regular DNS resolving is enabled. Built-in TCP server will not be routed to",
|
|
196
199
|
logger=system_logger, color="yellow")
|
|
197
200
|
else:
|
|
198
|
-
print_api("DNS Server is disabled.", logger=system_logger, color="yellow")
|
|
201
|
+
print_api.print_api("DNS Server is disabled.", logger=system_logger, color="yellow")
|
|
199
202
|
|
|
200
203
|
if config_static.TCPServer.enable:
|
|
201
|
-
print_api("TCP Server is enabled.", logger=system_logger)
|
|
204
|
+
print_api.print_api("TCP Server is enabled.", logger=system_logger)
|
|
202
205
|
|
|
203
206
|
if engines_list and not config_static.TCPServer.engines_usage:
|
|
204
207
|
message = \
|
|
205
208
|
f"Engines found, but the TCP server is set not to use them for processing. General responses only."
|
|
206
|
-
print_api(message, color="yellow", logger=system_logger)
|
|
209
|
+
print_api.print_api(message, color="yellow", logger=system_logger)
|
|
207
210
|
elif engines_list and config_static.TCPServer.engines_usage:
|
|
208
211
|
message = f"Engines found, and the TCP server is set to use them for processing."
|
|
209
|
-
print_api(message, logger=system_logger)
|
|
212
|
+
print_api.print_api(message, logger=system_logger)
|
|
210
213
|
elif not engines_list and config_static.TCPServer.engines_usage:
|
|
211
214
|
error_message = (
|
|
212
215
|
f"No engines were found in: [{config_static.MainConfig.ENGINES_DIRECTORY_PATH}]\n"
|
|
213
216
|
f"But the TCP server is set to use them for processing.\n"
|
|
214
217
|
f"Please check your TCP configuration in the 'config.ini' file.")
|
|
215
|
-
print_api(error_message, color="red")
|
|
218
|
+
print_api.print_api(error_message, color="red")
|
|
216
219
|
return 1
|
|
217
220
|
else:
|
|
218
|
-
print_api("TCP Server is disabled.", logger=system_logger, color="yellow")
|
|
221
|
+
print_api.print_api("TCP Server is disabled.", logger=system_logger, color="yellow")
|
|
219
222
|
|
|
220
223
|
# === EOF Engine Logging =======================================================================================
|
|
221
224
|
|
|
222
225
|
# Assigning all the engines domains to all time domains, that will be responsible for adding new domains.
|
|
223
226
|
config_static.Certificates.domains_all_times = list(domains_engine_list_full)
|
|
224
227
|
|
|
225
|
-
print_api("Press [Ctrl]+[C] to stop.", color='blue')
|
|
228
|
+
print_api.print_api("Press [Ctrl]+[C] to stop.", color='blue')
|
|
226
229
|
|
|
227
230
|
# Create request domain queue.
|
|
228
231
|
domain_queue = queues.NonBlockQueue()
|
|
@@ -250,7 +253,7 @@ def mitm_server(config_file_path: str):
|
|
|
250
253
|
logger=network_logger
|
|
251
254
|
)
|
|
252
255
|
except (dns_server.DnsPortInUseError, dns_server.DnsConfigurationValuesError) as e:
|
|
253
|
-
print_api(e, error_type=True, color="red", logger=system_logger)
|
|
256
|
+
print_api.print_api(e, error_type=True, color="red", logger=system_logger)
|
|
254
257
|
# Wait for the message to be printed and saved to file.
|
|
255
258
|
time.sleep(1)
|
|
256
259
|
return 1
|
|
@@ -296,6 +299,7 @@ def mitm_server(config_file_path: str):
|
|
|
296
299
|
ssh_pass=config_static.ProcessName.ssh_pass,
|
|
297
300
|
ssh_script_to_execute=config_static.ProcessName.ssh_script_to_execute,
|
|
298
301
|
logger=listener_logger,
|
|
302
|
+
exceptions_logger=MITM_ERROR_LOGGER,
|
|
299
303
|
statistics_logs_directory=config_static.LogRec.logs_path,
|
|
300
304
|
forwarding_dns_service_ipv4_list___only_for_localhost=(
|
|
301
305
|
config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
|
|
@@ -303,12 +307,12 @@ def mitm_server(config_file_path: str):
|
|
|
303
307
|
request_domain_from_dns_server_queue=domain_queue
|
|
304
308
|
)
|
|
305
309
|
except socket_wrapper.SocketWrapperPortInUseError as e:
|
|
306
|
-
print_api(e, error_type=True, color="red", logger=system_logger)
|
|
310
|
+
print_api.print_api(e, error_type=True, color="red", logger=system_logger)
|
|
307
311
|
# Wait for the message to be printed and saved to file.
|
|
308
312
|
time.sleep(1)
|
|
309
313
|
return 1
|
|
310
314
|
except socket_wrapper.SocketWrapperConfigurationValuesError as e:
|
|
311
|
-
print_api(e, error_type=True, color="red", logger=system_logger, logger_method='critical')
|
|
315
|
+
print_api.print_api(e, error_type=True, color="red", logger=system_logger, logger_method='critical')
|
|
312
316
|
# Wait for the message to be printed and saved to file.
|
|
313
317
|
time.sleep(1)
|
|
314
318
|
return 1
|
|
@@ -386,12 +390,12 @@ def mitm_server_main(config_file_path: str):
|
|
|
386
390
|
# Main function should return integer with error code, 0 is successful.
|
|
387
391
|
return mitm_server(config_file_path)
|
|
388
392
|
except KeyboardInterrupt:
|
|
389
|
-
print_api("Server Stopped by [KeyboardInterrupt].", color='blue')
|
|
393
|
+
print_api.print_api("Server Stopped by [KeyboardInterrupt].", color='blue')
|
|
390
394
|
exit_cleanup()
|
|
391
395
|
return 0
|
|
392
396
|
except Exception as e:
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
397
|
+
# The error logger will not be initiated if there will be a problem with configuration file or checks.
|
|
398
|
+
if MITM_ERROR_LOGGER is not None:
|
|
399
|
+
MITM_ERROR_LOGGER.write(e)
|
|
396
400
|
exit_cleanup()
|
|
397
401
|
return 1
|
atomicshop/print_api.py
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
import sys
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
|
-
from .basics
|
|
5
|
-
from .wrappers.loggingw import
|
|
4
|
+
from .basics import ansi_escape_codes
|
|
5
|
+
from .wrappers.loggingw import loggingw
|
|
6
6
|
from .basics import tracebacks
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
# noinspection PyUnusedLocal,PyIncorrectDocstring
|
|
10
9
|
def print_api(
|
|
11
10
|
message: any,
|
|
12
11
|
color: any = None,
|
|
13
12
|
print_end: str = '\n',
|
|
14
13
|
rtl: bool = False,
|
|
15
14
|
error_type: bool = False,
|
|
16
|
-
logger:
|
|
15
|
+
logger: logging.Logger = None,
|
|
17
16
|
logger_method: str = 'info',
|
|
18
17
|
stdout: bool = True,
|
|
19
18
|
stderr: bool = True,
|
|
@@ -21,8 +20,6 @@ def print_api(
|
|
|
21
20
|
traceback_string: bool = False,
|
|
22
21
|
oneline: bool = False,
|
|
23
22
|
oneline_end: str = '',
|
|
24
|
-
# raise_exception: bool = True,
|
|
25
|
-
# exit_on_error: bool = False,
|
|
26
23
|
**kwargs: object) -> None:
|
|
27
24
|
"""
|
|
28
25
|
Function of custom api that is responsible for printing messages to console.
|
|
@@ -84,10 +81,6 @@ def print_api(
|
|
|
84
81
|
|
|
85
82
|
# This section takes care of different types of string manipulations for message.
|
|
86
83
|
|
|
87
|
-
# If 'exit_on_error' is set to 'True', we'll add 'exit_message' on new line after 'message'.
|
|
88
|
-
# if error_type and exit_on_error and raise_exception:
|
|
89
|
-
# message = message + '\n' + exit_message
|
|
90
|
-
|
|
91
84
|
# If 'rtl' is set to 'True', we'll add Right-To-Left text conversion to 'message'.
|
|
92
85
|
if rtl:
|
|
93
86
|
# Lazy importing of 'bidi' library. It's not a problem since python caches the library after first import.
|
|
@@ -119,24 +112,8 @@ def print_api(
|
|
|
119
112
|
elif logger_method == 'critical' and not color:
|
|
120
113
|
color = 'red'
|
|
121
114
|
|
|
122
|
-
if color
|
|
123
|
-
message = get_colors_basic_dict(color) + message + ColorsBasic.END
|
|
124
|
-
elif color and logger:
|
|
125
|
-
# Save the original formatter
|
|
126
|
-
original_formatter = None
|
|
127
|
-
|
|
128
|
-
# Find the stream handler and change its formatter
|
|
129
|
-
# noinspection PyUnresolvedReferences
|
|
130
|
-
for handler in logger.handlers:
|
|
131
|
-
if isinstance(handler, logging.StreamHandler):
|
|
132
|
-
# Save the original formatter
|
|
133
|
-
original_formatter = handler.formatter
|
|
134
|
-
original_formatter_string = handlers.get_formatter_string(handler)
|
|
135
|
-
|
|
136
|
-
# Create a colored formatter for errors
|
|
137
|
-
color_formatter = logging.Formatter(
|
|
138
|
-
get_colors_basic_dict(color) + original_formatter_string + ColorsBasic.END)
|
|
139
|
-
handler.setFormatter(color_formatter)
|
|
115
|
+
if color is not None and logger is None:
|
|
116
|
+
message = ansi_escape_codes.get_colors_basic_dict(color) + message + ansi_escape_codes.ColorsBasic.END
|
|
140
117
|
|
|
141
118
|
# If 'online' is set to 'True', we'll output message as oneline.
|
|
142
119
|
if oneline:
|
|
@@ -149,23 +126,20 @@ def print_api(
|
|
|
149
126
|
if logger:
|
|
150
127
|
# Emit to logger only if 'print_end' is default, since we can't take responsibility for anything else.
|
|
151
128
|
if print_end == '\n':
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
handler.setFormatter(original_formatter)
|
|
129
|
+
if stdcolor and color is not None:
|
|
130
|
+
# Use logger to output message.
|
|
131
|
+
# with loggingw.temporary_change_logger_stream_handler_color(logger, color=color):
|
|
132
|
+
with loggingw.temporary_change_logger_stream_handler_emit_color(logger, color):
|
|
133
|
+
getattr(logger, logger_method)(message)
|
|
134
|
+
else:
|
|
135
|
+
# Use logger to output message.
|
|
136
|
+
getattr(logger, logger_method)(message)
|
|
161
137
|
# If logger wasn't passed.
|
|
162
138
|
else:
|
|
163
139
|
# Use print to output the message.
|
|
164
140
|
print(message, end=print_end)
|
|
165
141
|
|
|
166
142
|
# = Main Section with printing cases ===============================================================================
|
|
167
|
-
# exit_message: str = 'Exiting...'
|
|
168
|
-
|
|
169
143
|
# Convert message to string.
|
|
170
144
|
message = str(message)
|
|
171
145
|
|
|
@@ -179,20 +153,6 @@ def print_api(
|
|
|
179
153
|
if error_type:
|
|
180
154
|
print_or_logger()
|
|
181
155
|
|
|
182
|
-
# ==================================
|
|
183
|
-
# This section is responsible for ending the script.
|
|
184
|
-
|
|
185
|
-
# Check if we're inside exception. In this case each of 3 entries in 'sys.exc_info()' tuple will not equal
|
|
186
|
-
# to 'None', so picked only the first one.
|
|
187
|
-
# if sys.exc_info()[0] and not exit_on_error:
|
|
188
|
-
# # If 'raise_exception' is set to 'True', we'll end the script with exception.
|
|
189
|
-
# if pass_exception:
|
|
190
|
-
# pass
|
|
191
|
-
|
|
192
|
-
# If 'exit_on_error' is set to 'True', we'll end the script.
|
|
193
|
-
# if exit_on_error and error_type:
|
|
194
|
-
# sys.exit()
|
|
195
|
-
|
|
196
156
|
|
|
197
157
|
def print_status(
|
|
198
158
|
prefix_string: str,
|
|
@@ -2,8 +2,7 @@ from typing import Union
|
|
|
2
2
|
import threading
|
|
3
3
|
import multiprocessing.managers
|
|
4
4
|
|
|
5
|
-
from .
|
|
6
|
-
from . import system_resources
|
|
5
|
+
from . import system_resources, print_api
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
class SystemResourceMonitor:
|
|
@@ -109,7 +108,7 @@ class SystemResourceMonitor:
|
|
|
109
108
|
self.thread: Union[threading.Thread, None] = None
|
|
110
109
|
# Sets the running state of the monitoring process. Needed to stop the monitoring and queue threads.
|
|
111
110
|
self.running: bool = False
|
|
112
|
-
# The shared results dictionary.
|
|
111
|
+
# The shared results' dictionary.
|
|
113
112
|
self.results: dict = {}
|
|
114
113
|
|
|
115
114
|
def start(self, print_kwargs: dict = None):
|
|
@@ -128,7 +127,8 @@ class SystemResourceMonitor:
|
|
|
128
127
|
"""
|
|
129
128
|
|
|
130
129
|
while self.running:
|
|
131
|
-
# Get the results of the system resources check function and store them in
|
|
130
|
+
# Get the results of the system resources check function and store them in
|
|
131
|
+
# temporary results' dictionary.
|
|
132
132
|
results = system_resources.check_system_resources(
|
|
133
133
|
interval=interval, get_cpu=get_cpu, get_memory=get_memory,
|
|
134
134
|
get_disk_io_bytes=get_disk_io_bytes, get_disk_files_count=get_disk_files_count,
|
|
@@ -149,9 +149,9 @@ class SystemResourceMonitor:
|
|
|
149
149
|
for queue in queue_list:
|
|
150
150
|
queue.put(results)
|
|
151
151
|
|
|
152
|
-
# Update the shared results dictionary with the temporary results dictionary.
|
|
152
|
+
# Update the shared results dictionary with the temporary results' dictionary.
|
|
153
153
|
# This is done in separate steps to avoid overwriting the special 'multiprocessing.Manager.dict' object.
|
|
154
|
-
# So we update the shared results dictionary with the temporary results dictionary.
|
|
154
|
+
# So we update the shared results dictionary with the temporary results' dictionary.
|
|
155
155
|
if manager_dict is not None:
|
|
156
156
|
manager_dict.update(results)
|
|
157
157
|
|
|
@@ -169,7 +169,7 @@ class SystemResourceMonitor:
|
|
|
169
169
|
self.thread.daemon = True
|
|
170
170
|
self.thread.start()
|
|
171
171
|
else:
|
|
172
|
-
print_api("Monitoring is already running.", color='yellow', **print_kwargs)
|
|
172
|
+
print_api.print_api("Monitoring is already running.", color='yellow', **print_kwargs)
|
|
173
173
|
|
|
174
174
|
def get_results(self) -> dict:
|
|
175
175
|
"""
|
|
@@ -258,7 +258,7 @@ def start_monitoring(
|
|
|
258
258
|
)
|
|
259
259
|
SYSTEM_RESOURCES_MONITOR.start()
|
|
260
260
|
else:
|
|
261
|
-
print_api("System resources monitoring is already running.", color='yellow', **(print_kwargs or {}))
|
|
261
|
+
print_api.print_api("System resources monitoring is already running.", color='yellow', **(print_kwargs or {}))
|
|
262
262
|
|
|
263
263
|
|
|
264
264
|
def stop_monitoring():
|
atomicshop/system_resources.py
CHANGED
|
@@ -5,9 +5,8 @@ import shutil
|
|
|
5
5
|
import threading
|
|
6
6
|
import multiprocessing.managers
|
|
7
7
|
|
|
8
|
-
from .print_api import print_api
|
|
9
8
|
from .wrappers.psutilw import cpus, memories, disks
|
|
10
|
-
from . import system_resource_monitor
|
|
9
|
+
from . import system_resource_monitor, print_api
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
def check_system_resources(
|
|
@@ -129,13 +128,13 @@ def wait_for_resource_availability(
|
|
|
129
128
|
|
|
130
129
|
if result['cpu_usage'] < cpu_percent_max and result['memory_usage'] < memory_percent_max:
|
|
131
130
|
break
|
|
132
|
-
print_api(
|
|
131
|
+
print_api.print_api(
|
|
133
132
|
f"Waiting for resources to be available... "
|
|
134
133
|
f"CPU: {result['cpu_usage']}%, Memory: {result['memory_usage']}%", color='yellow')
|
|
135
134
|
time.sleep(wait_time) # Wait for 'wait_time' seconds before checking again
|
|
136
135
|
|
|
137
136
|
|
|
138
|
-
def
|
|
137
|
+
def _test_disk_speed_with_monitoring(
|
|
139
138
|
file_settings: list[dict],
|
|
140
139
|
remove_file_after_each_copy: bool = False,
|
|
141
140
|
target_directory=None,
|
|
@@ -144,6 +143,7 @@ def test_disk_speed_with_monitoring(
|
|
|
144
143
|
print_kwargs: dict = None
|
|
145
144
|
):
|
|
146
145
|
"""
|
|
146
|
+
THIS IS NOT TESTED.
|
|
147
147
|
Generates files and performs write and read operations in the specified target directory,
|
|
148
148
|
while monitoring disk I/O speeds in a separate thread. Returns the maximum read and write rates,
|
|
149
149
|
and the total operation time.
|
|
@@ -171,7 +171,7 @@ def test_disk_speed_with_monitoring(
|
|
|
171
171
|
if monitoring:
|
|
172
172
|
system_resource_monitor.start_monitoring(
|
|
173
173
|
interval=1, get_cpu=False, get_memory=False, get_disk_io_bytes=True, get_disk_used_percent=False,
|
|
174
|
-
get_disk_files_count=True, calculate_maximum_changed_disk_io=True
|
|
174
|
+
get_disk_files_count=True, calculate_maximum_changed_disk_io=True)
|
|
175
175
|
|
|
176
176
|
if target_directory is None:
|
|
177
177
|
target_directory = tempfile.mkdtemp()
|
|
@@ -196,7 +196,7 @@ def test_disk_speed_with_monitoring(
|
|
|
196
196
|
shutil.copy(src_file_path, dest_directory)
|
|
197
197
|
|
|
198
198
|
target_file_path = os.path.join(dest_directory, os.path.basename(src_file_path))
|
|
199
|
-
print_api(f"Copied: {target_file_path}", **(print_kwargs or {}))
|
|
199
|
+
print_api.print_api(f"Copied: {target_file_path}", **(print_kwargs or {}))
|
|
200
200
|
|
|
201
201
|
# Measure read speed.
|
|
202
202
|
with open(target_file_path, "rb") as file:
|
|
@@ -212,7 +212,7 @@ def test_disk_speed_with_monitoring(
|
|
|
212
212
|
|
|
213
213
|
overall_end_time = time.time()
|
|
214
214
|
total_execution_time = overall_end_time - overall_start_time
|
|
215
|
-
print_api(f"Total execution time: {total_execution_time}", **(print_kwargs or {}))
|
|
215
|
+
print_api.print_api(f"Total execution time: {total_execution_time}", **(print_kwargs or {}))
|
|
216
216
|
|
|
217
217
|
# Cleanup. Remove all created files and directories.
|
|
218
218
|
shutil.rmtree(source_directory)
|
|
@@ -220,7 +220,7 @@ def test_disk_speed_with_monitoring(
|
|
|
220
220
|
|
|
221
221
|
if monitoring:
|
|
222
222
|
# Stop the I/O monitoring.
|
|
223
|
-
max_io_changes = system_resource_monitor.
|
|
223
|
+
max_io_changes = system_resource_monitor.get_results()['maximum_disk_io']
|
|
224
224
|
system_resource_monitor.stop_monitoring()
|
|
225
225
|
|
|
226
226
|
return total_execution_time, max_io_changes
|
atomicshop/web.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import urllib.request
|
|
3
3
|
import ssl
|
|
4
|
+
# noinspection PyPackageRequirements
|
|
4
5
|
import certifi
|
|
5
6
|
|
|
6
|
-
from .print_api import print_api
|
|
7
7
|
from .archiver import zips
|
|
8
8
|
from .urls import url_parser
|
|
9
9
|
from .file_io import file_io
|
|
10
10
|
from .wrappers.playwrightw import scenarios
|
|
11
|
-
from . import filesystem
|
|
11
|
+
from . import filesystem, print_api
|
|
12
12
|
|
|
13
13
|
|
|
14
14
|
# https://www.useragents.me/
|
|
@@ -28,10 +28,10 @@ def is_status_ok(status_code: int, **kwargs) -> bool:
|
|
|
28
28
|
"""
|
|
29
29
|
|
|
30
30
|
if status_code != 200:
|
|
31
|
-
print_api(f'URL Error, status code: {str(status_code)}', error_type=True, **kwargs)
|
|
31
|
+
print_api.print_api(f'URL Error, status code: {str(status_code)}', error_type=True, **kwargs)
|
|
32
32
|
return False
|
|
33
33
|
else:
|
|
34
|
-
print_api('URL Status: 200 OK', color="green", **kwargs)
|
|
34
|
+
print_api.print_api('URL Status: 200 OK', color="green", **kwargs)
|
|
35
35
|
return True
|
|
36
36
|
|
|
37
37
|
|
|
@@ -165,10 +165,10 @@ def download(
|
|
|
165
165
|
|
|
166
166
|
def print_to_console(print_end=None):
|
|
167
167
|
if file_size_bytes_int:
|
|
168
|
-
print_api(
|
|
168
|
+
print_api.print_api(
|
|
169
169
|
f'Downloaded bytes: {aggregated_bytes_int} / {file_size_bytes_int}', print_end=print_end, **kwargs)
|
|
170
170
|
else:
|
|
171
|
-
print_api(f'Downloaded bytes: {aggregated_bytes_int}', print_end=print_end, **kwargs)
|
|
171
|
+
print_api.print_api(f'Downloaded bytes: {aggregated_bytes_int}', print_end=print_end, **kwargs)
|
|
172
172
|
|
|
173
173
|
# Size of the buffer to read each time from url.
|
|
174
174
|
buffer_size: int = 4096
|
|
@@ -185,8 +185,8 @@ def download(
|
|
|
185
185
|
# Build full path to file.
|
|
186
186
|
file_path: str = f'{target_directory}{os.sep}{file_name}'
|
|
187
187
|
|
|
188
|
-
print_api(f'Downloading: {file_url}', **kwargs)
|
|
189
|
-
print_api(f'To: {file_path}', **kwargs)
|
|
188
|
+
print_api.print_api(f'Downloading: {file_url}', **kwargs)
|
|
189
|
+
print_api.print_api(f'To: {file_path}', **kwargs)
|
|
190
190
|
|
|
191
191
|
# In order to use 'urllib.request', it is not enough to 'import urllib', you need to 'import urllib.request'.
|
|
192
192
|
# Open the URL for data gathering with SSL context from certifi
|
|
@@ -223,10 +223,10 @@ def download(
|
|
|
223
223
|
print_to_console()
|
|
224
224
|
break
|
|
225
225
|
if aggregated_bytes_int == file_size_bytes_int:
|
|
226
|
-
print_api(f'Successfully Downloaded to: {file_path}', color="green", **kwargs)
|
|
226
|
+
print_api.print_api(f'Successfully Downloaded to: {file_path}', color="green", **kwargs)
|
|
227
227
|
else:
|
|
228
228
|
message = f'Download failed: {aggregated_bytes_int} / {file_size_bytes_int}. File: {file_path}'
|
|
229
|
-
print_api(
|
|
229
|
+
print_api.print_api(
|
|
230
230
|
message, error_type=True, color="red", **kwargs)
|
|
231
231
|
|
|
232
232
|
return file_path
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import threading
|
|
2
3
|
import os
|
|
3
4
|
|
|
4
5
|
|
|
6
|
+
from ...basics import ansi_escape_codes
|
|
7
|
+
|
|
8
|
+
|
|
5
9
|
class HeaderFilter(logging.Filter):
|
|
6
10
|
"""
|
|
7
11
|
A logging.Filter that writes a header to a log file if the file is empty (
|
|
8
12
|
i.e., no log records have been written, i.e.2, on file rotation).
|
|
9
13
|
"""
|
|
14
|
+
|
|
15
|
+
# noinspection PyPep8Naming
|
|
10
16
|
def __init__(self, header, baseFilename):
|
|
11
17
|
super().__init__()
|
|
12
18
|
self.header = header
|
|
@@ -27,6 +33,23 @@ class HeaderFilter(logging.Filter):
|
|
|
27
33
|
return True
|
|
28
34
|
|
|
29
35
|
|
|
36
|
+
class ThreadColorLogFilter(logging.Filter):
|
|
37
|
+
"""
|
|
38
|
+
A logging.Filter that adds color to log records based on the thread that emitted the log record.
|
|
39
|
+
"""
|
|
40
|
+
def __init__(self, color: str, thread_id):
|
|
41
|
+
super().__init__()
|
|
42
|
+
self.color = color
|
|
43
|
+
self.thread_id = thread_id
|
|
44
|
+
|
|
45
|
+
def filter(self, record):
|
|
46
|
+
if threading.get_ident() == self.thread_id:
|
|
47
|
+
record.msg = (
|
|
48
|
+
ansi_escape_codes.get_colors_basic_dict(self.color) + record.msg +
|
|
49
|
+
ansi_escape_codes.ColorsBasic.END)
|
|
50
|
+
return True
|
|
51
|
+
|
|
52
|
+
|
|
30
53
|
"""
|
|
31
54
|
A logging.Filter in Python's logging module is an object that provides a way to perform fine-grained
|
|
32
55
|
filtering of log records.
|
|
@@ -8,6 +8,7 @@ import queue
|
|
|
8
8
|
from typing import Literal, Union
|
|
9
9
|
import threading
|
|
10
10
|
from datetime import datetime
|
|
11
|
+
import contextlib
|
|
11
12
|
|
|
12
13
|
from . import loggers, formatters, filters, consts
|
|
13
14
|
from ... import datetimes, filesystem
|
|
@@ -482,3 +483,22 @@ def get_formatter_string(handler: logging.Handler) -> str:
|
|
|
482
483
|
"""
|
|
483
484
|
|
|
484
485
|
return formatters.get_formatter_string(handler.formatter)
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
@contextlib.contextmanager
|
|
489
|
+
def temporary_change_formatter(handler: logging.Handler, formatter_string: str):
|
|
490
|
+
"""
|
|
491
|
+
Context manager to temporarily change the formatter of the handler.
|
|
492
|
+
|
|
493
|
+
Example:
|
|
494
|
+
with temporary_change_formatter(handler, formatter_string):
|
|
495
|
+
# Do something with the temporary formatter.
|
|
496
|
+
pass
|
|
497
|
+
"""
|
|
498
|
+
original_formatter = handler.formatter
|
|
499
|
+
|
|
500
|
+
try:
|
|
501
|
+
handler.setFormatter(logging.Formatter(formatter_string))
|
|
502
|
+
yield
|
|
503
|
+
finally:
|
|
504
|
+
handler.setFormatter(original_formatter)
|