naeural-client 2.7.11__py3-none-any.whl → 2.7.12__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 +142 -19
- naeural_client/base/pipeline.py +31 -1
- naeural_client/cli/cli_commands.py +31 -21
- naeural_client/utils/config.py +67 -1
- {naeural_client-2.7.11.dist-info → naeural_client-2.7.12.dist-info}/METADATA +1 -1
- {naeural_client-2.7.11.dist-info → naeural_client-2.7.12.dist-info}/RECORD +10 -10
- {naeural_client-2.7.11.dist-info → naeural_client-2.7.12.dist-info}/WHEEL +0 -0
- {naeural_client-2.7.11.dist-info → naeural_client-2.7.12.dist-info}/entry_points.txt +0 -0
- {naeural_client-2.7.11.dist-info → naeural_client-2.7.12.dist-info}/licenses/LICENSE +0 -0
naeural_client/_ver.py
CHANGED
@@ -534,10 +534,12 @@ class GenericSession(BaseDecentrAIObject):
|
|
534
534
|
|
535
535
|
Parameters
|
536
536
|
----------
|
537
|
-
node_addr : str
|
538
|
-
The address of the edge node that will receive the message.
|
537
|
+
node_addr : str or list
|
538
|
+
The address or list of the edge node(s) that will receive the message.
|
539
|
+
|
539
540
|
payload : dict
|
540
541
|
The payload dict to be sent.
|
542
|
+
|
541
543
|
**kwargs : dict
|
542
544
|
Additional data to be sent to __prepare_message.
|
543
545
|
"""
|
@@ -557,10 +559,11 @@ class GenericSession(BaseDecentrAIObject):
|
|
557
559
|
Request the pipelines for a node from the net-config monitor plugin instance.
|
558
560
|
Parameters
|
559
561
|
----------
|
560
|
-
node_addr : str
|
561
|
-
The address of the edge node that sent the message.
|
562
|
+
node_addr : str or list
|
563
|
+
The address or list of the edge node(s) that sent the message.
|
562
564
|
|
563
565
|
"""
|
566
|
+
assert node_addr is not None, "Node address cannot be None"
|
564
567
|
payload = {
|
565
568
|
NET_CONFIG.NET_CONFIG_DATA: {
|
566
569
|
NET_CONFIG.OPERATION: NET_CONFIG.REQUEST_COMMAND,
|
@@ -570,12 +573,18 @@ class GenericSession(BaseDecentrAIObject):
|
|
570
573
|
additional_data = {
|
571
574
|
PAYLOAD_DATA.EE_PAYLOAD_PATH: [self.bc_engine.address, DEFAULT_PIPELINES.ADMIN_PIPELINE, PLUGIN_SIGNATURES.NET_CONFIG_MONITOR, None]
|
572
575
|
}
|
573
|
-
|
576
|
+
if isinstance(node_addr, str):
|
577
|
+
node_addr = [node_addr]
|
578
|
+
dest = [
|
579
|
+
f"<{x}> '{self.__dct_node_address_to_alias.get(x, None)}'" for x in node_addr
|
580
|
+
]
|
581
|
+
self.D(f"<NETCFG> Sending request to:\n{json.dumps(dest, indent=2)}", color='y')
|
574
582
|
self.send_encrypted_payload(
|
575
583
|
node_addr=node_addr, payload=payload,
|
576
584
|
additional_data=additional_data
|
577
585
|
)
|
578
|
-
|
586
|
+
for node in node_addr:
|
587
|
+
self._dct_netconfig_pipelines_requests[node] = tm()
|
579
588
|
return
|
580
589
|
|
581
590
|
def __track_allowed_node_by_netmon(self, node_addr, dict_msg):
|
@@ -590,6 +599,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
590
599
|
dict_msg : dict
|
591
600
|
The message received from the communication server as a heartbeat of the object from netconfig
|
592
601
|
"""
|
602
|
+
needs_netconfig = False
|
593
603
|
node_whitelist = dict_msg.get(PAYLOAD_DATA.NETMON_WHITELIST, [])
|
594
604
|
node_secured = dict_msg.get(PAYLOAD_DATA.NETMON_NODE_SECURED, False)
|
595
605
|
node_online = dict_msg.get(PAYLOAD_DATA.NETMON_STATUS_KEY) == PAYLOAD_DATA.NETMON_STATUS_ONLINE
|
@@ -610,7 +620,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
610
620
|
# only attempt to request pipelines if the node is online and if not recently requested
|
611
621
|
last_requested_by_netmon = self._dct_netconfig_pipelines_requests.get(node_addr, 0)
|
612
622
|
if tm() - last_requested_by_netmon > SDK_NETCONFIG_REQUEST_DELAY:
|
613
|
-
|
623
|
+
needs_netconfig = True
|
614
624
|
else:
|
615
625
|
self.D(f"Node <{node_addr}> is online but pipelines were recently requested", color='y')
|
616
626
|
else:
|
@@ -618,7 +628,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
618
628
|
# endif node seen for the first time
|
619
629
|
|
620
630
|
self._dct_can_send_to_node[node_addr] = can_send
|
621
|
-
return
|
631
|
+
return needs_netconfig
|
622
632
|
|
623
633
|
|
624
634
|
def __process_node_pipelines(self, node_addr, pipelines):
|
@@ -657,7 +667,6 @@ class GenericSession(BaseDecentrAIObject):
|
|
657
667
|
The name of the instance that sent the message.
|
658
668
|
"""
|
659
669
|
# extract relevant data from the message
|
660
|
-
self.D("<HB> Received hb from: {}".format(msg_node_addr), verbosity=2)
|
661
670
|
|
662
671
|
if dict_msg.get(HB.HEARTBEAT_VERSION) == HB.V2:
|
663
672
|
str_data = self.log.decompress_text(dict_msg[HB.ENCODED_DATA])
|
@@ -683,6 +692,10 @@ class GenericSession(BaseDecentrAIObject):
|
|
683
692
|
# as the protocol should NOT send a heartbeat with active configs to
|
684
693
|
# the entire network, only to the interested parties via net-config
|
685
694
|
|
695
|
+
self.D("<HB> Received {} with {} pipelines".format(
|
696
|
+
msg_node_addr, len(msg_active_configs)), verbosity=2
|
697
|
+
)
|
698
|
+
|
686
699
|
if len(msg_active_configs) > 0:
|
687
700
|
# this is for legacy and custom implementation where heartbeats still contain
|
688
701
|
# the pipeline configuration.
|
@@ -701,8 +714,6 @@ class GenericSession(BaseDecentrAIObject):
|
|
701
714
|
for transaction in open_transactions_copy:
|
702
715
|
transaction.handle_heartbeat(dict_msg)
|
703
716
|
|
704
|
-
self.D("<HB> Received hb from: {}".format(msg_node_addr), verbosity=2)
|
705
|
-
|
706
717
|
self.__track_allowed_node_by_hb(msg_node_addr, dict_msg)
|
707
718
|
|
708
719
|
# call the custom callback, if defined
|
@@ -789,7 +800,9 @@ class GenericSession(BaseDecentrAIObject):
|
|
789
800
|
self.__current_network_statuses[sender_addr] = current_network
|
790
801
|
online_addresses = []
|
791
802
|
all_addresses = []
|
803
|
+
lst_netconfig_request = []
|
792
804
|
for _ , node_data in current_network.items():
|
805
|
+
needs_netconfig = False
|
793
806
|
node_addr = node_data.get(PAYLOAD_DATA.NETMON_ADDRESS, None)
|
794
807
|
all_addresses.append(node_addr)
|
795
808
|
is_online = node_data.get(PAYLOAD_DATA.NETMON_STATUS_KEY) == PAYLOAD_DATA.NETMON_STATUS_ONLINE
|
@@ -800,11 +813,16 @@ class GenericSession(BaseDecentrAIObject):
|
|
800
813
|
online_addresses.append(node_addr)
|
801
814
|
# end if is_online
|
802
815
|
if node_addr is not None:
|
803
|
-
self.__track_allowed_node_by_netmon(node_addr, node_data)
|
816
|
+
needs_netconfig = self.__track_allowed_node_by_netmon(node_addr, node_data)
|
804
817
|
# end if node_addr
|
818
|
+
if needs_netconfig:
|
819
|
+
lst_netconfig_request.append(node_addr)
|
805
820
|
# end for each node in network map
|
821
|
+
if len(lst_netconfig_request) > 0:
|
822
|
+
self.__request_pipelines_from_net_config_monitor(lst_netconfig_request)
|
823
|
+
# end if needs netconfig
|
806
824
|
nr_peers = sum(self._dct_can_send_to_node.values())
|
807
|
-
self.P(f"Net
|
825
|
+
self.P(f"Net mon from <{sender_addr}> `{ee_id}`: {len(online_addresses)}/{len(all_addresses)}", color='y')
|
808
826
|
if nr_peers > 0 and not self.__at_least_one_node_peered:
|
809
827
|
self.__at_least_one_node_peered = True
|
810
828
|
self.P(
|
@@ -833,6 +851,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
833
851
|
short_sender_addr = sender_addr[:8] + '...' + sender_addr[-4:]
|
834
852
|
if self.client_address == sender_addr:
|
835
853
|
self.D("<NETCFG> Ignoring message from self", color='d')
|
854
|
+
return
|
836
855
|
receiver = dict_msg.get(PAYLOAD_DATA.EE_DESTINATION, None)
|
837
856
|
if not isinstance(receiver, list):
|
838
857
|
receiver = [receiver]
|
@@ -856,11 +875,11 @@ class GenericSession(BaseDecentrAIObject):
|
|
856
875
|
return
|
857
876
|
net_config_data = dict_msg.get(NET_CONFIG.NET_CONFIG_DATA, {})
|
858
877
|
received_pipelines = net_config_data.get('PIPELINES', [])
|
859
|
-
self.D(f"<NETCFG> Received {len(received_pipelines)} pipelines from <{sender_addr}>")
|
878
|
+
self.D(f"<NETCFG> Received {len(received_pipelines)} pipelines from <{sender_addr}> `{ee_id}`")
|
860
879
|
new_pipelines = self.__process_node_pipelines(sender_addr, received_pipelines)
|
861
880
|
pipeline_names = [x.name for x in new_pipelines]
|
862
881
|
if len(new_pipelines) > 0:
|
863
|
-
self.P(f'<NETCFG> Received NEW pipelines from <{sender_addr}
|
882
|
+
self.P(f'<NETCFG> Received NEW pipelines from <{sender_addr}> `{ee_id}`:{pipeline_names}', color='y')
|
864
883
|
return True
|
865
884
|
|
866
885
|
|
@@ -907,7 +926,7 @@ class GenericSession(BaseDecentrAIObject):
|
|
907
926
|
msg_signature=msg_signature,
|
908
927
|
sender_addr=msg_node_addr
|
909
928
|
)
|
910
|
-
|
929
|
+
|
911
930
|
self.__maybe_process_net_config(
|
912
931
|
dict_msg=dict_msg,
|
913
932
|
msg_pipeline=msg_pipeline,
|
@@ -1476,12 +1495,17 @@ class GenericSession(BaseDecentrAIObject):
|
|
1476
1495
|
----------
|
1477
1496
|
msg_data : dict
|
1478
1497
|
The message to send.
|
1498
|
+
|
1479
1499
|
encrypt_message : bool
|
1480
1500
|
If True, will encrypt the message.
|
1481
|
-
|
1482
|
-
|
1501
|
+
|
1502
|
+
destination : str or list, optional
|
1503
|
+
The destination address or list of addresses, by default None
|
1504
|
+
|
1483
1505
|
destination_id : str, optional
|
1484
1506
|
The destination id, by default None
|
1507
|
+
IMPORTANT: this will be deprecated soon in favor of the direct use of the address
|
1508
|
+
|
1485
1509
|
additional_data : dict, optional
|
1486
1510
|
Additional data to send, by default None
|
1487
1511
|
This has to be dict!
|
@@ -1500,10 +1524,13 @@ class GenericSession(BaseDecentrAIObject):
|
|
1500
1524
|
assert destination is not None, f"Unknown address for id: {destination_id}"
|
1501
1525
|
# endif only destination_id provided
|
1502
1526
|
|
1527
|
+
# TODO: apply self.__get_node_address on all destination addresses
|
1503
1528
|
# This part is duplicated with the creation of payloads
|
1504
1529
|
if encrypt_message and destination is not None:
|
1505
1530
|
str_data = json.dumps(msg_data)
|
1506
|
-
str_enc_data = self.bc_engine.encrypt(
|
1531
|
+
str_enc_data = self.bc_engine.encrypt(
|
1532
|
+
plaintext=str_data, receiver_address=destination
|
1533
|
+
)
|
1507
1534
|
msg_data = {
|
1508
1535
|
comm_ct.COMM_SEND_MESSAGE.K_EE_IS_ENCRYPTED: True,
|
1509
1536
|
comm_ct.COMM_SEND_MESSAGE.K_EE_ENCRYPTED_DATA: str_enc_data,
|
@@ -2249,6 +2276,102 @@ class GenericSession(BaseDecentrAIObject):
|
|
2249
2276
|
self.P("Node '{}' did not appear online in {:.1f}s.".format(node, tm() - _start), color='r')
|
2250
2277
|
return found
|
2251
2278
|
|
2279
|
+
def wait_for_node_configs(self, node, /, timeout=15, verbose=True, attempt_additional_requests=True):
|
2280
|
+
"""
|
2281
|
+
Wait for the node to have its configurations loaded.
|
2282
|
+
|
2283
|
+
Parameters
|
2284
|
+
----------
|
2285
|
+
node : str
|
2286
|
+
The address or name of the Naeural Edge Protocol edge node.
|
2287
|
+
timeout : int, optional
|
2288
|
+
The timeout, by default 15
|
2289
|
+
attempt_additional_requests : bool, optional
|
2290
|
+
If True, will attempt to send additional requests to the node to get the configurations, by default True
|
2291
|
+
|
2292
|
+
Returns
|
2293
|
+
-------
|
2294
|
+
bool
|
2295
|
+
True if the node has its configurations loaded, False otherwise.
|
2296
|
+
"""
|
2297
|
+
|
2298
|
+
if verbose:
|
2299
|
+
self.P("Waiting for node '{}' to have its configurations loaded...".format(node))
|
2300
|
+
|
2301
|
+
_start = tm()
|
2302
|
+
found = self.check_node_config_received(node)
|
2303
|
+
additional_request_sent = False
|
2304
|
+
request_time_thr = timeout / 2
|
2305
|
+
while (tm() - _start) < timeout and not found:
|
2306
|
+
sleep(0.1)
|
2307
|
+
found = self.check_node_config_received(node)
|
2308
|
+
if not found and not additional_request_sent and (tm() - _start) > request_time_thr and attempt_additional_requests:
|
2309
|
+
if verbose:
|
2310
|
+
self.P("Re-requesting configurations of node '{}'...".format(node), show=True)
|
2311
|
+
node_addr = self.__get_node_address(node)
|
2312
|
+
self.__request_pipelines_from_net_config_monitor(node_addr)
|
2313
|
+
additional_request_sent = True
|
2314
|
+
# end while
|
2315
|
+
|
2316
|
+
if verbose:
|
2317
|
+
if found:
|
2318
|
+
self.P(f"Received configurations of node '{node}'.")
|
2319
|
+
else:
|
2320
|
+
self.P(f"Node '{node}' did not send configs in {(tm() - _start)}. Client might not be authorized!", color='r')
|
2321
|
+
return found
|
2322
|
+
|
2323
|
+
def check_node_config_received(self, node):
|
2324
|
+
"""
|
2325
|
+
Check if the SDK received the configuration of the specified node.
|
2326
|
+
Parameters
|
2327
|
+
----------
|
2328
|
+
node : str
|
2329
|
+
The address or name of the Ratio1 edge node.
|
2330
|
+
|
2331
|
+
Returns
|
2332
|
+
-------
|
2333
|
+
bool
|
2334
|
+
True if the configuration of the node was received, False otherwise.
|
2335
|
+
"""
|
2336
|
+
node = self.__get_node_address(node)
|
2337
|
+
return node in self._dct_online_nodes_pipelines
|
2338
|
+
|
2339
|
+
def is_peered(self, node):
|
2340
|
+
"""
|
2341
|
+
Public method for checking if a node is peered with the current session.
|
2342
|
+
Parameters
|
2343
|
+
----------
|
2344
|
+
node : str
|
2345
|
+
The address or name of the Ratio1 edge node.
|
2346
|
+
|
2347
|
+
Returns
|
2348
|
+
-------
|
2349
|
+
bool
|
2350
|
+
True if the node is peered, False otherwise.
|
2351
|
+
"""
|
2352
|
+
node = self.__get_node_address(node)
|
2353
|
+
return self._dct_can_send_to_node.get(node, False)
|
2354
|
+
|
2355
|
+
def get_last_seen_time(self, node, *, default_value=0):
|
2356
|
+
"""
|
2357
|
+
Get the last time the node was seen.
|
2358
|
+
Parameters
|
2359
|
+
----------
|
2360
|
+
node : str
|
2361
|
+
The address or name of the Ratio1 edge node.
|
2362
|
+
|
2363
|
+
default_value : float, optional
|
2364
|
+
The default value to return if the node was not seen, by default 0.
|
2365
|
+
In case the user needs a specific default value, it can be provided here.
|
2366
|
+
|
2367
|
+
Returns
|
2368
|
+
-------
|
2369
|
+
float or type(default_value)
|
2370
|
+
The last time the node was seen.
|
2371
|
+
"""
|
2372
|
+
node = self.__get_node_address(node)
|
2373
|
+
return self._dct_node_last_seen_time.get(node, default_value)
|
2374
|
+
|
2252
2375
|
def check_node_online(self, node, /):
|
2253
2376
|
"""
|
2254
2377
|
Check if a node is online.
|
naeural_client/base/pipeline.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
# TODO: for custom plugin, do the plugin verification locally too
|
2
|
-
|
3
2
|
import os
|
4
3
|
from time import sleep, time
|
5
4
|
|
@@ -1562,3 +1561,34 @@ class Pipeline(BaseCodeChecker):
|
|
1562
1561
|
"""
|
1563
1562
|
return self.node_alias
|
1564
1563
|
|
1564
|
+
def get_full_config(self):
|
1565
|
+
"""
|
1566
|
+
Get the full configuration of the pipeline.
|
1567
|
+
Returns
|
1568
|
+
-------
|
1569
|
+
|
1570
|
+
"""
|
1571
|
+
dct_signature_instances = {}
|
1572
|
+
for instance in self.lst_plugin_instances:
|
1573
|
+
signature = instance.signature
|
1574
|
+
if signature not in dct_signature_instances:
|
1575
|
+
dct_signature_instances[signature] = []
|
1576
|
+
dct_signature_instances[signature].append(instance)
|
1577
|
+
# endfor instances
|
1578
|
+
return {
|
1579
|
+
'NAME': self.name,
|
1580
|
+
'PLUGINS': [
|
1581
|
+
{
|
1582
|
+
'SIGNATURE': signature,
|
1583
|
+
'INSTANCES': [
|
1584
|
+
{
|
1585
|
+
'INSTANCE_ID': instance.instance_id,
|
1586
|
+
**instance.config
|
1587
|
+
}
|
1588
|
+
for instance in instances
|
1589
|
+
]
|
1590
|
+
}
|
1591
|
+
for signature, instances in dct_signature_instances.items()
|
1592
|
+
],
|
1593
|
+
**self.config
|
1594
|
+
}
|
@@ -4,7 +4,8 @@ from naeural_client.cli.nodes import (
|
|
4
4
|
)
|
5
5
|
from naeural_client.cli.oracles import get_availability
|
6
6
|
from naeural_client.utils.config import (
|
7
|
-
show_config, reset_config, show_address, get_set_network
|
7
|
+
show_config, reset_config, show_address, get_set_network,
|
8
|
+
get_apps
|
8
9
|
)
|
9
10
|
|
10
11
|
# Define the available commands
|
@@ -13,31 +14,40 @@ CLI_COMMANDS = {
|
|
13
14
|
"nodes": {
|
14
15
|
"func": get_nodes,
|
15
16
|
"params": {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
### use "(flag)" at the end of the description to indicate a boolean flag
|
18
|
+
### otherwise it will be treated as a str parameter
|
19
|
+
"--all": "Get all known nodes including those that have been gone missing (flag)", # DONE
|
20
|
+
"--online" : "Get only online nodes as seen by a active supervisor (flag)", # DONE
|
21
|
+
"--peered": "Get only peered nodes - ie nodes that can be used by current client address (flag)", # DONE
|
22
|
+
"--supervisor" : "Use a specific supervisor node",
|
23
|
+
"--eth" : "Use a specific node (flag)",
|
24
|
+
"--wide" : "Display all available information (flag)",
|
24
25
|
}
|
25
26
|
},
|
26
27
|
"supervisors": {
|
27
28
|
"func": get_supervisors, # DONE
|
28
29
|
},
|
29
30
|
"avail": {
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
"func": get_availability,
|
32
|
+
"params": {
|
33
|
+
### use "(flag)" at the end of the description to indicate a boolean flag
|
34
|
+
### otherwise it will be treated as a str parameter
|
35
|
+
"node": "The ETH address of the node to be checked via the oracle network.",
|
36
|
+
"--start": "The start epoch number to check the availability from",
|
37
|
+
"--end": "The end epoch number to check the availability to",
|
38
|
+
"--json": "Enable full JSON oracle network output (flag)",
|
39
|
+
"--rounds": "The number of rounds to check the availability for testing purposes (default=1)",
|
39
40
|
}
|
40
|
-
|
41
|
+
},
|
42
|
+
"apps": {
|
43
|
+
"func": get_apps,
|
44
|
+
"description": "Get the apps running on a given node, if the client is allowed on that node.",
|
45
|
+
"params": {
|
46
|
+
"node": "The ETH address or the specific address of the node to get the apps from",
|
47
|
+
"--full": "Include admin apps (flag)",
|
48
|
+
"--json": "Output the entire JSON config of applications (flag)",
|
49
|
+
}
|
50
|
+
}
|
41
51
|
},
|
42
52
|
"config": {
|
43
53
|
"show": {
|
@@ -62,8 +72,8 @@ CLI_COMMANDS = {
|
|
62
72
|
"func": get_set_network, # DONE
|
63
73
|
"description": "Get/Set network",
|
64
74
|
"params": {
|
65
|
-
|
66
|
-
|
75
|
+
"--new": "The network to set either 'mainnet' or 'testnet' (same as --set)",
|
76
|
+
"--set": "The network to set either 'mainnet' or 'testnet' (same as --new)",
|
67
77
|
}
|
68
78
|
},
|
69
79
|
},
|
naeural_client/utils/config.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
import json
|
1
2
|
import os
|
2
3
|
from pathlib import Path
|
3
4
|
import shutil
|
5
|
+
from pandas import DataFrame
|
6
|
+
from datetime import datetime
|
4
7
|
|
5
8
|
from naeural_client.const.base import BCct, dAuth
|
6
9
|
from naeural_client._ver import __VER__ as version
|
@@ -210,7 +213,70 @@ def show_config(args):
|
|
210
213
|
else:
|
211
214
|
log_with_color(f"No configuration found at {config_file}. Please run `reset_config` first.", color="r")
|
212
215
|
return
|
213
|
-
|
216
|
+
|
217
|
+
def get_apps(args):
|
218
|
+
"""
|
219
|
+
Shows the apps running on a given node, if the client is allowed on that node.
|
220
|
+
Parameters
|
221
|
+
----------
|
222
|
+
args : argparse.Namespace
|
223
|
+
Arguments passed to the function.
|
224
|
+
|
225
|
+
"""
|
226
|
+
verbose = args.verbose
|
227
|
+
node = args.node
|
228
|
+
show_full = args.full
|
229
|
+
as_json = args.json
|
230
|
+
|
231
|
+
# 1. Init session
|
232
|
+
from naeural_client import Session
|
233
|
+
sess = Session(
|
234
|
+
silent=not verbose
|
235
|
+
)
|
236
|
+
|
237
|
+
# 2. Wait for node to appear online
|
238
|
+
found = sess.wait_for_node(node)
|
239
|
+
if not found:
|
240
|
+
sess.P(f'Node {node} not found. Please check the configuration.', color='r')
|
241
|
+
return
|
242
|
+
# 3. Check if the node is peered with the client
|
243
|
+
is_allowed = sess.is_peered(node)
|
244
|
+
if not is_allowed:
|
245
|
+
log_with_color(f"Node {node} is not peered with the client. Please check the configuration.", color='r')
|
246
|
+
return
|
247
|
+
# 4. Wait for node to send the configuration.
|
248
|
+
sess.wait_for_node_configs(node)
|
249
|
+
apps = sess.get_active_pipelines(node)
|
250
|
+
if apps is None:
|
251
|
+
log_with_color(f"No apps found on node {node}. Client might not be authorized", color='r')
|
252
|
+
return
|
253
|
+
# 5. Maybe exclude admin application.
|
254
|
+
if not show_full:
|
255
|
+
apps = {k: v for k, v in apps.items() if str(k).lower() != 'admin_pipeline'}
|
256
|
+
# 6. Show the apps
|
257
|
+
if as_json:
|
258
|
+
# Will print a big JSON with all the app configurations.
|
259
|
+
json_data = {k: v.get_full_config() for k, v in apps.items()}
|
260
|
+
log_with_color(json.dumps(json_data, indent=2))
|
261
|
+
else:
|
262
|
+
lst_plugin_instance_data = []
|
263
|
+
for pipeline_name, pipeline in apps.items():
|
264
|
+
for instance in pipeline.lst_plugin_instances:
|
265
|
+
lst_plugin_instance_data.append({
|
266
|
+
'APP': pipeline_name,
|
267
|
+
'PLUGIN': instance.signature,
|
268
|
+
'ID': instance.instance_id
|
269
|
+
})
|
270
|
+
# endfor instances in app
|
271
|
+
# endfor apps
|
272
|
+
apps_df = DataFrame(lst_plugin_instance_data)
|
273
|
+
last_seen = sess.get_last_seen_time(node)
|
274
|
+
is_online = sess.check_node_online(node)
|
275
|
+
node_status = 'Online' if is_online else 'Offline'
|
276
|
+
last_seen_str = datetime.fromtimestamp(last_seen).strftime('%Y-%m-%d %H:%M:%S') if last_seen else None
|
277
|
+
log_with_color(f"Apps on node {node} [{node_status}| Last seen: {last_seen_str}]:\n{apps_df}", color='b')
|
278
|
+
# endif show as json
|
279
|
+
return
|
214
280
|
|
215
281
|
def load_user_defined_config(verbose=False):
|
216
282
|
"""
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: naeural_client
|
3
|
-
Version: 2.7.
|
3
|
+
Version: 2.7.12
|
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,12 +1,12 @@
|
|
1
1
|
naeural_client/__init__.py,sha256=YimqgDbjLuywsf8zCWE0EaUXH4MBUrqLxt0TDV558hQ,632
|
2
|
-
naeural_client/_ver.py,sha256=
|
2
|
+
naeural_client/_ver.py,sha256=XaVx0xRv5cdZj5yGPVxa3mygYTmp5n5m2gKvAT_E_2E,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=7yHc3lEE8gZ3O2kGYMktg63fIOWKArgz1lqVeQf0L5w,114952
|
8
8
|
naeural_client/base/instance.py,sha256=kcZJmjLBtx8Bjj_ysIOx1JmLA-qSpG7E28j5rq6IYus,20444
|
9
|
-
naeural_client/base/pipeline.py,sha256=
|
9
|
+
naeural_client/base/pipeline.py,sha256=b4BJlqZ4vsGNqYPjJD9Uzrv5G8CVYG_jbND5rh_s8E0,59702
|
10
10
|
naeural_client/base/plugin_template.py,sha256=7YAFaND2iXoZLgtunjYkFf_TBGieFr3VdNLO3vCqzmM,138795
|
11
11
|
naeural_client/base/responses.py,sha256=ZKBZmRhYDv8M8mQ5C_ahGsQvtWH4b9ImRcuerQdZmNw,6937
|
12
12
|
naeural_client/base/transaction.py,sha256=bfs6td5M0fINgPQNxhrl_AUjb1YiilLDQ-Cd_o3OR_E,5146
|
@@ -22,7 +22,7 @@ naeural_client/certs/r9092118.ala.eu-central-1.emqxsl.com.crt,sha256=y-6io0tseyx
|
|
22
22
|
naeural_client/certs/s624dbd4.ala.us-east-1.emqxsl.com.crt,sha256=y-6io0tseyx9-a4Pmde1z1gPULtJNSYUpG_YFkYaMKU,1337
|
23
23
|
naeural_client/cli/README.md,sha256=WPdI_EjzAbUW1aPyj1sSR8rLydcJKZtoiaEtklQrjHo,74
|
24
24
|
naeural_client/cli/cli.py,sha256=EC7-ehOMQJ_Dq7R9TTrajpvQWwdalAOgb1JAeBGHF50,3830
|
25
|
-
naeural_client/cli/cli_commands.py,sha256=
|
25
|
+
naeural_client/cli/cli_commands.py,sha256=08nZOgdZU8wZsI8fVvzCppltZ3iVU62FvhB2yV90_kI,3679
|
26
26
|
naeural_client/cli/nodes.py,sha256=53-Ht42Xiq3rJEVA2ErZHLLC9OUjh6-rNGrc2RA-U8o,5733
|
27
27
|
naeural_client/cli/oracles.py,sha256=Y_PzHshfSERS_Utjjtw5d_BsQRdGr6P4L6uW8yTdA0M,4809
|
28
28
|
naeural_client/code_cheker/__init__.py,sha256=pwkdeZGVL16ZA4Qf2mRahEhoOvKhL7FyuQbMFLr1E5M,33
|
@@ -82,11 +82,11 @@ naeural_client/logging/tzlocal/win32.py,sha256=zBoj0vFVrGhnCm_f7xmYzGym4-fV-4Ij2
|
|
82
82
|
naeural_client/logging/tzlocal/windows_tz.py,sha256=Sv9okktjZJfRGGUOOppsvQuX_eXyXUxkSKCAFmWT9Hw,34203
|
83
83
|
naeural_client/utils/__init__.py,sha256=mAnke3-MeRzz3nhQvhuHqLnpaaCSmDxicd7Ck9uwpmI,77
|
84
84
|
naeural_client/utils/comm_utils.py,sha256=4cS9llRr_pK_3rNgDcRMCQwYPO0kcNU7AdWy_LtMyCY,1072
|
85
|
-
naeural_client/utils/config.py,sha256=
|
85
|
+
naeural_client/utils/config.py,sha256=43lhvYbn9-u78MvF2L9n07Q-nJ6IRGOdIBdTC3erlvM,9756
|
86
86
|
naeural_client/utils/dotenv.py,sha256=_AgSo35n7EnQv5yDyu7C7i0kHragLJoCGydHjvOkrYY,2008
|
87
87
|
naeural_client/utils/oracle_sync/oracle_tester.py,sha256=GmZwu2JM9_UB2K-4rKB3o0RgWLqM-7Im6HwBnQLXmHI,25312
|
88
|
-
naeural_client-2.7.
|
89
|
-
naeural_client-2.7.
|
90
|
-
naeural_client-2.7.
|
91
|
-
naeural_client-2.7.
|
92
|
-
naeural_client-2.7.
|
88
|
+
naeural_client-2.7.12.dist-info/METADATA,sha256=azpHwUgKaiOLDlMEFsdVWfDa84wzK42JsqIT8aR78y8,12354
|
89
|
+
naeural_client-2.7.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
90
|
+
naeural_client-2.7.12.dist-info/entry_points.txt,sha256=CTua17GUrRa4aXeafezGC9TiWKGKQzwTjQmB2jyj22g,91
|
91
|
+
naeural_client-2.7.12.dist-info/licenses/LICENSE,sha256=cvOsJVslde4oIaTCadabXnPqZmzcBO2f2zwXZRmJEbE,11311
|
92
|
+
naeural_client-2.7.12.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|