atomicshop 2.16.34__py3-none-any.whl → 2.16.36__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/a_installs/ubuntu/mongodb.py +12 -0
- atomicshop/a_installs/ubuntu/pycharm.py +1 -0
- atomicshop/a_installs/win/mongodb.py +2 -2
- atomicshop/basics/exceptions.py +5 -1
- atomicshop/mitm/connection_thread_worker.py +2 -0
- atomicshop/wrappers/mongodbw/install_mongodb_ubuntu.py +100 -0
- atomicshop/wrappers/mongodbw/mongodbw.py +297 -13
- atomicshop/wrappers/socketw/sender.py +1 -1
- atomicshop/wrappers/socketw/socket_client.py +58 -65
- {atomicshop-2.16.34.dist-info → atomicshop-2.16.36.dist-info}/METADATA +1 -1
- {atomicshop-2.16.34.dist-info → atomicshop-2.16.36.dist-info}/RECORD +16 -14
- /atomicshop/wrappers/mongodbw/{install_mongodb.py → install_mongodb_win.py} +0 -0
- {atomicshop-2.16.34.dist-info → atomicshop-2.16.36.dist-info}/LICENSE.txt +0 -0
- {atomicshop-2.16.34.dist-info → atomicshop-2.16.36.dist-info}/WHEEL +0 -0
- {atomicshop-2.16.34.dist-info → atomicshop-2.16.36.dist-info}/top_level.txt +0 -0
atomicshop/__init__.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
from atomicshop.wrappers.mongodbw import
|
|
1
|
+
from atomicshop.wrappers.mongodbw import install_mongodb_win
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
def main():
|
|
5
|
-
|
|
5
|
+
install_mongodb_win.download_install_latest_main()
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
if __name__ == "__main__":
|
atomicshop/basics/exceptions.py
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
# v1.0.3 - 28.03.2023 17:20
|
|
2
1
|
import sys
|
|
3
2
|
|
|
4
3
|
from .threads import current_thread_id
|
|
@@ -15,3 +14,8 @@ def print_exception() -> None:
|
|
|
15
14
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
|
16
15
|
|
|
17
16
|
print(f"{error_log_prefix} Thread {thread_id}: * Details: {exc_type}, {exc_value}")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_exception_type_string(exception: Exception) -> str:
|
|
20
|
+
""" Get exception type string """
|
|
21
|
+
return type(exception).__name__
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import subprocess
|
|
2
|
+
import sys
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
from ... import print_api, web
|
|
7
|
+
from .. import ubuntu_terminal
|
|
8
|
+
from ...permissions import ubuntu_permissions
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
COMPASS_INSTALLATION_SCRIPT_URL: str = \
|
|
12
|
+
'https://raw.githubusercontent.com/mongodb/mongo/master/src/mongo/installer/compass/install_compass'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run_command(command):
|
|
16
|
+
"""Run a system command and exit if the command fails."""
|
|
17
|
+
try:
|
|
18
|
+
subprocess.run(command, check=True, shell=True)
|
|
19
|
+
except subprocess.CalledProcessError as e:
|
|
20
|
+
print_api.print_api(f"Error: {e}", color='red')
|
|
21
|
+
sys.exit(1)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def install_mongodb(version):
|
|
25
|
+
"""Install the specified major version of MongoDB on Ubuntu."""
|
|
26
|
+
|
|
27
|
+
if not version.endswith(".0"):
|
|
28
|
+
version = f"{version}.0"
|
|
29
|
+
|
|
30
|
+
print_api.print_api(f"Installing MongoDB {version} on Ubuntu...")
|
|
31
|
+
print_api.print_api(f"Installing Prerequisites...")
|
|
32
|
+
ubuntu_terminal.update_system_packages()
|
|
33
|
+
ubuntu_terminal.install_packages(["wget", "curl", "gnupg"])
|
|
34
|
+
|
|
35
|
+
# Step 1: Import the MongoDB public GPG key
|
|
36
|
+
print_api.print_api("Step 1: Importing the MongoDB public GPG key...")
|
|
37
|
+
run_command(f"curl -fsSL https://pgp.mongodb.com/server-{version}.asc | "
|
|
38
|
+
f"sudo gpg --dearmor -o /usr/share/keyrings/mongodb-server-{version}.gpg")
|
|
39
|
+
|
|
40
|
+
# Step 2: Create the MongoDB list file for APT
|
|
41
|
+
print_api.print_api("Step 2: Creating MongoDB APT list file...")
|
|
42
|
+
distro_version = subprocess.check_output("lsb_release -sc", shell=True).decode('utf-8').strip()
|
|
43
|
+
run_command(
|
|
44
|
+
f"echo 'deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-{version}.gpg ] "
|
|
45
|
+
f"https://repo.mongodb.org/apt/ubuntu {distro_version}/mongodb-org/{version} multiverse' | "
|
|
46
|
+
f"sudo tee /etc/apt/sources.list.d/mongodb-org-{version}.list")
|
|
47
|
+
|
|
48
|
+
# Step 3: Update the APT package index
|
|
49
|
+
print_api.print_api("Step 3: Updating the APT package index...")
|
|
50
|
+
ubuntu_terminal.update_system_packages()
|
|
51
|
+
|
|
52
|
+
# Step 4: Install the latest version of MongoDB for the specified major version
|
|
53
|
+
print_api.print_api(f"Step 4: Installing MongoDB version {version}...")
|
|
54
|
+
ubuntu_terminal.install_packages(["mongodb-org"])
|
|
55
|
+
|
|
56
|
+
# Step 5: Start MongoDB service and enable it on startup
|
|
57
|
+
print_api.print_api("Step 5: Starting MongoDB service and enabling it on startup...")
|
|
58
|
+
ubuntu_terminal.start_enable_service_check_availability("mongod")
|
|
59
|
+
|
|
60
|
+
print_api.print_api(f"MongoDB {version} installation complete!", color='green')
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def install_main(
|
|
64
|
+
compass: bool = False,
|
|
65
|
+
):
|
|
66
|
+
"""
|
|
67
|
+
Install the latest minor version of MongoDB Community Server on Ubuntu by providing the major version.
|
|
68
|
+
:param compass: bool, if True, MongoDB Compass will be installed.
|
|
69
|
+
:return:
|
|
70
|
+
"""
|
|
71
|
+
# Ensure the user provides a MongoDB major version as an argument.
|
|
72
|
+
if len(sys.argv) != 2:
|
|
73
|
+
message: str = ("Usage: python install_mongodb.py <mongo_major_version>\n"
|
|
74
|
+
"Example: python install_mongodb.py 7")
|
|
75
|
+
print_api.print_api(message, color='red')
|
|
76
|
+
return 1
|
|
77
|
+
|
|
78
|
+
mongo_version = sys.argv[1]
|
|
79
|
+
|
|
80
|
+
# Call the 'install' function with the major version.
|
|
81
|
+
install_mongodb(mongo_version)
|
|
82
|
+
|
|
83
|
+
if not compass:
|
|
84
|
+
return 0
|
|
85
|
+
|
|
86
|
+
# It doesn't matter what you do with the MSI it will not install Compass, only if you run it manually.
|
|
87
|
+
# So we will use installation script from their GitHub.
|
|
88
|
+
print_api.print_api("Downloading MongoDB Compass installation script...")
|
|
89
|
+
compass_script_path: str = web.download(COMPASS_INSTALLATION_SCRIPT_URL)
|
|
90
|
+
|
|
91
|
+
print_api.print_api("Installing MongoDB Compass from script...")
|
|
92
|
+
ubuntu_permissions.set_executable(compass_script_path)
|
|
93
|
+
run_command(f'sudo -E python3 {compass_script_path}')
|
|
94
|
+
|
|
95
|
+
# Clean up the installer file
|
|
96
|
+
if os.path.exists(compass_script_path):
|
|
97
|
+
os.remove(compass_script_path)
|
|
98
|
+
print_api.print_api("Cleaned up the Compass installer file.")
|
|
99
|
+
|
|
100
|
+
return 0
|
|
@@ -18,6 +18,18 @@ These are good examples to get you started, but can't really cover all the use c
|
|
|
18
18
|
"""
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
class MongoDBReplaceOneError(Exception):
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class MongoDBUpdateOneError(Exception):
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MongoDBUpdateManyError(Exception):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
21
33
|
class MongoDBWrapper:
|
|
22
34
|
def __init__(
|
|
23
35
|
self,
|
|
@@ -80,13 +92,15 @@ class MongoDBWrapper:
|
|
|
80
92
|
|
|
81
93
|
def delete(
|
|
82
94
|
self,
|
|
83
|
-
|
|
95
|
+
query_instance: Union[list[dict], dict],
|
|
84
96
|
collection_name: str
|
|
85
97
|
):
|
|
86
98
|
"""
|
|
87
|
-
Remove a list of dictionaries or a dictionary from a MongoDB collection.
|
|
99
|
+
Remove a dict or list of dictionaries or a dictionary from a MongoDB collection.
|
|
100
|
+
For pure mongo, this is the list of queries to remove.
|
|
101
|
+
Each query for a single item.
|
|
88
102
|
|
|
89
|
-
:param
|
|
103
|
+
:param query_instance: dict or list of dictionaries, the list of queries to remove from the collection.
|
|
90
104
|
:param collection_name: str, the name of the collection.
|
|
91
105
|
|
|
92
106
|
:return: None
|
|
@@ -95,7 +109,30 @@ class MongoDBWrapper:
|
|
|
95
109
|
self.connect()
|
|
96
110
|
|
|
97
111
|
delete(
|
|
98
|
-
|
|
112
|
+
query_instance=query_instance,
|
|
113
|
+
database=self.db, collection_name=collection_name,
|
|
114
|
+
mongo_client=self.client, close_client=False)
|
|
115
|
+
|
|
116
|
+
def delete_many(
|
|
117
|
+
self,
|
|
118
|
+
query: dict,
|
|
119
|
+
collection_name: str
|
|
120
|
+
):
|
|
121
|
+
"""
|
|
122
|
+
Remove all entries that match the query from a MongoDB collection.
|
|
123
|
+
|
|
124
|
+
:param query: dict, the query to search for.
|
|
125
|
+
Example, search for all entries with column name 'name' equal to 'John':
|
|
126
|
+
query = {'name': 'John'}
|
|
127
|
+
:param collection_name: str, the name of the collection.
|
|
128
|
+
|
|
129
|
+
:return: result of the operation.
|
|
130
|
+
"""
|
|
131
|
+
|
|
132
|
+
self.connect()
|
|
133
|
+
|
|
134
|
+
return delete_many(
|
|
135
|
+
query=query,
|
|
99
136
|
database=self.db, collection_name=collection_name,
|
|
100
137
|
mongo_client=self.client, close_client=False)
|
|
101
138
|
|
|
@@ -203,6 +240,69 @@ class MongoDBWrapper:
|
|
|
203
240
|
|
|
204
241
|
return distinct_values
|
|
205
242
|
|
|
243
|
+
def update(
|
|
244
|
+
self,
|
|
245
|
+
collection_name: str,
|
|
246
|
+
query: dict,
|
|
247
|
+
update_instance: Union[dict, list[dict]],
|
|
248
|
+
add_timestamp: bool = False,
|
|
249
|
+
convert_mixed_lists_to_strings: bool = False
|
|
250
|
+
):
|
|
251
|
+
"""
|
|
252
|
+
Update one entry in a MongoDB collection by query.
|
|
253
|
+
:param collection_name: str, the name of the collection.
|
|
254
|
+
:param query: dict, the query to search for.
|
|
255
|
+
Example, search for all entries with column name 'name' equal to 'John':
|
|
256
|
+
query = {'name': 'John'}
|
|
257
|
+
Find by Object id:
|
|
258
|
+
query = {'_id': ObjectId('5f3e3b3b4b9f3b3b4b9f3b3b')}
|
|
259
|
+
:param update_instance: dict or list of dicts, the update to apply.
|
|
260
|
+
Get examples for operators for each dict in the docstring of the function 'update' below.
|
|
261
|
+
:param add_timestamp: bool, if True, a current time timestamp will be added to the object.
|
|
262
|
+
:param convert_mixed_lists_to_strings: bool, if True, mixed lists or tuples when entries are
|
|
263
|
+
strings and integers, the integers will be converted to strings.
|
|
264
|
+
:return: result of the operation.
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
self.connect()
|
|
268
|
+
|
|
269
|
+
return update(
|
|
270
|
+
database=self.db, collection_name=collection_name,
|
|
271
|
+
query=query, update_instance=update_instance, add_timestamp=add_timestamp,
|
|
272
|
+
convert_mixed_lists_to_strings=convert_mixed_lists_to_strings,
|
|
273
|
+
mongo_client=self.client, close_client=False)
|
|
274
|
+
|
|
275
|
+
def replace(
|
|
276
|
+
self,
|
|
277
|
+
collection_name: str,
|
|
278
|
+
query: dict,
|
|
279
|
+
replacement: dict,
|
|
280
|
+
add_timestamp: bool = False,
|
|
281
|
+
convert_mixed_lists_to_strings: bool = False
|
|
282
|
+
):
|
|
283
|
+
"""
|
|
284
|
+
Replace one entry in a MongoDB collection by query.
|
|
285
|
+
:param collection_name: str, the name of the collection.
|
|
286
|
+
:param query: dict, the query to search for.
|
|
287
|
+
Example, search for all entries with column name 'name' equal to 'John':
|
|
288
|
+
query = {'name': 'John'}
|
|
289
|
+
Find by Object id:
|
|
290
|
+
query = {'_id': ObjectId('5f3e3b3b4b9f3b3b4b9f3b3b')}
|
|
291
|
+
:param replacement: dict, the replacement to apply.
|
|
292
|
+
:param add_timestamp: bool, if True, a current time timestamp will be added to the object.
|
|
293
|
+
:param convert_mixed_lists_to_strings: bool, if True, mixed lists or tuples when entries are
|
|
294
|
+
|
|
295
|
+
:return: result of the operation.
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
self.connect()
|
|
299
|
+
|
|
300
|
+
return replace(
|
|
301
|
+
database=self.db, collection_name=collection_name,
|
|
302
|
+
query=query, replacement=replacement,
|
|
303
|
+
add_timestamp=add_timestamp, convert_mixed_lists_to_strings=convert_mixed_lists_to_strings,
|
|
304
|
+
mongo_client=self.client, close_client=False)
|
|
305
|
+
|
|
206
306
|
def count_entries_in_collection(
|
|
207
307
|
self,
|
|
208
308
|
collection_name: str,
|
|
@@ -328,7 +428,11 @@ def index(
|
|
|
328
428
|
collection = db[collection_name]
|
|
329
429
|
|
|
330
430
|
if convert_mixed_lists_to_strings:
|
|
331
|
-
|
|
431
|
+
if isinstance(object_instance, dict):
|
|
432
|
+
object_instance = dicts.convert_int_to_str_in_mixed_lists(object_instance)
|
|
433
|
+
elif isinstance(object_instance, list):
|
|
434
|
+
for doc_index, doc in enumerate(object_instance):
|
|
435
|
+
object_instance[doc_index] = dicts.convert_int_to_str_in_mixed_lists(doc)
|
|
332
436
|
|
|
333
437
|
if add_timestamp:
|
|
334
438
|
timestamp = datetime.datetime.now()
|
|
@@ -348,16 +452,18 @@ def index(
|
|
|
348
452
|
|
|
349
453
|
|
|
350
454
|
def delete(
|
|
351
|
-
|
|
455
|
+
query_instance: Union[list[dict], dict],
|
|
352
456
|
database: Union[str, pymongo.database.Database],
|
|
353
457
|
collection_name: str,
|
|
354
458
|
mongo_client: pymongo.MongoClient = None,
|
|
355
459
|
close_client: bool = False
|
|
356
460
|
):
|
|
357
461
|
"""
|
|
358
|
-
Remove a list of dictionaries or a dictionary from a MongoDB collection.
|
|
462
|
+
Remove a dict or list of dictionaries or a dictionary from a MongoDB collection.
|
|
359
463
|
|
|
360
|
-
:param
|
|
464
|
+
:param query_instance: list of dictionaries, the list of dictionaries to remove from the collection.
|
|
465
|
+
For pure mongo, this is the list of queries to remove.
|
|
466
|
+
Each query for a single item.
|
|
361
467
|
:param database: String or the database object.
|
|
362
468
|
str - the name of the database. In this case the database object will be created.
|
|
363
469
|
pymongo.database.Database - the database object that will be used instead of creating a new one.
|
|
@@ -369,7 +475,7 @@ def delete(
|
|
|
369
475
|
:return: None
|
|
370
476
|
"""
|
|
371
477
|
|
|
372
|
-
_is_object_list_of_dicts_or_dict(
|
|
478
|
+
_is_object_list_of_dicts_or_dict(query_instance)
|
|
373
479
|
|
|
374
480
|
if not mongo_client:
|
|
375
481
|
mongo_client = connect()
|
|
@@ -378,16 +484,55 @@ def delete(
|
|
|
378
484
|
db = _get_pymongo_db_from_string_or_pymongo_db(database, mongo_client)
|
|
379
485
|
collection = db[collection_name]
|
|
380
486
|
|
|
381
|
-
if isinstance(
|
|
382
|
-
collection.delete_one(
|
|
383
|
-
elif isinstance(
|
|
384
|
-
for doc in
|
|
487
|
+
if isinstance(query_instance, dict):
|
|
488
|
+
collection.delete_one(query_instance)
|
|
489
|
+
elif isinstance(query_instance, list):
|
|
490
|
+
for doc in query_instance:
|
|
385
491
|
collection.delete_one(doc)
|
|
386
492
|
|
|
387
493
|
if close_client:
|
|
388
494
|
mongo_client.close()
|
|
389
495
|
|
|
390
496
|
|
|
497
|
+
def delete_many(
|
|
498
|
+
query: dict,
|
|
499
|
+
database: Union[str, pymongo.database.Database],
|
|
500
|
+
collection_name: str,
|
|
501
|
+
mongo_client: pymongo.MongoClient = None,
|
|
502
|
+
close_client: bool = False
|
|
503
|
+
):
|
|
504
|
+
"""
|
|
505
|
+
Remove all entries that match the query from a MongoDB collection.
|
|
506
|
+
|
|
507
|
+
:param query: dict, the query to search for.
|
|
508
|
+
Example, search for all entries with column name 'name' equal to 'John':
|
|
509
|
+
query = {'name': 'John'}
|
|
510
|
+
:param database: String or the database object.
|
|
511
|
+
str - the name of the database. In this case the database object will be created.
|
|
512
|
+
pymongo.database.Database - the database object that will be used instead of creating a new one.
|
|
513
|
+
:param collection_name: str, the name of the collection.
|
|
514
|
+
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
515
|
+
If None, a new connection will be created to default URI.
|
|
516
|
+
:param close_client: bool, if True, the connection will be closed after the operation.
|
|
517
|
+
|
|
518
|
+
:return: result of the operation.
|
|
519
|
+
"""
|
|
520
|
+
|
|
521
|
+
if not mongo_client:
|
|
522
|
+
mongo_client = connect()
|
|
523
|
+
close_client = True
|
|
524
|
+
|
|
525
|
+
db = _get_pymongo_db_from_string_or_pymongo_db(database, mongo_client)
|
|
526
|
+
collection = db[collection_name]
|
|
527
|
+
|
|
528
|
+
result = collection.delete_many(query)
|
|
529
|
+
|
|
530
|
+
if close_client:
|
|
531
|
+
mongo_client.close()
|
|
532
|
+
|
|
533
|
+
return result
|
|
534
|
+
|
|
535
|
+
|
|
391
536
|
def find(
|
|
392
537
|
database: Union[str, pymongo.database.Database],
|
|
393
538
|
collection_name: str,
|
|
@@ -614,6 +759,145 @@ def distinct(
|
|
|
614
759
|
return distinct_values
|
|
615
760
|
|
|
616
761
|
|
|
762
|
+
def update(
|
|
763
|
+
database: Union[str, pymongo.database.Database],
|
|
764
|
+
collection_name: str,
|
|
765
|
+
query: dict,
|
|
766
|
+
update_instance: Union[dict, list[dict]],
|
|
767
|
+
add_timestamp: bool = False,
|
|
768
|
+
convert_mixed_lists_to_strings: bool = False,
|
|
769
|
+
mongo_client: pymongo.MongoClient = None,
|
|
770
|
+
close_client: bool = False
|
|
771
|
+
):
|
|
772
|
+
"""
|
|
773
|
+
Update one entry in a MongoDB collection by query.
|
|
774
|
+
:param database: String or the database object.
|
|
775
|
+
str - the name of the database. In this case the database object will be created.
|
|
776
|
+
pymongo.database.Database - the database object that will be used instead of creating a new one.
|
|
777
|
+
:param collection_name: str, the name of the collection.
|
|
778
|
+
:param query: dict, the query to search for.
|
|
779
|
+
Example, search for all entries with column name 'name' equal to 'John':
|
|
780
|
+
query = {'name': 'John'}
|
|
781
|
+
Find by Object id:
|
|
782
|
+
query = {'_id': ObjectId('5f3e3b3b4b9f3b3b4b9f3b3b')}
|
|
783
|
+
:param update_instance: dict or list of dicts, the update to apply.
|
|
784
|
+
If dict, the update will be applied to one entry using 'update_one'.
|
|
785
|
+
If list of dicts, the update will be applied to multiple entries using 'update_many'.
|
|
786
|
+
|
|
787
|
+
Examples for operators for each dict:
|
|
788
|
+
$set: update the column 'name' to 'Alice':
|
|
789
|
+
update_instance = {'$set': {'name': 'Alice'}}
|
|
790
|
+
$inc: increment the column 'age' by 1:
|
|
791
|
+
update_instance = {'$inc': {'age': 1}}
|
|
792
|
+
$unset: remove the column 'name':
|
|
793
|
+
update_instance = {'$unset': {'name': ''}}
|
|
794
|
+
$push: add a value to the list 'hobbies':
|
|
795
|
+
update_instance = {'$push': {'hobbies': 'swimming'}}
|
|
796
|
+
$pull: remove a value from the list 'hobbies':
|
|
797
|
+
update_instance = {'$pull': {'hobbies': 'swimming'}}
|
|
798
|
+
:param add_timestamp: bool, if True, a current time timestamp will be added to the object.
|
|
799
|
+
:param convert_mixed_lists_to_strings: bool, if True, mixed lists or tuples when entries are
|
|
800
|
+
strings and integers, the integers will be converted to strings.
|
|
801
|
+
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
802
|
+
If None, a new connection will be created to default URI.
|
|
803
|
+
:param close_client: bool, if True, the connection will be closed after the operation.
|
|
804
|
+
|
|
805
|
+
:return: None
|
|
806
|
+
"""
|
|
807
|
+
|
|
808
|
+
if not mongo_client:
|
|
809
|
+
mongo_client = connect()
|
|
810
|
+
close_client = True
|
|
811
|
+
|
|
812
|
+
db = _get_pymongo_db_from_string_or_pymongo_db(database, mongo_client)
|
|
813
|
+
collection = db[collection_name]
|
|
814
|
+
|
|
815
|
+
if convert_mixed_lists_to_strings:
|
|
816
|
+
if isinstance(update_instance, dict):
|
|
817
|
+
object_instance = dicts.convert_int_to_str_in_mixed_lists(update_instance)
|
|
818
|
+
elif isinstance(update_instance, list):
|
|
819
|
+
for doc_index, doc in enumerate(update_instance):
|
|
820
|
+
update_instance[doc_index] = dicts.convert_int_to_str_in_mixed_lists(doc)
|
|
821
|
+
|
|
822
|
+
if add_timestamp:
|
|
823
|
+
timestamp = datetime.datetime.now()
|
|
824
|
+
if isinstance(update_instance, dict):
|
|
825
|
+
update_instance['timestamp'] = timestamp
|
|
826
|
+
elif isinstance(update_instance, list):
|
|
827
|
+
for doc in update_instance:
|
|
828
|
+
doc['timestamp'] = timestamp
|
|
829
|
+
|
|
830
|
+
result = None
|
|
831
|
+
if isinstance(update_instance, dict):
|
|
832
|
+
result = collection.update_one(query, update_instance)
|
|
833
|
+
elif isinstance(update_instance, list):
|
|
834
|
+
result = collection.update_many(query, update_instance)
|
|
835
|
+
|
|
836
|
+
if result.matched_count == 0:
|
|
837
|
+
raise MongoDBUpdateOneError("No document found to update.")
|
|
838
|
+
|
|
839
|
+
if close_client:
|
|
840
|
+
mongo_client.close()
|
|
841
|
+
|
|
842
|
+
return result
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
def replace(
|
|
846
|
+
database: Union[str, pymongo.database.Database],
|
|
847
|
+
collection_name: str,
|
|
848
|
+
query: dict,
|
|
849
|
+
replacement: dict,
|
|
850
|
+
add_timestamp: bool = False,
|
|
851
|
+
convert_mixed_lists_to_strings: bool = False,
|
|
852
|
+
mongo_client: pymongo.MongoClient = None,
|
|
853
|
+
close_client: bool = False
|
|
854
|
+
):
|
|
855
|
+
"""
|
|
856
|
+
Replace one entry in a MongoDB collection by query.
|
|
857
|
+
:param database: String or the database object.
|
|
858
|
+
str - the name of the database. In this case the database object will be created.
|
|
859
|
+
pymongo.database.Database - the database object that will be used instead of creating a new one.
|
|
860
|
+
:param collection_name: str, the name of the collection.
|
|
861
|
+
:param query: dict, the query to search for.
|
|
862
|
+
Example, search for all entries with column name 'name' equal to 'John':
|
|
863
|
+
query = {'name': 'John'}
|
|
864
|
+
Find by Object id:
|
|
865
|
+
query = {'_id': ObjectId('5f3e3b3b4b9f3b3b4b9f3b3b')}
|
|
866
|
+
:param replacement: dict, the replacement to apply.
|
|
867
|
+
:param add_timestamp: bool, if True, a current time timestamp will be added to the object.
|
|
868
|
+
:param convert_mixed_lists_to_strings: bool, if True, mixed lists or tuples when entries are strings and integers,
|
|
869
|
+
the integers will be converted to strings.
|
|
870
|
+
:param mongo_client: pymongo.MongoClient, the connection object.
|
|
871
|
+
If None, a new connection will be created to default URI.
|
|
872
|
+
:param close_client: bool, if True, the connection will be closed after the operation.
|
|
873
|
+
|
|
874
|
+
:return: None
|
|
875
|
+
"""
|
|
876
|
+
|
|
877
|
+
if not mongo_client:
|
|
878
|
+
mongo_client = connect()
|
|
879
|
+
close_client = True
|
|
880
|
+
|
|
881
|
+
db = _get_pymongo_db_from_string_or_pymongo_db(database, mongo_client)
|
|
882
|
+
collection = db[collection_name]
|
|
883
|
+
|
|
884
|
+
if convert_mixed_lists_to_strings:
|
|
885
|
+
replacement = dicts.convert_int_to_str_in_mixed_lists(replacement)
|
|
886
|
+
|
|
887
|
+
if add_timestamp:
|
|
888
|
+
timestamp = datetime.datetime.now()
|
|
889
|
+
replacement['timestamp'] = timestamp
|
|
890
|
+
|
|
891
|
+
result = collection.replace_one(query, replacement)
|
|
892
|
+
if result.matched_count == 0:
|
|
893
|
+
raise MongoDBReplaceOneError("No document found to replace.")
|
|
894
|
+
|
|
895
|
+
if close_client:
|
|
896
|
+
mongo_client.close()
|
|
897
|
+
|
|
898
|
+
return result
|
|
899
|
+
|
|
900
|
+
|
|
617
901
|
def count_entries_in_collection(
|
|
618
902
|
database: Union[str, pymongo.database.Database],
|
|
619
903
|
collection_name: str,
|
|
@@ -76,7 +76,7 @@ class Sender:
|
|
|
76
76
|
destination_address = self.ssl_socket.server_hostname
|
|
77
77
|
destination: str = f'[{source_address}:{source_port}<->{destination_address}:{destination_port}]'
|
|
78
78
|
|
|
79
|
-
error_class_type =
|
|
79
|
+
error_class_type = type(e).__name__
|
|
80
80
|
exception_error = tracebacks.get_as_string(one_line=True)
|
|
81
81
|
|
|
82
82
|
if 'ssl' in error_class_type.lower():
|
|
@@ -18,6 +18,7 @@ from .. import cryptographyw
|
|
|
18
18
|
from ..loggingw import loggingw
|
|
19
19
|
from ...print_api import print_api
|
|
20
20
|
from ...file_io import file_io
|
|
21
|
+
from ...basics import tracebacks
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
class SocketClient:
|
|
@@ -55,6 +56,12 @@ class SocketClient:
|
|
|
55
56
|
self.connection_ip = connection_ip
|
|
56
57
|
self.dns_servers_list = dns_servers_list
|
|
57
58
|
|
|
59
|
+
if logger:
|
|
60
|
+
# Create child logger for the provided logger with the module's name.
|
|
61
|
+
self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
|
|
62
|
+
else:
|
|
63
|
+
self.logger: logging.Logger = logger
|
|
64
|
+
|
|
58
65
|
self.socket_instance = None
|
|
59
66
|
|
|
60
67
|
# If 'connection_ip' was specified, but no 'dns_servers_list', then this IP will be used for 'socket.connect()'.
|
|
@@ -68,12 +75,6 @@ class SocketClient:
|
|
|
68
75
|
elif self.connection_ip and self.dns_servers_list:
|
|
69
76
|
raise ValueError("Both 'connection_ip' and 'dns_servers_list' were specified.")
|
|
70
77
|
|
|
71
|
-
if logger:
|
|
72
|
-
# Create child logger for the provided logger with the module's name.
|
|
73
|
-
self.logger: logging.Logger = loggingw.get_logger_with_level(f'{logger.name}.{Path(__file__).stem}')
|
|
74
|
-
else:
|
|
75
|
-
self.logger: logging.Logger = logger
|
|
76
|
-
|
|
77
78
|
# Function to create SSL socket to destination service
|
|
78
79
|
def create_service_socket(self):
|
|
79
80
|
# If TLS is enabled.
|
|
@@ -86,8 +87,18 @@ class SocketClient:
|
|
|
86
87
|
return creator.wrap_socket_with_ssl_context_client___default_certs___ignore_verification(
|
|
87
88
|
socket_object, self.service_name)
|
|
88
89
|
|
|
89
|
-
def service_connection(
|
|
90
|
-
|
|
90
|
+
def service_connection(
|
|
91
|
+
self
|
|
92
|
+
) -> tuple[
|
|
93
|
+
Union[socket.socket, ssl.SSLSocket, None],
|
|
94
|
+
Union[str, None]]:
|
|
95
|
+
"""
|
|
96
|
+
Function to establish connection to server
|
|
97
|
+
|
|
98
|
+
:return: Tuple with socket object and error string.
|
|
99
|
+
If connection was successful, the error string will be None.
|
|
100
|
+
If connection wasn't successful, the socket object will be None.
|
|
101
|
+
"""
|
|
91
102
|
# Check if socket to service domain exists.
|
|
92
103
|
# If not
|
|
93
104
|
if not self.socket_instance:
|
|
@@ -106,8 +117,8 @@ class SocketClient:
|
|
|
106
117
|
f"Socket already defined to [{self.service_name}:{self.service_port}]. "
|
|
107
118
|
f"Should be connected - Reusing.")
|
|
108
119
|
# Since, restart the function each send_receive iteration, and there's still a connection we need to
|
|
109
|
-
#
|
|
110
|
-
return
|
|
120
|
+
# return the socket, or the socket object will be nullified in the next step.
|
|
121
|
+
return self.socket_instance
|
|
111
122
|
|
|
112
123
|
# If 'dns_servers_list' was provided, we will resolve the domain to ip through these servers.
|
|
113
124
|
if self.dns_servers_list:
|
|
@@ -125,11 +136,13 @@ class SocketClient:
|
|
|
125
136
|
# Get only the first entry of the list of IPs [0]
|
|
126
137
|
self.connection_ip = function_server_address[0].to_text()
|
|
127
138
|
self.logger.info(f"Resolved to [{self.connection_ip}]")
|
|
128
|
-
except dns.resolver.NXDOMAIN:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
139
|
+
except dns.resolver.NXDOMAIN as e:
|
|
140
|
+
exception_type: str = type(e).__name__
|
|
141
|
+
error_string = (
|
|
142
|
+
f"Socket Client Connect: {exception_type}: "
|
|
143
|
+
f"Domain {self.service_name} doesn't exist - Couldn't resolve with {self.dns_servers_list}.")
|
|
144
|
+
print_api(error_string, logger=self.logger, logger_method='error')
|
|
145
|
+
return None, error_string
|
|
133
146
|
|
|
134
147
|
# If DNS was resolved correctly or DNS servers weren't specified - we can try connecting.
|
|
135
148
|
# If 'connection_ip' was manually specified or resolved with 'dnspython' - the connection
|
|
@@ -144,43 +157,25 @@ class SocketClient:
|
|
|
144
157
|
try:
|
|
145
158
|
# "connect()" to the server using address and port
|
|
146
159
|
self.socket_instance.connect((destination, self.service_port))
|
|
147
|
-
except
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
except ssl.SSLError:
|
|
167
|
-
message = f"SSLError raised on connection to {self.service_name}."
|
|
168
|
-
print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
|
|
169
|
-
# Socket close will be handled in the thread_worker_main
|
|
170
|
-
pass
|
|
171
|
-
return None
|
|
172
|
-
except TimeoutError:
|
|
173
|
-
message = f"TimeoutError raised on connection to {self.service_name}."
|
|
174
|
-
print_api(message, logger=self.logger, logger_method='error', traceback_string=True, oneline=True)
|
|
175
|
-
# Socket close will be handled in the thread_worker_main
|
|
176
|
-
pass
|
|
177
|
-
return None
|
|
178
|
-
except ValueError as e:
|
|
179
|
-
message = f'{str(e)} | on connect to [{self.service_name}].'
|
|
180
|
-
print_api(message, logger=self.logger, logger_method='error')
|
|
181
|
-
# Socket close will be handled in the thread_worker_main
|
|
182
|
-
pass
|
|
183
|
-
return None
|
|
160
|
+
except Exception as e:
|
|
161
|
+
exception_type: str = type(e).__name__
|
|
162
|
+
exception_error: str = tracebacks.get_as_string(one_line=True)
|
|
163
|
+
error_string: str = f"Socket Client Connect: {destination}: {exception_type}"
|
|
164
|
+
|
|
165
|
+
if exception_type in ['ConnectionRefusedError', 'ConnectionAbortedError', 'ConnectionResetError',
|
|
166
|
+
'ssl.SSLError', 'TimeoutError']:
|
|
167
|
+
error_message: str = f"{error_string}: {exception_error}"
|
|
168
|
+
print_api(error_message, logger=self.logger, logger_method='error')
|
|
169
|
+
return None, error_message
|
|
170
|
+
elif exception_type == 'socket.gaierror':
|
|
171
|
+
custom_error_message: str = (
|
|
172
|
+
f"Couldn't resolve [{self.service_name}] to IP using default methods. "
|
|
173
|
+
f"Domain doesn't exist or there's no IP assigned to it.")
|
|
174
|
+
error_message: str = f"{error_string}: {custom_error_message}"
|
|
175
|
+
print_api(error_message, logger=self.logger, logger_method='error')
|
|
176
|
+
return None, error_message
|
|
177
|
+
else:
|
|
178
|
+
raise e
|
|
184
179
|
|
|
185
180
|
# If everything was fine, we'll log the connection.
|
|
186
181
|
self.logger.info("Connected...")
|
|
@@ -200,14 +195,12 @@ class SocketClient:
|
|
|
200
195
|
def send_receive_to_service(self, request_bytes: bytearray):
|
|
201
196
|
# Define variables
|
|
202
197
|
function_service_data = None
|
|
203
|
-
|
|
198
|
+
error_message = None
|
|
204
199
|
|
|
200
|
+
service_socket, error_message = self.service_connection()
|
|
205
201
|
# If connection to service server wasn't successful
|
|
206
|
-
if
|
|
207
|
-
|
|
208
|
-
print_api(error_string, logger=self.logger, logger_method='error')
|
|
209
|
-
|
|
210
|
-
# We'll close the socket and nullify the object
|
|
202
|
+
if error_message:
|
|
203
|
+
# Wasn't able to connect to service, closing the destination service socket and nullify the object.
|
|
211
204
|
self.close_socket()
|
|
212
205
|
# If the connection to the service was successful
|
|
213
206
|
else:
|
|
@@ -227,7 +220,7 @@ class SocketClient:
|
|
|
227
220
|
|
|
228
221
|
# If the socket disconnected on data send
|
|
229
222
|
if error_on_send:
|
|
230
|
-
|
|
223
|
+
error_message = f"Service socket closed on data send: {error_on_send}"
|
|
231
224
|
|
|
232
225
|
# We'll close the socket and nullify the object
|
|
233
226
|
self.close_socket()
|
|
@@ -238,12 +231,12 @@ class SocketClient:
|
|
|
238
231
|
|
|
239
232
|
# If data received is empty meaning the socket was closed on the other side
|
|
240
233
|
if not function_service_data:
|
|
241
|
-
|
|
234
|
+
error_message = "Service server closed the connection on receive"
|
|
242
235
|
|
|
243
236
|
# We'll close the socket and nullify the object
|
|
244
237
|
self.close_socket()
|
|
245
238
|
|
|
246
|
-
return function_service_data,
|
|
239
|
+
return function_service_data, error_message, self.connection_ip, self.socket_instance
|
|
247
240
|
|
|
248
241
|
def send_receive_message_list_with_interval(
|
|
249
242
|
self, requests_bytes_list: list, intervals_list: list, intervals_defaults: int, cycles: int = 1):
|
|
@@ -316,15 +309,15 @@ class SocketClient:
|
|
|
316
309
|
# be passed.
|
|
317
310
|
# If there was connection error or socket close, then "ssl_socket" of the "service_client"
|
|
318
311
|
# will be empty.
|
|
319
|
-
response_raw_bytes,
|
|
312
|
+
response_raw_bytes, error_message, self.connection_ip, service_ssl_socket = \
|
|
320
313
|
self.send_receive_to_service(request_raw_bytes)
|
|
321
314
|
|
|
322
315
|
# Adding the response to responses list. Same for error.
|
|
323
316
|
responses_list.append(response_raw_bytes)
|
|
324
|
-
errors_list.append(
|
|
317
|
+
errors_list.append(error_message)
|
|
325
318
|
|
|
326
319
|
self.logger.info(f"Response: {response_raw_bytes}")
|
|
327
|
-
self.logger.info(f"Error: {
|
|
320
|
+
self.logger.info(f"Error: {error_message}")
|
|
328
321
|
|
|
329
322
|
# So if the socket was closed and there was an error we can break the loop.
|
|
330
323
|
# This is needed for more complex operations
|
|
@@ -359,7 +352,7 @@ class SocketClient:
|
|
|
359
352
|
raise ValueError("If 'save_as_file' is True, then 'cert_file_path' must be provided.")
|
|
360
353
|
|
|
361
354
|
# Connect and get the connected socket.
|
|
362
|
-
server_socket_for_certificate = self.service_connection()
|
|
355
|
+
server_socket_for_certificate, error_message = self.service_connection()
|
|
363
356
|
# Get the DER byte certificate from the socket.
|
|
364
357
|
certificate_from_socket_der_bytes = ssl_base.get_certificate_from_socket(server_socket_for_certificate)
|
|
365
358
|
print_api('Fetched certificate from socket.', logger=self.logger, **kwargs)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
atomicshop/__init__.py,sha256=
|
|
1
|
+
atomicshop/__init__.py,sha256=OeOIovtO11WvqryrnXL0p8647yTwRAMmL0vtoDpvg5A,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
|
|
@@ -48,9 +48,10 @@ atomicshop/web.py,sha256=DkpdUYiwRu_Du5J8LlUyxLj-NAEnDLfEwfVlSI22trM,11642
|
|
|
48
48
|
atomicshop/a_installs/ubuntu/docker_rootless.py,sha256=9IPNtGZYjfy1_n6ZRt7gWz9KZgR6XCgevjqq02xk-o0,281
|
|
49
49
|
atomicshop/a_installs/ubuntu/docker_sudo.py,sha256=JzayxeyKDtiuT4Icp2L2LyFRbx4wvpyN_bHLfZ-yX5E,281
|
|
50
50
|
atomicshop/a_installs/ubuntu/elastic_search_and_kibana.py,sha256=yRB-l1zBxdiN6av-FwNkhcBlaeu4zrDPjQ0uPGgpK2I,244
|
|
51
|
-
atomicshop/a_installs/ubuntu/
|
|
51
|
+
atomicshop/a_installs/ubuntu/mongodb.py,sha256=xuRJS1qqOZ0EZp7of5R3tTjSu6CwBIxYg8-NaM7othE,230
|
|
52
|
+
atomicshop/a_installs/ubuntu/pycharm.py,sha256=Ld7YQBwPxrjuZcTG1K4kZqjbBdt8aooCVRa15u5FOmE,157
|
|
52
53
|
atomicshop/a_installs/win/fibratus.py,sha256=TU4e9gdZ_zI73C40uueJ59pD3qmN-UFGdX5GFoVf6cM,179
|
|
53
|
-
atomicshop/a_installs/win/mongodb.py,sha256=
|
|
54
|
+
atomicshop/a_installs/win/mongodb.py,sha256=AqyItXu19aaoe49pppDxtEkXey6PMy0PoT2Y_RmPpPE,179
|
|
54
55
|
atomicshop/a_installs/win/pycharm.py,sha256=j_RSd7aDOyC3yDd-_GUTMLlQTmDrqtVFG--oUfGLiZk,140
|
|
55
56
|
atomicshop/a_installs/win/wsl_ubuntu_lts.py,sha256=dZbPRLNKFeMd6MotjkE6UDY9cOiIaaclIdR1kGYWI50,139
|
|
56
57
|
atomicshop/a_mains/dns_gateway_setting.py,sha256=ncc2rFQCChxlNP59UshwmTonLqC6MWblrVAzbbz-13M,149
|
|
@@ -89,7 +90,7 @@ atomicshop/basics/dicts.py,sha256=DeYHIh940pMMBrFhpXt4dsigFVYzTrlqWymNo4Pq_Js,14
|
|
|
89
90
|
atomicshop/basics/dicts_nested.py,sha256=StYxYnYPa0SEJr1lmEwAv5zfERWWqoULeyG8e0zRAwE,4107
|
|
90
91
|
atomicshop/basics/enumerations.py,sha256=41VVQYh_vnVapggxKg2IRU5e_EiMpZzX1n1mtxvoSzM,1364
|
|
91
92
|
atomicshop/basics/enums.py,sha256=aAk1jFeQLvrC4NOpk9kgyX1-DCBr2ArPhZ8Ad7cMAVA,3537
|
|
92
|
-
atomicshop/basics/exceptions.py,sha256
|
|
93
|
+
atomicshop/basics/exceptions.py,sha256=8mhhdQloYVz8D3u16I5O_cMeuIf5pPTXoi1iY94O9zw,616
|
|
93
94
|
atomicshop/basics/guids.py,sha256=iRx5n18ATZWhpo748BwEjuLWLsu9y3OwF5-Adp-Dtik,403
|
|
94
95
|
atomicshop/basics/hexs.py,sha256=i8CTG-J0TGGa25yFSbWEvpVyHFnof_qSWUrmXY-ylKM,1054
|
|
95
96
|
atomicshop/basics/if_else.py,sha256=MakivJChofZCpr0mOVjwCthzpiaBxXVB-zv7GwMOqVo,202
|
|
@@ -124,7 +125,7 @@ atomicshop/file_io/xmls.py,sha256=zh3SuK-dNaFq2NDNhx6ivcf4GYCfGM8M10PcEwDSpxk,21
|
|
|
124
125
|
atomicshop/mitm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
125
126
|
atomicshop/mitm/config_static.py,sha256=ROAtbibSWSsF3BraUbhu-QO3MPIFqYY5KUKgsQbiSkk,7813
|
|
126
127
|
atomicshop/mitm/config_toml_editor.py,sha256=2p1CMcktWRR_NW-SmyDwylu63ad5e0-w1QPMa8ZLDBw,1635
|
|
127
|
-
atomicshop/mitm/connection_thread_worker.py,sha256=
|
|
128
|
+
atomicshop/mitm/connection_thread_worker.py,sha256=YdPL2E2ZYV5nnuaXXtyBZssT4qDalVb05BVO62MwW0k,16627
|
|
128
129
|
atomicshop/mitm/import_config.py,sha256=ZKQXxbtjVqzN9fpRrMwPNQREecH06RG8F_nXZAKTUJM,8182
|
|
129
130
|
atomicshop/mitm/initialize_engines.py,sha256=VyJE8QnzlgD3QbX5inz5o6rC3zQ3is9CeTL7-B10g1w,8292
|
|
130
131
|
atomicshop/mitm/message.py,sha256=URR5JKSuAT8XmGIkyprEjlPW2GW4ef_gfUz_GgcFseE,2184
|
|
@@ -253,9 +254,10 @@ atomicshop/wrappers/loggingw/loggers.py,sha256=mmM__XR3W4QC82wbsDRG_M4_0JYGGEP0Q
|
|
|
253
254
|
atomicshop/wrappers/loggingw/loggingw.py,sha256=uLY7DJS-3xIYQBRvI--9eFvdcnvsWSXmtJKS-gTRfjM,20863
|
|
254
255
|
atomicshop/wrappers/loggingw/reading.py,sha256=sCNlgqLNH5XdKqOOjjEox7CvViMHzs6h7-hwCnx4NKk,17566
|
|
255
256
|
atomicshop/wrappers/mongodbw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
256
|
-
atomicshop/wrappers/mongodbw/
|
|
257
|
+
atomicshop/wrappers/mongodbw/install_mongodb_ubuntu.py,sha256=pmI9AwWJ2cv5h8GionSpSJkllg6kfp0M381pk6y4Y5U,4015
|
|
258
|
+
atomicshop/wrappers/mongodbw/install_mongodb_win.py,sha256=3ZPqrXxj3lC-PnAKGXclylLuOqsbyXYeUpb5iGjdeUU,6626
|
|
257
259
|
atomicshop/wrappers/mongodbw/mongo_infra.py,sha256=IjEF0jPzQz866MpTm7rnksnyyWQeUT_B2h2DA9ryAio,2034
|
|
258
|
-
atomicshop/wrappers/mongodbw/mongodbw.py,sha256=
|
|
260
|
+
atomicshop/wrappers/mongodbw/mongodbw.py,sha256=DlKiZaB__OIkWNQgQxKD569qrzm1l7m1TWKH2NTe8qs,44278
|
|
259
261
|
atomicshop/wrappers/nodejsw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
260
262
|
atomicshop/wrappers/nodejsw/install_nodejs.py,sha256=TKGa3jSlSqZTL2NA0nMkWDFtlkz7rxGGn44ywCg7MN8,5228
|
|
261
263
|
atomicshop/wrappers/playwrightw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -301,17 +303,17 @@ atomicshop/wrappers/socketw/dns_server.py,sha256=VHV6s7vd0zqqW3dhE6li-260YRzmEB5
|
|
|
301
303
|
atomicshop/wrappers/socketw/exception_wrapper.py,sha256=B-X5SHLSUIWToihH2MKnOB1F4A81_X0DpLLfnYKYbEc,7067
|
|
302
304
|
atomicshop/wrappers/socketw/get_process.py,sha256=aJC-_qFUv3NgWCSUzDI72E4z8_-VTZE9NVZ0CwUoNlM,5698
|
|
303
305
|
atomicshop/wrappers/socketw/receiver.py,sha256=XVvWOoeCo3vA0O5p19ryi-hcDIyx382WNG7WzMNVeYk,9322
|
|
304
|
-
atomicshop/wrappers/socketw/sender.py,sha256=
|
|
306
|
+
atomicshop/wrappers/socketw/sender.py,sha256=vjgU1TaADJjaYiZOkLzfxcdCbmkvjhEhVjSV5mmIbw8,4969
|
|
305
307
|
atomicshop/wrappers/socketw/sni.py,sha256=J1kPnQ77XwKN1pO5aOI1c_VfhuivCm95OOaQxMpPuZ0,17627
|
|
306
|
-
atomicshop/wrappers/socketw/socket_client.py,sha256=
|
|
308
|
+
atomicshop/wrappers/socketw/socket_client.py,sha256=TduqAFBHvPWojMnj4q6--1bQyLZpv8os0vYJ1sBupRM,19855
|
|
307
309
|
atomicshop/wrappers/socketw/socket_server_tester.py,sha256=Qobmh4XV8ZxLUaw-eW4ESKAbeSLecCKn2OWFzMhadk0,6420
|
|
308
310
|
atomicshop/wrappers/socketw/socket_wrapper.py,sha256=WtylpezgIIBuz-A6PfM0hO1sm9Exd4j3qhDXcFc74-E,35567
|
|
309
311
|
atomicshop/wrappers/socketw/ssl_base.py,sha256=kmiif84kMhBr5yjQW17p935sfjR5JKG0LxIwBA4iVvU,2275
|
|
310
312
|
atomicshop/wrappers/socketw/statistics_csv.py,sha256=w1AH-zf4mBuT4euf28UKij9ihM-b1BRU9Qfby0QDdqI,2957
|
|
311
313
|
atomicshop/wrappers/winregw/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
312
314
|
atomicshop/wrappers/winregw/winreg_network.py,sha256=bQ8Jql8bVGBJ0dt3VQ56lga_1LBOMLI3Km_otvvbU6c,7138
|
|
313
|
-
atomicshop-2.16.
|
|
314
|
-
atomicshop-2.16.
|
|
315
|
-
atomicshop-2.16.
|
|
316
|
-
atomicshop-2.16.
|
|
317
|
-
atomicshop-2.16.
|
|
315
|
+
atomicshop-2.16.36.dist-info/LICENSE.txt,sha256=lLU7EYycfYcK2NR_1gfnhnRC8b8ccOTElACYplgZN88,1094
|
|
316
|
+
atomicshop-2.16.36.dist-info/METADATA,sha256=7WSrbRJAwsJH5uWhqieDDjUdx-uUgxLcqKzfV3nFCDE,10473
|
|
317
|
+
atomicshop-2.16.36.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
318
|
+
atomicshop-2.16.36.dist-info/top_level.txt,sha256=EgKJB-7xcrAPeqTRF2laD_Np2gNGYkJkd4OyXqpJphA,11
|
|
319
|
+
atomicshop-2.16.36.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|