atomicshop 2.16.42__py3-none-any.whl → 2.16.43__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 CHANGED
@@ -1,4 +1,4 @@
1
1
  """Atomic Basic functions and classes to make developer life easier"""
2
2
 
3
3
  __author__ = "Den Kras"
4
- __version__ = '2.16.42'
4
+ __version__ = '2.16.43'
@@ -53,6 +53,30 @@ def convert_sequence_of_bytes_to_sequence_of_strings(byte_sequence: bytes) -> li
53
53
  return result
54
54
 
55
55
 
56
+ def convert_sequence_of_bytes_to_exact_string(
57
+ byte_sequence: bytes,
58
+ add_space_between_bytes: bool = False,
59
+ ) -> str:
60
+ """
61
+ Convert sequence of bytes to exact string.
62
+ Example: b'\xc0\x00' -> 'c000'
63
+
64
+ :param byte_sequence: bytes, sequence of bytes.
65
+ :param add_space_between_bytes: bool, add space between bytes.
66
+ Example: b'\xc0\x00' -> 'c0 00'
67
+ :return: string.
68
+ """
69
+
70
+ # Convert to hex string and format
71
+ byte_list: list = []
72
+ for byte in byte_sequence:
73
+ byte_list.append(f'{byte:02x}')
74
+
75
+ result = ''.join(byte_list)
76
+
77
+ return result
78
+
79
+
56
80
  def find_position(target: bytes, file_path: str = None, file_bytes: bytes = None, chunk_size: int = None, starting_position: int = 0) -> int:
57
81
  """
58
82
  Find position of the target bytes string in the file.
atomicshop/dns.py CHANGED
@@ -77,6 +77,17 @@ def get_default_dns_gateway() -> tuple[bool, list[str]]:
77
77
  return is_dynamic, dns_servers
78
78
 
79
79
 
80
+ def get_default_dns_gateway_with_dns_resolver() -> list[str]:
81
+ """
82
+ Get the default DNS gateway from the system using dns.resolver.
83
+ :return: tuple(is dynamic boolean, list of DNS server IPv4s).
84
+ """
85
+
86
+ resolver = dns.resolver.Resolver()
87
+ dns_servers = list(resolver.nameservers)
88
+ return dns_servers
89
+
90
+
80
91
  def set_connection_dns_gateway_static(
81
92
  dns_servers: list[str],
82
93
  connection_name: str = None,
atomicshop/http_parse.py CHANGED
@@ -2,7 +2,6 @@ from http.server import BaseHTTPRequestHandler
2
2
  from http.client import HTTPResponse
3
3
  import http
4
4
  from io import BytesIO
5
- import socket
6
5
 
7
6
 
8
7
  class HTTPRequestParse(BaseHTTPRequestHandler):
@@ -50,8 +49,8 @@ class HTTPRequestParse(BaseHTTPRequestHandler):
50
49
  """
51
50
 
52
51
  # noinspection PyMissingConstructor
53
- def __init__(self, request_text):
54
- self.request_text = request_text
52
+ def __init__(self, request_bytes: bytes):
53
+ self.request_bytes: bytes = request_bytes
55
54
 
56
55
  # noinspection PyTypeChecker
57
56
  self.rfile = None
@@ -107,7 +106,7 @@ class HTTPRequestParse(BaseHTTPRequestHandler):
107
106
  error: str = str()
108
107
  info: str = str()
109
108
 
110
- self.rfile = BytesIO(self.request_text)
109
+ self.rfile = BytesIO(self.request_bytes)
111
110
  self.raw_requestline = self.rfile.readline()
112
111
  self.error_code = self.error_message = None
113
112
  self.parse_request()
@@ -152,6 +151,7 @@ class FakeSocket:
152
151
  def __init__(self, response_bytes):
153
152
  self._file = BytesIO(response_bytes)
154
153
 
154
+ # noinspection PyUnusedLocal
155
155
  def makefile(self, mode='rb', buffering=-1) -> BytesIO:
156
156
  """
157
157
  Mimics the socket's makefile method, returning the BytesIO object.
@@ -100,15 +100,12 @@ def thread_worker_main(
100
100
  client_message.protocol = 'HTTP'
101
101
  client_message.request_raw_decoded = request_decoded
102
102
  print_api(request_parsing_info, logger=network_logger, logger_method='info')
103
- network_logger.info(f"Method: {request_decoded.command}")
104
- network_logger.info(f"Path: {request_decoded.path}")
105
- # If there was error - the request is really HTTP, but there's a problem with its structure.
103
+ network_logger.info(f"Method: {request_decoded.command} | Path: {request_decoded.path}")
106
104
  else:
107
- # client_message.error = request_parsing_error
108
- print_api(request_parsing_error, logger=network_logger, logger_method='error', color='yellow')
109
105
  # It doesn't matter if we have HTTP Parsing error, since the request may not be really HTTP, so it is OK
110
106
  # not to log it into statistics.
111
107
  # statistics_error_list.append(error_message)
108
+ print_api(request_parsing_error, logger=network_logger, logger_method='error', color='yellow')
112
109
 
113
110
  def finish_thread():
114
111
  # At this stage there could be several times that the same socket was used to the service server - we need to
@@ -204,8 +201,6 @@ def thread_worker_main(
204
201
  client_message.request_raw_bytes = client_received_raw_data
205
202
 
206
203
  parse_http()
207
- if client_message.protocol != 'HTTP':
208
- pass
209
204
 
210
205
  # Custom parser, should parse HTTP body or the whole message if not HTTP.
211
206
  parser_instance = parser(client_message)
@@ -19,6 +19,7 @@ from . import config_static, recs_files
19
19
 
20
20
  NETWORK_INTERFACE_IS_DYNAMIC: bool = bool()
21
21
  NETWORK_INTERFACE_IPV4_ADDRESS_LIST: list[str] = list()
22
+ IS_SET_DNS_GATEWAY: bool = False
22
23
  # noinspection PyTypeChecker
23
24
  RECS_PROCESS_INSTANCE: multiprocessing.Process = None
24
25
 
@@ -36,7 +37,7 @@ except win_console.NotWindowsConsoleError:
36
37
 
37
38
 
38
39
  def exit_cleanup():
39
- if permissions.is_admin():
40
+ if permissions.is_admin() and IS_SET_DNS_GATEWAY:
40
41
  is_dns_dynamic, current_dns_gateway = dns.get_default_dns_gateway()
41
42
  status_string = 'Dynamic' if is_dns_dynamic else 'Static'
42
43
  print_api.print_api(f'Current DNS Gateway: {status_string}, {current_dns_gateway}')
@@ -347,10 +348,14 @@ def mitm_server(config_file_path: str):
347
348
  dns_gateway_server_list = [base.DEFAULT_IPV4]
348
349
  set_dns_gateway = True
349
350
 
350
- # Get current network interface state.
351
- global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
352
- NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
353
351
  if set_dns_gateway:
352
+ global IS_SET_DNS_GATEWAY
353
+ IS_SET_DNS_GATEWAY = True
354
+
355
+ # Get current network interface state.
356
+ global NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST
357
+ NETWORK_INTERFACE_IS_DYNAMIC, NETWORK_INTERFACE_IPV4_ADDRESS_LIST = dns.get_default_dns_gateway()
358
+
354
359
  # Set the DNS gateway to the specified one only if the DNS gateway is dynamic, or it is static but different
355
360
  # from the one specified in the configuration file.
356
361
  if (NETWORK_INTERFACE_IS_DYNAMIC or (not NETWORK_INTERFACE_IS_DYNAMIC and
atomicshop/web.py CHANGED
@@ -90,10 +90,13 @@ def get_page_bytes(
90
90
 
91
91
 
92
92
  def get_page_content(
93
- url: str, get_method: str = 'urllib', path: str = None,
93
+ url: str,
94
+ get_method: str = 'urllib',
95
+ path: str = None,
94
96
  playwright_pdf_format: str = 'A4',
95
97
  playwright_html_txt_convert_to_bytes: bool = True,
96
- print_kwargs: dict = None) -> any:
98
+ print_kwargs: dict = None
99
+ ) -> any:
97
100
  """
98
101
  Function returns the page content from the given URL.
99
102
 
@@ -0,0 +1,176 @@
1
+ from typing import Union
2
+ import logging
3
+
4
+ from websockets.server import ServerProtocol
5
+ from websockets.client import ClientProtocol
6
+ from websockets.extensions.permessage_deflate import ServerPerMessageDeflateFactory, ClientPerMessageDeflateFactory
7
+ from websockets.http11 import Request, Response
8
+ from websockets.frames import Frame, Opcode, Close
9
+ from websockets.uri import parse_uri
10
+ from websockets.exceptions import InvalidHeaderValue
11
+ from websockets.protocol import OPEN
12
+
13
+
14
+ class WebsocketRequestParse:
15
+ """
16
+ Parse the websocket request and return the data
17
+ """
18
+ def __init__(
19
+ self,
20
+ enable_logging: bool = False,
21
+ ):
22
+ """
23
+ Initialize the websocket parser.
24
+
25
+ :param enable_logging: bool: Enable logging for the websocket protocol.
26
+ """
27
+ # noinspection PyTypeChecker
28
+ self.request_bytes: bytes = None
29
+
30
+ # Set up extensions
31
+ permessage_deflate_factory = ServerPerMessageDeflateFactory()
32
+
33
+ # Create the protocol instance
34
+ self.protocol = ServerProtocol(
35
+ extensions=[permessage_deflate_factory],
36
+ )
37
+ # At this state the protocol.state is State.CONNECTING
38
+
39
+ if enable_logging:
40
+ logging.basicConfig(level=logging.DEBUG)
41
+ self.protocol.logger.setLevel(logging.DEBUG)
42
+
43
+ def parse(
44
+ self,
45
+ request_bytes: bytes
46
+ ) -> Union[str, bytes, Request]:
47
+ """
48
+ Parse the websocket request and return the data
49
+
50
+ :param request_bytes: bytes: The raw bytes of the websocket request.
51
+ :return: Request: The parsed request object.
52
+ """
53
+
54
+ self.protocol.receive_data(request_bytes)
55
+ events = self.protocol.events_received()
56
+ for event in events:
57
+ if isinstance(event, Request):
58
+ # Accept the handshake.
59
+ # After the response is sent, it means the handshake was successful, the protocol.state is State.OPEN
60
+ # Only after this state we can parse frames.
61
+ response = self.protocol.accept(event)
62
+ self.protocol.send_response(response)
63
+ return event
64
+ elif isinstance(event, Frame):
65
+ frame = event
66
+ if frame.opcode == Opcode.TEXT:
67
+ message = frame.data.decode('utf-8')
68
+ return message
69
+ elif frame.opcode == Opcode.BINARY:
70
+ return frame.data
71
+
72
+ """
73
+ # Handle control frames, these are here for the future references.
74
+ elif frame.opcode == Opcode.CLOSE:
75
+ close_info = Close.parse(frame.data)
76
+ print(f"Connection closed by client: {close_info.code}, {close_info.reason}")
77
+ # Send a close frame in response if not already sent
78
+ if self.protocol.state == self.protocol.OPEN:
79
+ self.protocol.send_close()
80
+ elif frame.opcode == Opcode.PING:
81
+ # Respond to ping with pong
82
+ self.protocol.send_pong(frame.data)
83
+ elif frame.opcode == Opcode.PONG:
84
+ print("Received pong")
85
+ """
86
+
87
+
88
+ class WebsocketResponseParse:
89
+ """
90
+ Parse the websocket response and return the data
91
+ """
92
+ def __init__(
93
+ self,
94
+ enable_logging: bool = False,
95
+ ):
96
+ """
97
+ Initialize the websocket parser.
98
+
99
+ :param enable_logging: bool: Enable logging for the websocket protocol.
100
+ """
101
+ # noinspection PyTypeChecker
102
+ self.response_bytes: bytes = None
103
+
104
+ # Set up extensions
105
+ permessage_deflate_factory = ClientPerMessageDeflateFactory()
106
+
107
+ # Parse the WebSocket URI.
108
+ # Since we're parsing the response, we don't need the URI, but the protocol object requires it.
109
+ # So we will just use a dummy URI.
110
+ wsuri = parse_uri('ws://example.com/websocket')
111
+
112
+ # Create the protocol instance
113
+ self.protocol = ClientProtocol(
114
+ wsuri,
115
+ extensions=[permessage_deflate_factory],
116
+ )
117
+
118
+ if enable_logging:
119
+ logging.basicConfig(level=logging.DEBUG)
120
+ # self.protocol.logger.setLevel(logging.DEBUG)
121
+ self.protocol.debug = True
122
+
123
+ # Perform the handshake and emulate the connection and request sending.
124
+ request = self.protocol.connect()
125
+ self.protocol.send_request(request)
126
+ _ = self.protocol.data_to_send()
127
+ # At this state the protocol.state is State.CONNECTING
128
+
129
+ def parse(
130
+ self,
131
+ response_bytes: bytes
132
+ ) -> Union[str, bytes, Response]:
133
+ """
134
+ Parse the websocket response and return the data
135
+
136
+ :param response_bytes: bytes: The raw bytes of the websocket response.
137
+ :return: The parsed response.
138
+ """
139
+
140
+ self.protocol.receive_data(response_bytes)
141
+ events = self.protocol.events_received()
142
+ for event in events:
143
+ if isinstance(event, Response):
144
+ # Accept the handshake.
145
+ # After the response is sent, it means the handshake was successful, the protocol.state is State.OPEN
146
+ # Only after this state we can parse frames.
147
+ try:
148
+ self.protocol.process_response(event)
149
+ except InvalidHeaderValue as e:
150
+ headers = event.headers
151
+ self.protocol.extensions = self.protocol.process_extensions(headers)
152
+ self.protocol.subprotocol = self.protocol.process_subprotocol(headers)
153
+ self.protocol.state = OPEN
154
+ return event
155
+ elif isinstance(event, Frame):
156
+ frame = event
157
+ if frame.opcode == Opcode.TEXT:
158
+ message = frame.data.decode('utf-8')
159
+ return message
160
+ elif frame.opcode == Opcode.BINARY:
161
+ return frame.data
162
+
163
+ """
164
+ # Handle control frames, these are here for the future references.
165
+ elif frame.opcode == Opcode.CLOSE:
166
+ close_info = Close.parse(frame.data)
167
+ print(f"Connection closed by client: {close_info.code}, {close_info.reason}")
168
+ # Send a close frame in response if not already sent
169
+ if self.protocol.state == self.protocol.OPEN:
170
+ self.protocol.send_close()
171
+ elif frame.opcode == Opcode.PING:
172
+ # Respond to ping with pong
173
+ self.protocol.send_pong(frame.data)
174
+ elif frame.opcode == Opcode.PONG:
175
+ print("Received pong")
176
+ """
@@ -7,7 +7,12 @@ from .. import config_install
7
7
 
8
8
  def install_after_restart(
9
9
  installation_directory: str,
10
- install_type: Union[None, Literal['backend', 'frontend', 'db']] = None
10
+ install_type: Union[
11
+ None,
12
+ Literal['backend', 'frontend', 'db']] = None,
13
+ log_level: Union[
14
+ None,
15
+ Literal['DEBUG', 'INFO', 'WARNING', 'ERROR']] = None
11
16
  ):
12
17
  """
13
18
  This function will continue the installation the FACT_core after the restart of the computer.
@@ -20,6 +25,9 @@ def install_after_restart(
20
25
  --backend: Distributed setup, Install the FACT_core backend.
21
26
  --frontend: Distributed setup, Install the FACT_core frontend.
22
27
  --db: Distributed setup, Install the FACT_core database.
28
+ :param log_level: string, the log level to use for the installation.
29
+ The same as using the '--log-level' parameter in the 'install.py' script.
30
+ The default is 'INFO' in the 'install.py' script.
23
31
  :return:
24
32
  """
25
33
 
@@ -28,8 +36,11 @@ def install_after_restart(
28
36
  if install_type:
29
37
  install_command = install_command + ' --' + install_type
30
38
 
39
+ if log_level:
40
+ install_command = install_command + ' --log-level ' + log_level
41
+
31
42
  # Install the FACT_core repo.
32
43
  process.execute_with_live_output(cmd=install_command, verbose=True)
33
44
  # Remove the FACT_core installation log.
34
- working_directory_path: str = filesystem.get_working_directory()
45
+ # working_directory_path: str = filesystem.get_working_directory()
35
46
  # filesystem.remove_file(str(Path(working_directory_path, config_install.INSTALL_LOG_FILE_NAME)))
@@ -174,6 +174,7 @@ class MongoDBWrapper:
174
174
  self,
175
175
  collection_name: str,
176
176
  filter_query: dict = None,
177
+ projection: dict = None,
177
178
  page: int = None,
178
179
  items: int = None,
179
180
  sort: dict[str, Literal[
@@ -192,6 +193,7 @@ class MongoDBWrapper:
192
193
  filter_query = None
193
194
 
194
195
  CHECK MORE EXAMPLES IN THE DOCSTRING OF THE FUNCTION 'find' BELOW which is not in this class.
196
+ :param projection: dict, the only fields to return or exclude.
195
197
  :param page: int, the page number (Optional).
196
198
  The results are filtered after results are fetched from db.
197
199
  :param items: int, the number of results per page (Optional).
@@ -229,7 +231,8 @@ class MongoDBWrapper:
229
231
 
230
232
  entries: list[dict] = find(
231
233
  database=self.db, collection_name=collection_name,
232
- filter_query=filter_query, page=page, items=items, sort=sort,
234
+ filter_query=filter_query, projection=projection,
235
+ page=page, items=items, sort=sort,
233
236
  convert_object_id_to_str=convert_object_id_to_str, key_convert_to_dict=keys_convert_to_dict,
234
237
  mongo_client=self.client, close_client=False)
235
238
 
@@ -827,7 +830,7 @@ def find(
827
830
 
828
831
  entries: list[dict] = list(collection_items)
829
832
 
830
- if convert_object_id_to_str:
833
+ if entries and convert_object_id_to_str and '_id' in entries[0]:
831
834
  for entry_index, entry in enumerate(entries):
832
835
  entries[entry_index]['_id'] = str(entry['_id'])
833
836
 
@@ -44,8 +44,12 @@ def get_page_text_content(page) -> str:
44
44
  :return: string, text content of the page.
45
45
  """
46
46
 
47
- text_content: str = page.evaluate('''() => {
48
- return document.body.innerText;
49
- }''')
47
+ # Full javascript.
48
+ # text_content: str = page.evaluate('''() => {
49
+ # return document.body.innerText;
50
+ # }''')
51
+
52
+ # Short javascript.
53
+ text_content: str = page.evaluate("document.body.innerText")
50
54
 
51
55
  return text_content
@@ -43,8 +43,12 @@ def get_text_from_html_tag(url: str, tag_name: str, attribute: str, value: str)
43
43
 
44
44
 
45
45
  def get_page_content(
46
- url: str, page_format: str = 'html', path: str = None, print_kwargs: dict = None, pdf_format: str = 'A4',
47
- html_txt_convert_to_bytes: bool = True
46
+ url: str,
47
+ page_format: str = 'html',
48
+ path: str = None,
49
+ pdf_format: str = 'A4',
50
+ html_txt_convert_to_bytes: bool = True,
51
+ print_kwargs: dict = None
48
52
  ) -> any:
49
53
  """
50
54
  The function receives playwright engine and page object, navigates to URL, gets page content in specified format,
@@ -57,10 +61,10 @@ def get_page_content(
57
61
  'png' - returns png binary.
58
62
  'jpeg' - returns jpeg binary.
59
63
  :param path: string of path to save the file to. Default is None.
60
- :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
61
64
  :param pdf_format: string of pdf format, applicable only if 'page_format=pdf'. Default is 'A4'.
62
65
  :param html_txt_convert_to_bytes: boolean, applicable only if 'page_format=html' or 'page_format=txt'.
63
66
  Default is True.
67
+ :param print_kwargs: dict, that contains all the arguments for 'print_api' function.
64
68
 
65
69
  :return: any page content in specified format.
66
70
  """
@@ -95,8 +99,13 @@ def get_page_content(
95
99
 
96
100
 
97
101
  def get_page_content_in_thread(
98
- url: str, page_format: str = 'html', path: str = None, print_kwargs: dict = None, pdf_format: str = 'A4',
99
- html_txt_convert_to_bytes: bool = True):
102
+ url: str,
103
+ page_format: str = 'html',
104
+ path: str = None,
105
+ pdf_format: str = 'A4',
106
+ html_txt_convert_to_bytes: bool = True,
107
+ print_kwargs: dict = None
108
+ ):
100
109
  """
101
110
  The function uses 'threads.thread_wrap_var' function in order to wrap the function 'get_page_content' and
102
111
  execute it in a thread with arguments and return the result.
@@ -144,8 +144,23 @@ def get_default_dns_gateway() -> tuple[bool, list[str]]:
144
144
  :return: tuple(is dynamic boolean, list of DNS server IPv4s).
145
145
  """
146
146
 
147
+ def get_current_interface_status(current_interface_settings: dict) -> tuple[bool, list[str]]:
148
+ if current_interface_settings['NameServer']:
149
+ result = (False, current_interface_settings['NameServer'].split(','))
150
+ else:
151
+ result = (True, current_interface_settings['DhcpNameServer'].split(','))
152
+
153
+ return result
154
+
155
+
147
156
  # Get current default IPv4 address of the interface that is being used for internet.
148
157
  default_ipv4_address: str = socket.gethostbyname(socket.gethostname())
158
+ # If the default IPv4 address is localhost, then it could mean that the system is not connected to the internet.
159
+ # Or there is no network adapter at all.
160
+ default_dns_gateway_list: list[str] = []
161
+ if default_ipv4_address == '127.0.0.1':
162
+ from ... import dns
163
+ default_dns_gateway_list = dns.get_default_dns_gateway_with_dns_resolver()
149
164
 
150
165
  # Get all network interface settings from the registry.
151
166
  all_interfaces_configurations = get_network_interfaces_settings()
@@ -153,22 +168,36 @@ def get_default_dns_gateway() -> tuple[bool, list[str]]:
153
168
  # Find the interface that has this IPv4 assigned.
154
169
  function_result: tuple = tuple()
155
170
  for interface_guid, interface_settings in all_interfaces_configurations.items():
156
- current_interface_static_ipv4_address: list = interface_settings.get('IPAddress', None)
157
- current_interface_dynamic_ipv4_address: str = interface_settings.get('DhcpIPAddress', None)
158
-
159
- static_and_ip_match: bool = (
160
- current_interface_static_ipv4_address and
161
- current_interface_static_ipv4_address[0] == default_ipv4_address)
162
- dynamic_and_ip_match: bool = (
163
- current_interface_dynamic_ipv4_address and
164
- current_interface_dynamic_ipv4_address == default_ipv4_address)
165
- if static_and_ip_match or dynamic_and_ip_match:
166
- if interface_settings['NameServer']:
167
- function_result = (False, interface_settings['NameServer'].split(','))
168
- else:
169
- function_result = (True, interface_settings['DhcpNameServer'].split(','))
170
-
171
- break
171
+ if not interface_settings:
172
+ continue
173
+
174
+ if ' ' in interface_settings['NameServer']:
175
+ interface_settings['NameServer'] = interface_settings['NameServer'].replace(' ', ',')
176
+ if ' ' in interface_settings['DhcpNameServer']:
177
+ interface_settings['DhcpNameServer'] = interface_settings['DhcpNameServer'].replace(' ', ',')
178
+
179
+ if not default_dns_gateway_list:
180
+ current_interface_static_ipv4_address: list = interface_settings.get('IPAddress', None)
181
+ current_interface_dynamic_ipv4_address: str = interface_settings.get('DhcpIPAddress', None)
182
+
183
+ static_and_ip_match: bool = (
184
+ current_interface_static_ipv4_address and
185
+ current_interface_static_ipv4_address[0] == default_ipv4_address)
186
+ dynamic_and_ip_match: bool = (
187
+ current_interface_dynamic_ipv4_address and
188
+ current_interface_dynamic_ipv4_address == default_ipv4_address)
189
+ if static_and_ip_match or dynamic_and_ip_match:
190
+ function_result = get_current_interface_status(interface_settings)
191
+
192
+ break
193
+ else:
194
+ current_interface_name_server_list: list[str] = interface_settings['NameServer'].split(',')
195
+ current_interface_dhcp_name_server_list: list[str] = interface_settings['DhcpNameServer'].split(',')
196
+ if (current_interface_name_server_list == default_dns_gateway_list or
197
+ current_interface_dhcp_name_server_list == default_dns_gateway_list):
198
+ function_result = get_current_interface_status(interface_settings)
199
+
200
+ break
172
201
 
173
202
  # noinspection PyTypeChecker
174
203
  return function_result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.42
3
+ Version: 2.16.43
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -60,6 +60,7 @@ Requires-Dist: SoundCard
60
60
  Requires-Dist: soundfile
61
61
  Requires-Dist: SpeechRecognition
62
62
  Requires-Dist: tldextract
63
+ Requires-Dist: websockets
63
64
  Requires-Dist: pywin32 ; platform_system == "Windows"
64
65
 
65
66
  <h1 align="center">Atomic Workshop</h1>
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=tWZJJS59JBaRpS5l3fKPYI9YQJf0dM6cQNGppw5sjoo,124
1
+ atomicshop/__init__.py,sha256=eN5mJMelXPzsx3RapgUonBJKKZKyH4jUURpdEWoMogA,124
2
2
  atomicshop/_basics_temp.py,sha256=6cu2dd6r2dLrd1BRNcVDKTHlsHs_26Gpw8QS6v32lQ0,3699
3
3
  atomicshop/_create_pdf_demo.py,sha256=Yi-PGZuMg0RKvQmLqVeLIZYadqEZwUm-4A9JxBl_vYA,3713
4
4
  atomicshop/_patch_import.py,sha256=ENp55sKVJ0e6-4lBvZnpz9PQCt3Otbur7F6aXDlyje4,6334
@@ -10,7 +10,7 @@ atomicshop/console_output.py,sha256=AOSJjrRryE97PAGtgDL03IBtWSi02aNol8noDnW3k6M,
10
10
  atomicshop/console_user_response.py,sha256=31HIy9QGXa7f-GVR8MzJauQ79E_ZqAeagF3Ks4GGdDU,3234
11
11
  atomicshop/datetimes.py,sha256=IQZ66lmta-ZqxYbyHzm_9eugbJFSilXK1e0kfMgoXGg,18371
12
12
  atomicshop/diff_check.py,sha256=Q9RCqRa-jEgo7Fujx08_JTuZ6qcgttMI6aNYB6zN9Ik,27173
13
- atomicshop/dns.py,sha256=3AWZFczxwuYPyVG2r_gXrmHOyLYaqWjO7QYQk9Heghk,6484
13
+ atomicshop/dns.py,sha256=5Gimq_WY2arqg7BeGmR7P--fGfnH0Dsh8lrOt_H0jRY,6817
14
14
  atomicshop/domains.py,sha256=Rxu6JhhMqFZRcoFs69IoEd1PtYca0lMCG6F1AomP7z4,3197
15
15
  atomicshop/emails.py,sha256=I0KyODQpIMEsNRi9YWSOL8EUPBiWyon3HRdIuSj3AEU,1410
16
16
  atomicshop/file_types.py,sha256=-0jzQMRlmU1AP9DARjk-HJm1tVE22E6ngP2mRblyEjY,763
@@ -19,7 +19,7 @@ atomicshop/functions.py,sha256=pK8hoCE9z61PtWCxQJsda7YAphrLH1wxU5x-1QJP-sY,499
19
19
  atomicshop/get_process_list.py,sha256=8cxb7gKe9sl4R6H2yMi8J6oe-RkonTvCdKjRFqi-Fs4,6075
20
20
  atomicshop/get_process_name_cmd_dll.py,sha256=CtaSp3mgxxJKCCVW8BLx6BJNx4giCklU_T7USiCEwfc,5162
21
21
  atomicshop/hashing.py,sha256=Le8qGFyt3_wX-zGTeQShz7L2HL_b6nVv9PnawjglyHo,3474
22
- atomicshop/http_parse.py,sha256=bIrJODFmumfI6uSwWkTtjtJWS-o40kn_eg7J9Mmwr20,10002
22
+ atomicshop/http_parse.py,sha256=WoUoz5HeiIjPzFQYn7d2aeuAKa0kVWvrswyKMZT6VUg,10039
23
23
  atomicshop/inspect_wrapper.py,sha256=sGRVQhrJovNygHTydqJj0hxES-aB2Eg9KbIk3G31apw,11429
24
24
  atomicshop/ip_addresses.py,sha256=Hvi4TumEFoTEpKWaq5WNF-YzcRzt24IxmNgv-Mgax1s,1190
25
25
  atomicshop/keyboard_press.py,sha256=1W5kRtOB75fulVx-uF2yarBhW0_IzdI1k73AnvXstk0,452
@@ -44,7 +44,8 @@ atomicshop/timer.py,sha256=7Zw1KRV0acHCRATMnanyX2MLBb63Hc-6us3rCZ9dNlY,2345
44
44
  atomicshop/urls.py,sha256=aJ0NGS9qqaKeqjkkWBs80jaBBg6MYBiPuLIyPGxscVc,1557
45
45
  atomicshop/uuids.py,sha256=JSQdm3ZTJiwPQ1gYe6kU0TKS_7suwVrHc8JZDGYlydM,2214
46
46
  atomicshop/virtualization.py,sha256=LPP4vjE0Vr10R6DA4lqhfX_WaNdDGRAZUW0Am6VeGco,494
47
- atomicshop/web.py,sha256=DkpdUYiwRu_Du5J8LlUyxLj-NAEnDLfEwfVlSI22trM,11642
47
+ atomicshop/web.py,sha256=GLdTXgMxg1_0UQaXC4bOvARVyuFg7SPIeJdsCHV8rNE,11662
48
+ atomicshop/websocket_parse.py,sha256=Ykva7XI_t-f4H_z0mKxLuyQ04LxZBblHZN_PbYB9idY,6968
48
49
  atomicshop/a_installs/ubuntu/docker_rootless.py,sha256=9IPNtGZYjfy1_n6ZRt7gWz9KZgR6XCgevjqq02xk-o0,281
49
50
  atomicshop/a_installs/ubuntu/docker_sudo.py,sha256=JzayxeyKDtiuT4Icp2L2LyFRbx4wvpyN_bHLfZ-yX5E,281
50
51
  atomicshop/a_installs/ubuntu/elastic_search_and_kibana.py,sha256=yRB-l1zBxdiN6av-FwNkhcBlaeu4zrDPjQ0uPGgpK2I,244
@@ -84,7 +85,7 @@ atomicshop/basics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU
84
85
  atomicshop/basics/ansi_escape_codes.py,sha256=WtIkm-BjSZS5J5irDUdAMBNvdX-qXFZcTX98jcBMpJE,3140
85
86
  atomicshop/basics/argparse_template.py,sha256=horwgSf3MX1ZgRnYxtmmQuz9OU_vKrKggF65gmjlmfg,5836
86
87
  atomicshop/basics/booleans.py,sha256=V36NaMf8AffhCom_ovQeOZlYcdtGyIcQwWKki6h7O0M,1745
87
- atomicshop/basics/bytes_arrays.py,sha256=WvSRDhIGt1ywF95t-yNgpxLm1nlZUbM1Dz6QckcyE8Y,5915
88
+ atomicshop/basics/bytes_arrays.py,sha256=tU7KF0UAFSErGNcan4Uz1GJxeIYVRuUu9sHVZHgyNnw,6542
88
89
  atomicshop/basics/classes.py,sha256=T0Bm13hKvkXG3med68ptL7XuoWiCi3TE-K5TMINDlrY,10655
89
90
  atomicshop/basics/dicts.py,sha256=DeYHIh940pMMBrFhpXt4dsigFVYzTrlqWymNo4Pq_Js,14049
90
91
  atomicshop/basics/dicts_nested.py,sha256=StYxYnYPa0SEJr1lmEwAv5zfERWWqoULeyG8e0zRAwE,4107
@@ -125,11 +126,11 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
125
126
  atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
126
127
  atomicshop/mitm/config_static.py,sha256=ROAtbibSWSsF3BraUbhu-QO3MPIFqYY5KUKgsQbiSkk,7813
127
128
  atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
128
- atomicshop/mitm/connection_thread_worker.py,sha256=q_h4rRHupuUMwGsHEyKUhOLCtIAEHDB4loLrxApzQvQ,17859
129
+ atomicshop/mitm/connection_thread_worker.py,sha256=DxHCgDtCbSQCIX80WK9hJhp3v37pMjmm-mr3y6tyJMY,17581
129
130
  atomicshop/mitm/import_config.py,sha256=0Ij14aISTllTOiWYJpIUMOWobQqGofD6uafui5uWllE,9272
130
131
  atomicshop/mitm/initialize_engines.py,sha256=VyJE8QnzlgD3QbX5inz5o6rC3zQ3is9CeTL7-B10g1w,8292
131
132
  atomicshop/mitm/message.py,sha256=URR5JKSuAT8XmGIkyprEjlPW2GW4ef_gfUz_GgcFseE,2184
132
- atomicshop/mitm/mitm_main.py,sha256=tT6U4UuJ1PgNs__gDkExSR_qIbCjdBPkOQl8RPMMC5c,23224
133
+ atomicshop/mitm/mitm_main.py,sha256=5c-9oxBiLueTbZr4Dyd4EEOorEUix5vSWxX9p5O1fBs,23375
133
134
  atomicshop/mitm/recs_files.py,sha256=mMyO1kPB-VkS_pbWCDhZHKdbWzlPbYSout61QuzHOao,3077
134
135
  atomicshop/mitm/shared_functions.py,sha256=l6oEyv4ug5D_03V3QLADYoocbcL2Ml_dYVW2WKM21l4,1818
135
136
  atomicshop/mitm/statistic_analyzer.py,sha256=5_sAYGX2Xunzo_pS2W5WijNCwr_BlGJbbOO462y_wN4,27533
@@ -228,7 +229,7 @@ atomicshop/wrappers/factw/fact_extractor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5
228
229
  atomicshop/wrappers/factw/fact_extractor/docker_image.py,sha256=2FyYjnw8gxFNwISQ83OwH-iGivkFi6EAluyCZ0loHEQ,2501
229
230
  atomicshop/wrappers/factw/fact_extractor/get_extractor.py,sha256=2mfOAftHIlCcGt1s7MWdq7DsDCuI6wX3MtvcEZ4SK-0,756
230
231
  atomicshop/wrappers/factw/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
231
- atomicshop/wrappers/factw/install/install_after_restart.py,sha256=-VXC3KDX2BzF0oi0ELCmfch55vLk-3t16KxlmYyUGD8,1560
232
+ atomicshop/wrappers/factw/install/install_after_restart.py,sha256=zsghES-pyCNiGU2Yix_fFBiDEOWfQ0dtbmyVeZozgL8,2012
232
233
  atomicshop/wrappers/factw/install/pre_install_and_install_before_restart.py,sha256=GFsO9MTH0czKoxkiPJtjalilUwsmFLBCcx9Znv37S4M,5945
233
234
  atomicshop/wrappers/factw/postgresql/__init__.py,sha256=xMBn2d3Exo23IPP2F_9-SXmOlhFbwWDgS9KwozSTjA0,162
234
235
  atomicshop/wrappers/factw/postgresql/analysis.py,sha256=2Rxzy2jyq3zEKIo53z8VkjuslKE_i5mq2ZpmJAvyd6U,716
@@ -257,7 +258,7 @@ atomicshop/wrappers/mongodbw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
257
258
  atomicshop/wrappers/mongodbw/install_mongodb_ubuntu.py,sha256=pmI9AwWJ2cv5h8GionSpSJkllg6kfp0M381pk6y4Y5U,4015
258
259
  atomicshop/wrappers/mongodbw/install_mongodb_win.py,sha256=3ZPqrXxj3lC-PnAKGXclylLuOqsbyXYeUpb5iGjdeUU,6626
259
260
  atomicshop/wrappers/mongodbw/mongo_infra.py,sha256=IjEF0jPzQz866MpTm7rnksnyyWQeUT_B2h2DA9ryAio,2034
260
- atomicshop/wrappers/mongodbw/mongodbw.py,sha256=Vxsw0lNaJxAVzQWRx_9dNQXKTIKjMyZnx9FbYbINkBk,52435
261
+ atomicshop/wrappers/mongodbw/mongodbw.py,sha256=IkEw86QFyVRU-5p5s6_6yupvSxmaQxr59GKNgSEkAm4,52617
261
262
  atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
262
263
  atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=TKGa3jSlSqZTL2NA0nMkWDFtlkz7rxGGn44ywCg7MN8,5228
263
264
  atomicshop/wrappers/playwrightw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -266,11 +267,11 @@ atomicshop/wrappers/playwrightw/base.py,sha256=WeRpx8otdXuKSr-BjY-uCJTze21kbPpfi
266
267
  atomicshop/wrappers/playwrightw/combos.py,sha256=215y7wugyyBrFK9_0WutnMXsF1jqJ2PLm9eHEa2PMz0,7145
267
268
  atomicshop/wrappers/playwrightw/engine.py,sha256=fapOeaqSMNoxJucTvhzp30cKfKNSVe45drhZJcJ-fOk,15191
268
269
  atomicshop/wrappers/playwrightw/infra.py,sha256=ncp62l6CgAgLz4lqBtKEWZO_6ES8cqnbzJBov-tlpBo,97
269
- atomicshop/wrappers/playwrightw/javascript.py,sha256=CL3tVE9C4SVvy76FEgGCl77B-xziCG6JZR5Ed8IfcSo,1112
270
+ atomicshop/wrappers/playwrightw/javascript.py,sha256=_bW7CAtm0Y8IHYrAalg5HpPFnk6juiqicmkvZ9dITaA,1235
270
271
  atomicshop/wrappers/playwrightw/keyboard.py,sha256=zN3YddGO-qUkn6C0CRVFejP4cTuaUwXLDNFhFREjERY,422
271
272
  atomicshop/wrappers/playwrightw/locators.py,sha256=6wsLywZxDuii7mwv-zQsRbqQC8r7j96Bma5b5_7ZoVo,2411
272
273
  atomicshop/wrappers/playwrightw/mouse.py,sha256=-2FZbQtjgH7tdXWld6ZPGqlKFUdf5in0ujN0hewxa50,656
273
- atomicshop/wrappers/playwrightw/scenarios.py,sha256=Wz7aVYfG7K4fuSe_TUAc1jhFXVq5jYvZKbDtvqUiONc,5236
274
+ atomicshop/wrappers/playwrightw/scenarios.py,sha256=OzI3SV0QgazRwMZ0hMEopDHUYG-aygBSxZ50w78lIP8,5310
274
275
  atomicshop/wrappers/playwrightw/waits.py,sha256=PBFdz_PoM7Fo7O8hLqMrxNPzBEYgPoXwZceFFCGGeu8,7182
275
276
  atomicshop/wrappers/psutilw/cpus.py,sha256=w6LPBMINqS-T_X8vzdYkLS2Wzuve28Ydp_GafTCngrc,236
276
277
  atomicshop/wrappers/psutilw/disks.py,sha256=3ZSVoommKH1TWo37j_83frB-NqXF4Nf5q5mBCX8G4jE,9221
@@ -313,9 +314,9 @@ atomicshop/wrappers/socketw/socket_wrapper.py,sha256=WtylpezgIIBuz-A6PfM0hO1sm9E
313
314
  atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
314
315
  atomicshop/wrappers/socketw/statistics_csv.py,sha256=w1AH-zf4mBuT4euf28UKij9ihM-b1BRU9Qfby0QDdqI,2957
315
316
  atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
316
- atomicshop/wrappers/winregw/winreg_network.py,sha256=4tIBitgT4X_y76k3T1ychRu85KNRflLfjFumSmoj7es,7138
317
- atomicshop-2.16.42.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
318
- atomicshop-2.16.42.dist-info/METADATA,sha256=PPS3bp3ZqUTDio5PNmC2vlny1J9gavc8P4HHXhrnaQE,10473
319
- atomicshop-2.16.42.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
320
- atomicshop-2.16.42.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
321
- atomicshop-2.16.42.dist-info/RECORD,,
317
+ atomicshop/wrappers/winregw/winreg_network.py,sha256=ChnVG8ZecKJ-DMF8nUHRiifWJq2M4slEwKat6FBfPfE,8685
318
+ atomicshop-2.16.43.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
319
+ atomicshop-2.16.43.dist-info/METADATA,sha256=QVoeyIJQUE341VUy8UhCrEqSabPP8SLi8qUJjyi6f98,10500
320
+ atomicshop-2.16.43.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
321
+ atomicshop-2.16.43.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
322
+ atomicshop-2.16.43.dist-info/RECORD,,