kax 0.1.0__tar.gz
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.
- kax-0.1.0/LICENSE +0 -0
- kax-0.1.0/PKG-INFO +41 -0
- kax-0.1.0/README.md +16 -0
- kax-0.1.0/kax/__init__.py +0 -0
- kax-0.1.0/kax/acts.py +211 -0
- kax-0.1.0/kax/fsOperations.py +93 -0
- kax-0.1.0/kax/mem.py +71 -0
- kax-0.1.0/kax/pub.py +76 -0
- kax-0.1.0/kax/sub.py +55 -0
- kax-0.1.0/pyproject.toml +26 -0
kax-0.1.0/LICENSE
ADDED
|
File without changes
|
kax-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: kax
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Biblioteca cliente de sistema de almacenamiento en memoria.
|
|
5
|
+
Author: Julio Salazar
|
|
6
|
+
Author-email: julio.salazar@cinvestav.mx
|
|
7
|
+
Requires-Python: >=3.10
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
13
|
+
Requires-Dist: certifi (==2025.6.15)
|
|
14
|
+
Requires-Dist: charset-normalizer (==3.4.2)
|
|
15
|
+
Requires-Dist: idna (==3.10)
|
|
16
|
+
Requires-Dist: paho-mqtt (==2.1.0)
|
|
17
|
+
Requires-Dist: python-dateutil (==2.9.0.post0)
|
|
18
|
+
Requires-Dist: pytz (==2025.2)
|
|
19
|
+
Requires-Dist: requests (==2.32.4)
|
|
20
|
+
Requires-Dist: six (==1.17.0)
|
|
21
|
+
Requires-Dist: tzdata (==2025.2)
|
|
22
|
+
Requires-Dist: urllib3 (==2.5.0)
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# Biblioteca cliente de sistema de almacenamiento basado en memoria
|
|
27
|
+
|
|
28
|
+
Biblioteca cliente para el sistema de almacenamiento en memoria "ESS v1". El cliente es capaz de cargar en datos memoria de forma local, enviar datos al sistema de almacenamiento en memoria y descargar datos del sistema de almacenamiento.
|
|
29
|
+
|
|
30
|
+
UTILIZAR EN SISTEMA OPERATIVO LINUX.
|
|
31
|
+
|
|
32
|
+
## Authors
|
|
33
|
+
|
|
34
|
+
- [@juliocsp03](https://www.github.com/juliocsp03)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
[MIT](https://choosealicense.com/licenses/mit/)
|
|
40
|
+
|
|
41
|
+
|
kax-0.1.0/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
|
|
2
|
+
# Biblioteca cliente de sistema de almacenamiento basado en memoria
|
|
3
|
+
|
|
4
|
+
Biblioteca cliente para el sistema de almacenamiento en memoria "ESS v1". El cliente es capaz de cargar en datos memoria de forma local, enviar datos al sistema de almacenamiento en memoria y descargar datos del sistema de almacenamiento.
|
|
5
|
+
|
|
6
|
+
UTILIZAR EN SISTEMA OPERATIVO LINUX.
|
|
7
|
+
|
|
8
|
+
## Authors
|
|
9
|
+
|
|
10
|
+
- [@juliocsp03](https://www.github.com/juliocsp03)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## License
|
|
14
|
+
|
|
15
|
+
[MIT](https://choosealicense.com/licenses/mit/)
|
|
16
|
+
|
|
File without changes
|
kax-0.1.0/kax/acts.py
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from multiprocessing import shared_memory, Pool
|
|
3
|
+
from . import fsOperations as fso
|
|
4
|
+
from . import mem
|
|
5
|
+
from . import sub
|
|
6
|
+
from . import pub
|
|
7
|
+
|
|
8
|
+
url = "localhost"
|
|
9
|
+
urlStorage = "localhost"
|
|
10
|
+
chunk_size = 1048576
|
|
11
|
+
workers = 1
|
|
12
|
+
originFile = None
|
|
13
|
+
use_workers = True
|
|
14
|
+
|
|
15
|
+
def loadRes(path, s = False, load_to_memory = True):
|
|
16
|
+
mem.remove_shm_from_resource_tracker()
|
|
17
|
+
metadata = fso.getMetadata(path)
|
|
18
|
+
# print(json.dumps(metadata))
|
|
19
|
+
segments = []
|
|
20
|
+
for index, resource in enumerate(metadata["resources"]): # GENERA LOS ESPACIOS DE MEMEORIA
|
|
21
|
+
try: # SI YA EXISTEN SE AGREGA UN CAMPO 'local' CON VALOR 'True'
|
|
22
|
+
shm = shared_memory.SharedMemory(name = resource['hash'], create = False)
|
|
23
|
+
metadata["resources"][index]['local'] = True
|
|
24
|
+
shm.close()
|
|
25
|
+
except FileNotFoundError: # SI NO EXISTEN SE AGREGA UN CAMPO 'local' CON VALOR 'False'
|
|
26
|
+
if (load_to_memory):
|
|
27
|
+
mem.createLocalSharedMemorySpace(resource['hash'], resource['size'])
|
|
28
|
+
metadata["resources"][index]['local'] = False
|
|
29
|
+
except Exception as e:
|
|
30
|
+
return
|
|
31
|
+
for file in metadata["resources"]: # OBTENER LOS SEGMENTOS DE LOS ARCHIVOS QUE NO ESTÁN EN MEMORIA
|
|
32
|
+
if(file['local'] == False or file['local'] == True):
|
|
33
|
+
segments+=fso.array_of_segments(file['size'], file["path"], file['hash'], chunk_size)
|
|
34
|
+
|
|
35
|
+
if (load_to_memory):
|
|
36
|
+
with Pool(processes = workers) as p: # CARGARLOS EN MEMORIA A TRAVÉS DE TRABAJADORES
|
|
37
|
+
p.map(mem.loadToLocalSharedMemory, segments)
|
|
38
|
+
|
|
39
|
+
for index, resource in enumerate(metadata["resources"]):
|
|
40
|
+
if(resource['local'] == False):
|
|
41
|
+
metadata["resources"][index]['local'] = True
|
|
42
|
+
if s:
|
|
43
|
+
return metadata, segments
|
|
44
|
+
else:
|
|
45
|
+
return metadata
|
|
46
|
+
|
|
47
|
+
def loadAndUploadToCloud(path):
|
|
48
|
+
res, segments = loadRes(path, True)
|
|
49
|
+
res = uploadToCloud(res, segments)
|
|
50
|
+
return res
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def uploadToCloudFromDisk(path):
|
|
54
|
+
res, segments = loadRes(path, True, False)
|
|
55
|
+
res = uploadToCloud(res, segments, "Disk")
|
|
56
|
+
return res
|
|
57
|
+
|
|
58
|
+
def uploadToCloudFromMemory(res):
|
|
59
|
+
# res, segments = loadRes(path, True, False)
|
|
60
|
+
segments = []
|
|
61
|
+
segments+=fso.array_of_segments(res['resources'][0]['size'], res['resources'][0]["path"], res['resources'][0]['hash'], chunk_size)
|
|
62
|
+
res = uploadToCloud(res, segments, "Memory")
|
|
63
|
+
return res
|
|
64
|
+
|
|
65
|
+
def uploadToCloud(res = None, segments = False, origin = "Memory"):
|
|
66
|
+
global originFile
|
|
67
|
+
originFile = origin
|
|
68
|
+
mem.remove_shm_from_resource_tracker()
|
|
69
|
+
for index, resource in enumerate(res["resources"]):
|
|
70
|
+
# print("Verificando en la nube el recurso: ", resource['hash'])
|
|
71
|
+
verification = verify(resource['hash'])
|
|
72
|
+
# print(verification)
|
|
73
|
+
if verification:
|
|
74
|
+
# print("Verificación: ", verification)
|
|
75
|
+
if (verification['file']['state']=="reserving"):
|
|
76
|
+
sub.subToTopic(resource['hash'])
|
|
77
|
+
verification['file']['state']="ready"
|
|
78
|
+
res['resources'][index] = verification['file']
|
|
79
|
+
elif (verification['file']['state']=="ready"):
|
|
80
|
+
res['resources'][index] = verification['file']
|
|
81
|
+
# print("Archivo listo para consumo")
|
|
82
|
+
pass
|
|
83
|
+
else:
|
|
84
|
+
return False
|
|
85
|
+
else:
|
|
86
|
+
if 'local' in resource: resource.pop("local")
|
|
87
|
+
resource['state'] = "reserving"
|
|
88
|
+
register = registry(resource)
|
|
89
|
+
pub.pubTopic(resource['hash'], "loading")
|
|
90
|
+
if (register["created"]):
|
|
91
|
+
response_reserve = requests.post(f"{urlStorage}/reserve", json={"name":resource['hash'], "size": resource['size']})
|
|
92
|
+
segments_res = list(filter(lambda x : f"{x['segment']}" == resource['hash'], segments))
|
|
93
|
+
if use_workers:
|
|
94
|
+
with Pool(processes = workers) as p:
|
|
95
|
+
p.map(sendToCloud, segments_res)
|
|
96
|
+
else:
|
|
97
|
+
data = None
|
|
98
|
+
for segment in segments_res:
|
|
99
|
+
if (originFile == "Memory"):
|
|
100
|
+
data = mem.getChunk(segment['segment'], segment['start_position'], segment['end_position'])
|
|
101
|
+
else:
|
|
102
|
+
with open(segment['origin'], "rb") as file:
|
|
103
|
+
file.seek(segment['start_position'])
|
|
104
|
+
data = file.read(segment['chunk_size'])
|
|
105
|
+
files = {"files": data}
|
|
106
|
+
response_fill = requests.post(f"{urlStorage}/fill", files = files, data = segment)
|
|
107
|
+
resUpdateState = update(resource['hash'], "ready")
|
|
108
|
+
pub.pubTopic(resource['hash'], "ready")
|
|
109
|
+
originFile = None
|
|
110
|
+
return res
|
|
111
|
+
|
|
112
|
+
def sendToCloud(segment):
|
|
113
|
+
global originFile
|
|
114
|
+
# print("worker: ", os.getpid(), "\tSegment: ", segment['segment'])
|
|
115
|
+
data = None
|
|
116
|
+
if (originFile == "Memory"):
|
|
117
|
+
data = mem.getChunk(segment['segment'], segment['start_position'], segment['end_position'])
|
|
118
|
+
else:
|
|
119
|
+
with open(segment['origin'], "rb") as file:
|
|
120
|
+
file.seek(segment['start_position'])
|
|
121
|
+
data = file.read(segment['chunk_size'])
|
|
122
|
+
files = {"files": data}
|
|
123
|
+
response_fill = requests.post(f"{urlStorage}/fill", files = files, data = segment)
|
|
124
|
+
|
|
125
|
+
def downloadFromCloud(hash):
|
|
126
|
+
mem.remove_shm_from_resource_tracker()
|
|
127
|
+
md = verify(hash)
|
|
128
|
+
md = md['file']
|
|
129
|
+
original_hash = md['hash']
|
|
130
|
+
mem.createLocalSharedMemorySpace(md['hash'], md['size'])
|
|
131
|
+
segments_to_get = fso.array_of_segments_for_server_file(md['size'], original_hash, chunk_size)
|
|
132
|
+
for segment in segments_to_get:
|
|
133
|
+
response = requests.post(f"{urlStorage}/chunk", data = segment)
|
|
134
|
+
mem.loadDowloadedToLocalSharedMemory(md['hash'], segment['start_position'], segment['end_position'], response.content)
|
|
135
|
+
return {"message": True, "file": md['hash']}
|
|
136
|
+
|
|
137
|
+
def verify(hash):
|
|
138
|
+
try:
|
|
139
|
+
response = requests.post(f"{url}/hash", json = {"hash": hash})
|
|
140
|
+
if response.json()['registered']:
|
|
141
|
+
return response.json()
|
|
142
|
+
else:
|
|
143
|
+
return False
|
|
144
|
+
except requests.exceptions.RequestException as err:
|
|
145
|
+
return {"message": "Error"}
|
|
146
|
+
|
|
147
|
+
def update(hash, state):
|
|
148
|
+
try:
|
|
149
|
+
response = requests.post(f"{url}/update-file-state", json = {"hash": hash, "state": state})
|
|
150
|
+
if response.json():
|
|
151
|
+
return response.json()
|
|
152
|
+
else:
|
|
153
|
+
return False
|
|
154
|
+
except requests.exceptions.RequestException as err:
|
|
155
|
+
return {"message": "Error"}
|
|
156
|
+
|
|
157
|
+
def registry(rmd):
|
|
158
|
+
try:
|
|
159
|
+
response = requests.post(f"{url}/register-file", json=rmd)
|
|
160
|
+
return response.json()
|
|
161
|
+
except requests.exceptions.RequestException as err:
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
def removeShm(shm_name):
|
|
165
|
+
mem.removeShm(shm_name)
|
|
166
|
+
|
|
167
|
+
def getRes(file):
|
|
168
|
+
return mem.getData(file)
|
|
169
|
+
|
|
170
|
+
def saveFile(path, data, name):
|
|
171
|
+
fso.saveFile(path, data, name)
|
|
172
|
+
|
|
173
|
+
def setWorkers(w):
|
|
174
|
+
global workers
|
|
175
|
+
workers = w
|
|
176
|
+
|
|
177
|
+
def setChunkSize(cs):
|
|
178
|
+
global chunk_size
|
|
179
|
+
chunk_size = cs
|
|
180
|
+
|
|
181
|
+
def setUrl(u):
|
|
182
|
+
global url
|
|
183
|
+
url = u
|
|
184
|
+
|
|
185
|
+
def setStorageUrl(u):
|
|
186
|
+
global urlStorage
|
|
187
|
+
urlStorage = u
|
|
188
|
+
|
|
189
|
+
def getWorkers():
|
|
190
|
+
return workers
|
|
191
|
+
|
|
192
|
+
def getChunkSize():
|
|
193
|
+
return chunk_size
|
|
194
|
+
|
|
195
|
+
def getUrl():
|
|
196
|
+
return url
|
|
197
|
+
|
|
198
|
+
def getStorageUrl():
|
|
199
|
+
return urlStorage
|
|
200
|
+
|
|
201
|
+
def setBrokerUrl(url):
|
|
202
|
+
pub.setBrokerUrl(url)
|
|
203
|
+
sub.setBrokerUrl(url)
|
|
204
|
+
|
|
205
|
+
def setBrokerPort(p):
|
|
206
|
+
pub.setBrokerPort(p)
|
|
207
|
+
sub.setBrokerPort(p)
|
|
208
|
+
|
|
209
|
+
def setUseWorkers(value):
|
|
210
|
+
global use_workers
|
|
211
|
+
use_workers = value
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import hashlib
|
|
3
|
+
|
|
4
|
+
def getMetadata(res):
|
|
5
|
+
type = None
|
|
6
|
+
data = []
|
|
7
|
+
if (os.path.isdir(res)):
|
|
8
|
+
data = dirs(res)
|
|
9
|
+
type = "directorio"
|
|
10
|
+
elif (os.path.isfile(res)):
|
|
11
|
+
data.append(files(res))
|
|
12
|
+
type = "archivo"
|
|
13
|
+
else:
|
|
14
|
+
print("Entrada inválida")
|
|
15
|
+
return {"type": type, "resources": data}
|
|
16
|
+
|
|
17
|
+
def getSegmentData(segment):
|
|
18
|
+
data = None
|
|
19
|
+
with open(segment['origin'], "rb") as file:
|
|
20
|
+
file.seek(segment['start_position'])
|
|
21
|
+
data = file.read(segment['chunk_size'])
|
|
22
|
+
return data
|
|
23
|
+
|
|
24
|
+
def files(res):
|
|
25
|
+
with open(res, "rb") as file:
|
|
26
|
+
digest = getFileHash(res)
|
|
27
|
+
return {"hash": digest, "path": res, "size": os.path.getsize(res), "extension": os.path.splitext(res)[1], "state": "none", "temperature": "none", "owners": "none" }
|
|
28
|
+
|
|
29
|
+
def getFileHash(path):
|
|
30
|
+
hash_func = getattr(hashlib, "sha256")()
|
|
31
|
+
with open(path, "rb") as file:
|
|
32
|
+
while chunk := file.read(1048576):
|
|
33
|
+
hash_func.update(chunk)
|
|
34
|
+
return hash_func.hexdigest()
|
|
35
|
+
|
|
36
|
+
def saveFile(path, data, name):
|
|
37
|
+
with open(f"{path}{name}", "wb") as file:
|
|
38
|
+
file.write(data)
|
|
39
|
+
|
|
40
|
+
def dirs(res):
|
|
41
|
+
list_metadata = []
|
|
42
|
+
for element in os.listdir(res):
|
|
43
|
+
if os.path.isdir(res + '/' + element):
|
|
44
|
+
list_metadata = list_metadata + dirs(res + '/' + element)
|
|
45
|
+
elif os.path.isfile(res + '/' + element):
|
|
46
|
+
list_metadata.append(files(f"{res}/{element}"))
|
|
47
|
+
return list_metadata
|
|
48
|
+
|
|
49
|
+
def array_of_segments(file_size, path, segment_name, chunk_size):
|
|
50
|
+
# INICIALIZA POSICIÓN EN 0
|
|
51
|
+
position = 0
|
|
52
|
+
# DEFINE EL TAMAÑO DEL SEGMENTO
|
|
53
|
+
chunk = chunk_size
|
|
54
|
+
# OBTIENE EL NOMBRE Y EXTENSIÓN DEL ARCHIVO
|
|
55
|
+
filename, extension = os.path.splitext(os.path.basename(path))
|
|
56
|
+
# DEFINE ARREGLO DE POSICIONES
|
|
57
|
+
positions = []
|
|
58
|
+
while position < file_size:
|
|
59
|
+
# DEFINE POSICIÓN FINAL DE UN CHUNK
|
|
60
|
+
end_position = position + chunk if ((position + chunk) < file_size) else position + (file_size - position)
|
|
61
|
+
# AGREGA ELEMENTO AL ARREGLO DE POSICIONES
|
|
62
|
+
positions.append({"origin": path, "filename": filename, "extension": extension,"start_position": position, "end_position": end_position, "file_size": file_size, "segment": segment_name, "chunk_size": chunk})
|
|
63
|
+
# ACTUALIZA LA POSICIÓN
|
|
64
|
+
position = position + chunk
|
|
65
|
+
# RETORNA LAS POSICIONES
|
|
66
|
+
return positions
|
|
67
|
+
|
|
68
|
+
def array_of_segments_for_server_file(file_size, segment_name, chunk_size):
|
|
69
|
+
# INICIALIZA POSICIÓN EN 0
|
|
70
|
+
position = 0
|
|
71
|
+
# DEFINE EL TAMAÑO DEL SEGMENTO
|
|
72
|
+
chunk = chunk_size
|
|
73
|
+
# OBTIENE EL NOMBRE Y EXTENSIÓN DEL ARCHIVO
|
|
74
|
+
# filename, extension = os.path.splitext(os.path.basename(path))
|
|
75
|
+
# DEFINE ARREGLO DE POSICIONES
|
|
76
|
+
positions = []
|
|
77
|
+
while position < file_size:
|
|
78
|
+
# DEFINE POSICIÓN FINAL DE UN CHUNK
|
|
79
|
+
end_position = position + chunk if ((position + chunk) < file_size) else position + (file_size - position)
|
|
80
|
+
# AGREGA ELEMENTO AL ARREGLO DE POSICIONES
|
|
81
|
+
positions.append({"start_position": position, "end_position": end_position, "file_size": file_size, "segment": segment_name, "chunk_size": chunk})
|
|
82
|
+
# ACTUALIZA LA POSICIÓN
|
|
83
|
+
position = position + chunk
|
|
84
|
+
# RETORNA LAS POSICIONES
|
|
85
|
+
return positions
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
# if __name__ == '__main__':
|
|
89
|
+
# response = get_metadata("/home/julio/objects")
|
|
90
|
+
# # response = metadata_extractor("/home/julio/objects/one/f.txt")
|
|
91
|
+
# # response = dirs("/home/julio/objects")
|
|
92
|
+
# # print()
|
|
93
|
+
# print(json.dumps(response))
|
kax-0.1.0/kax/mem.py
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from multiprocessing import shared_memory, Pool
|
|
2
|
+
from multiprocessing import resource_tracker
|
|
3
|
+
|
|
4
|
+
def createLocalSharedMemorySpace(name, size):
|
|
5
|
+
# self.remove_shm_from_resource_tracker()
|
|
6
|
+
try:
|
|
7
|
+
shm = shared_memory.SharedMemory(create=True, size = size, name = name)
|
|
8
|
+
# resource_tracker.unregister(shm._name, 'shared_memory')
|
|
9
|
+
# shm.close()
|
|
10
|
+
except Exception as e:
|
|
11
|
+
removeShm(name)
|
|
12
|
+
shm = shared_memory.SharedMemory(create=True, size = size, name = name)
|
|
13
|
+
finally:
|
|
14
|
+
resource_tracker.unregister(shm._name, 'shared_memory')
|
|
15
|
+
shm.close()
|
|
16
|
+
return shm.name
|
|
17
|
+
# shm = shared_memory.SharedMemory(create=True, size = size, name = name)
|
|
18
|
+
# resource_tracker.unregister(shm._name, 'shared_memory')
|
|
19
|
+
# shm.close()
|
|
20
|
+
# return shm.name
|
|
21
|
+
|
|
22
|
+
def loadToLocalSharedMemory(segment):
|
|
23
|
+
shm = shared_memory.SharedMemory(name = segment['segment'], create=False)
|
|
24
|
+
with open(segment['origin'], "rb") as file:
|
|
25
|
+
file.seek(segment['start_position'])
|
|
26
|
+
shm.buf[segment['start_position']:segment['end_position']] = file.read(segment['chunk_size'])
|
|
27
|
+
shm.close()
|
|
28
|
+
|
|
29
|
+
def loadDowloadedToLocalSharedMemory(shm_name, start_position, end_position, data):
|
|
30
|
+
shm = shared_memory.SharedMemory(name = shm_name, create=False)
|
|
31
|
+
shm.buf[start_position:end_position] = data
|
|
32
|
+
shm.close()
|
|
33
|
+
|
|
34
|
+
def getChunk(shm_name, start_position, end_position):
|
|
35
|
+
shm = shared_memory.SharedMemory(name = shm_name, create=False)
|
|
36
|
+
data = bytes(shm.buf[int(start_position):int(end_position)])
|
|
37
|
+
shm.close()
|
|
38
|
+
return data
|
|
39
|
+
|
|
40
|
+
def getData(file):
|
|
41
|
+
shm = shared_memory.SharedMemory(name = file, create=False)
|
|
42
|
+
data = bytes(shm.buf[:])
|
|
43
|
+
resource_tracker.unregister(shm._name, 'shared_memory')
|
|
44
|
+
shm.close()
|
|
45
|
+
return data
|
|
46
|
+
|
|
47
|
+
def removeShm(shm_name):
|
|
48
|
+
shm = shared_memory.SharedMemory(name = shm_name, create=False)
|
|
49
|
+
shm.close()
|
|
50
|
+
shm.unlink()
|
|
51
|
+
|
|
52
|
+
def remove_shm_from_resource_tracker():
|
|
53
|
+
"""Monkey-patch multiprocessing.resource_tracker so SharedMemory won't be tracked
|
|
54
|
+
|
|
55
|
+
More details at: https://bugs.python.org/issue38119
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
def fix_register(name, rtype):
|
|
59
|
+
if rtype == "shared_memory":
|
|
60
|
+
return
|
|
61
|
+
return resource_tracker._resource_tracker.register(self, name, rtype)
|
|
62
|
+
resource_tracker.register = fix_register
|
|
63
|
+
|
|
64
|
+
def fix_unregister(name, rtype):
|
|
65
|
+
if rtype == "shared_memory":
|
|
66
|
+
return
|
|
67
|
+
return resource_tracker._resource_tracker.unregister(self, name, rtype)
|
|
68
|
+
resource_tracker.unregister = fix_unregister
|
|
69
|
+
|
|
70
|
+
if "shared_memory" in resource_tracker._CLEANUP_FUNCS:
|
|
71
|
+
del resource_tracker._CLEANUP_FUNCS["shared_memory"]
|
kax-0.1.0/kax/pub.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import paho.mqtt.client as mqtt
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
# broker = "148.247.201.226"
|
|
5
|
+
broker = "localhost"
|
|
6
|
+
port = 1883
|
|
7
|
+
topic = "files/"
|
|
8
|
+
pub_confirmed = False
|
|
9
|
+
def on_connect(client, userdata, flags, rc, properties = None):
|
|
10
|
+
if rc == 0:
|
|
11
|
+
# print("Conectado al broker MQTT!")
|
|
12
|
+
pass
|
|
13
|
+
else:
|
|
14
|
+
# print(f"Fallo al conectar, código de retorno: {rc}")
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
def on_publish(client, userdata, mid, rc, properties=None):
|
|
18
|
+
global pub_confirmed
|
|
19
|
+
if rc == 0:
|
|
20
|
+
# print(f"Mensaje con ID {mid} publicado y confirmado.")
|
|
21
|
+
pub_confirmed = True
|
|
22
|
+
else:
|
|
23
|
+
# print(f"Fallo al publicar el mensaje con ID {mid}.")
|
|
24
|
+
pub_confirmed = False
|
|
25
|
+
|
|
26
|
+
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
|
27
|
+
|
|
28
|
+
def pubTopic(hash = "test-hash", value = "test value"):
|
|
29
|
+
client.on_connect = on_connect
|
|
30
|
+
client.on_publish = on_publish
|
|
31
|
+
try:
|
|
32
|
+
client.connect(broker, port, 60)
|
|
33
|
+
except Exception as e:
|
|
34
|
+
# print(f"Error al conectar: {e}")
|
|
35
|
+
exit()
|
|
36
|
+
|
|
37
|
+
client.loop_start()
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
result = client.publish(f"{topic}{hash}", value, retain=True, qos = 1)
|
|
41
|
+
timeout = time.time() + 10
|
|
42
|
+
while not pub_confirmed and time.time() < timeout:
|
|
43
|
+
time.sleep(0.1)
|
|
44
|
+
if (pub_confirmed):
|
|
45
|
+
# print(f"Publicado exitosamente '{value}' en el tema '{topic}{hash}'")
|
|
46
|
+
client.loop_stop()
|
|
47
|
+
client.disconnect()
|
|
48
|
+
# print("Publicador detenido.")
|
|
49
|
+
return {"pub": True}
|
|
50
|
+
else:
|
|
51
|
+
# print(f"Fallo al publicar mensaje al tema {topic}")
|
|
52
|
+
client.loop_stop()
|
|
53
|
+
client.disconnect()
|
|
54
|
+
# print("Publicador detenido.")
|
|
55
|
+
return {"pub": False}
|
|
56
|
+
# if result[0] == 0:
|
|
57
|
+
# print(f"Publicado exitosamente '{value}' en el tema '{topic}{hash}'")
|
|
58
|
+
# return {"pub": True}
|
|
59
|
+
# else:
|
|
60
|
+
# # print(f"Fallo al publicar mensaje al tema {topic}")
|
|
61
|
+
# return {"pub": False}
|
|
62
|
+
# client.loop_stop()
|
|
63
|
+
# client.disconnect()
|
|
64
|
+
# print("Publicador detenido.")
|
|
65
|
+
|
|
66
|
+
except KeyboardInterrupt:
|
|
67
|
+
# print("Fallo inesperado.")
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
def setBrokerUrl(url):
|
|
71
|
+
global broker
|
|
72
|
+
broker = url
|
|
73
|
+
|
|
74
|
+
def setBrokerPort(p):
|
|
75
|
+
global port
|
|
76
|
+
port = p
|
kax-0.1.0/kax/sub.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import paho.mqtt.client as mqtt
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
# broker = "148.247.201.226"
|
|
5
|
+
broker = "localhost"
|
|
6
|
+
port = 1883
|
|
7
|
+
topic = "files/"
|
|
8
|
+
hash = "ejemplo"
|
|
9
|
+
file_state = None
|
|
10
|
+
waiting = True
|
|
11
|
+
|
|
12
|
+
def on_connect(client, userdata, flags, rc, properties = None):
|
|
13
|
+
if rc == 0:
|
|
14
|
+
client.subscribe(f"{topic}{hash}", qos = 1)
|
|
15
|
+
else:
|
|
16
|
+
# print(f"Fallo al conectar, código: {rc}")
|
|
17
|
+
pass
|
|
18
|
+
|
|
19
|
+
def on_message(client, userdata, msg):
|
|
20
|
+
# print(f"Mensaje recibido: {msg.payload.decode()} en el tema: {msg.topic}")
|
|
21
|
+
if (msg.payload.decode() == "ready"):
|
|
22
|
+
# print("ENTRANDO A CANCELAR")
|
|
23
|
+
global waiting
|
|
24
|
+
waiting = False
|
|
25
|
+
# client.loop_stop()
|
|
26
|
+
|
|
27
|
+
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
|
|
28
|
+
|
|
29
|
+
def subToTopic(topic_hash):
|
|
30
|
+
global hash
|
|
31
|
+
hash = topic_hash
|
|
32
|
+
|
|
33
|
+
client.on_connect = on_connect
|
|
34
|
+
client.on_message = on_message
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
client.connect(broker, port)
|
|
38
|
+
# client.loop_forever()
|
|
39
|
+
client.loop_start()
|
|
40
|
+
while waiting:
|
|
41
|
+
time.sleep(0.3)
|
|
42
|
+
except Exception as e:
|
|
43
|
+
# print(f"Error al conectar: {e}")
|
|
44
|
+
exit()
|
|
45
|
+
finally:
|
|
46
|
+
client.loop_stop()
|
|
47
|
+
client.disconnect()
|
|
48
|
+
|
|
49
|
+
def setBrokerUrl(url):
|
|
50
|
+
global broker
|
|
51
|
+
broker = url
|
|
52
|
+
|
|
53
|
+
def setBrokerPort(p):
|
|
54
|
+
global port
|
|
55
|
+
port = p
|
kax-0.1.0/pyproject.toml
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "kax"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Biblioteca cliente de sistema de almacenamiento en memoria."
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "Julio Salazar", email = "julio.salazar@cinvestav.mx"}
|
|
7
|
+
]
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.10"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"certifi==2025.6.15",
|
|
12
|
+
"charset-normalizer==3.4.2",
|
|
13
|
+
"idna==3.10",
|
|
14
|
+
"paho-mqtt==2.1.0",
|
|
15
|
+
"python-dateutil==2.9.0.post0",
|
|
16
|
+
"pytz==2025.2",
|
|
17
|
+
"requests==2.32.4",
|
|
18
|
+
"six==1.17.0",
|
|
19
|
+
"tzdata==2025.2",
|
|
20
|
+
"urllib3==2.5.0"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
26
|
+
build-backend = "poetry.core.masonry.api"
|