digitalkin 0.2.25rc0__py3-none-any.whl → 0.3.2.dev14__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.
Files changed (122) hide show
  1. base_server/server_async_insecure.py +6 -5
  2. base_server/server_async_secure.py +6 -5
  3. base_server/server_sync_insecure.py +5 -4
  4. base_server/server_sync_secure.py +5 -4
  5. digitalkin/__version__.py +1 -1
  6. digitalkin/core/__init__.py +1 -0
  7. digitalkin/core/common/__init__.py +9 -0
  8. digitalkin/core/common/factories.py +156 -0
  9. digitalkin/core/job_manager/__init__.py +1 -0
  10. digitalkin/{modules → core}/job_manager/base_job_manager.py +138 -32
  11. digitalkin/core/job_manager/single_job_manager.py +373 -0
  12. digitalkin/{modules → core}/job_manager/taskiq_broker.py +121 -26
  13. digitalkin/core/job_manager/taskiq_job_manager.py +541 -0
  14. digitalkin/core/task_manager/__init__.py +1 -0
  15. digitalkin/core/task_manager/base_task_manager.py +539 -0
  16. digitalkin/core/task_manager/local_task_manager.py +108 -0
  17. digitalkin/core/task_manager/remote_task_manager.py +87 -0
  18. digitalkin/core/task_manager/surrealdb_repository.py +266 -0
  19. digitalkin/core/task_manager/task_executor.py +249 -0
  20. digitalkin/core/task_manager/task_session.py +368 -0
  21. digitalkin/grpc_servers/__init__.py +1 -19
  22. digitalkin/grpc_servers/_base_server.py +3 -3
  23. digitalkin/grpc_servers/module_server.py +120 -195
  24. digitalkin/grpc_servers/module_servicer.py +81 -44
  25. digitalkin/grpc_servers/utils/__init__.py +1 -0
  26. digitalkin/grpc_servers/utils/exceptions.py +0 -8
  27. digitalkin/grpc_servers/utils/grpc_client_wrapper.py +25 -9
  28. digitalkin/grpc_servers/utils/grpc_error_handler.py +53 -0
  29. digitalkin/grpc_servers/utils/utility_schema_extender.py +100 -0
  30. digitalkin/logger.py +64 -27
  31. digitalkin/mixins/__init__.py +19 -0
  32. digitalkin/mixins/base_mixin.py +10 -0
  33. digitalkin/mixins/callback_mixin.py +24 -0
  34. digitalkin/mixins/chat_history_mixin.py +110 -0
  35. digitalkin/mixins/cost_mixin.py +76 -0
  36. digitalkin/mixins/file_history_mixin.py +93 -0
  37. digitalkin/mixins/filesystem_mixin.py +46 -0
  38. digitalkin/mixins/logger_mixin.py +51 -0
  39. digitalkin/mixins/storage_mixin.py +79 -0
  40. digitalkin/models/__init__.py +1 -1
  41. digitalkin/models/core/__init__.py +1 -0
  42. digitalkin/{modules/job_manager → models/core}/job_manager_models.py +3 -11
  43. digitalkin/models/core/task_monitor.py +74 -0
  44. digitalkin/models/grpc_servers/__init__.py +1 -0
  45. digitalkin/{grpc_servers/utils → models/grpc_servers}/models.py +92 -7
  46. digitalkin/models/module/__init__.py +18 -11
  47. digitalkin/models/module/base_types.py +61 -0
  48. digitalkin/models/module/module.py +9 -1
  49. digitalkin/models/module/module_context.py +282 -6
  50. digitalkin/models/module/module_types.py +29 -105
  51. digitalkin/models/module/setup_types.py +490 -0
  52. digitalkin/models/module/tool_cache.py +68 -0
  53. digitalkin/models/module/tool_reference.py +117 -0
  54. digitalkin/models/module/utility.py +167 -0
  55. digitalkin/models/services/__init__.py +9 -0
  56. digitalkin/models/services/cost.py +1 -0
  57. digitalkin/models/services/registry.py +35 -0
  58. digitalkin/models/services/storage.py +39 -5
  59. digitalkin/modules/__init__.py +5 -1
  60. digitalkin/modules/_base_module.py +265 -167
  61. digitalkin/modules/archetype_module.py +6 -1
  62. digitalkin/modules/tool_module.py +16 -3
  63. digitalkin/modules/trigger_handler.py +7 -6
  64. digitalkin/modules/triggers/__init__.py +8 -0
  65. digitalkin/modules/triggers/healthcheck_ping_trigger.py +45 -0
  66. digitalkin/modules/triggers/healthcheck_services_trigger.py +63 -0
  67. digitalkin/modules/triggers/healthcheck_status_trigger.py +52 -0
  68. digitalkin/services/__init__.py +4 -0
  69. digitalkin/services/communication/__init__.py +7 -0
  70. digitalkin/services/communication/communication_strategy.py +76 -0
  71. digitalkin/services/communication/default_communication.py +101 -0
  72. digitalkin/services/communication/grpc_communication.py +234 -0
  73. digitalkin/services/cost/__init__.py +9 -2
  74. digitalkin/services/cost/grpc_cost.py +9 -42
  75. digitalkin/services/filesystem/default_filesystem.py +0 -2
  76. digitalkin/services/filesystem/grpc_filesystem.py +10 -39
  77. digitalkin/services/registry/__init__.py +22 -1
  78. digitalkin/services/registry/default_registry.py +135 -4
  79. digitalkin/services/registry/exceptions.py +47 -0
  80. digitalkin/services/registry/grpc_registry.py +306 -0
  81. digitalkin/services/registry/registry_models.py +15 -0
  82. digitalkin/services/registry/registry_strategy.py +88 -4
  83. digitalkin/services/services_config.py +25 -3
  84. digitalkin/services/services_models.py +5 -1
  85. digitalkin/services/setup/default_setup.py +6 -7
  86. digitalkin/services/setup/grpc_setup.py +52 -15
  87. digitalkin/services/storage/grpc_storage.py +4 -4
  88. digitalkin/services/user_profile/__init__.py +12 -0
  89. digitalkin/services/user_profile/default_user_profile.py +55 -0
  90. digitalkin/services/user_profile/grpc_user_profile.py +69 -0
  91. digitalkin/services/user_profile/user_profile_strategy.py +25 -0
  92. digitalkin/utils/__init__.py +28 -0
  93. digitalkin/utils/arg_parser.py +1 -1
  94. digitalkin/utils/development_mode_action.py +2 -2
  95. digitalkin/utils/dynamic_schema.py +483 -0
  96. digitalkin/utils/package_discover.py +1 -2
  97. digitalkin/utils/schema_splitter.py +207 -0
  98. {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/METADATA +11 -30
  99. digitalkin-0.3.2.dev14.dist-info/RECORD +143 -0
  100. {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/top_level.txt +1 -0
  101. modules/archetype_with_tools_module.py +244 -0
  102. modules/cpu_intensive_module.py +1 -1
  103. modules/dynamic_setup_module.py +338 -0
  104. modules/minimal_llm_module.py +1 -1
  105. modules/text_transform_module.py +1 -1
  106. monitoring/digitalkin_observability/__init__.py +46 -0
  107. monitoring/digitalkin_observability/http_server.py +150 -0
  108. monitoring/digitalkin_observability/interceptors.py +176 -0
  109. monitoring/digitalkin_observability/metrics.py +201 -0
  110. monitoring/digitalkin_observability/prometheus.py +137 -0
  111. monitoring/tests/test_metrics.py +172 -0
  112. services/filesystem_module.py +7 -5
  113. services/storage_module.py +4 -2
  114. digitalkin/grpc_servers/registry_server.py +0 -65
  115. digitalkin/grpc_servers/registry_servicer.py +0 -456
  116. digitalkin/grpc_servers/utils/factory.py +0 -180
  117. digitalkin/modules/job_manager/single_job_manager.py +0 -294
  118. digitalkin/modules/job_manager/taskiq_job_manager.py +0 -290
  119. digitalkin-0.2.25rc0.dist-info/RECORD +0 -89
  120. /digitalkin/{grpc_servers/utils → models/grpc_servers}/types.py +0 -0
  121. {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/WHEEL +0 -0
  122. {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/licenses/LICENSE +0 -0
@@ -3,16 +3,16 @@
3
3
  import asyncio
4
4
  import datetime
5
5
  from collections.abc import Callable
6
- from typing import TYPE_CHECKING, Any
6
+ from typing import Any
7
7
 
8
8
  from pydantic import BaseModel, Field
9
9
 
10
10
  from digitalkin.logger import logger
11
11
  from digitalkin.models.module import ModuleStatus
12
12
  from digitalkin.modules.archetype_module import ArchetypeModule
13
+ from digitalkin.services.filesystem.filesystem_strategy import FileFilter, UploadFileData
13
14
  from digitalkin.services.services_config import ServicesConfig
14
15
  from digitalkin.services.services_models import ServicesMode
15
- from digitalkin.services.filesystem.filesystem_strategy import FilesystemRecord, FileFilter, UploadFileData
16
16
 
17
17
 
18
18
  class ExampleInput(BaseModel):
@@ -62,7 +62,10 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
62
62
 
63
63
  # Define services_config_params with default values
64
64
  services_config_strategies = {}
65
- services_config_params = {"cost": {"config": {}}, "storage": {"config": {}}} # Filesystem has no config but it's enabled
65
+ services_config_params = {
66
+ "cost": {"config": {}},
67
+ "storage": {"config": {}},
68
+ } # Filesystem has no config but it's enabled
66
69
 
67
70
  def __init__(self, job_id: str, mission_id: str, setup_version_id: str) -> None:
68
71
  """Initialize the example module.
@@ -128,7 +131,6 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
128
131
  callback(record.model_dump())
129
132
  # Call the callback with the output data
130
133
 
131
-
132
134
  # Wait a bit to simulate processing time
133
135
  await asyncio.sleep(1)
134
136
 
@@ -173,7 +175,7 @@ async def test_module() -> None:
173
175
 
174
176
  # Check the storage
175
177
  if module.status == ModuleStatus.STOPPED:
176
- files, nb_results = module.filesystem.get_files(
178
+ files, _nb_results = module.filesystem.get_files(
177
179
  filters=FileFilter(name="example_output.txt", context="test-mission-123"),
178
180
  )
179
181
  for file in files:
@@ -64,7 +64,7 @@ class ExampleModule(ArchetypeModule[ExampleInput, ExampleOutput, ExampleSetup, E
64
64
 
65
65
  # Define services_config_params with default values
66
66
  services_config_strategies = {}
67
- services_config_params = {"storage": {"config": {"example": ExampleOutput}},"cost": {"config":{}}}
67
+ services_config_params = {"storage": {"config": {"example": ExampleOutput}}, "cost": {"config": {}}}
68
68
 
69
69
  def __init__(self, job_id: str, mission_id: str, setup_version_id: str) -> None:
70
70
  """Initialize the example module.
@@ -184,7 +184,9 @@ async def test_module() -> None:
184
184
  def test_storage_directly() -> None:
185
185
  """Test the storage service directly."""
186
186
  # Initialize storage service
187
- storage = ServicesConfig().storage(mission_id="test-mission",setup_version_id="test-setup-123", config={"example": ExampleStorage})
187
+ storage = ServicesConfig().storage(
188
+ mission_id="test-mission", setup_version_id="test-setup-123", config={"example": ExampleStorage}
189
+ )
188
190
 
189
191
  # Create a test record
190
192
  storage.store("example", "test_table", {"test_key": "test_value"}, "OUTPUT")
@@ -1,65 +0,0 @@
1
- """Registry gRPC server implementation for DigitalKin."""
2
-
3
- from digitalkin_proto.digitalkin.module_registry.v2 import (
4
- module_registry_service_pb2,
5
- module_registry_service_pb2_grpc,
6
- )
7
-
8
- from digitalkin.grpc_servers._base_server import BaseServer
9
- from digitalkin.grpc_servers.registry_servicer import RegistryModule, RegistryServicer
10
- from digitalkin.grpc_servers.utils.models import RegistryServerConfig
11
- from digitalkin.logger import logger
12
-
13
-
14
- class RegistryServer(BaseServer):
15
- """gRPC server for DigitalKin module registry.
16
-
17
- This server implements the ModuleRegistryService which allows modules to register
18
- themselves and be discovered by other components in the system.
19
-
20
- Attributes:
21
- config: Server configuration.
22
- registry_servicer: The gRPC servicer handling registry requests.
23
- """
24
-
25
- def __init__(
26
- self,
27
- config: RegistryServerConfig,
28
- ) -> None:
29
- """Initialize the registry server.
30
-
31
- Args:
32
- config: Server configuration.
33
- """
34
- super().__init__(config)
35
- self.config = config
36
- self.registry_servicer: RegistryServicer | None = None
37
-
38
- def _register_servicers(self) -> None:
39
- """Register the registry servicer with the gRPC server.
40
-
41
- Raises:
42
- RuntimeError: If server is not registered during server creation
43
- """
44
- if self.server is None:
45
- msg = "Server must be created before registering servicers"
46
- raise RuntimeError(msg)
47
-
48
- logger.debug("Registering registry servicer")
49
- self.registry_servicer = RegistryServicer()
50
- self.register_servicer(
51
- self.registry_servicer,
52
- module_registry_service_pb2_grpc.add_ModuleRegistryServiceServicer_to_server,
53
- service_descriptor=module_registry_service_pb2.DESCRIPTOR,
54
- )
55
- logger.debug("Registered registry servicer")
56
-
57
- def get_registered_modules(self) -> list[RegistryModule]:
58
- """Get a list of all registered modules.
59
-
60
- Returns:
61
- A list of module information objects.
62
- """
63
- if self.registry_servicer:
64
- return list(self.registry_servicer.registered_modules.values())
65
- return []
@@ -1,456 +0,0 @@
1
- """Registry servicer implementation for DigitalKin.
2
-
3
- This module provides the gRPC service implementation for the Module Registry,
4
- which handles registration, deregistration, discovery, and status management
5
- of DigitalKin modules.
6
- """
7
-
8
- from collections.abc import Iterator
9
- from enum import Enum
10
-
11
- import grpc
12
- from digitalkin_proto.digitalkin.module_registry.v2 import (
13
- discover_pb2,
14
- metadata_pb2,
15
- module_registry_service_pb2_grpc,
16
- registration_pb2,
17
- status_pb2,
18
- )
19
- from pydantic import BaseModel
20
- from typing_extensions import Self
21
-
22
- from digitalkin.logger import logger
23
-
24
-
25
- class ExtendedEnum(Enum):
26
- """Tool enum class."""
27
-
28
- @classmethod
29
- def list(cls) -> list:
30
- """Classmethod to generate a list of enum values.
31
-
32
- Returns:
33
- list: Enum members' values
34
- """
35
- return [c.value for c in cls]
36
-
37
-
38
- class ModuleStatus(ExtendedEnum):
39
- """Describe a Module current status.
40
-
41
- Represents the possible states a module can be in during its lifecycle.
42
- """
43
-
44
- # RUNNING: Module alive.
45
- RUNNING = 0
46
- # IDLE: Module waiting for an event / update.
47
- IDLE = 1
48
- # ENDED: Module signals the end of task or have been killed.
49
- ENDED = 2
50
-
51
-
52
- class Tag(BaseModel):
53
- """Words representing a module capabilities.
54
-
55
- Used for module discovery and categorization.
56
- """
57
-
58
- # tag: Describe a Module function.
59
- tag: str
60
-
61
- def to_proto(self) -> metadata_pb2.Tag:
62
- """Convert Tag object from Pydantic to Proto.
63
-
64
- Returns:
65
- metadata_pb2.Tag: The protobuf representation of this tag.
66
- """
67
- return metadata_pb2.Tag(tag=self.tag)
68
-
69
-
70
- class Metadata(BaseModel):
71
- """Different informations to index and describe a module.
72
-
73
- Contains human-readable information about a module and its capabilities.
74
- """
75
-
76
- # name: Module's name
77
- name: str
78
- # tags: List of tag to describe a module functionalities.
79
- tags: list[Tag]
80
- # description: Module's description for search and indexing
81
- description: str | None
82
-
83
- def to_proto(self) -> metadata_pb2.Metadata:
84
- """Convert Metadata object from Pydantic to Proto.
85
-
86
- Returns:
87
- metadata_pb2.Metadata: The protobuf representation of this metadata.
88
- """
89
- return metadata_pb2.Metadata(
90
- name=self.name,
91
- tags=(t.to_proto() for t in self.tags),
92
- description=self.description,
93
- )
94
-
95
- @classmethod
96
- def from_proto(cls, request_metadata: metadata_pb2.Metadata) -> Self:
97
- """Create Metadata object from Proto message.
98
-
99
- Args:
100
- request_metadata: The protobuf metadata to convert.
101
-
102
- Returns:
103
- Metadata: The Pydantic model representation of the metadata.
104
- """
105
- return cls(
106
- name=request_metadata.name,
107
- tags=[Tag(tag=t.tag) for t in request_metadata.tags],
108
- description=request_metadata.description,
109
- )
110
-
111
-
112
- class RegistryModule(BaseModel):
113
- """Module's technical representation to index, search and monitor.
114
-
115
- Contains all the information needed to identify, locate and communicate
116
- with a module in the system.
117
- """
118
-
119
- # module_id: Id of the module
120
- module_id: str
121
- # module_type: Type of the module (trigger, tool, kin, view)
122
- module_type: str
123
- # address: Address used to communicate with the module
124
- address: str
125
- # port: Port used to communicate with the module
126
- port: int
127
- # version: Current module version.
128
- version: str
129
- # metadata: user defined module name, description and tags
130
- metadata: Metadata
131
- # status: Representation of the Module current state (running, idle, ended...).
132
- status: ModuleStatus
133
- # message: (Optional) Details about the status.
134
- message: str | None
135
-
136
- def to_proto(self) -> discover_pb2.DiscoverInfoResponse:
137
- """Convert RegistryModule object from Pydantic to Proto.
138
-
139
- Returns:
140
- metadata_pb2.Metadata: The protobuf representation of this metadata.
141
- """
142
- return discover_pb2.DiscoverInfoResponse(
143
- module_id=self.module_id,
144
- module_type=self.module_type,
145
- address=self.address,
146
- port=self.port,
147
- version=self.version,
148
- metadata=self.metadata.to_proto(),
149
- )
150
-
151
-
152
- class RegistryServicer(module_registry_service_pb2_grpc.ModuleRegistryServiceServicer):
153
- """Implementation of the ModuleRegistryService.
154
-
155
- This servicer handles the registration, deregistration, and discovery of modules.
156
- It maintains an in-memory registry of all active modules and their metadata.
157
-
158
- Attributes:
159
- registered_modules: Dictionary mapping module_id to RegistryModule objects.
160
- """
161
-
162
- registered_modules: dict[str, RegistryModule]
163
-
164
- def __init__(self) -> None:
165
- """Initialize the registry servicer with an empty module registry."""
166
- self.registered_modules = {} # TODO replace with a database
167
-
168
- def RegisterModule( # noqa: N802
169
- self,
170
- request: registration_pb2.RegisterRequest,
171
- context: grpc.ServicerContext,
172
- ) -> registration_pb2.RegisterResponse:
173
- """Register a module with the registry.
174
-
175
- Adds a new module to the registry with its connection information and metadata.
176
- Fails if a module with the same ID is already registered.
177
-
178
- Args:
179
- request: The register request containing module info and address.
180
- context: The gRPC context for setting status codes and details.
181
-
182
- Returns:
183
- registration_pb2.RegisterResponse: A response indicating success or failure.
184
- """
185
- module_id = request.module_id
186
- logger.debug("Registering module: %s", module_id)
187
-
188
- # Check if module is already registered
189
- if module_id in self.registered_modules:
190
- message = f"Module '{module_id}' already registered"
191
- logger.warning(message)
192
-
193
- context.set_code(grpc.StatusCode.ALREADY_EXISTS)
194
- context.set_details(message)
195
- return registration_pb2.RegisterResponse(success=False)
196
-
197
- # Store the module info with address
198
- self.registered_modules[module_id] = RegistryModule(
199
- module_id=request.module_id,
200
- module_type=request.module_type,
201
- address=request.address,
202
- port=request.port,
203
- version=request.version,
204
- metadata=Metadata.from_proto(request.metadata),
205
- status=ModuleStatus.RUNNING,
206
- message=None,
207
- )
208
-
209
- logger.debug("Module %s registered at %s:%d", module_id, request.address, request.port)
210
- return registration_pb2.RegisterResponse(success=True)
211
-
212
- def DeregisterModule( # noqa: N802
213
- self,
214
- request: registration_pb2.DeregisterRequest,
215
- context: grpc.ServicerContext,
216
- ) -> registration_pb2.DeregisterResponse:
217
- """Deregister a module from the registry.
218
-
219
- Removes a module from the registry based on its ID.
220
- Fails if the specified module is not found in the registry.
221
-
222
- Args:
223
- request: The deregister request containing the module ID.
224
- context: The gRPC context for setting status codes and details.
225
-
226
- Returns:
227
- registration_pb2.DeregisterResponse: A response indicating success or failure.
228
- """
229
- module_id = request.module_id
230
- logger.debug("Deregistering module: %s", module_id)
231
-
232
- # Check if module exists in registry
233
- if module_id not in self.registered_modules:
234
- message = f"Module {module_id} not found in registry"
235
- logger.warning(message)
236
-
237
- context.set_code(grpc.StatusCode.NOT_FOUND)
238
- context.set_details(message)
239
- return registration_pb2.DeregisterResponse()
240
-
241
- # Remove the module
242
- del self.registered_modules[module_id]
243
-
244
- logger.debug("Module %s deregistered", module_id)
245
- return registration_pb2.DeregisterResponse(success=True)
246
-
247
- def DiscoverInfoModule( # noqa: N802
248
- self,
249
- request: discover_pb2.DiscoverInfoRequest,
250
- context: grpc.ServicerContext,
251
- ) -> discover_pb2.DiscoverInfoResponse:
252
- """Discover detailed information about a specific module.
253
-
254
- Retrieves complete information about a module based on its ID.
255
-
256
- Args:
257
- request: The discover request containing the module ID.
258
- context: The gRPC context (unused).
259
-
260
- Returns:
261
- discover_pb2.DiscoverInfoResponse: A response containing the module's information.
262
- """
263
- logger.debug("Discovering module: %s", request.module_id)
264
-
265
- # Check if module exists in registry
266
- if request.module_id not in self.registered_modules:
267
- message = f"Module {request.module_id} not found in registry"
268
- logger.warning(message)
269
- context.set_code(grpc.StatusCode.NOT_FOUND)
270
- context.set_details(message)
271
- return discover_pb2.DiscoverInfoResponse()
272
- return self.registered_modules[request.module_id].to_proto()
273
-
274
- def DiscoverSearchModule( # noqa: N802
275
- self,
276
- request: discover_pb2.DiscoverSearchRequest,
277
- context: grpc.ServicerContext, # noqa: ARG002
278
- ) -> discover_pb2.DiscoverSearchResponse:
279
- """Discover modules based on the specified criteria.
280
-
281
- Searches for modules that match the provided filters such as name,
282
- type, and tags.
283
-
284
- Args:
285
- request: The discover request containing search criteria.
286
- context: The gRPC context (unused).
287
-
288
- Returns:
289
- discover_pb2.DiscoverSearchResponse: A response containing matching modules.
290
- """
291
- logger.debug("Discovering modules with criteria:")
292
-
293
- # Start with all modules
294
- results = list(self.registered_modules.values())
295
- logger.debug("%s", list(results))
296
- # Filter by name if specified
297
- if request.name:
298
- logger.debug("\tname %s", request.name)
299
- results = [m for m in results if request.name in m.metadata.name]
300
-
301
- # Filter by type if specified
302
- if request.module_type:
303
- logger.debug("\tmodule_type %s", request.module_type)
304
- results = [m for m in results if m.module_type == request.module_type]
305
-
306
- # Filter by tags if specified
307
- if request.tags:
308
- logger.debug("\ttags %s", request.tags)
309
- results = [m for m in results if any(tag in m.metadata.tags for tag in request.tags)]
310
-
311
- # Filter by description if specified
312
- """
313
- if request.description:
314
- results = [m for m in results if request.description in m.metadata.description]
315
- """
316
-
317
- logger.debug("Found %d matching modules", len(results))
318
- return discover_pb2.DiscoverSearchResponse(modules=[r.to_proto() for r in results])
319
-
320
- def GetModuleStatus( # noqa: N802
321
- self,
322
- request: status_pb2.ModuleStatusRequest,
323
- context: grpc.ServicerContext,
324
- ) -> status_pb2.ModuleStatusResponse:
325
- """Query a specific module's status.
326
-
327
- Retrieves the current status of a module based on its ID.
328
-
329
- Args:
330
- request: The status request containing the module ID.
331
- context: The gRPC context (unused).
332
-
333
- Returns:
334
- status_pb2.ModuleStatusResponse: A response containing the module's status.
335
- """
336
- logger.debug("Getting status for module: %s", request.module_id)
337
-
338
- # Check if module exists in registry
339
- if request.module_id not in self.registered_modules:
340
- message = f"Module {request.module_id} not found in registry"
341
- logger.warning(message)
342
- context.set_code(grpc.StatusCode.NOT_FOUND)
343
- context.set_details(message)
344
- return status_pb2.ModuleStatusResponse()
345
-
346
- module = self.registered_modules[request.module_id]
347
- return status_pb2.ModuleStatusResponse(module_id=module.module_id, status=module.status.name)
348
-
349
- def ListModuleStatus( # noqa: N802
350
- self,
351
- request: status_pb2.ListModulesStatusRequest,
352
- context: grpc.ServicerContext,
353
- ) -> status_pb2.ListModulesStatusResponse:
354
- """Get a paginated list of registered modules and their statuses.
355
-
356
- Returns a subset of registered modules based on pagination parameters.
357
-
358
- Args:
359
- request: The request containing offset and list_size for pagination.
360
- context: The gRPC context (unused).
361
-
362
- Returns:
363
- status_pb2.ListModulesStatusResponse: A response containing a list of module statuses.
364
- """
365
- logger.debug(
366
- "Getting registered modules with offset %d and limit %d",
367
- request.offset,
368
- request.list_size,
369
- )
370
- if request.offset > len(self.registered_modules):
371
- message = f"Out of range {request.offset}"
372
- logger.warning(message)
373
- context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
374
- context.set_details(message)
375
- return status_pb2.ListModulesStatusResponse()
376
-
377
- list_size = request.list_size
378
- if list_size == 0:
379
- list_size = len(self.registered_modules)
380
-
381
- modules_statuses = [
382
- status_pb2.ModuleStatusResponse(module_id=module.module_id, status=module.status.name)
383
- for module in list(self.registered_modules.values())[request.offset : request.offset + list_size]
384
- ]
385
-
386
- logger.debug("Found %d registered modules", len(modules_statuses))
387
- return status_pb2.ListModulesStatusResponse(
388
- list_size=len(modules_statuses),
389
- modules_statuses=modules_statuses,
390
- )
391
-
392
- def GetAllModuleStatus( # noqa: N802
393
- self,
394
- request: status_pb2.GetAllModulesStatusRequest, # noqa: ARG002
395
- context: grpc.ServicerContext, # noqa: ARG002
396
- ) -> Iterator[status_pb2.ModuleStatusResponse]:
397
- """Get all registered modules via a stream.
398
-
399
- Streams the status of all registered modules one by one.
400
-
401
- Args:
402
- request: The get all modules request (unused).
403
- context: The gRPC context (unused).
404
-
405
- Yields:
406
- status_pb2.ModuleStatusResponse: Responses containing individual module statuses.
407
- """
408
- logger.debug("Streaming all %d registered modules", len(self.registered_modules))
409
- for module in self.registered_modules.values():
410
- yield status_pb2.ModuleStatusResponse(
411
- module_id=module.module_id,
412
- status=module.status.name,
413
- )
414
-
415
- def UpdateModuleStatus( # noqa: N802
416
- self,
417
- request: status_pb2.UpdateStatusRequest,
418
- context: grpc.ServicerContext,
419
- ) -> status_pb2.UpdateStatusResponse:
420
- """Update the status of a registered module.
421
-
422
- Changes the current status of a module based on the provided request.
423
- Fails if the specified module is not found in the registry.
424
-
425
- Args:
426
- request: The update status request with module ID and new status.
427
- context: The gRPC context (unused).
428
-
429
- Returns:
430
- status_pb2.UpdateStatusResponse: A response indicating success or failure.
431
- """
432
- module_id = request.module_id
433
- logger.debug("Updating status for module: %s to %s", module_id, request.status)
434
-
435
- # Check if module exists in registry
436
- if request.module_id not in self.registered_modules:
437
- message = f"Module {request.module_id} not found in registry"
438
- logger.warning(message)
439
- context.set_code(grpc.StatusCode.NOT_FOUND)
440
- context.set_details(message)
441
- return status_pb2.UpdateStatusResponse()
442
-
443
- # Check if module status is correct
444
- if request.status not in ModuleStatus.list() or request.status is None:
445
- message = f"ModuleStatus {request.status} is unknonw, please check the requested status"
446
- logger.warning(message)
447
- context.set_code(grpc.StatusCode.INVALID_ARGUMENT)
448
- context.set_details(message)
449
- return status_pb2.UpdateStatusResponse(success=False)
450
-
451
- # Update module status
452
- module_info = self.registered_modules[module_id]
453
- module_info.status = ModuleStatus(request.status)
454
-
455
- logger.debug("Status for module %s updated to %s", module_id, request.status)
456
- return status_pb2.UpdateStatusResponse(success=True)