naeural-client 2.6.5__tar.gz → 2.6.7__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.
Files changed (142) hide show
  1. {naeural_client-2.6.5 → naeural_client-2.6.7}/PKG-INFO +1 -1
  2. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/_ver.py +1 -1
  3. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/generic_session.py +154 -19
  4. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/bc/base.py +27 -10
  5. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/cli/nodes.py +5 -0
  6. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/base.py +12 -9
  7. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/heartbeat.py +1 -0
  8. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/payload.py +4 -1
  9. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/base_logger.py +33 -26
  10. {naeural_client-2.6.5 → naeural_client-2.6.7}/pyproject.toml +1 -1
  11. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex01_part1_connect.py +10 -15
  12. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex01_part2_filter.py +2 -2
  13. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex01_part3_adv_filter.py +27 -21
  14. {naeural_client-2.6.5 → naeural_client-2.6.7}/.devcontainer/Dockerfile +0 -0
  15. {naeural_client-2.6.5 → naeural_client-2.6.7}/.devcontainer/devcontainer.json +0 -0
  16. {naeural_client-2.6.5 → naeural_client-2.6.7}/.gitattributes +0 -0
  17. {naeural_client-2.6.5 → naeural_client-2.6.7}/.github/workflows/python-publish.yml +0 -0
  18. {naeural_client-2.6.5 → naeural_client-2.6.7}/.gitignore +0 -0
  19. {naeural_client-2.6.5 → naeural_client-2.6.7}/.vscode/launch.json +0 -0
  20. {naeural_client-2.6.5 → naeural_client-2.6.7}/LICENSE +0 -0
  21. {naeural_client-2.6.5 → naeural_client-2.6.7}/README.md +0 -0
  22. {naeural_client-2.6.5 → naeural_client-2.6.7}/TODOs.md +0 -0
  23. {naeural_client-2.6.5 → naeural_client-2.6.7}/__init__.py +0 -0
  24. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/__init__.py +0 -0
  25. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/__init__.py +0 -0
  26. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/distributed_custom_code_presets.py +0 -0
  27. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/instance.py +0 -0
  28. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/payload/__init__.py +0 -0
  29. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/payload/payload.py +0 -0
  30. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/pipeline.py +0 -0
  31. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/plugin_template.py +0 -0
  32. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/responses.py +0 -0
  33. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/transaction.py +0 -0
  34. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base/webapp_pipeline.py +0 -0
  35. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/base_decentra_object.py +0 -0
  36. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/bc/__init__.py +0 -0
  37. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/bc/chain.py +0 -0
  38. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/bc/ec.py +0 -0
  39. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/certs/__init__.py +0 -0
  40. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/certs/r9092118.ala.eu-central-1.emqxsl.com.crt +0 -0
  41. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/cli/README.md +0 -0
  42. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/cli/cli.py +0 -0
  43. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/cli/cli_commands.py +0 -0
  44. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/code_cheker/__init__.py +0 -0
  45. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/code_cheker/base.py +0 -0
  46. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/code_cheker/checker.py +0 -0
  47. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/comm/__init__.py +0 -0
  48. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/comm/amqp_wrapper.py +0 -0
  49. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/comm/mqtt_wrapper.py +0 -0
  50. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/README.md +0 -0
  51. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/__init__.py +0 -0
  52. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/apps.py +0 -0
  53. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/comms.py +0 -0
  54. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/environment.py +0 -0
  55. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/formatter.py +0 -0
  56. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/const/misc.py +0 -0
  57. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/__init__.py +0 -0
  58. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/instance/__init__.py +0 -0
  59. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/instance/chain_dist_custom_job_01_plugin.py +0 -0
  60. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/instance/custom_webapi_01_plugin.py +0 -0
  61. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/instance/net_mon_01_plugin.py +0 -0
  62. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/instance/telegram_basic_bot_01_plugin.py +0 -0
  63. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/instance/telegram_conversational_bot_01_plugin.py +0 -0
  64. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/instance/view_scene_01_plugin.py +0 -0
  65. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/default/session/mqtt_session.py +0 -0
  66. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/io_formatter/__init__.py +0 -0
  67. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/io_formatter/base/__init__.py +0 -0
  68. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/io_formatter/base/base_formatter.py +0 -0
  69. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/io_formatter/default/__init__.py +0 -0
  70. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/io_formatter/default/a_dummy.py +0 -0
  71. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/io_formatter/default/aixp1.py +0 -0
  72. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/io_formatter/default/default.py +0 -0
  73. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/io_formatter/io_formatter_manager.py +0 -0
  74. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/__init__.py +0 -0
  75. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/__init__.py +0 -0
  76. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/class_instance_mixin.py +0 -0
  77. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/computer_vision_mixin.py +0 -0
  78. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/datetime_mixin.py +0 -0
  79. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/download_mixin.py +0 -0
  80. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/general_serialization_mixin.py +0 -0
  81. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/json_serialization_mixin.py +0 -0
  82. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/pickle_serialization_mixin.py +0 -0
  83. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/process_mixin.py +0 -0
  84. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/resource_size_mixin.py +0 -0
  85. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/timers_mixin.py +0 -0
  86. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/upload_mixin.py +0 -0
  87. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/logger_mixins/utils_mixin.py +0 -0
  88. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/small_logger.py +0 -0
  89. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/tzlocal/__init__.py +0 -0
  90. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/tzlocal/unix.py +0 -0
  91. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/tzlocal/utils.py +0 -0
  92. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/tzlocal/win32.py +0 -0
  93. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/logging/tzlocal/windows_tz.py +0 -0
  94. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/plugins_manager_mixin.py +0 -0
  95. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/utils/__init__.py +0 -0
  96. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/utils/comm_utils.py +0 -0
  97. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/utils/config.py +0 -0
  98. {naeural_client-2.6.5 → naeural_client-2.6.7}/naeural_client/utils/dotenv.py +0 -0
  99. {naeural_client-2.6.5 → naeural_client-2.6.7}/nepctl.MD +0 -0
  100. {naeural_client-2.6.5 → naeural_client-2.6.7}/requirements.txt +0 -0
  101. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/.example_env +0 -0
  102. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/8. custom_code_fastapi_assets/index.html +0 -0
  103. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/9. code_sandbox_from_scratch_assets/index.html +0 -0
  104. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/_example_pk_sdk.pem +0 -0
  105. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex02_first_deploy.py +0 -0
  106. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex03_custom_code_on_one_remote__example_1.py +0 -0
  107. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex04_custom_code_on_one_remote__example_2.py +0 -0
  108. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex05_custom_code_on_one_remote__example_3.py +0 -0
  109. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex06_custom_code_on_multiple_remotes__example_1.py +0 -0
  110. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex07_custom_code_on_multiple_remotes__example_2.py +0 -0
  111. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex08_custom_webapi.py +0 -0
  112. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex09_code_sandbox_from_scratch.py +0 -0
  113. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex10_telegram_echo_bot.py +0 -0
  114. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex11_telegram_blackjack_bot.py +0 -0
  115. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex12_telegram_smart_bot.py +0 -0
  116. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/ex13_launch_repo_based_webapp.py +0 -0
  117. {naeural_client-2.6.5 → naeural_client-2.6.7}/tutorials/video_presentation/1. hello_world.ipynb +0 -0
  118. {naeural_client-2.6.5 → naeural_client-2.6.7}/winrun.bat +0 -0
  119. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/.example_env +0 -0
  120. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/_archive/test.py +0 -0
  121. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/_tutorials/3. simple_real_time_custom_code.py +0 -0
  122. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/_tutorials/4. real_time_custom_code_2.py +0 -0
  123. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/_tutorials/8. chatbot.py +0 -0
  124. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/auth/t1.py +0 -0
  125. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/check_local_keys/check1.py +0 -0
  126. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/decentralized/chain_dist_example.py +0 -0
  127. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/decentralized/chain_dist_example_initiator.py +0 -0
  128. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/decentralized/chain_dist_example_worker.py +0 -0
  129. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/enc_dec/enc_dec_test.py +0 -0
  130. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/eth/eth_sign.py +0 -0
  131. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/eth/info.md +0 -0
  132. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/eth/sign.py +0 -0
  133. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/multi-enc-dec/multi_test1.py +0 -0
  134. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/multi-enc-dec/multi_test2.py +0 -0
  135. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/sign/test_sign1.py +0 -0
  136. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/utils/get_documentation.py +0 -0
  137. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/various/README.md +0 -0
  138. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/various/attach_example.py +0 -0
  139. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/various/ex1.py +0 -0
  140. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/various/hello.py +0 -0
  141. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/various/remote_exec.py +0 -0
  142. {naeural_client-2.6.5 → naeural_client-2.6.7}/xperimental/various/save_images.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: naeural_client
3
- Version: 2.6.5
3
+ Version: 2.6.7
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,4 +1,4 @@
1
- __VER__ = "2.6.5"
1
+ __VER__ = "2.6.7"
2
2
 
3
3
  if __name__ == "__main__":
4
4
  with open("pyproject.toml", "rt") as fd:
@@ -50,6 +50,10 @@ class GenericSession(BaseDecentrAIObject):
50
50
  A Session manages `Pipelines` and handles all messages received from the communication server.
51
51
  The Session handles all callbacks that are user-defined and passed as arguments in the API calls.
52
52
  """
53
+
54
+ START_TIMEOUT = 30
55
+
56
+
53
57
  default_config = {
54
58
  "CONFIG_CHANNEL": {
55
59
  "TOPIC": "{}/{}/config"
@@ -164,7 +168,14 @@ class GenericSession(BaseDecentrAIObject):
164
168
  root_topic : str, optional
165
169
  This is the root of the topics used by the SDK. It is used to create the topics for the communication channels.
166
170
  Defaults to "naeural"
171
+
172
+ auto_configuration : bool, optional
173
+ If True, the SDK will attempt to complete the dauth process automatically.
174
+ Defaults to True.
167
175
  """
176
+
177
+ self.__at_least_one_node_peered = False
178
+ self.__at_least_a_netmon_received = False
168
179
 
169
180
  # TODO: maybe read config from file?
170
181
  self._config = {**self.default_config, **config}
@@ -274,6 +285,7 @@ class GenericSession(BaseDecentrAIObject):
274
285
  dauth_endp=None, # get from consts or env
275
286
  add_env=self.__auto_configuration,
276
287
  debug=False,
288
+ sender_alias='ratio1-SDK'
277
289
  )
278
290
  # end bc_engine
279
291
  # END TODO
@@ -466,21 +478,59 @@ class GenericSession(BaseDecentrAIObject):
466
478
  self._dct_node_addr_name[node_addr] = node_id
467
479
  return
468
480
 
469
- def __track_allowed_node(self, node_addr, dict_msg):
481
+ def __track_allowed_node_by_hb(self, node_addr, dict_msg):
470
482
  """
471
- Track if this session is allowed to send messages to node.
483
+ Track if this session is allowed to send messages to node using hb data
472
484
 
473
485
  Parameters
474
486
  ----------
475
487
  node_addr : str
476
488
  The address of the Naeural Edge Protocol edge node that sent the message.
489
+
477
490
  dict_msg : dict
478
- The message received from the communication server.
491
+ The message received from the communication server as a heartbeat of the object from netconfig
479
492
  """
480
493
  node_whitelist = dict_msg.get(HB.EE_WHITELIST, [])
481
494
  node_secured = dict_msg.get(HB.SECURED, False)
495
+
496
+ client_is_allowed = self.bc_engine.contains_current_address(node_whitelist)
497
+
498
+ self._dct_can_send_to_node[node_addr] = not node_secured or client_is_allowed or self.bc_engine.address == node_addr
499
+ return
500
+
501
+ def __track_allowed_node_by_netmon(self, node_addr, dict_msg):
502
+ """
503
+ Track if this session is allowed to send messages to node using net-mon data
504
+
505
+ Parameters
506
+ ----------
507
+ node_addr : str
508
+ The address of the Naeural Edge Protocol edge node that sent the message.
509
+
510
+ dict_msg : dict
511
+ The message received from the communication server as a heartbeat of the object from netconfig
512
+ """
513
+ node_whitelist = dict_msg.get(PAYLOAD_DATA.NETMON_WHITELIST, [])
514
+ node_secured = dict_msg.get(PAYLOAD_DATA.NETMON_NODE_SECURED, False)
515
+
516
+ client_is_allowed = self.bc_engine.contains_current_address(node_whitelist)
482
517
 
483
- self._dct_can_send_to_node[node_addr] = not node_secured or self.bc_engine.address_no_prefix in node_whitelist or self.bc_engine.address == node_addr
518
+ self._dct_can_send_to_node[node_addr] = not node_secured or client_is_allowed or self.bc_engine.address == node_addr
519
+ return
520
+
521
+
522
+ def __process_node_pipelines(self, node_addr, pipelines):
523
+ """
524
+ Given a list of pipeline configurations, create or update the pipelines for a node.
525
+ """
526
+ for config in pipelines:
527
+ pipeline_name = config[PAYLOAD_DATA.NAME]
528
+ pipeline: Pipeline = self._dct_online_nodes_pipelines[node_addr].get(pipeline_name, None)
529
+ if pipeline is not None:
530
+ pipeline._sync_configuration_with_remote({k.upper(): v for k, v in config.items()})
531
+ else:
532
+ self._dct_online_nodes_pipelines[node_addr][pipeline_name] = self.__create_pipeline_from_config(
533
+ node_addr, config)
484
534
  return
485
535
 
486
536
  def __on_heartbeat(self, dict_msg: dict, msg_node_addr, msg_pipeline, msg_signature, msg_instance):
@@ -516,19 +566,20 @@ class GenericSession(BaseDecentrAIObject):
516
566
 
517
567
  msg_active_configs = dict_msg.get(HB.CONFIG_STREAMS)
518
568
  if msg_active_configs is None:
519
- return
569
+ msg_active_configs = []
570
+ # at this point we dont return if no active configs are present
571
+ # as the protocol should NOT send a heartbeat with active configs to
572
+ # the entire network, only to the interested parties via net-config
520
573
 
521
574
  # default action
522
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
523
577
  self._dct_online_nodes_pipelines[msg_node_addr] = {}
524
- for config in msg_active_configs:
525
- pipeline_name = config[PAYLOAD_DATA.NAME]
526
- pipeline: Pipeline = self._dct_online_nodes_pipelines[msg_node_addr].get(pipeline_name, None)
527
- if pipeline is not None:
528
- pipeline._sync_configuration_with_remote({k.upper(): v for k, v in config.items()})
529
- else:
530
- self._dct_online_nodes_pipelines[msg_node_addr][pipeline_name] = self.__create_pipeline_from_config(
531
- msg_node_addr, config)
578
+
579
+ if len(msg_active_configs) > 0:
580
+ # this is for legacy and custom implementation where heartbeats still contain
581
+ # the pipeline configuration.
582
+ self.__process_node_pipelines(msg_node_addr, msg_active_configs)
532
583
 
533
584
  # TODO: move this call in `__on_message_default_callback`
534
585
  if self.__maybe_ignore_message(msg_node_addr):
@@ -543,7 +594,7 @@ class GenericSession(BaseDecentrAIObject):
543
594
 
544
595
  self.D("Received hb from: {}".format(msg_node_addr), verbosity=2)
545
596
 
546
- self.__track_allowed_node(msg_node_addr, dict_msg)
597
+ self.__track_allowed_node_by_hb(msg_node_addr, dict_msg)
547
598
 
548
599
  # call the custom callback, if defined
549
600
  if self.custom_on_heartbeat is not None:
@@ -613,7 +664,8 @@ class GenericSession(BaseDecentrAIObject):
613
664
  self,
614
665
  dict_msg: dict,
615
666
  msg_pipeline : str,
616
- msg_signature : str
667
+ msg_signature : str,
668
+ sender_addr: str,
617
669
  ):
618
670
  REQUIRED_PIPELINE = DEFAULT_PIPELINES.ADMIN_PIPELINE
619
671
  REQUIRED_SIGNATURE = PLUGIN_SIGNATURES.NET_MON_01
@@ -624,6 +676,7 @@ class GenericSession(BaseDecentrAIObject):
624
676
  ee_id = dict_msg.get(PAYLOAD_DATA.EE_ID, None)
625
677
  current_network = dict_msg.get(PAYLOAD_DATA.NETMON_CURRENT_NETWORK, {})
626
678
  if current_network:
679
+ self.__at_least_a_netmon_received = True
627
680
  all_addresses = [
628
681
  x[PAYLOAD_DATA.NETMON_ADDRESS] for x in current_network.values()
629
682
  ]
@@ -633,10 +686,30 @@ class GenericSession(BaseDecentrAIObject):
633
686
  ]
634
687
  self.P(f"Net config from <{sender_addr}> `{ee_id}`: {len(online_addresses)}/{len(all_addresses)}", color='y')
635
688
  self.__current_network_statuses[sender_addr] = current_network
689
+
690
+ for _ , node_data in current_network.items():
691
+ node_addr = node_data.get("address", None)
692
+ if node_addr is not None:
693
+ self.__track_allowed_node_by_netmon(node_addr, node_data)
694
+ nr_peers = sum([v for k, v in self._dct_can_send_to_node.items()])
695
+ if nr_peers > 0 and not self.__at_least_one_node_peered:
696
+ self.__at_least_one_node_peered = True
697
+ self.P(f"Received {PLUGIN_SIGNATURES.NET_MON_01} from {sender_addr}, so far {nr_peers} peers that allow me: {json.dumps(self._dct_can_send_to_node, indent=2)}", color='g')
698
+ # end for each node in network map
636
699
  # end if current_network is valid
637
700
  # end if NET_MON_01
638
701
  return
639
702
 
703
+
704
+ def __maybe_process_net_config(
705
+ self,
706
+ dict_msg: dict,
707
+ msg_pipeline : str,
708
+ msg_signature : str,
709
+ sender_addr: str,
710
+ ):
711
+ return
712
+
640
713
 
641
714
  # TODO: maybe convert dict_msg to Payload object
642
715
  # also maybe strip the dict from useless info for the user of the sdk
@@ -656,12 +729,16 @@ class GenericSession(BaseDecentrAIObject):
656
729
  ----------
657
730
  dict_msg : dict
658
731
  The message received from the communication server
732
+
659
733
  msg_node_addr : str
660
734
  The address of the Naeural Edge Protocol edge node that sent the message.
735
+
661
736
  msg_pipeline : str
662
737
  The name of the pipeline that sent the message.
738
+
663
739
  msg_signature : str
664
740
  The signature of the plugin that sent the message.
741
+
665
742
  msg_instance : str
666
743
  The name of the instance that sent the message.
667
744
  """
@@ -671,7 +748,19 @@ class GenericSession(BaseDecentrAIObject):
671
748
  if self.__maybe_ignore_message(msg_node_addr):
672
749
  return
673
750
 
674
- self.__maybe_process_net_mon(dict_msg, msg_pipeline, msg_signature)
751
+ self.__maybe_process_net_mon(
752
+ dict_msg=dict_msg,
753
+ msg_pipeline=msg_pipeline,
754
+ msg_signature=msg_signature,
755
+ sender_addr=msg_node_addr
756
+ )
757
+
758
+ self.__maybe_process_net_config(
759
+ dict_msg=dict_msg,
760
+ msg_pipeline=msg_pipeline,
761
+ msg_signature=msg_signature,
762
+ sender_addr=msg_node_addr
763
+ )
675
764
 
676
765
  # call the pipeline and instance defined callbacks
677
766
  for pipeline in self.own_pipelines:
@@ -727,6 +816,8 @@ class GenericSession(BaseDecentrAIObject):
727
816
 
728
817
  self.__running_main_loop_thread = True
729
818
  self._main_loop_thread.start()
819
+
820
+ # we could wait here for `self.__at_least_one_node_peered` but is not a good idea
730
821
  return
731
822
 
732
823
  def __handle_open_transactions(self):
@@ -847,10 +938,16 @@ class GenericSession(BaseDecentrAIObject):
847
938
  This method runs on a separate thread from the main thread, and it is responsible for handling all messages received from the communication server.
848
939
  We use it like this to avoid blocking the main thread, which is used by the user.
849
940
  """
941
+ self.__start_main_loop_time = tm()
850
942
  while self.__running_main_loop_thread:
851
943
  self.__maybe_reconnect()
852
944
  self.__handle_open_transactions()
853
945
  sleep(0.1)
946
+ if not self.__at_least_a_netmon_received:
947
+ if (tm() - self.__start_main_loop_time) > self.START_TIMEOUT:
948
+ msg = "Timeout waiting for NET_MON_01 message. Exiting..."
949
+ self.P(msg, color='r', show=True)
950
+ break
854
951
  # end while self.running
855
952
 
856
953
  self.P("Main loop thread exiting...", verbosity=2)
@@ -900,7 +997,7 @@ class GenericSession(BaseDecentrAIObject):
900
997
 
901
998
  return
902
999
 
903
- def sleep(self, wait=True):
1000
+ def sleep(self, wait=True, close_session=True, close_pipelines=False):
904
1001
  """
905
1002
  Sleep for a given amount of time.
906
1003
 
@@ -926,7 +1023,37 @@ class GenericSession(BaseDecentrAIObject):
926
1023
  callable_loop_condition = callable(wait) and wait()
927
1024
  except KeyboardInterrupt:
928
1025
  self.P("CTRL+C detected. Stopping loop.", color='r', verbosity=1)
1026
+
1027
+ if close_session:
1028
+ self.close(close_pipelines, wait_close=True)
929
1029
  return
1030
+
1031
+ def wait(
1032
+ self,
1033
+ seconds=10,
1034
+ close_session_on_timeout=True,
1035
+ close_pipeline_on_timeout=False
1036
+ ):
1037
+ """
1038
+ Wait for a given amount of time.
1039
+
1040
+ Parameters
1041
+ ----------
1042
+ seconds : int, float, optional
1043
+ The amount of time to wait, by default 10
1044
+
1045
+ close_session_on_timeout : bool, optional
1046
+ If `True`, will close the session when the time is up, by default True
1047
+
1048
+ close_pipeline_on_timeout : bool, optional
1049
+ If `True`, will close the pipelines when the time is up, by default False
1050
+ """
1051
+ self.run(
1052
+ wait=seconds,
1053
+ close_session=close_session_on_timeout,
1054
+ close_pipelines=close_pipeline_on_timeout
1055
+ )
1056
+ return
930
1057
 
931
1058
  # Utils
932
1059
  if True:
@@ -2352,6 +2479,7 @@ class GenericSession(BaseDecentrAIObject):
2352
2479
  allowed_only=False,
2353
2480
  supervisor=None,
2354
2481
  df_only=False,
2482
+ debug=False,
2355
2483
  ):
2356
2484
  """
2357
2485
  This function will return a Pandas dataframe known nodes in the network based on
@@ -2400,10 +2528,11 @@ class GenericSession(BaseDecentrAIObject):
2400
2528
  'Address': PAYLOAD_DATA.NETMON_ADDRESS,
2401
2529
  'Alias' : PAYLOAD_DATA.NETMON_EEID,
2402
2530
  'Seen ago' : PAYLOAD_DATA.NETMON_LAST_SEEN,
2403
- 'Last state': PAYLOAD_DATA.NETMON_STATUS_KEY,
2531
+ 'Version' : PAYLOAD_DATA.NETMON_NODE_VERSION,
2532
+ 'State': PAYLOAD_DATA.NETMON_STATUS_KEY,
2404
2533
  'Last probe' : PAYLOAD_DATA.NETMON_LAST_REMOTE_TIME,
2405
2534
  'Zone' : PAYLOAD_DATA.NETMON_NODE_UTC,
2406
- 'Supervisor' : PAYLOAD_DATA.NETMON_IS_SUPERVISOR,
2535
+ 'Oracle' : PAYLOAD_DATA.NETMON_IS_SUPERVISOR,
2407
2536
  'Peered' : PAYLOAD_DATA.NETMON_WHITELIST,
2408
2537
  })
2409
2538
  reverse_mapping = {v: k for k, v in mapping.items()}
@@ -2441,6 +2570,7 @@ class GenericSession(BaseDecentrAIObject):
2441
2570
  # the following will get the whitelist for the current inspected node
2442
2571
  # without calling self.get_allowed_nodes but instead using the netmon data
2443
2572
  whitelist = node_info.get(PAYLOAD_DATA.NETMON_WHITELIST, [])
2573
+ version = node_info.get(PAYLOAD_DATA.NETMON_NODE_VERSION, '0.0.0')
2444
2574
  client_is_allowed = self.bc_engine.contains_current_address(whitelist)
2445
2575
  if allowed_only and not client_is_allowed:
2446
2576
  continue
@@ -2464,6 +2594,8 @@ class GenericSession(BaseDecentrAIObject):
2464
2594
  val = self.bc_engine._add_prefix(val)
2465
2595
  elif key == PAYLOAD_DATA.NETMON_WHITELIST:
2466
2596
  val = client_is_allowed
2597
+ elif key in [PAYLOAD_DATA.NETMON_STATUS_KEY, PAYLOAD_DATA.NETMON_NODE_VERSION]:
2598
+ val = val.split(' ')[0]
2467
2599
  res[column].append(val)
2468
2600
  # end for
2469
2601
  # end if
@@ -2475,6 +2607,9 @@ class GenericSession(BaseDecentrAIObject):
2475
2607
  SESSION_CT.NETSTATS_NR_SUPERVISORS : len(self.__current_network_statuses),
2476
2608
  SESSION_CT.NETSTATS_ELAPSED : elapsed,
2477
2609
  })
2610
+ if debug:
2611
+ self.P(f"Peering:\n{json.dumps(self._dct_can_send_to_node, indent=2)}", color='y')
2612
+ self.P(f"Used netmon data from {best_super} ({best_super_alias}):\n{json.dumps(best_info, indent=2)}", color='y')
2478
2613
  if df_only:
2479
2614
  return dct_result[SESSION_CT.NETSTATS_REPORT]
2480
2615
  return dct_result
@@ -16,7 +16,11 @@ from cryptography.hazmat.primitives import serialization
16
16
 
17
17
  from ..utils.config import get_user_folder
18
18
 
19
- from ..const.base import BCctbase, BCct, DAUTH_SUBKEY, DAUTH_URL
19
+ from ..const.base import (
20
+ BCctbase, BCct,
21
+ DAUTH_SUBKEY, DAUTH_URL, DAUTH_ENV_KEY,
22
+ DAUTH_NONCE, DAUTH_VARS,
23
+ )
20
24
 
21
25
 
22
26
 
@@ -1216,7 +1220,8 @@ class BaseBlockEngine:
1216
1220
  ### end Ethereum
1217
1221
 
1218
1222
 
1219
- def dauth_autocomplete(self, dauth_endp=None, add_env=True, debug=False, max_tries=5):
1223
+ def dauth_autocomplete(self, dauth_endp=None, add_env=True, debug=False, max_tries=5, **kwargs):
1224
+ MIN_LEN = 10
1220
1225
  dct_env = {}
1221
1226
  dct_result = {}
1222
1227
  done = False
@@ -1224,25 +1229,34 @@ class BaseBlockEngine:
1224
1229
  in_env = False
1225
1230
  url = dauth_endp
1226
1231
 
1227
- if url is None:
1232
+ if not isinstance(url, str) or len(url) < MIN_LEN:
1228
1233
  if isinstance(DAUTH_URL, str) and len(DAUTH_URL) > 0:
1229
1234
  url = DAUTH_URL
1230
- else:
1231
- url = os.environ.get('DAUTH_URL')
1235
+
1236
+ if DAUTH_ENV_KEY in os.environ:
1232
1237
  in_env = True
1238
+ url = os.environ[DAUTH_ENV_KEY]
1233
1239
 
1234
1240
  if isinstance(url, str) and len(url) > 0:
1235
1241
  if dauth_endp is None:
1236
- self.P("Found dAuth URL in environment: '{}'".format(url), color='g')
1242
+ if in_env:
1243
+ self.P("Found dAuth URL in environment: '{}'".format(url), color='g')
1244
+ else:
1245
+ self.P("Using default dAuth URL: '{}'".format(url), color='g')
1237
1246
 
1238
1247
  while not done:
1239
1248
  self.P(f"Trying dAuth `{url}` information... (try {tries})")
1240
1249
  try:
1241
- nonce_data = {
1242
- 'nonce' : str(uuid.uuid4())[:8]
1250
+ to_send = {
1251
+ **kwargs,
1252
+ DAUTH_NONCE : str(uuid.uuid4())[:8],
1243
1253
  }
1244
- self.sign(nonce_data)
1245
- response = requests.post(url, json={'body' : nonce_data})
1254
+ ######
1255
+ if len(kwargs) == 0:
1256
+ to_send['sender_alias'] = 'direct-call'
1257
+ ######
1258
+ self.sign(to_send)
1259
+ response = requests.post(url, json={'body' : to_send})
1246
1260
  if response.status_code == 200:
1247
1261
  dct_response = response.json()
1248
1262
  if debug:
@@ -1275,4 +1289,7 @@ class BaseBlockEngine:
1275
1289
  if tries >= max_tries:
1276
1290
  done = True
1277
1291
  #end while
1292
+ else:
1293
+ self.P(f"dAuth URL is not invalid: {url}", color='r')
1294
+ #end if url is valid
1278
1295
  return dct_env
@@ -49,6 +49,9 @@ def get_nodes(args):
49
49
  supervisor=supervisor_addr,
50
50
  )
51
51
  df, supervisor, super_alias, nr_supers, elapsed = res
52
+ if args.online:
53
+ FILTERED = ['State']
54
+ df = df[[c for c in df.columns if c not in FILTERED]]
52
55
 
53
56
  prefix = "Online n" if (args.online or args.peered) else "N"
54
57
  if supervisor == "ERROR":
@@ -72,6 +75,8 @@ def get_supervisors(args):
72
75
  supervisors_only=True,
73
76
  )
74
77
  df, supervisor, super_alias, nr_supers, elapsed = res
78
+ FILTERED = ['Oracle', 'State']
79
+ df = df[[c for c in df.columns if c not in FILTERED]]
75
80
 
76
81
  if supervisor == "ERROR":
77
82
  log_with_color(f"No supervisors or no comms available in {elapsed:.1f}s. Please check your settings.", color='r')
@@ -1,24 +1,27 @@
1
1
  EE_ID = 'EE_ID'
2
2
  SB_ID = 'SB_ID' # change to SB_ID = EE_ID post mod from sb to ee
3
3
 
4
+ class BCctbase:
5
+ SIGN = 'EE_SIGN'
6
+ SENDER = 'EE_SENDER'
7
+ HASH = 'EE_HASH'
8
+
9
+ ETH_SIGN = 'EE_ETH_SIGN'
10
+ ETH_SENDER= 'EE_ETH_SENDER'
11
+
4
12
 
5
13
  DAUTH_URL = 'https://dauth.ratio1.ai/get_auth_data'
6
14
  DAUTH_SUBKEY = 'auth'
15
+ DAUTH_ENV_KEY = 'DAUTH_URL'
16
+ DAUTH_NONCE = 'nonce'
17
+ DAUTH_VARS = [DAUTH_NONCE, BCctbase.SIGN, BCctbase.SENDER, BCctbase.HASH]
18
+
7
19
 
8
20
  class LocalInfo:
9
21
  LOCAL_INFO_FILE = 'local_info.json'
10
22
  K_ADDRESS = 'address'
11
23
  K_ALIAS = 'alias'
12
24
  K_ETH_ADDRESS = 'eth_address'
13
-
14
-
15
- class BCctbase:
16
- SIGN = 'EE_SIGN'
17
- SENDER = 'EE_SENDER'
18
- HASH = 'EE_HASH'
19
-
20
- ETH_SIGN = 'EE_ETH_SIGN'
21
- ETH_SENDER= 'EE_ETH_SENDER'
22
25
 
23
26
 
24
27
  class BCct:
@@ -23,6 +23,7 @@ EE_ADDR = 'EE_ADDR'
23
23
  EE_WHITELIST = 'EE_WHITELIST'
24
24
  EE_IS_SUPER = 'EE_IS_SUPER'
25
25
  EE_FORMATTER = 'EE_FORMATTER'
26
+ EE_ID = 'EE_ID'
26
27
 
27
28
  SECURED = 'SECURED'
28
29
 
@@ -205,6 +205,8 @@ class PAYLOAD_DATA:
205
205
  NETMON_LAST_SEEN = 'last_seen_sec'
206
206
  NETMON_IS_SUPERVISOR = 'is_supervisor'
207
207
  NETMON_WHITELIST = 'whitelist'
208
+ NETMON_NODE_SECURED = 'secured'
209
+ NETMON_NODE_VERSION = 'version'
208
210
 
209
211
 
210
212
  class NET_CONFIG:
@@ -212,4 +214,5 @@ class NET_CONFIG:
212
214
  REQUEST_COMMAND = "GET_CONFIG"
213
215
  NET_CONFIG_DATA = 'NET_CONFIG_DATA'
214
216
  OPERATION = 'OP'
215
- DESTINATION = 'DEST'
217
+ DESTINATION = 'DEST'
218
+ DATA = 'DATA'
@@ -91,6 +91,7 @@ class BaseLogger(object):
91
91
  if os.name == 'nt':
92
92
  os.system('color')
93
93
  self.__lib__ = lib_name
94
+ self.__folder_setup_done = False
94
95
  self.append_spaces = append_spaces
95
96
  self.show_time = show_time
96
97
  self.no_folders_no_save = no_folders_no_save
@@ -1112,35 +1113,41 @@ class BaseLogger(object):
1112
1113
  BaseLogger.print_color(" Config modified with following env vars: {}".format(matches))
1113
1114
  else:
1114
1115
  BaseLogger.print_color(" No secrets/template found in config")
1116
+
1117
+ if not self.__folder_setup_done:
1118
+ # if not already done lets setup de folders
1119
+ self._base_folder = self.expand_tilda(self._base_folder)
1120
+ self._base_folder = self._get_cloud_base_folder(self._base_folder)
1121
+ self._root_folder = os.path.abspath(self._base_folder)
1122
+ self._base_folder = os.path.join(self._base_folder, self._app_folder)
1123
+
1124
+ if not self.silent:
1125
+ BaseLogger.print_color("BASE: {}".format(self._base_folder))
1115
1126
 
1116
- self._base_folder = self.expand_tilda(self._base_folder)
1117
- self._base_folder = self._get_cloud_base_folder(self._base_folder)
1118
- self._root_folder = os.path.abspath(self._base_folder)
1119
- self._base_folder = os.path.join(self._base_folder, self._app_folder)
1120
- if not self.silent:
1121
- BaseLogger.print_color("BASE: {}".format(self._base_folder))
1122
-
1123
- self._normalize_path_sep()
1124
-
1125
- if not os.path.isdir(self._base_folder):
1126
- BaseLogger.print_color(
1127
- f"WARNING! Invalid app base folder '{self._base_folder}'! We create it automatically!",
1128
- color='r'
1129
- )
1130
- #endif
1131
-
1132
- self._logs_dir = os.path.join(self._base_folder, self.get_logs_dir_name())
1133
- self._outp_dir = os.path.join(self._base_folder, self.get_output_dir_name())
1134
- self._data_dir = os.path.join(self._base_folder, self.get_data_dir_name())
1135
- self._modl_dir = os.path.join(self._base_folder, self.get_models_dir_name())
1127
+ self._normalize_path_sep()
1136
1128
 
1137
- self._setup_folders([
1138
- self._outp_dir,
1139
- self._logs_dir,
1140
- self._data_dir,
1141
- self._modl_dir
1142
- ])
1129
+ if not os.path.isdir(self._base_folder):
1130
+ BaseLogger.print_color(
1131
+ f"WARNING! Invalid app base folder '{self._base_folder}'! We create it automatically!",
1132
+ color='r'
1133
+ )
1134
+ #endif
1143
1135
 
1136
+ self._logs_dir = os.path.join(self._base_folder, self.get_logs_dir_name())
1137
+ self._outp_dir = os.path.join(self._base_folder, self.get_output_dir_name())
1138
+ self._data_dir = os.path.join(self._base_folder, self.get_data_dir_name())
1139
+ self._modl_dir = os.path.join(self._base_folder, self.get_models_dir_name())
1140
+
1141
+ self._setup_folders([
1142
+ self._outp_dir,
1143
+ self._logs_dir,
1144
+ self._data_dir,
1145
+ self._modl_dir
1146
+ ])
1147
+ self.__folder_setup_done = True
1148
+ else:
1149
+ BaseLogger.print_color("Folders already configured.", color='y')
1150
+ #endif apply only first time
1144
1151
  return
1145
1152
 
1146
1153
  @staticmethod
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "naeural_client"
7
- version = "2.6.5"
7
+ version = "2.6.7"
8
8
  authors = [
9
9
  { name="Andrei Ionut Damian", email="andrei.damian@me.com" },
10
10
  { name="Cristan Bleotiu", email="cristibleotiu@gmail.com" },
@@ -18,7 +18,7 @@ IMPORTANT: Session will WAIT until network map is clarified.
18
18
  """
19
19
  import json
20
20
 
21
- from naeural_client import Session, Payload, PAYLOAD_DATA
21
+ from naeural_client import Session, Payload, PAYLOAD_DATA, HEARTBEAT_DATA
22
22
 
23
23
 
24
24
  class MessageHandler:
@@ -43,11 +43,10 @@ class MessageHandler:
43
43
  heartbeat : dict
44
44
  The heartbeat received from the edge node.
45
45
  """
46
- session.P("{} ({}) has a {}".format(
47
- heartbeat[PAYLOAD_DATA.EE_ID],
48
- self.shorten_address(node_addr),
49
- heartbeat["CPU"])
50
- )
46
+ node_alias = heartbeat[PAYLOAD_DATA.EE_ID]
47
+ short_addr = self.shorten_address(node_addr)
48
+ cpu = heartbeat[HEARTBEAT_DATA.CPU]
49
+ session.P(f"{node_alias} <{short_addr}> has a {cpu}", color='magenta')
51
50
  return
52
51
 
53
52
 
@@ -62,17 +61,13 @@ if __name__ == '__main__':
62
61
  on_heartbeat=filterer.on_heartbeat,
63
62
  )
64
63
 
65
- session.P("Client address is: {}".format(session.get_client_address()), color='g')
64
+ session.P("Client address is: {}".format(session.get_client_address()), color='m')
66
65
 
67
66
  # lets see top 5 online nodes
68
67
  netinfo = session.get_network_known_nodes(online_only=True)
69
68
  session.P(f"Online nodes reported by {netinfo.reporter}:\n{netinfo.report}")
70
69
 
71
- # Observation:
72
- # next code is not mandatory - it is used to keep the session open and cleanup the resources
73
- # in production, you would not need this code as the script can close after the pipeline will be sent
74
- session.run(
75
- wait=30, # wait for the user to stop the execution or a given time
76
- close_pipelines=True # when the user stops the execution, the remote edge-node pipelines will be closed
77
- )
78
- session.P("Main thread exiting...")
70
+ session.sleep(10) # wait for 10 seconds
71
+ session.P("Closing session...", color='m')
72
+ session.close()
73
+ session.P("Main thread exiting...", color='m')
@@ -128,7 +128,7 @@ if __name__ == '__main__':
128
128
  )
129
129
 
130
130
  # lets see top 5 online nodes
131
- netinfo = session.get_network_known_nodes(online_only=True)
131
+ netinfo = session.get_network_known_nodes(online_only=True, debug=True)
132
132
  session.P(f"Online nodes reported by {netinfo.reporter}:\n{netinfo.report}")
133
133
 
134
134
 
@@ -136,7 +136,7 @@ if __name__ == '__main__':
136
136
  # next code is not mandatory - it is used to keep the session open and cleanup the resources
137
137
  # in production, you would not need this code as the script can close after the pipeline will be sent
138
138
  session.run(
139
- wait=30, # wait for the user to stop the execution or a given time
139
+ wait=15, # wait for the user to stop the execution or a given time
140
140
  close_pipelines=True # when the user stops the execution, the remote edge-node pipelines will be closed
141
141
  )
142
142
  session.P("Main thread exiting...")