cgse-core 0.17.2__tar.gz → 0.17.3__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 (64) hide show
  1. {cgse_core-0.17.2 → cgse_core-0.17.3}/PKG-INFO +1 -1
  2. {cgse_core-0.17.2 → cgse_core-0.17.3}/pyproject.toml +1 -1
  3. cgse_core-0.17.3/src/egse/connect.py +55 -0
  4. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/dummy.py +3 -19
  5. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/logger/__init__.py +2 -2
  6. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/notifyhub/server.py +1 -3
  7. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/registry/client.py +3 -9
  8. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/registry/server.py +3 -11
  9. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/registry/service.py +5 -11
  10. cgse_core-0.17.2/src/egse/async_control.py +0 -1085
  11. cgse_core-0.17.2/src/egse/async_control_claude.py +0 -807
  12. cgse_core-0.17.2/src/egse/confman/confman_acs.py +0 -35
  13. cgse_core-0.17.2/src/egse/connect.py +0 -528
  14. cgse_core-0.17.2/src/egse/metricshub/__init__.py +0 -0
  15. cgse_core-0.17.2/src/egse/metricshub/server.py +0 -271
  16. cgse_core-0.17.2/src/egse/notifyhub/test.py +0 -303
  17. {cgse_core-0.17.2 → cgse_core-0.17.3}/.gitignore +0 -0
  18. {cgse_core-0.17.2 → cgse_core-0.17.3}/README.md +0 -0
  19. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/cgse_core/__init__.py +0 -0
  20. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/cgse_core/_start.py +0 -0
  21. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/cgse_core/_status.py +0 -0
  22. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/cgse_core/_stop.py +0 -0
  23. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/cgse_core/cgse_explore.py +0 -0
  24. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/cgse_core/services.py +0 -0
  25. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/cgse_core/settings.yaml +0 -0
  26. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/_setup_core.py +0 -0
  27. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/command.py +0 -0
  28. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/confman/__init__.py +0 -0
  29. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/confman/__main__.py +0 -0
  30. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/confman/confman.yaml +0 -0
  31. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/confman/confman_cs.py +0 -0
  32. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/control.py +0 -0
  33. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/icons/busy.svg +0 -0
  34. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/icons/operational-mode.svg +0 -0
  35. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/icons/pm_ui.svg +0 -0
  36. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/icons/simulator-mode.svg +0 -0
  37. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/icons/start-process-button.svg +0 -0
  38. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/icons/stop-process-button.svg +0 -0
  39. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/icons/user-interface.svg +0 -0
  40. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/listener.py +0 -0
  41. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/logger/__main__.py +0 -0
  42. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/logger/log_cs.py +0 -0
  43. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/mixin.py +0 -0
  44. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/monitoring.py +0 -0
  45. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/notifyhub/__init__.py +0 -0
  46. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/notifyhub/client.py +0 -0
  47. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/notifyhub/event.py +0 -0
  48. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/notifyhub/services.py +0 -0
  49. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/procman/__init__.py +0 -0
  50. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/procman/procman.yaml +0 -0
  51. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/procman/procman_cs.py +0 -0
  52. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/procman/procman_protocol.py +0 -0
  53. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/procman/procman_ui.py +0 -0
  54. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/protocol.py +0 -0
  55. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/proxy.py +0 -0
  56. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/registry/__init__.py +0 -0
  57. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/registry/backend.py +0 -0
  58. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/services.py +0 -0
  59. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/services.yaml +0 -0
  60. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/storage/__init__.py +0 -0
  61. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/storage/__main__.py +0 -0
  62. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/storage/persistence.py +0 -0
  63. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/storage/storage.yaml +0 -0
  64. {cgse_core-0.17.2 → cgse_core-0.17.3}/src/egse/storage/storage_cs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cgse-core
3
- Version: 0.17.2
3
+ Version: 0.17.3
4
4
  Summary: Core services for the CGSE framework
5
5
  Author: IvS KU Leuven
6
6
  Maintainer-email: Rik Huygen <rik.huygen@kuleuven.be>, Sara Regibo <sara.regibo@kuleuven.be>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "cgse-core"
3
- version = "0.17.2"
3
+ version = "0.17.3"
4
4
  description = "Core services for the CGSE framework"
5
5
  authors = [
6
6
  {name = "IvS KU Leuven"}
@@ -0,0 +1,55 @@
1
+ from egse.env import bool_env
2
+ from egse.log import logging
3
+ from egse.zmq_ser import connect_address
4
+
5
+ logger = logging.getLogger("egse.connect")
6
+
7
+ # random.seed(time.monotonic()) # uncomment for testing only, main application should set a seed.
8
+
9
+ VERBOSE_DEBUG = bool_env("VERBOSE_DEBUG")
10
+
11
+
12
+ def get_endpoint(
13
+ service_type: str,
14
+ protocol: str = "tcp",
15
+ hostname: str = "localhost",
16
+ port: int = 0,
17
+ ):
18
+ """
19
+ Returns the endpoint for a service, either from the registry or by constructing
20
+ it from protocol, hostname and port.
21
+
22
+ If port is 0 (the default), attempt to retrieve the endpoint from the service registry.
23
+
24
+ Args:
25
+ service_type: The service type to look up in the registry.
26
+ protocol: Protocol to use if constructing the endpoint, defaults to tcp.
27
+ hostname: Hostname to use if constructing the endpoint, defaults to localhost.
28
+ port: Port to use if constructing the endpoint, defaults to 0.
29
+
30
+ Returns:
31
+ The endpoint string.
32
+
33
+ Raises:
34
+ RuntimeError: If no endpoint can be determined.
35
+ """
36
+ endpoint = None
37
+ from egse.registry.client import RegistryClient
38
+
39
+ if port == 0:
40
+ with RegistryClient() as reg:
41
+ endpoint = reg.get_endpoint(service_type)
42
+ if endpoint:
43
+ if VERBOSE_DEBUG:
44
+ logger.debug(f"Endpoint for {service_type} found in registry: {endpoint}")
45
+ else:
46
+ logger.warning(f"No endpoint for {service_type} found in registry.")
47
+
48
+ if not endpoint:
49
+ if port == 0:
50
+ raise RuntimeError(f"No service registered as {service_type} and no port provided.")
51
+ endpoint = connect_address(protocol, hostname, port)
52
+ if VERBOSE_DEBUG:
53
+ logger.debug(f"Endpoint constructed from protocol/hostname/port: {endpoint}")
54
+
55
+ return endpoint
@@ -35,7 +35,6 @@ and stopped with:
35
35
 
36
36
  from __future__ import annotations
37
37
 
38
- import contextlib
39
38
  import multiprocessing
40
39
  import random
41
40
  import select
@@ -53,14 +52,12 @@ from egse.device import DeviceConnectionError
53
52
  from egse.device import DeviceConnectionInterface
54
53
  from egse.device import DeviceTimeoutError
55
54
  from egse.device import DeviceTransport
56
- from egse.env import bool_env
57
55
  from egse.log import logger
58
56
  from egse.protocol import CommandProtocol
59
57
  from egse.proxy import Proxy
60
58
  from egse.system import SignalCatcher
61
59
  from egse.system import attrdict
62
60
  from egse.system import format_datetime
63
- from egse.system import type_name
64
61
  from egse.zmq_ser import bind_address
65
62
  from egse.zmq_ser import connect_address
66
63
 
@@ -80,9 +77,6 @@ WRITE_TIMEOUT = 1.0
80
77
  CONNECT_TIMEOUT = 3.0
81
78
  """The maximum time in seconds to wait for establishing a socket connect."""
82
79
 
83
-
84
- VERBOSE_DEBUG = bool_env("VERBOSE_DEBUG", default=False)
85
-
86
80
  # Especially DummyCommand and DummyController need to be defined in a known module
87
81
  # because those objects are pickled and when de-pickled at the clients side the class
88
82
  # definition must be known.
@@ -122,17 +116,14 @@ def is_dummy_cs_active() -> bool:
122
116
 
123
117
 
124
118
  def is_dummy_dev_active() -> bool:
125
- if VERBOSE_DEBUG:
126
- logger.debug("Checking if dummy device is active...")
127
119
  try:
128
120
  dev = DummyDeviceEthernetInterface(DEV_HOST, DEV_PORT)
129
121
  dev.connect()
130
122
  rc = dev.trans("ping\n")
131
123
  dev.disconnect()
132
124
  return rc.decode().strip() == "pong"
133
- except (DeviceConnectionError, ConnectionResetError, DeviceTimeoutError) as exc:
134
- if VERBOSE_DEBUG:
135
- logger.debug(f"Caught {type_name(exc)}: {exc} - returning False")
125
+ except DeviceConnectionError as exc:
126
+ # logger.error(f"Caught {type_name(exc)}: {exc}")
136
127
  return False
137
128
 
138
129
 
@@ -589,18 +580,11 @@ def start_dev():
589
580
  with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
590
581
  s.bind((DEV_HOST, DEV_PORT))
591
582
  s.listen()
592
- s.settimeout(CONNECT_TIMEOUT)
593
583
  logger.info(f"Ready to accept connection on {DEV_HOST}:{DEV_PORT}...")
594
- while True:
595
- with contextlib.suppress(socket.timeout):
596
- conn, addr = s.accept()
597
- break
598
- if killer.term_signal_received:
599
- return
584
+ conn, addr = s.accept()
600
585
  with conn:
601
586
  logger.info(f"Accepted connection from {addr}")
602
587
  conn.sendall(f"Dummy Device {__version__}".encode())
603
- conn.settimeout(READ_TIMEOUT)
604
588
  try:
605
589
  while True:
606
590
  error_msg = ""
@@ -57,7 +57,7 @@ COMMANDER_PORT = settings.get("COMMANDER_PORT", 0) # dynamically assigned by th
57
57
  _initialised = False # will be set to True in the setup_logging() function
58
58
 
59
59
 
60
- def get_log_file_name() -> str:
60
+ def get_log_file_name():
61
61
  """
62
62
  Returns the filename of the log file as defined in the Settings or return the default name 'general.log'.
63
63
  """
@@ -315,7 +315,7 @@ def send_request(command_request: str):
315
315
  """Sends a request to the Logger Control Server and waits for a response."""
316
316
 
317
317
  if COMMANDER_PORT == 0:
318
- endpoint = get_endpoint_from_registry(SERVICE_TYPE)
318
+ endpoint = get_endpoint_from_registry()
319
319
  else:
320
320
  endpoint = f"{PROTOCOL}://{HOSTNAME}:{COMMANDER_PORT}"
321
321
 
@@ -23,12 +23,10 @@ from egse.notifyhub import SERVICE_TYPE
23
23
  from egse.notifyhub import STATS_INTERVAL
24
24
  from egse.notifyhub.client import AsyncNotificationHubClient
25
25
  from egse.registry import MessageType
26
- from egse.registry.client import REQUEST_TIMEOUT
27
- from egse.registry.client import AsyncRegistryClient
26
+ from egse.registry.client import AsyncRegistryClient, REQUEST_TIMEOUT
28
27
  from egse.system import TyperAsyncCommand
29
28
  from egse.system import get_host_ip
30
29
  from egse.zmq_ser import get_port_number
31
-
32
30
  from .event import NotificationEvent
33
31
 
34
32
  REQUEST_POLL_TIMEOUT = 1.0
@@ -639,8 +639,6 @@ class AsyncRegistryClient:
639
639
  The response from the registry as a dictionary.
640
640
  """
641
641
 
642
- assert self.req_socket is not None, "REQ socket is not connected, cannot send request."
643
-
644
642
  timeout = timeout or self.timeout
645
643
  try:
646
644
  self.logger.debug(f"Sending request: {request}")
@@ -689,8 +687,6 @@ class AsyncRegistryClient:
689
687
  The response from the registry as a dictionary.
690
688
  """
691
689
 
692
- assert self.hb_socket is not None, "HB socket is not connected, cannot send heartbeat request."
693
-
694
690
  try:
695
691
  self.logger.debug(f"Sending heartbeat request: {request}")
696
692
  await self.hb_socket.send_string(json.dumps(request))
@@ -871,8 +867,7 @@ class AsyncRegistryClient:
871
867
  await self.reregister()
872
868
 
873
869
  else:
874
- if VERBOSE_DEBUG:
875
- self.logger.debug(f"Heartbeat succeeded: {response.get('message')}")
870
+ VERBOSE_DEBUG and self.logger.debug(f"Heartbeat succeeded: {response.get('message')}")
876
871
 
877
872
  except Exception as exc:
878
873
  self.logger.error(f"Error in heartbeat loop: {exc}", exc_info=True)
@@ -905,7 +900,6 @@ class AsyncRegistryClient:
905
900
  try:
906
901
  await self._heartbeat_task
907
902
  except asyncio.CancelledError:
908
- self.logger.info("Heartbeat task cancelled")
909
903
  pass
910
904
  self._tasks.discard(self._heartbeat_task)
911
905
  self._heartbeat_task = None
@@ -1152,8 +1146,8 @@ class AsyncRegistryClient:
1152
1146
  if hasattr(self, "context") and self.context:
1153
1147
  self.logger.info(f"{self.context = !r}")
1154
1148
  self.logger.info(f"{self.context._sockets = !r}")
1155
- # if not self.context.closed:
1156
- # self.context.term()
1149
+ if not self.context.closed:
1150
+ self.context.term()
1157
1151
  except Exception as exc:
1158
1152
  self.logger.error(f"Error during cleanup: {exc}")
1159
1153
 
@@ -218,18 +218,16 @@ class AsyncRegistryServer:
218
218
  """Task that handles incoming requests."""
219
219
  self.logger.info("Started request handler task")
220
220
 
221
- assert self.req_socket is not None, "REQ socket is not connected, cannot handle requests."
222
-
223
221
  try:
224
222
  message_parts = None
225
223
  while self._running:
226
224
  try:
227
225
  # Wait for a request with timeout to allow checking if still running
228
226
  try:
229
- self.logger.info("Waiting for a request with 1s timeout...")
227
+ # self.logger.info("Waiting for a request with 1s timeout...")
230
228
  message_parts = await asyncio.wait_for(self.req_socket.recv_multipart(), timeout=1.0)
231
229
  except asyncio.TimeoutError:
232
- self.logger.debug("waiting for command request...")
230
+ # self.logger.debug("waiting for command request...")
233
231
  continue
234
232
 
235
233
  if len(message_parts) >= 3:
@@ -243,9 +241,6 @@ class AsyncRegistryServer:
243
241
  response = await self._process_request(message_data)
244
242
 
245
243
  await self._send_response(client_id, message_type, response)
246
- else:
247
- self.logger.warning("Request handler: message corrupted, check debug messages.")
248
- self.logger.debug(f"{message_parts=}")
249
244
 
250
245
  except zmq.ZMQError as exc:
251
246
  self.logger.error(f"ZMQ error: {exc}", exc_info=True)
@@ -402,8 +397,6 @@ class AsyncRegistryServer:
402
397
  """Task that handles heartbeat messages."""
403
398
  self.logger.info("Started heartbeats handler task")
404
399
 
405
- assert self.hb_socket is not None, "HB socket is not connected, cannot handle heartbeat messages."
406
-
407
400
  try:
408
401
  message_parts = None
409
402
  while self._running:
@@ -432,8 +425,7 @@ class AsyncRegistryServer:
432
425
  self.logger.warning("Heartbeat request: message corrupted, check debug messages.")
433
426
 
434
427
  except asyncio.TimeoutError:
435
- if VERBOSE_DEBUG:
436
- self.logger.debug("waiting for heartbeat...")
428
+ VERBOSE_DEBUG and self.logger.debug("waiting for heartbeat...")
437
429
  continue
438
430
 
439
431
  except Exception as exc:
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import asyncio
4
4
  import json
5
+ import logging
5
6
  import time
6
7
  from typing import Any
7
8
  from typing import Callable
@@ -9,14 +10,13 @@ from typing import Callable
9
10
  import zmq
10
11
  import zmq.asyncio
11
12
 
12
- from egse.log import logging
13
13
  from egse.registry import DEFAULT_RS_PUB_PORT
14
14
  from egse.registry import DEFAULT_RS_REQ_PORT
15
15
  from egse.registry.client import AsyncRegistryClient
16
16
  from egse.system import get_host_ip
17
17
  from egse.zmq_ser import get_port_number
18
18
 
19
- module_module_logger_name = "egse.async_microservice"
19
+ module_module_logger_name = "async_microservice"
20
20
  module_logger = logging.getLogger(module_module_logger_name)
21
21
 
22
22
 
@@ -64,7 +64,7 @@ class ZMQMicroservice:
64
64
  self.registry_sub_endpoint = registry_sub_endpoint or f"tcp://localhost:{DEFAULT_RS_PUB_PORT}"
65
65
  self.metadata = metadata or {}
66
66
 
67
- self.host_ip = get_host_ip() or "localhost"
67
+ self.host_ip = get_host_ip()
68
68
 
69
69
  # Service ID will be set when registered
70
70
  self.service_id = None
@@ -164,7 +164,6 @@ class ZMQMicroservice:
164
164
 
165
165
  if not self.service_id:
166
166
  module_logger.error("Failed to register with the service registry")
167
- await self._cleanup()
168
167
  return True
169
168
 
170
169
  module_logger.info(f"Registered with service ID: {self.service_id}")
@@ -176,17 +175,12 @@ class ZMQMicroservice:
176
175
  # Start request handler
177
176
  request_task = asyncio.create_task(self._handle_requests())
178
177
  self._tasks.add(request_task)
179
- # request_task.add_done_callback(self._tasks.discard)
178
+ request_task.add_done_callback(self._tasks.discard)
180
179
 
181
180
  # Wait for shutdown signal
182
181
  await self._shutdown.wait()
183
182
 
184
- # request_task.cancel()
185
- # try:
186
- # await request_task
187
- # except asyncio.CancelledError:
188
- # module_logger.info("Request handler task cancelled during shutdown")
189
-
183
+ # Clean shutdown
190
184
  await self._cleanup()
191
185
 
192
186
  return False