atomicshop 2.16.2__py3-none-any.whl → 2.16.4__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.2'
4
+ __version__ = '2.16.4'
@@ -31,6 +31,7 @@ def thread_worker_main(
31
31
  host=client_message.server_name,
32
32
  tls_type=tls_type,
33
33
  tls_version=tls_version,
34
+ protocol=client_message.protocol,
34
35
  path=client_message.request_raw_decoded.path,
35
36
  status_code=status_code,
36
37
  command=client_message.request_raw_decoded.command,
@@ -145,6 +146,7 @@ def thread_worker_main(
145
146
 
146
147
  # If the request is HTTP protocol.
147
148
  if request_is_http:
149
+ client_message.protocol = 'HTTP'
148
150
  network_logger.info(f"Method: {request_decoded.command}")
149
151
  network_logger.info(f"Path: {request_decoded.path}")
150
152
  # statistics.dict['path'] = request_decoded.path
@@ -33,7 +33,7 @@ def initialize_mitm_server(config_file_path: str):
33
33
  # Main function should return integer with error code, 0 is successful.
34
34
  # Since listening server is infinite, this will not be reached.
35
35
  # After modules import - we check for python version.
36
- check_python_version_compliance(minimum_version='3.11')
36
+ check_python_version_compliance(minimum_version='3.12')
37
37
 
38
38
  # Import the configuration file.
39
39
  result = config_static.load_config(config_file_path)
@@ -267,7 +267,8 @@ def initialize_mitm_server(config_file_path: str):
267
267
  statistics_logs_directory=config_static.Log.logs_path,
268
268
  forwarding_dns_service_ipv4_list___only_for_localhost=(
269
269
  config_static.TCPServer.forwarding_dns_service_ipv4_list___only_for_localhost),
270
- skip_extension_id_list=config_static.SkipExtensions.SKIP_EXTENSION_ID_LIST
270
+ skip_extension_id_list=config_static.SkipExtensions.SKIP_EXTENSION_ID_LIST,
271
+ request_domain_from_dns_server_queue=domain_queue
271
272
  )
272
273
  except socket_wrapper.SocketWrapperPortInUseError as e:
273
274
  print_api(e, error_type=True, color="red", logger=system_logger)
@@ -279,8 +280,6 @@ def initialize_mitm_server(config_file_path: str):
279
280
 
280
281
  socket_wrapper_instance.create_tcp_listening_socket_list()
281
282
 
282
- socket_wrapper_instance.requested_domain_from_dns_server = domain_queue
283
-
284
283
  # Before we start the loop. we can set the default gateway if specified.
285
284
  set_dns_gateway = False
286
285
  dns_gateway_server_list = list()
@@ -20,6 +20,7 @@ class ClientMessage:
20
20
  self.thread_id = None
21
21
  self.info: str = str()
22
22
  self.error: str = str()
23
+ self.protocol: str = str()
23
24
 
24
25
  def reinitialize(self) -> None:
25
26
  """
@@ -40,12 +40,12 @@ def calculate_moving_average(
40
40
  :param print_kwargs: dict, the print_api arguments.
41
41
  """
42
42
 
43
- date_pattern: str = consts.DEFAULT_ROTATING_SUFFIXES_FROM_WHEN['midnight']
43
+ date_format: str = consts.DEFAULT_ROTATING_SUFFIXES_FROM_WHEN['midnight']
44
44
 
45
45
  # Get all the file paths and their midnight rotations.
46
46
  logs_paths: list = reading.get_logs_paths(
47
47
  log_file_path=file_path,
48
- date_pattern=date_pattern
48
+ date_format=date_format
49
49
  )
50
50
 
51
51
  if get_deviation_for_last_day_only:
@@ -4,6 +4,7 @@ from pathlib import Path
4
4
  import datetime
5
5
 
6
6
  from ... import filesystem, datetimes
7
+ from ...basics import booleans
7
8
  from ...file_io import csvs
8
9
 
9
10
 
@@ -15,9 +16,10 @@ def get_logs_paths(
15
16
  log_files_directory_path: str = None,
16
17
  log_file_path: str = None,
17
18
  file_name_pattern: str = '*.*',
18
- date_pattern: str = None,
19
+ date_format: str = None,
19
20
  latest_only: bool = False,
20
- previous_day_only: bool = False
21
+ previous_day_only: bool = False,
22
+ specific_date: str = None
21
23
  ):
22
24
  """
23
25
  This function gets the logs file paths from the directory. Supports rotating files to get the logs by time.
@@ -37,11 +39,18 @@ def get_logs_paths(
37
39
  log_files_directory_path = 'C:/logs'
38
40
  :param file_name_pattern: Pattern to match the log files names.
39
41
  Default file_name_pattern will match all the files.
40
- :param date_pattern: Pattern to match the date in the log file name.
42
+ :param date_format: date format string pattern to match the date in the log file name.
41
43
  If specified, the function will get the log file by the date pattern.
42
44
  If not specified, the function will get the file date by file last modified time.
45
+
46
+ Example:
47
+ date_format = '%Y-%m-%d'
43
48
  :param latest_only: Boolean, if True, only the latest log file path will be returned.
44
49
  :param previous_day_only: Boolean, if True, only the log file path from the previous day will be returned.
50
+ :param specific_date: Specific date to get the log file path.
51
+ If specified, the function will get the log file by the specific date.
52
+ Meaning that 'date_format' must be specified.
53
+
45
54
  """
46
55
 
47
56
  if not log_files_directory_path and not log_file_path:
@@ -49,8 +58,14 @@ def get_logs_paths(
49
58
  elif log_files_directory_path and log_file_path:
50
59
  raise ValueError('Both "log_files_directory_path" and "log_file_path" cannot be specified at the same time.')
51
60
 
52
- if latest_only and previous_day_only:
53
- raise ValueError('Both "latest_only" and "previous_day_only" cannot be True at the same time.')
61
+ if latest_only or previous_day_only or specific_date:
62
+ booleans.check_3_booleans_when_only_1_can_be_true(
63
+ (latest_only, 'latest_only'),
64
+ (previous_day_only, 'previous_day_only'),
65
+ (specific_date, 'specific_date'))
66
+
67
+ if not date_format and specific_date:
68
+ raise ValueError('If "specific_date" is specified, "date_format" must be specified.')
54
69
 
55
70
  # If log file path is specified, get the file_name_pattern from the file name.
56
71
  if log_file_path:
@@ -74,22 +89,22 @@ def get_logs_paths(
74
89
  if logs_files:
75
90
  first_file_name: str = Path(logs_files[0]['file_path']).name
76
91
  first_datetime_object, first_date_string, first_timestamp_float = (
77
- datetimes.get_datetime_from_complex_string_by_pattern(first_file_name, date_pattern))
92
+ datetimes.get_datetime_from_complex_string_by_pattern(first_file_name, date_format))
78
93
 
79
94
  # The problem here is the file name that doesn't contain the date string in the name.
80
95
  # If it is regular log rotation, then there will be one file that doesn't have the date string in the name.
81
96
  # If the function used to get the previous day log, then there will be no file that doesn't have the date string.
82
97
  if len(logs_files) > 1 or (len(logs_files) == 1 and first_date_string):
83
- if date_pattern:
98
+ if date_format:
84
99
  latest_timestamp: float = 0
85
100
  for file_index, single_file in enumerate(logs_files):
86
101
  # Get file name from current loop file path.
87
102
  current_file_name: str = Path(single_file['file_path']).name
88
103
  logs_files[file_index]['file_name'] = current_file_name
89
104
 
90
- # Get the datetime object from the file name by the date pattern.
105
+ # Get the datetime object from the file name by the date format pattern.
91
106
  datetime_object, date_string, timestamp_float = (
92
- datetimes.get_datetime_from_complex_string_by_pattern(current_file_name, date_pattern))
107
+ datetimes.get_datetime_from_complex_string_by_pattern(current_file_name, date_format))
93
108
 
94
109
  # Update the last modified time to the dictionary.
95
110
  logs_files[file_index]['last_modified'] = timestamp_float
@@ -113,7 +128,7 @@ def get_logs_paths(
113
128
  latest_timestamp += 86400
114
129
  logs_files[file_index]['last_modified'] = latest_timestamp
115
130
  logs_files[file_index]['datetime'] = datetime.datetime.fromtimestamp(latest_timestamp)
116
- logs_files[file_index]['date_string'] = logs_files[file_index]['datetime'].strftime(date_pattern)
131
+ logs_files[file_index]['date_string'] = logs_files[file_index]['datetime'].strftime(date_format)
117
132
  break
118
133
 
119
134
  # Sort the files by the last modified time.
@@ -128,6 +143,10 @@ def get_logs_paths(
128
143
  logs_files = []
129
144
  else:
130
145
  logs_files = [logs_files[-2]]
146
+
147
+ if specific_date:
148
+ # Check if there is a specific date log file.
149
+ logs_files = [single_file for single_file in logs_files if single_file['date_string'] == specific_date]
131
150
  # If there is only one file, meaning it is the current day log.
132
151
  # If the 'previous_day_only' is True, then there are no previous day logs to output.
133
152
  elif len(logs_files) == 1 and previous_day_only:
@@ -140,7 +159,7 @@ def get_all_log_files_into_list(
140
159
  log_files_directory_path: str = None,
141
160
  log_file_path: str = None,
142
161
  file_name_pattern: str = '*.*',
143
- date_pattern: str = None,
162
+ date_format: str = None,
144
163
  log_type: Literal['csv'] = 'csv',
145
164
  header_type_of_files: Literal['first', 'all'] = 'first',
146
165
  remove_logs: bool = False,
@@ -155,9 +174,12 @@ def get_all_log_files_into_list(
155
174
  :param log_file_path: Path to the log file. Check the 'get_logs_paths' function for more details.
156
175
  :param file_name_pattern: Pattern to match the log files names.
157
176
  Default file_name_pattern will match all the files.
158
- :param date_pattern: Pattern to match the date in the log file name.
177
+ :param date_format: date format string pattern to match the date in the log file name.
159
178
  If specified, the function will get the log file by the date pattern.
160
179
  If not specified, the function will get the file date by file last modified time.
180
+
181
+ Example:
182
+ date_format = '%Y-%m-%d'
161
183
  :param log_type: Type of log to get.
162
184
  :param header_type_of_files: Type of header to get from the files.
163
185
  'first' - Only the first file has a header for CSV. This header will be used for the rest of the files.
@@ -183,7 +205,7 @@ def get_all_log_files_into_list(
183
205
  log_files_directory_path=log_files_directory_path,
184
206
  log_file_path=log_file_path,
185
207
  file_name_pattern=file_name_pattern,
186
- date_pattern=date_pattern)
208
+ date_format=date_format)
187
209
 
188
210
  # Read all the logs.
189
211
  logs_content: list = list()
@@ -263,16 +285,19 @@ class LogReader:
263
285
  def __init__(
264
286
  self,
265
287
  log_file_path: str,
266
- date_pattern: str = None,
288
+ date_format: str = None,
267
289
  log_type: Literal['csv'] = 'csv',
268
290
  get_previous_file: bool = False,
269
291
  header: list = None
270
292
  ):
271
293
  """
272
294
  :param log_file_path: Path to the log file.
273
- :param date_pattern: Pattern to match the date in the log file name.
295
+ :param date_format: date format string pattern to match the date in the log file name.
274
296
  If specified, the function will get the log file by the date pattern.
275
297
  If not specified, the function will get the file date by file last modified time.
298
+
299
+ Example:
300
+ date_format = '%Y-%m-%d'
276
301
  :param log_type: Type of log to get.
277
302
  :param get_previous_file: Boolean, if True, the function will get the previous log file.
278
303
  For example, your log is set to rotate every Midnight.
@@ -287,7 +312,7 @@ class LogReader:
287
312
  """
288
313
 
289
314
  self.log_file_path: str = log_file_path
290
- self.date_pattern: str = date_pattern
315
+ self.date_format: str = date_format
291
316
  self.log_type: Literal['csv'] = log_type
292
317
  self.get_previous_file: bool = get_previous_file
293
318
  self.header: list = header
@@ -329,7 +354,7 @@ class LogReader:
329
354
  # Get the latest statistics file path.
330
355
  latest_statistics_file_path_object = get_logs_paths(
331
356
  log_file_path=self.log_file_path,
332
- date_pattern=self.date_pattern,
357
+ date_format=self.date_format,
333
358
  latest_only=True
334
359
  )
335
360
 
@@ -344,7 +369,7 @@ class LogReader:
344
369
  try:
345
370
  previous_day_statistics_file_path = get_logs_paths(
346
371
  log_file_path=self.log_file_path,
347
- date_pattern=self.date_pattern,
372
+ date_format=self.date_format,
348
373
  previous_day_only=True
349
374
  )[0]['file_path']
350
375
  # If you get IndexError, it means that there are no previous day logs to read.
@@ -58,7 +58,7 @@ class SocketWrapper:
58
58
  ] = None,
59
59
  logger=None,
60
60
  statistics_logs_directory: str = None,
61
- request_domain_queue: queues.NonBlockQueue = None
61
+ request_domain_from_dns_server_queue: queues.NonBlockQueue = None
62
62
  ):
63
63
  """
64
64
  Socket Wrapper class that will be used to create sockets, listen on them, accept connections and send them to
@@ -140,8 +140,8 @@ class SocketWrapper:
140
140
 
141
141
  statistics_writer: statistics_csv.StatisticsCSVWriter object, there is a logger object that
142
142
  will be used to write the statistics file.
143
- :param request_domain_queue: queues.NonBlockQueue object, non-blocking queue that will be used to get
144
- the domain name that was requested from the DNS server (atomicshop.wrappers.socketw.dns_server).
143
+ :param request_domain_from_dns_server_queue: queues.NonBlockQueue object, non-blocking queue that will be used
144
+ to get the domain name that was requested from the DNS server (atomicshop.wrappers.socketw.dns_server).
145
145
  This is used to get the domain name that got to the DNS server and set it to the socket in case SNI
146
146
  was empty (in the SNIHandler class to set the 'server_hostname' for the socket).
147
147
  """
@@ -175,6 +175,7 @@ class SocketWrapper:
175
175
  self.statistics_logs_directory: str = statistics_logs_directory
176
176
  self.forwarding_dns_service_ipv4_list___only_for_localhost = (
177
177
  forwarding_dns_service_ipv4_list___only_for_localhost)
178
+ self.request_domain_from_dns_server_queue = request_domain_from_dns_server_queue
178
179
 
179
180
  self.socket_object = None
180
181
 
@@ -184,7 +185,6 @@ class SocketWrapper:
184
185
 
185
186
  self.sni_received_dict: dict = dict()
186
187
  self.sni_execute_extended: bool = False
187
- self.requested_domain_from_dns_server = None
188
188
  self.certauth_wrapper = None
189
189
 
190
190
  # Defining list of threads, so we can "join()" them in the end all at once.
@@ -343,9 +343,10 @@ class SocketWrapper:
343
343
  # Get the domain queue. Tried using "Queue.Queue" object, but it stomped the SSL Sockets
344
344
  # from accepting connections.
345
345
  domain_from_dns_server = None
346
- if self.requested_domain_from_dns_server.queue:
347
- domain_from_dns_server = self.requested_domain_from_dns_server.queue
348
- self.logger.info(f"Requested domain from DNS Server: {self.requested_domain_from_dns_server.queue}")
346
+ if self.request_domain_from_dns_server_queue.queue:
347
+ domain_from_dns_server = self.request_domain_from_dns_server_queue.queue
348
+ self.logger.info(
349
+ f"Requested domain from DNS Server: {self.request_domain_from_dns_server_queue.queue}")
349
350
 
350
351
  # Wait from any connection on "accept()".
351
352
  # 'client_socket' is socket or ssl socket, 'client_address' is a tuple (ip_address, port).
@@ -7,8 +7,8 @@ from ..loggingw import loggingw
7
7
 
8
8
  LOGGER_NAME: str = 'statistics'
9
9
  STATISTICS_HEADER: str = \
10
- ('request_time_sent,tls,host,path,command,status_code,request_size_bytes,response_size_bytes,file_path,process_cmd,'
11
- 'error')
10
+ ('request_time_sent,tls,protocol,host,path,command,status_code,request_size_bytes,response_size_bytes,file_path,'
11
+ 'process_cmd,error')
12
12
 
13
13
 
14
14
  class StatisticsCSVWriter:
@@ -36,6 +36,7 @@ class StatisticsCSVWriter:
36
36
  host: str,
37
37
  tls_type: str,
38
38
  tls_version: str,
39
+ protocol: str,
39
40
  path: str,
40
41
  status_code: str,
41
42
  command: str,
@@ -57,6 +58,7 @@ class StatisticsCSVWriter:
57
58
  escaped_line_string: str = csvs.escape_csv_line_to_string([
58
59
  request_time_sent,
59
60
  tls_info,
61
+ protocol,
60
62
  host,
61
63
  path,
62
64
  command,
@@ -90,6 +92,7 @@ class StatisticsCSVWriter:
90
92
  host=host,
91
93
  tls_type='',
92
94
  tls_version='',
95
+ protocol='',
93
96
  path='',
94
97
  status_code='',
95
98
  command='',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: atomicshop
3
- Version: 2.16.2
3
+ Version: 2.16.4
4
4
  Summary: Atomic functions and classes to make developer life easier
5
5
  Author: Denis Kras
6
6
  License: MIT License
@@ -1,4 +1,4 @@
1
- atomicshop/__init__.py,sha256=DzLsNeiwKWTo5p75-S_CaNb8QEBZEyoz2eM5n5isUr8,123
1
+ atomicshop/__init__.py,sha256=qvqC-jKfoVnKLC0gKh74skVKFkhCyeZoJmqVnB7ZHVs,123
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
@@ -123,11 +123,11 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
123
123
  atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
124
124
  atomicshop/mitm/config_static.py,sha256=PZp9AAW2ihSUZCen1fhuwFW7Rucd9jA1Pw6pK6Q3DVM,6994
125
125
  atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
126
- atomicshop/mitm/connection_thread_worker.py,sha256=BHSUwSKJfdGigPH1zsFXvjDH1RQV-UkRA7pyx2yn8-Q,18992
126
+ atomicshop/mitm/connection_thread_worker.py,sha256=I5Oq6tSUIXAS6FYlflZzYDtC1rbIYdIKax_R1WsFjso,19093
127
127
  atomicshop/mitm/import_config.py,sha256=fvUESPMkpRvkL7HtMaUqQRPwPF0eHV5V6pwueg4DQkU,7881
128
128
  atomicshop/mitm/initialize_engines.py,sha256=YoSNksMdu4vHjr5xy77t9t5W74zyDZIdjIXrzd3eRXc,8204
129
- atomicshop/mitm/initialize_mitm_server.py,sha256=PMYjt06IysdDpq5utKof4X578EAgCp4TDjiLC7uxDPQ,18382
130
- atomicshop/mitm/message.py,sha256=u2U2f2SOHdBNU-6r1Ik2W14ai2EOwxUV4wVfGZA098k,1732
129
+ atomicshop/mitm/initialize_mitm_server.py,sha256=qP41_hgSa5Wd9WIwIugTqSmWxaL3S3Hh9OCQfcxUwqk,18367
130
+ atomicshop/mitm/message.py,sha256=fHvYEyEx-FAXbIMrKMJ_ybBinezF6IFbPlwCqpRrF44,1768
131
131
  atomicshop/mitm/shared_functions.py,sha256=hplm98tz8pgJ4WHUVI9sf_oVqUM2KJ1Y2pD6EFSb8P0,1879
132
132
  atomicshop/mitm/statistic_analyzer.py,sha256=E0ba1PjsUEcmQUPPw2YH911lyWkbQb9OSAdgB3pihsY,24658
133
133
  atomicshop/mitm/engines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -143,7 +143,7 @@ atomicshop/mitm/engines/__reference_general/recorder___reference_general.py,sha2
143
143
  atomicshop/mitm/engines/__reference_general/responder___reference_general.py,sha256=1AM49UaFTKA0AHw-k3SV3uH3QbG-o6ux0c-GoWkKNU0,6993
144
144
  atomicshop/mitm/statistic_analyzer_helper/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
145
145
  atomicshop/mitm/statistic_analyzer_helper/analyzer_helper.py,sha256=pk6L1t1ea1kvlBoR9QEJptOmaX-mumhwLsP2GCKukbk,5920
146
- atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py,sha256=9weATjSy0Ne8XceW0LeEZ-dI_y_yZfgUNx9ZfuQsjcc,16618
146
+ atomicshop/mitm/statistic_analyzer_helper/moving_average_helper.py,sha256=lsG_eSWf6M_3AfWqIYEBNwYAyVHJfBiRVKHhmWIOZ9A,16615
147
147
  atomicshop/monitor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
148
148
  atomicshop/monitor/change_monitor.py,sha256=K5NlVp99XIDDPnQQMdru4BDmua_DtcDIhVAzkTOvD5s,7673
149
149
  atomicshop/monitor/checks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -248,7 +248,7 @@ atomicshop/wrappers/loggingw/formatters.py,sha256=7XUJvlB0CK4DCkEp8NTL0S0dkyrZD0
248
248
  atomicshop/wrappers/loggingw/handlers.py,sha256=yFYBeTkxnpmtlauoH3ZEFEHUYQYu9YL-ycd9sYTvOl4,16928
249
249
  atomicshop/wrappers/loggingw/loggers.py,sha256=DHOOTAtqkwn1xgvLHSkOiBm6yFGNuQy1kvbhG-TDog8,2374
250
250
  atomicshop/wrappers/loggingw/loggingw.py,sha256=lo4OZPXCbYZi3GqpaaJSs9SOGFfqD2EgHzzTK7f5IR4,11275
251
- atomicshop/wrappers/loggingw/reading.py,sha256=ZgFbmQdStLg2nlgzJEznsvEP0r63ki_2RRwsNnggLDI,18148
251
+ atomicshop/wrappers/loggingw/reading.py,sha256=ZVFc6jjxNBbxknK8m4ec5WUFHtDUiM7vnsyYnWUBjWU,19109
252
252
  atomicshop/wrappers/mongodbw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
253
253
  atomicshop/wrappers/mongodbw/infrastructure.py,sha256=tHqtt__yKGtj24CT5AIk0V0k9t1p_PjezFExXRmmmcA,1517
254
254
  atomicshop/wrappers/mongodbw/install_mongodb.py,sha256=21Re0NpikgYOKelyPTkosoQQxzu67dy80Kj204TL5eo,6644
@@ -301,11 +301,11 @@ atomicshop/wrappers/socketw/sender.py,sha256=hHpBLc0LCfOIUErq2mc0ATfp0tDDQ5XhcYT
301
301
  atomicshop/wrappers/socketw/sni.py,sha256=JUlPmM5e_Wzv2QcYxOrW_mwYZlft2JMPin6nSXFW9ug,17169
302
302
  atomicshop/wrappers/socketw/socket_client.py,sha256=FNmTt94YvjZP0X4RPb7icO3xD_nBHQ_XynnObdWFiAU,19682
303
303
  atomicshop/wrappers/socketw/socket_server_tester.py,sha256=SdchUf9qrPk1Rrat0RzvMeN_2NioD7b7a97MkToCYgM,6332
304
- atomicshop/wrappers/socketw/socket_wrapper.py,sha256=655nGQp0HFy-7KNx8zHsA-miXi9ufC7DNeGsvvGALak,28415
304
+ atomicshop/wrappers/socketw/socket_wrapper.py,sha256=g7f_8RkW80EZeQWNTqGYnfrQkgAI56T3SwWybq7ZsXg,28521
305
305
  atomicshop/wrappers/socketw/ssl_base.py,sha256=k4V3gwkbq10MvOH4btU4onLX2GNOsSfUAdcHmL1rpVE,2274
306
- atomicshop/wrappers/socketw/statistics_csv.py,sha256=q5vRA7jL5ERFhIGctn5HjBlOppwSY9qMoEVgo898AIo,2979
307
- atomicshop-2.16.2.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
308
- atomicshop-2.16.2.dist-info/METADATA,sha256=XKUGZGKugdxkcysucbwMsc6KljxRiR0m2sT0HKOtStU,10502
309
- atomicshop-2.16.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
310
- atomicshop-2.16.2.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
311
- atomicshop-2.16.2.dist-info/RECORD,,
306
+ atomicshop/wrappers/socketw/statistics_csv.py,sha256=Jc0D12crkKRaqoCRQ-2Mz1zm6n4UUx9dXakf-N2TYWA,3065
307
+ atomicshop-2.16.4.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
308
+ atomicshop-2.16.4.dist-info/METADATA,sha256=QTPJ7H6koTAVNzjcFBpcUg5HDA2YC1DdC_Ejg47aG0Y,10502
309
+ atomicshop-2.16.4.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
310
+ atomicshop-2.16.4.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
311
+ atomicshop-2.16.4.dist-info/RECORD,,