naeural-client 2.6.13__py3-none-any.whl → 2.6.15__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.
- naeural_client/_ver.py +1 -1
- naeural_client/base/generic_session.py +251 -75
- naeural_client/bc/base.py +37 -19
- naeural_client/const/apps.py +1 -0
- naeural_client/default/session/mqtt_session.py +19 -4
- {naeural_client-2.6.13.dist-info → naeural_client-2.6.15.dist-info}/METADATA +1 -1
- {naeural_client-2.6.13.dist-info → naeural_client-2.6.15.dist-info}/RECORD +10 -10
- {naeural_client-2.6.13.dist-info → naeural_client-2.6.15.dist-info}/WHEEL +0 -0
- {naeural_client-2.6.13.dist-info → naeural_client-2.6.15.dist-info}/entry_points.txt +0 -0
- {naeural_client-2.6.13.dist-info → naeural_client-2.6.15.dist-info}/licenses/LICENSE +0 -0
naeural_client/_ver.py
CHANGED
@@ -23,7 +23,7 @@ from ..bc import DefaultBlockEngine, _DotDict
|
|
23
23
|
from ..const import (
|
24
24
|
COMMANDS, ENVIRONMENT, HB, PAYLOAD_DATA, STATUS_TYPE,
|
25
25
|
PLUGIN_SIGNATURES, DEFAULT_PIPELINES,
|
26
|
-
BLOCKCHAIN_CONFIG, SESSION_CT
|
26
|
+
BLOCKCHAIN_CONFIG, SESSION_CT, NET_CONFIG
|
27
27
|
)
|
28
28
|
from ..const import comms as comm_ct
|
29
29
|
from ..io_formatter import IOFormatterWrapper
|
@@ -366,24 +366,33 @@ class GenericSession(BaseDecentrAIObject):
|
|
366
366
|
"""
|
367
367
|
# check if payload is encrypted
|
368
368
|
if dict_msg.get(PAYLOAD_DATA.EE_IS_ENCRYPTED, False):
|
369
|
-
|
370
|
-
|
369
|
+
destination = dict_msg.get(PAYLOAD_DATA.EE_DESTINATION, [])
|
370
|
+
if not isinstance(destination, list):
|
371
|
+
destination = [destination]
|
372
|
+
if self.bc_engine.contains_current_address(destination):
|
371
373
|
|
372
|
-
|
374
|
+
encrypted_data = dict_msg.get(PAYLOAD_DATA.EE_ENCRYPTED_DATA, None)
|
375
|
+
sender_addr = dict_msg.get(comm_ct.COMM_SEND_MESSAGE.K_SENDER_ADDR, None)
|
373
376
|
|
374
|
-
|
375
|
-
self.D("Cannot decrypt message, dropping..\n{}".format(str_data), verbosity=2)
|
376
|
-
return None
|
377
|
+
str_data = self.bc_engine.decrypt(encrypted_data, sender_addr)
|
377
378
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
self.P("Error while decrypting message: {}".format(e), color='r', verbosity=1)
|
382
|
-
self.D("Message: {}".format(str_data), verbosity=2)
|
383
|
-
return None
|
379
|
+
if str_data is None:
|
380
|
+
self.D("Cannot decrypt message, dropping..\n{}".format(str_data), verbosity=2)
|
381
|
+
return None
|
384
382
|
|
385
|
-
|
386
|
-
|
383
|
+
try:
|
384
|
+
dict_data = json.loads(str_data)
|
385
|
+
except Exception as e:
|
386
|
+
self.P("Error while decrypting message: {}".format(e), color='r', verbosity=1)
|
387
|
+
self.D("Message: {}".format(str_data), verbosity=2)
|
388
|
+
return None
|
389
|
+
|
390
|
+
dict_msg = {**dict_data, **dict_msg}
|
391
|
+
dict_msg.pop(PAYLOAD_DATA.EE_ENCRYPTED_DATA, None)
|
392
|
+
else:
|
393
|
+
payload_path = dict_msg.get(PAYLOAD_DATA.EE_PAYLOAD_PATH, None)
|
394
|
+
self.D(f"Message {payload_path} is encrypted but not for this address.", verbosity=2)
|
395
|
+
# endif message for us
|
387
396
|
# end if encrypted
|
388
397
|
|
389
398
|
formatter = self.formatter_wrapper \
|
@@ -498,6 +507,56 @@ class GenericSession(BaseDecentrAIObject):
|
|
498
507
|
self._dct_can_send_to_node[node_addr] = not node_secured or client_is_allowed or self.bc_engine.address == node_addr
|
499
508
|
return
|
500
509
|
|
510
|
+
def send_encrypted_payload(self, node_addr, payload, **kwargs):
|
511
|
+
"""
|
512
|
+
TODO: move in BlockChainEngine
|
513
|
+
Send an encrypted payload to a node.
|
514
|
+
|
515
|
+
Parameters
|
516
|
+
----------
|
517
|
+
node_addr : str
|
518
|
+
The address of the edge node that will receive the message.
|
519
|
+
payload : dict
|
520
|
+
The payload dict to be sent.
|
521
|
+
**kwargs : dict
|
522
|
+
Additional data to be sent to __prepare_message.
|
523
|
+
"""
|
524
|
+
msg_to_send = self.__prepare_message(
|
525
|
+
msg_data=payload,
|
526
|
+
encrypt_message=True,
|
527
|
+
destination=node_addr,
|
528
|
+
**kwargs
|
529
|
+
)
|
530
|
+
self.bc_engine.sign(msg_to_send)
|
531
|
+
if not self.silent:
|
532
|
+
self.P(f'Sending encrypted payload to <{node_addr}>', color='y')
|
533
|
+
self._send_payload(msg_to_send)
|
534
|
+
return
|
535
|
+
|
536
|
+
def __request_pipelines_from_net_config_monitor(self, node_addr):
|
537
|
+
"""
|
538
|
+
Request the pipelines for a node from the net-config monitor plugin instance.
|
539
|
+
Parameters
|
540
|
+
----------
|
541
|
+
node_addr : str
|
542
|
+
The address of the edge node that sent the message.
|
543
|
+
|
544
|
+
"""
|
545
|
+
payload = {
|
546
|
+
NET_CONFIG.NET_CONFIG_DATA: {
|
547
|
+
NET_CONFIG.OPERATION: NET_CONFIG.REQUEST_COMMAND,
|
548
|
+
NET_CONFIG.DESTINATION: node_addr,
|
549
|
+
}
|
550
|
+
}
|
551
|
+
additional_data = {
|
552
|
+
PAYLOAD_DATA.EE_PAYLOAD_PATH: [self.bc_engine.address, DEFAULT_PIPELINES.ADMIN_PIPELINE, PLUGIN_SIGNATURES.NET_CONFIG_MONITOR, None]
|
553
|
+
}
|
554
|
+
self.send_encrypted_payload(
|
555
|
+
node_addr=node_addr, payload=payload,
|
556
|
+
additional_data=additional_data
|
557
|
+
)
|
558
|
+
return
|
559
|
+
|
501
560
|
def __track_allowed_node_by_netmon(self, node_addr, dict_msg):
|
502
561
|
"""
|
503
562
|
Track if this session is allowed to send messages to node using net-mon data
|
@@ -505,7 +564,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
505
564
|
Parameters
|
506
565
|
----------
|
507
566
|
node_addr : str
|
508
|
-
The address of the
|
567
|
+
The address of the edge node that sent the message.
|
509
568
|
|
510
569
|
dict_msg : dict
|
511
570
|
The message received from the communication server as a heartbeat of the object from netconfig
|
@@ -514,8 +573,12 @@ class GenericSession(BaseDecentrAIObject):
|
|
514
573
|
node_secured = dict_msg.get(PAYLOAD_DATA.NETMON_NODE_SECURED, False)
|
515
574
|
|
516
575
|
client_is_allowed = self.bc_engine.contains_current_address(node_whitelist)
|
576
|
+
can_send = not node_secured or client_is_allowed or self.bc_engine.address == node_addr
|
577
|
+
if node_addr not in self._dct_can_send_to_node and can_send:
|
578
|
+
self.__request_pipelines_from_net_config_monitor(node_addr)
|
579
|
+
# endif node seen for the first time
|
517
580
|
|
518
|
-
self._dct_can_send_to_node[node_addr] =
|
581
|
+
self._dct_can_send_to_node[node_addr] = can_send
|
519
582
|
return
|
520
583
|
|
521
584
|
|
@@ -523,6 +586,9 @@ class GenericSession(BaseDecentrAIObject):
|
|
523
586
|
"""
|
524
587
|
Given a list of pipeline configurations, create or update the pipelines for a node.
|
525
588
|
"""
|
589
|
+
new_pipelines = []
|
590
|
+
if node_addr not in self._dct_online_nodes_pipelines:
|
591
|
+
self._dct_online_nodes_pipelines[node_addr] = {}
|
526
592
|
for config in pipelines:
|
527
593
|
pipeline_name = config[PAYLOAD_DATA.NAME]
|
528
594
|
pipeline: Pipeline = self._dct_online_nodes_pipelines[node_addr].get(pipeline_name, None)
|
@@ -531,7 +597,8 @@ class GenericSession(BaseDecentrAIObject):
|
|
531
597
|
else:
|
532
598
|
self._dct_online_nodes_pipelines[node_addr][pipeline_name] = self.__create_pipeline_from_config(
|
533
599
|
node_addr, config)
|
534
|
-
|
600
|
+
new_pipelines.append(self._dct_online_nodes_pipelines[node_addr][pipeline_name])
|
601
|
+
return new_pipelines
|
535
602
|
|
536
603
|
def __on_heartbeat(self, dict_msg: dict, msg_node_addr, msg_pipeline, msg_signature, msg_instance):
|
537
604
|
"""
|
@@ -571,14 +638,11 @@ class GenericSession(BaseDecentrAIObject):
|
|
571
638
|
# as the protocol should NOT send a heartbeat with active configs to
|
572
639
|
# the entire network, only to the interested parties via net-config
|
573
640
|
|
574
|
-
# default action
|
575
|
-
if msg_node_addr not in self._dct_online_nodes_pipelines:
|
576
|
-
# this is ok here although we dont get the pipelines from the heartbeat
|
577
|
-
self._dct_online_nodes_pipelines[msg_node_addr] = {}
|
578
|
-
|
579
641
|
if len(msg_active_configs) > 0:
|
580
642
|
# this is for legacy and custom implementation where heartbeats still contain
|
581
643
|
# the pipeline configuration.
|
644
|
+
pipeline_names = [x.get(PAYLOAD_DATA.NAME, None) for x in msg_active_configs]
|
645
|
+
self.D(f'<HB>Received pipelines from <{msg_node_addr}>:{pipeline_names}', color='y')
|
582
646
|
self.__process_node_pipelines(msg_node_addr, msg_active_configs)
|
583
647
|
|
584
648
|
# TODO: move this call in `__on_message_default_callback`
|
@@ -699,8 +763,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
699
763
|
# end if current_network is valid
|
700
764
|
# end if NET_MON_01
|
701
765
|
return
|
702
|
-
|
703
|
-
|
766
|
+
|
704
767
|
def __maybe_process_net_config(
|
705
768
|
self,
|
706
769
|
dict_msg: dict,
|
@@ -708,7 +771,39 @@ class GenericSession(BaseDecentrAIObject):
|
|
708
771
|
msg_signature : str,
|
709
772
|
sender_addr: str,
|
710
773
|
):
|
711
|
-
|
774
|
+
# TODO: bleo if session is in debug mode then for each net-config show what pipelines have
|
775
|
+
# been received
|
776
|
+
REQUIRED_PIPELINE = DEFAULT_PIPELINES.ADMIN_PIPELINE
|
777
|
+
REQUIRED_SIGNATURE = PLUGIN_SIGNATURES.NET_CONFIG_MONITOR
|
778
|
+
if msg_pipeline.lower() == REQUIRED_PIPELINE.lower() and msg_signature.upper() == REQUIRED_SIGNATURE.upper():
|
779
|
+
# extract data
|
780
|
+
sender_addr = dict_msg.get(PAYLOAD_DATA.EE_SENDER, None)
|
781
|
+
receiver = dict_msg.get(PAYLOAD_DATA.EE_DESTINATION, None)
|
782
|
+
if not isinstance(receiver, list):
|
783
|
+
receiver = [receiver]
|
784
|
+
path = dict_msg.get(PAYLOAD_DATA.EE_PAYLOAD_PATH, [None, None, None, None])
|
785
|
+
ee_id = dict_msg.get(PAYLOAD_DATA.EE_ID, None)
|
786
|
+
|
787
|
+
# check if I am allowed to see this payload
|
788
|
+
if not self.bc_engine.contains_current_address(receiver):
|
789
|
+
self.P(f"Received net-config from <{sender_addr}> `{ee_id}` but I am not in the receiver list: {receiver}", color='d')
|
790
|
+
return
|
791
|
+
|
792
|
+
# decrypt payload
|
793
|
+
is_encrypted = dict_msg.get(PAYLOAD_DATA.EE_IS_ENCRYPTED, False)
|
794
|
+
if not is_encrypted:
|
795
|
+
self.P(f"Received net-config from <{sender_addr}> `{ee_id}` but it is not encrypted", color='r')
|
796
|
+
return
|
797
|
+
net_config_data = dict_msg.get(NET_CONFIG.NET_CONFIG_DATA, {})
|
798
|
+
received_pipelines = net_config_data.get('PIPELINES', [])
|
799
|
+
self.D(f"Received {len(received_pipelines)} pipelines from <{sender_addr}>")
|
800
|
+
new_pipelines = self.__process_node_pipelines(sender_addr, received_pipelines)
|
801
|
+
pipeline_names = [x.name for x in new_pipelines]
|
802
|
+
self.P(f'<NETCFG>Received pipelines from <{sender_addr}>:{pipeline_names}', color='y')
|
803
|
+
self.D(f'[DEBUG][NETCFG]Received pipelines from <{sender_addr}>:\n{new_pipelines}', color='y')
|
804
|
+
|
805
|
+
# load with same method as a hb
|
806
|
+
return True
|
712
807
|
|
713
808
|
|
714
809
|
# TODO: maybe convert dict_msg to Payload object
|
@@ -908,15 +1003,38 @@ class GenericSession(BaseDecentrAIObject):
|
|
908
1003
|
"""
|
909
1004
|
raise NotImplementedError
|
910
1005
|
|
911
|
-
def
|
1006
|
+
def _send_raw_message(self, to, msg, communicator='default'):
|
912
1007
|
"""
|
913
|
-
Send a
|
1008
|
+
Send a message to a node.
|
914
1009
|
|
915
1010
|
Parameters
|
916
1011
|
----------
|
917
1012
|
to : str
|
918
|
-
The name of the Naeural Edge Protocol edge node that will receive the
|
919
|
-
|
1013
|
+
The name of the Naeural Edge Protocol edge node that will receive the message.
|
1014
|
+
msg : dict or str
|
1015
|
+
The message to send.
|
1016
|
+
"""
|
1017
|
+
raise NotImplementedError
|
1018
|
+
|
1019
|
+
def _send_command(self, to, command):
|
1020
|
+
"""
|
1021
|
+
Send a command to a node.
|
1022
|
+
|
1023
|
+
Parametersc
|
1024
|
+
----------
|
1025
|
+
to : str
|
1026
|
+
The name of the Naeural Edge Protocol edge node that will receive the command.
|
1027
|
+
command : str or dict
|
1028
|
+
The command to send.
|
1029
|
+
"""
|
1030
|
+
raise NotImplementedError
|
1031
|
+
|
1032
|
+
def _send_payload(self, payload):
|
1033
|
+
"""
|
1034
|
+
Send a payload to a node.
|
1035
|
+
Parameters
|
1036
|
+
----------
|
1037
|
+
payload : dict or str
|
920
1038
|
The payload to send.
|
921
1039
|
"""
|
922
1040
|
raise NotImplementedError
|
@@ -1241,6 +1359,68 @@ class GenericSession(BaseDecentrAIObject):
|
|
1241
1359
|
result = aliases.get(node, None)
|
1242
1360
|
return result
|
1243
1361
|
|
1362
|
+
def __prepare_message(
|
1363
|
+
self, msg_data, encrypt_message: bool = True,
|
1364
|
+
destination: str = None, destination_id: str = None,
|
1365
|
+
session_id: str = None, additional_data: dict = None
|
1366
|
+
):
|
1367
|
+
"""
|
1368
|
+
Prepare and maybe encrypt a message for sending.
|
1369
|
+
Parameters
|
1370
|
+
----------
|
1371
|
+
msg_data : dict
|
1372
|
+
The message to send.
|
1373
|
+
encrypt_message : bool
|
1374
|
+
If True, will encrypt the message.
|
1375
|
+
destination : str, optional
|
1376
|
+
The destination address, by default None
|
1377
|
+
destination_id : str, optional
|
1378
|
+
The destination id, by default None
|
1379
|
+
additional_data : dict, optional
|
1380
|
+
Additional data to send, by default None
|
1381
|
+
This has to be dict!
|
1382
|
+
|
1383
|
+
Returns
|
1384
|
+
-------
|
1385
|
+
msg_to_send : dict
|
1386
|
+
The message to send.
|
1387
|
+
"""
|
1388
|
+
if destination is None and destination_id is not None:
|
1389
|
+
# Initial code `str_enc_data = self.bc_engine.encrypt(str_data, destination_id)` could not work under any
|
1390
|
+
# circumstances due to the fact that encrypt requires the public key of the receiver not the alias
|
1391
|
+
# of the receiver. The code below is a workaround to encrypt the message
|
1392
|
+
# TODO: furthermore the code will be migrated to the use of the address of the worker
|
1393
|
+
destination = self.get_addr_by_name(destination_id)
|
1394
|
+
assert destination is not None, f"Unknown address for id: {destination_id}"
|
1395
|
+
# endif only destination_id provided
|
1396
|
+
|
1397
|
+
# This part is duplicated with the creation of payloads
|
1398
|
+
if encrypt_message and destination is not None:
|
1399
|
+
str_data = json.dumps(msg_data)
|
1400
|
+
str_enc_data = self.bc_engine.encrypt(str_data, destination)
|
1401
|
+
msg_data = {
|
1402
|
+
comm_ct.COMM_SEND_MESSAGE.K_EE_IS_ENCRYPTED: True,
|
1403
|
+
comm_ct.COMM_SEND_MESSAGE.K_EE_ENCRYPTED_DATA: str_enc_data,
|
1404
|
+
}
|
1405
|
+
else:
|
1406
|
+
msg_data[comm_ct.COMM_SEND_MESSAGE.K_EE_IS_ENCRYPTED] = False
|
1407
|
+
if encrypt_message:
|
1408
|
+
msg_data[comm_ct.COMM_SEND_MESSAGE.K_EE_ENCRYPTED_DATA] = "Error! No receiver address found!"
|
1409
|
+
# endif encrypt_message and destination available
|
1410
|
+
msg_to_send = {
|
1411
|
+
**msg_data,
|
1412
|
+
PAYLOAD_DATA.EE_DESTINATION: destination,
|
1413
|
+
comm_ct.COMM_SEND_MESSAGE.K_EE_ID: destination_id,
|
1414
|
+
comm_ct.COMM_SEND_MESSAGE.K_SESSION_ID: session_id or self.name,
|
1415
|
+
comm_ct.COMM_SEND_MESSAGE.K_INITIATOR_ID: self.name,
|
1416
|
+
comm_ct.COMM_SEND_MESSAGE.K_SENDER_ADDR: self.bc_engine.address,
|
1417
|
+
comm_ct.COMM_SEND_MESSAGE.K_TIME: dt.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
|
1418
|
+
}
|
1419
|
+
if additional_data is not None and isinstance(additional_data, dict):
|
1420
|
+
msg_to_send.update(additional_data)
|
1421
|
+
# endif additional_data provided
|
1422
|
+
return msg_to_send
|
1423
|
+
|
1244
1424
|
def _send_command_to_box(self, command, worker, payload, show_command=True, session_id=None, **kwargs):
|
1245
1425
|
"""
|
1246
1426
|
Send a command to a node.
|
@@ -1273,37 +1453,12 @@ class GenericSession(BaseDecentrAIObject):
|
|
1273
1453
|
comm_ct.COMM_SEND_MESSAGE.K_PAYLOAD: payload,
|
1274
1454
|
}
|
1275
1455
|
|
1276
|
-
|
1277
|
-
|
1278
|
-
|
1279
|
-
|
1280
|
-
|
1281
|
-
|
1282
|
-
# circumstances due to the fact that encrypt requires the public key of the receiver not the alias
|
1283
|
-
# of the receiver. The code below is a workaround to encrypt the message
|
1284
|
-
# TODO: furthermore the code will be migrated to the use of the address of the worker
|
1285
|
-
worker_addr = self.get_addr_by_name(worker)
|
1286
|
-
assert worker_addr is not None, f"Unknown worker address: {worker} - {worker_addr}"
|
1287
|
-
|
1288
|
-
str_enc_data = self.bc_engine.encrypt(str_data, worker_addr)
|
1289
|
-
critical_data = {
|
1290
|
-
comm_ct.COMM_SEND_MESSAGE.K_EE_IS_ENCRYPTED: True,
|
1291
|
-
comm_ct.COMM_SEND_MESSAGE.K_EE_ENCRYPTED_DATA: str_enc_data,
|
1292
|
-
}
|
1293
|
-
else:
|
1294
|
-
critical_data[comm_ct.COMM_SEND_MESSAGE.K_EE_IS_ENCRYPTED] = False
|
1295
|
-
if encrypt_payload:
|
1296
|
-
critical_data[comm_ct.COMM_SEND_MESSAGE.K_EE_ENCRYPTED_DATA] = "Error! No receiver address found!"
|
1297
|
-
|
1298
|
-
# endif
|
1299
|
-
msg_to_send = {
|
1300
|
-
**critical_data,
|
1301
|
-
comm_ct.COMM_SEND_MESSAGE.K_EE_ID: worker,
|
1302
|
-
comm_ct.COMM_SEND_MESSAGE.K_SESSION_ID: session_id or self.name,
|
1303
|
-
comm_ct.COMM_SEND_MESSAGE.K_INITIATOR_ID: self.name,
|
1304
|
-
comm_ct.COMM_SEND_MESSAGE.K_SENDER_ADDR: self.bc_engine.address,
|
1305
|
-
comm_ct.COMM_SEND_MESSAGE.K_TIME: dt.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
|
1306
|
-
}
|
1456
|
+
msg_to_send = self.__prepare_message(
|
1457
|
+
msg_data=critical_data,
|
1458
|
+
encrypt_message=self.encrypt_comms,
|
1459
|
+
destination_id=worker,
|
1460
|
+
session_id=session_id,
|
1461
|
+
)
|
1307
1462
|
self.bc_engine.sign(msg_to_send, use_digest=True)
|
1308
1463
|
if show_command:
|
1309
1464
|
self.P(
|
@@ -1311,7 +1466,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
1311
1466
|
color='y',
|
1312
1467
|
verbosity=1
|
1313
1468
|
)
|
1314
|
-
self.
|
1469
|
+
self._send_command(worker, msg_to_send)
|
1315
1470
|
return
|
1316
1471
|
|
1317
1472
|
def _send_command_create_pipeline(self, worker, pipeline_config, **kwargs):
|
@@ -2470,6 +2625,35 @@ class GenericSession(BaseDecentrAIObject):
|
|
2470
2625
|
def client_address(self):
|
2471
2626
|
return self.get_client_address()
|
2472
2627
|
|
2628
|
+
def __wait_for_supervisors_net_mon_data(
|
2629
|
+
self,
|
2630
|
+
supervisor=None,
|
2631
|
+
timeout=10,
|
2632
|
+
min_supervisors=2
|
2633
|
+
):
|
2634
|
+
# the following loop will wait for the desired number of supervisors to appear online
|
2635
|
+
# for the current session
|
2636
|
+
start = tm()
|
2637
|
+
result = False
|
2638
|
+
while (tm() - start) < timeout:
|
2639
|
+
if supervisor is not None:
|
2640
|
+
if supervisor in self.__current_network_statuses:
|
2641
|
+
result = True
|
2642
|
+
break
|
2643
|
+
elif len(self.__current_network_statuses) >= min_supervisors:
|
2644
|
+
result = True
|
2645
|
+
break
|
2646
|
+
sleep(0.1)
|
2647
|
+
elapsed = tm() - start
|
2648
|
+
# end while
|
2649
|
+
# done waiting for supervisors
|
2650
|
+
return result, elapsed
|
2651
|
+
|
2652
|
+
|
2653
|
+
def get_all_nodes_pipelines(self):
|
2654
|
+
# TODO: Bleo inject this function in __on_hb and maybe_process_net_config and dump result
|
2655
|
+
return self._dct_online_nodes_pipelines
|
2656
|
+
|
2473
2657
|
def get_network_known_nodes(
|
2474
2658
|
self,
|
2475
2659
|
timeout=10,
|
@@ -2540,19 +2724,11 @@ class GenericSession(BaseDecentrAIObject):
|
|
2540
2724
|
for k in mapping:
|
2541
2725
|
res[k] = []
|
2542
2726
|
|
2543
|
-
|
2544
|
-
|
2545
|
-
|
2546
|
-
|
2547
|
-
|
2548
|
-
if supervisor in self.__current_network_statuses:
|
2549
|
-
break
|
2550
|
-
elif len(self.__current_network_statuses) >= min_supervisors:
|
2551
|
-
break
|
2552
|
-
sleep(0.1)
|
2553
|
-
elapsed = tm() - start
|
2554
|
-
# end while
|
2555
|
-
# done waiting for supervisors
|
2727
|
+
result, elapsed = self.__wait_for_supervisors_net_mon_data(
|
2728
|
+
supervisor=supervisor,
|
2729
|
+
timeout=timeout,
|
2730
|
+
min_supervisors=min_supervisors,
|
2731
|
+
)
|
2556
2732
|
best_super = 'ERROR'
|
2557
2733
|
best_super_alias = 'ERROR'
|
2558
2734
|
|
naeural_client/bc/base.py
CHANGED
@@ -260,6 +260,7 @@ class BaseBlockEngine:
|
|
260
260
|
|
261
261
|
"""
|
262
262
|
_lock: Lock = Lock()
|
263
|
+
_whitelist_lock : Lock = Lock()
|
263
264
|
__instances = {}
|
264
265
|
|
265
266
|
def __new__(
|
@@ -544,25 +545,42 @@ class BaseBlockEngine:
|
|
544
545
|
|
545
546
|
|
546
547
|
def _load_and_maybe_create_allowed(self):
|
547
|
-
fn = self._get_allowed_file()
|
548
|
-
lst_allowed = []
|
549
|
-
if os.path.isfile(fn):
|
550
|
-
with open(fn, 'rt') as fh:
|
551
|
-
lst_allowed = fh.readlines()
|
552
|
-
else:
|
553
|
-
full_path = os.path.abspath(fn)
|
554
|
-
self.P("WARNING: no `{}` file found. Creating empty one.".format(full_path), verbosity=1)
|
555
|
-
with open(fn, 'wt') as fh:
|
556
|
-
fh.write('\n')
|
557
|
-
lst_allowed = [x.strip() for x in lst_allowed]
|
558
|
-
lst_allowed = [x.split()[0] for x in lst_allowed if x != '']
|
559
|
-
lst_allowed = [self._remove_prefix(x) for x in lst_allowed if x != '']
|
560
548
|
lst_final = []
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
549
|
+
with self._whitelist_lock:
|
550
|
+
try:
|
551
|
+
fn = self._get_allowed_file()
|
552
|
+
lst_allowed = []
|
553
|
+
if os.path.isfile(fn):
|
554
|
+
with open(fn, 'rt') as fh:
|
555
|
+
lst_allowed = fh.readlines()
|
556
|
+
else:
|
557
|
+
full_path = os.path.abspath(fn)
|
558
|
+
self.P("WARNING: no `{}` file found. Creating empty one.".format(full_path), verbosity=1)
|
559
|
+
with open(fn, 'wt') as fh:
|
560
|
+
fh.write('\n')
|
561
|
+
lst_allowed = [x.strip() for x in lst_allowed]
|
562
|
+
lst_allowed = [x for x in lst_allowed if x != '']
|
563
|
+
lst_lines = []
|
564
|
+
errors = False
|
565
|
+
for allowed_tuple in lst_allowed:
|
566
|
+
allowed = allowed_tuple.split()[0]
|
567
|
+
allowed = self._remove_prefix(allowed)
|
568
|
+
if not self.address_is_valid(allowed):
|
569
|
+
self.P("WARNING: address <{}> is not valid. Removing {} from allowed list.".format(
|
570
|
+
allowed, allowed_tuple), color='r'
|
571
|
+
)
|
572
|
+
errors = True
|
573
|
+
else:
|
574
|
+
lst_final.append(allowed)
|
575
|
+
lst_lines.append(allowed_tuple)
|
576
|
+
if errors:
|
577
|
+
with open(fn, 'wt') as fh:
|
578
|
+
for line in lst_lines:
|
579
|
+
fh.write("{}\n".format(line))
|
580
|
+
except Exception as exc:
|
581
|
+
self.P(f"ERROR: failed to load the allowed list of addresses: {exc}", color='r')
|
582
|
+
#endtry
|
583
|
+
#endwith
|
566
584
|
return lst_final
|
567
585
|
|
568
586
|
|
@@ -1296,4 +1314,4 @@ class BaseBlockEngine:
|
|
1296
1314
|
else:
|
1297
1315
|
self.P(f"dAuth URL is not invalid: {url}", color='r')
|
1298
1316
|
#end if url is valid
|
1299
|
-
return dct_env
|
1317
|
+
return dct_env
|
naeural_client/const/apps.py
CHANGED
@@ -10,6 +10,7 @@ class PLUGIN_SIGNATURES:
|
|
10
10
|
CHAIN_DIST_CUSTOM_JOB_01 = 'PROCESS_REAL_TIME_COLLECTED_DATA_CUSTOM_EXEC_CHAIN_DIST'
|
11
11
|
TELEGRAM_BASIC_BOT_01 = 'TELEGRAM_BASIC_BOT_01'
|
12
12
|
TELEGRAM_CONVERSATIONAL_BOT_01 = 'TELEGRAM_CONVERSATIONAL_BOT_01'
|
13
|
+
NET_CONFIG_MONITOR = 'NET_CONFIG_MONITOR'
|
13
14
|
# INSERT_NEW_PLUGIN_HERE
|
14
15
|
|
15
16
|
|
@@ -10,7 +10,7 @@ class MqttSession(GenericSession):
|
|
10
10
|
self._default_communicator = MQTTWrapper(
|
11
11
|
log=self.log,
|
12
12
|
config=self._config,
|
13
|
-
send_channel_name=comm_ct.
|
13
|
+
send_channel_name=comm_ct.COMMUNICATION_PAYLOADS_CHANNEL,
|
14
14
|
recv_channel_name=comm_ct.COMMUNICATION_PAYLOADS_CHANNEL,
|
15
15
|
comm_type=comm_ct.COMMUNICATION_DEFAULT,
|
16
16
|
recv_buff=self._payload_messages,
|
@@ -21,6 +21,7 @@ class MqttSession(GenericSession):
|
|
21
21
|
self._heartbeats_communicator = MQTTWrapper(
|
22
22
|
log=self.log,
|
23
23
|
config=self._config,
|
24
|
+
send_channel_name=comm_ct.COMMUNICATION_CONFIG_CHANNEL,
|
24
25
|
recv_channel_name=comm_ct.COMMUNICATION_CTRL_CHANNEL,
|
25
26
|
comm_type=comm_ct.COMMUNICATION_HEARTBEATS,
|
26
27
|
recv_buff=self._hb_messages,
|
@@ -37,6 +38,11 @@ class MqttSession(GenericSession):
|
|
37
38
|
connection_name=self.name,
|
38
39
|
verbosity=self._verbosity,
|
39
40
|
)
|
41
|
+
self.__communicators = {
|
42
|
+
'default': self._default_communicator,
|
43
|
+
'heartbeats': self._heartbeats_communicator,
|
44
|
+
'notifications': self._notifications_communicator,
|
45
|
+
}
|
40
46
|
return super(MqttSession, self).startup()
|
41
47
|
|
42
48
|
@property
|
@@ -64,9 +70,18 @@ class MqttSession(GenericSession):
|
|
64
70
|
self._notifications_communicator.release()
|
65
71
|
return
|
66
72
|
|
67
|
-
def
|
73
|
+
def _send_raw_message(self, to, msg, communicator='default'):
|
68
74
|
payload = json.dumps(msg)
|
75
|
+
communicator_obj = self.__communicators.get(communicator, self._default_communicator)
|
76
|
+
communicator_obj._send_to = to
|
77
|
+
communicator_obj.send(payload)
|
78
|
+
return
|
69
79
|
|
70
|
-
|
71
|
-
|
80
|
+
def _send_payload(self, payload):
|
81
|
+
# `to` parameter will be added after migrating to segregated payloads.
|
82
|
+
self._send_raw_message(to=None, msg=payload, communicator='default')
|
72
83
|
return
|
84
|
+
|
85
|
+
def _send_command(self, to, command):
|
86
|
+
self._send_raw_message(to, command, communicator='heartbeats')
|
87
|
+
return
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: naeural_client
|
3
|
-
Version: 2.6.
|
3
|
+
Version: 2.6.15
|
4
4
|
Summary: `naeural_client` is the Python SDK required for client app development for the Naeural Edge Protocol Edge Protocol framework
|
5
5
|
Project-URL: Homepage, https://github.com/NaeuralEdgeProtocol/naeural_client
|
6
6
|
Project-URL: Bug Tracker, https://github.com/NaeuralEdgeProtocol/naeural_client/issues
|
@@ -1,10 +1,10 @@
|
|
1
1
|
naeural_client/__init__.py,sha256=YimqgDbjLuywsf8zCWE0EaUXH4MBUrqLxt0TDV558hQ,632
|
2
|
-
naeural_client/_ver.py,sha256=
|
2
|
+
naeural_client/_ver.py,sha256=s5A-FwAfqI4BeZ8fzrRTwGs3LEc-m4EQ8BufoeG3kSI,331
|
3
3
|
naeural_client/base_decentra_object.py,sha256=C4iwZTkhKNBS4VHlJs5DfElRYLo4Q9l1V1DNVSk1fyQ,4412
|
4
4
|
naeural_client/plugins_manager_mixin.py,sha256=X1JdGLDz0gN1rPnTN_5mJXR8JmqoBFQISJXmPR9yvCo,11106
|
5
5
|
naeural_client/base/__init__.py,sha256=hACh83_cIv7-PwYMM3bQm2IBmNqiHw-3PAfDfAEKz9A,259
|
6
6
|
naeural_client/base/distributed_custom_code_presets.py,sha256=cvz5R88P6Z5V61Ce1vHVVh8bOkgXd6gve_vdESDNAsg,2544
|
7
|
-
naeural_client/base/generic_session.py,sha256=
|
7
|
+
naeural_client/base/generic_session.py,sha256=Vw08ywfW03aN0_5kmXOF5-VkRthl7FwAXqJu3M3NDMs,104275
|
8
8
|
naeural_client/base/instance.py,sha256=kcZJmjLBtx8Bjj_ysIOx1JmLA-qSpG7E28j5rq6IYus,20444
|
9
9
|
naeural_client/base/pipeline.py,sha256=b4uNHrEIOlAtw4PGUx20dxwBhDck5__SrVXaHcSi8ZA,58251
|
10
10
|
naeural_client/base/plugin_template.py,sha256=qGaXByd_JZFpjvH9GXNbT7KaitRxIJB6-1IhbKrZjq4,138123
|
@@ -14,7 +14,7 @@ naeural_client/base/webapp_pipeline.py,sha256=QmPLVmhP0CPdi0YuvbZEH4APYz2Amtw3gy
|
|
14
14
|
naeural_client/base/payload/__init__.py,sha256=y8fBI8tG2ObNfaXFWjyWZXwu878FRYj_I8GIbHT4GKE,29
|
15
15
|
naeural_client/base/payload/payload.py,sha256=x-au7l67Z_vfn_4R2C_pjZCaFuUVXHngJiGOfIAYVdE,2690
|
16
16
|
naeural_client/bc/__init__.py,sha256=FQj23D1PrY06NUOARiKQi4cdj0-VxnoYgYDEht8lpr8,158
|
17
|
-
naeural_client/bc/base.py,sha256=
|
17
|
+
naeural_client/bc/base.py,sha256=KC-wtymP9tEvXGG6wfiRirgshjW7_y58ylWjbe_lUWo,36160
|
18
18
|
naeural_client/bc/chain.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
19
|
naeural_client/bc/ec.py,sha256=qI8l7YqiS4MNftlx-tF7IZUswrSeQc7KMn5OZ0fEaJs,23370
|
20
20
|
naeural_client/certs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -31,7 +31,7 @@ naeural_client/comm/amqp_wrapper.py,sha256=hzj6ih07DnLQy2VSfA88giDIFHaCp9uSdGLTA
|
|
31
31
|
naeural_client/comm/mqtt_wrapper.py,sha256=Ig3bFZkCbWd4y_Whn2PPa91Z3aLgNbNPau6Tn5yLPZ8,16167
|
32
32
|
naeural_client/const/README.md,sha256=6OHesr-f5NBuuJGryEoi_TCu2XdlhfQYlDKx_IJoXeg,177
|
33
33
|
naeural_client/const/__init__.py,sha256=MM6Zib6i7M2qWcMkLtLx14zqU-lE-u2uPHjNvbh2jAM,478
|
34
|
-
naeural_client/const/apps.py,sha256=
|
34
|
+
naeural_client/const/apps.py,sha256=ePBiJXLuPfFOKuw-LJrT9OWbaodU7QApfDurIPNDoB4,655
|
35
35
|
naeural_client/const/base.py,sha256=Ld6WuQeqm5FbARL_-xs3gXxpa46ypksHimAk1g4qanw,4467
|
36
36
|
naeural_client/const/comms.py,sha256=La6JXWHexH8CfcBCKyT4fCIoeaoZlcm7KtZ57ab4ZgU,2201
|
37
37
|
naeural_client/const/environment.py,sha256=iytmTDgbOjvORPwHQmc0K0r-xJx7dnnzNnqAJJiFCDA,870
|
@@ -47,7 +47,7 @@ naeural_client/default/instance/net_mon_01_plugin.py,sha256=u85i2AiYHkLJnam0wOx-
|
|
47
47
|
naeural_client/default/instance/telegram_basic_bot_01_plugin.py,sha256=P_W2K_ng7svbhoIoYGvkGxa4v9UUoxuOAAgtoM36wDo,161
|
48
48
|
naeural_client/default/instance/telegram_conversational_bot_01_plugin.py,sha256=XkyE-uNbtFnTSGA1nOf-XNmUipAUjhg0xXV1glRb7gc,179
|
49
49
|
naeural_client/default/instance/view_scene_01_plugin.py,sha256=5kMhd23kL5AYCdOJzrdCqi2ohoQNvmpv8oE6hWQtUWk,720
|
50
|
-
naeural_client/default/session/mqtt_session.py,sha256=
|
50
|
+
naeural_client/default/session/mqtt_session.py,sha256=QdL0LPCqV3Fw0VSNgnsXWKJoxnkl17BtSYvEmhNU_zM,3079
|
51
51
|
naeural_client/io_formatter/__init__.py,sha256=_wy7c-Z9kgb26jN7uNTDq88G7xZ3wI_ObuQd3QWNPkQ,85
|
52
52
|
naeural_client/io_formatter/io_formatter_manager.py,sha256=MiZ70cGVD6hR99QiEk9wvJ_vADxpI-y2bTb0ITlMNI0,3451
|
53
53
|
naeural_client/io_formatter/base/__init__.py,sha256=VmLHY35NCRR46lgjhcrwtFxmJIVOjX2ADV9wOXt9CKA,41
|
@@ -81,8 +81,8 @@ naeural_client/utils/__init__.py,sha256=mAnke3-MeRzz3nhQvhuHqLnpaaCSmDxicd7Ck9uw
|
|
81
81
|
naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_LtMyCY,1072
|
82
82
|
naeural_client/utils/config.py,sha256=v7xHikr6Z5Sbvf3opYeMhYzGWD2pe0HlRwa-aGJzUh8,6323
|
83
83
|
naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
|
84
|
-
naeural_client-2.6.
|
85
|
-
naeural_client-2.6.
|
86
|
-
naeural_client-2.6.
|
87
|
-
naeural_client-2.6.
|
88
|
-
naeural_client-2.6.
|
84
|
+
naeural_client-2.6.15.dist-info/METADATA,sha256=F37VysVyxouaFh-B_tDEHDG_AFQMH03gNF0UbbanqKI,13176
|
85
|
+
naeural_client-2.6.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
86
|
+
naeural_client-2.6.15.dist-info/entry_points.txt,sha256=PNdyotDaQBAslZREx5luVyj0kqpQnwNACwkFNTPIHU4,55
|
87
|
+
naeural_client-2.6.15.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
|
88
|
+
naeural_client-2.6.15.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|