django-cfg 1.5.20__py3-none-any.whl → 1.5.29__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.
Potentially problematic release.
This version of django-cfg might be problematic. Click here for more details.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/integrations/centrifugo/__init__.py +2 -0
- django_cfg/apps/integrations/centrifugo/services/client/client.py +1 -1
- django_cfg/apps/integrations/centrifugo/services/logging.py +47 -0
- django_cfg/apps/integrations/centrifugo/views/admin_api.py +29 -32
- django_cfg/apps/integrations/centrifugo/views/testing_api.py +31 -37
- django_cfg/apps/integrations/centrifugo/views/wrapper.py +25 -23
- django_cfg/apps/integrations/grpc/auth/api_key_auth.py +11 -10
- django_cfg/apps/integrations/grpc/management/commands/generate_protos.py +1 -1
- django_cfg/apps/integrations/grpc/management/commands/rungrpc.py +21 -36
- django_cfg/apps/integrations/grpc/managers/grpc_request_log.py +84 -0
- django_cfg/apps/integrations/grpc/managers/grpc_server_status.py +126 -3
- django_cfg/apps/integrations/grpc/models/grpc_api_key.py +7 -1
- django_cfg/apps/integrations/grpc/models/grpc_server_status.py +22 -3
- django_cfg/apps/integrations/grpc/services/__init__.py +102 -17
- django_cfg/apps/integrations/grpc/services/centrifugo/bridge.py +469 -0
- django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/demo.py +1 -1
- django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/test_publish.py +4 -4
- django_cfg/apps/integrations/grpc/services/client/__init__.py +26 -0
- django_cfg/apps/integrations/grpc/services/commands/IMPLEMENTATION.md +456 -0
- django_cfg/apps/integrations/grpc/services/commands/README.md +252 -0
- django_cfg/apps/integrations/grpc/services/commands/__init__.py +93 -0
- django_cfg/apps/integrations/grpc/services/commands/base.py +243 -0
- django_cfg/apps/integrations/grpc/services/commands/examples/__init__.py +22 -0
- django_cfg/apps/integrations/grpc/services/commands/examples/base_client.py +228 -0
- django_cfg/apps/integrations/grpc/services/commands/examples/client.py +272 -0
- django_cfg/apps/integrations/grpc/services/commands/examples/config.py +177 -0
- django_cfg/apps/integrations/grpc/services/commands/examples/start.py +125 -0
- django_cfg/apps/integrations/grpc/services/commands/examples/stop.py +101 -0
- django_cfg/apps/integrations/grpc/services/commands/registry.py +170 -0
- django_cfg/apps/integrations/grpc/services/discovery/__init__.py +39 -0
- django_cfg/apps/integrations/grpc/services/{discovery.py → discovery/discovery.py} +62 -55
- django_cfg/apps/integrations/grpc/services/{service_registry.py → discovery/registry.py} +215 -5
- django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/metrics.py +3 -3
- django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/request_logger.py +10 -13
- django_cfg/apps/integrations/grpc/services/management/__init__.py +37 -0
- django_cfg/apps/integrations/grpc/services/monitoring/__init__.py +38 -0
- django_cfg/apps/integrations/grpc/services/{monitoring_service.py → monitoring/monitoring.py} +2 -2
- django_cfg/apps/integrations/grpc/services/{testing_service.py → monitoring/testing.py} +5 -5
- django_cfg/apps/integrations/grpc/services/rendering/__init__.py +27 -0
- django_cfg/apps/integrations/grpc/services/{chart_generator.py → rendering/charts.py} +1 -1
- django_cfg/apps/integrations/grpc/services/routing/__init__.py +59 -0
- django_cfg/apps/integrations/grpc/services/routing/config.py +76 -0
- django_cfg/apps/integrations/grpc/services/routing/router.py +430 -0
- django_cfg/apps/integrations/grpc/services/streaming/__init__.py +117 -0
- django_cfg/apps/integrations/grpc/services/streaming/config.py +451 -0
- django_cfg/apps/integrations/grpc/services/streaming/service.py +651 -0
- django_cfg/apps/integrations/grpc/services/streaming/types.py +367 -0
- django_cfg/apps/integrations/grpc/utils/__init__.py +58 -1
- django_cfg/apps/integrations/grpc/utils/converters.py +565 -0
- django_cfg/apps/integrations/grpc/utils/handlers.py +242 -0
- django_cfg/apps/integrations/grpc/utils/proto_gen.py +1 -1
- django_cfg/apps/integrations/grpc/utils/streaming_logger.py +55 -8
- django_cfg/apps/integrations/grpc/views/charts.py +1 -1
- django_cfg/apps/integrations/grpc/views/config.py +1 -1
- django_cfg/core/base/config_model.py +11 -0
- django_cfg/core/builders/middleware_builder.py +5 -0
- django_cfg/management/commands/pool_status.py +153 -0
- django_cfg/middleware/pool_cleanup.py +261 -0
- django_cfg/models/api/grpc/config.py +2 -2
- django_cfg/models/infrastructure/database/config.py +16 -0
- django_cfg/models/infrastructure/database/converters.py +2 -0
- django_cfg/modules/django_admin/utils/html/composition.py +57 -13
- django_cfg/modules/django_admin/utils/html_builder.py +1 -0
- django_cfg/modules/django_client/core/groups/manager.py +25 -18
- django_cfg/modules/django_client/management/commands/generate_client.py +9 -5
- django_cfg/modules/django_logging/django_logger.py +58 -19
- django_cfg/pyproject.toml +3 -3
- django_cfg/static/frontend/admin.zip +0 -0
- django_cfg/templates/admin/index.html +0 -39
- django_cfg/utils/pool_monitor.py +320 -0
- django_cfg/utils/smart_defaults.py +233 -7
- {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/METADATA +75 -5
- {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/RECORD +87 -59
- django_cfg/apps/integrations/grpc/centrifugo/bridge.py +0 -277
- /django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/__init__.py +0 -0
- /django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/config.py +0 -0
- /django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/transformers.py +0 -0
- /django_cfg/apps/integrations/grpc/services/{grpc_client.py → client/client.py} +0 -0
- /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/__init__.py +0 -0
- /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/centrifugo.py +0 -0
- /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/errors.py +0 -0
- /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/logging.py +0 -0
- /django_cfg/apps/integrations/grpc/services/{config_helper.py → management/config_helper.py} +0 -0
- /django_cfg/apps/integrations/grpc/services/{proto_files_manager.py → management/proto_manager.py} +0 -0
- {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/WHEEL +0 -0
- {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Protocol type definitions for type-safe gRPC bidirectional streaming.
|
|
3
|
+
|
|
4
|
+
This module defines Protocol types used for generic, reusable gRPC streaming components.
|
|
5
|
+
All protocols are fully typed and support generic message/command types.
|
|
6
|
+
|
|
7
|
+
**Design Goals**:
|
|
8
|
+
- 100% type-safe callbacks
|
|
9
|
+
- Zero runtime overhead (protocols are compile-time only)
|
|
10
|
+
- Compatible with any protobuf message types
|
|
11
|
+
- Enables IDE autocomplete and mypy validation
|
|
12
|
+
|
|
13
|
+
**Usage Example**:
|
|
14
|
+
```python
|
|
15
|
+
# Define your processor
|
|
16
|
+
async def process_signal_message(
|
|
17
|
+
client_id: str,
|
|
18
|
+
message: SignalCommand,
|
|
19
|
+
output_queue: asyncio.Queue[SignalMessage]
|
|
20
|
+
) -> None:
|
|
21
|
+
# Your logic here
|
|
22
|
+
await output_queue.put(response)
|
|
23
|
+
|
|
24
|
+
# Type checker validates signature matches MessageProcessor protocol
|
|
25
|
+
service = BidirectionalStreamingService(
|
|
26
|
+
message_processor=process_signal_message, # ✅ Type-safe
|
|
27
|
+
...
|
|
28
|
+
)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Created: 2025-11-07
|
|
32
|
+
Status: %%PRODUCTION%%
|
|
33
|
+
Phase: Phase 1 - Universal Components
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
from typing import Protocol, TypeVar, Any
|
|
37
|
+
import asyncio
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
# ============================================================================
|
|
41
|
+
# Generic Type Variables
|
|
42
|
+
# ============================================================================
|
|
43
|
+
|
|
44
|
+
TMessage = TypeVar('TMessage', contravariant=True)
|
|
45
|
+
"""
|
|
46
|
+
Generic type for incoming gRPC messages (commands from client).
|
|
47
|
+
|
|
48
|
+
**Contravariant**: Allows passing more specific message types where generic is expected.
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
- Protocol expects: Message (base)
|
|
52
|
+
- Can pass: SignalCommand (subclass)
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
TCommand = TypeVar('TCommand', covariant=True)
|
|
56
|
+
"""
|
|
57
|
+
Generic type for outgoing gRPC commands (responses to client).
|
|
58
|
+
|
|
59
|
+
**Covariant**: Allows returning more general command types where specific is expected.
|
|
60
|
+
|
|
61
|
+
Example:
|
|
62
|
+
- Protocol returns: BotResponse (specific)
|
|
63
|
+
- Can be treated as: Message (base)
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
# ============================================================================
|
|
68
|
+
# Core Processing Protocols
|
|
69
|
+
# ============================================================================
|
|
70
|
+
|
|
71
|
+
class MessageProcessor(Protocol[TMessage, TCommand]):
|
|
72
|
+
"""
|
|
73
|
+
Protocol for processing incoming gRPC messages and generating responses.
|
|
74
|
+
|
|
75
|
+
This is the core business logic handler that processes each message from the client
|
|
76
|
+
and optionally enqueues response commands.
|
|
77
|
+
|
|
78
|
+
**Type Parameters**:
|
|
79
|
+
TMessage: Type of incoming messages (e.g., SignalCommand, BotCommand)
|
|
80
|
+
TCommand: Type of outgoing commands (e.g., SignalMessage, BotResponse)
|
|
81
|
+
|
|
82
|
+
**Signature**:
|
|
83
|
+
async def(client_id: str, message: TMessage, output_queue: Queue[TCommand]) -> None
|
|
84
|
+
|
|
85
|
+
**Parameters**:
|
|
86
|
+
client_id: Unique identifier for the connected client
|
|
87
|
+
message: Incoming message from client (generic type TMessage)
|
|
88
|
+
output_queue: Queue to enqueue response commands (generic type TCommand)
|
|
89
|
+
|
|
90
|
+
**Example Implementation**:
|
|
91
|
+
```python
|
|
92
|
+
async def process_bot_command(
|
|
93
|
+
client_id: str,
|
|
94
|
+
message: BotCommand,
|
|
95
|
+
output_queue: asyncio.Queue[BotResponse]
|
|
96
|
+
) -> None:
|
|
97
|
+
logger.info(f"Processing command for {client_id}")
|
|
98
|
+
|
|
99
|
+
if message.command_type == CommandType.START:
|
|
100
|
+
response = BotResponse(status="started")
|
|
101
|
+
await output_queue.put(response)
|
|
102
|
+
```
|
|
103
|
+
"""
|
|
104
|
+
async def __call__(
|
|
105
|
+
self,
|
|
106
|
+
client_id: str,
|
|
107
|
+
message: TMessage,
|
|
108
|
+
output_queue: asyncio.Queue[TCommand]
|
|
109
|
+
) -> None:
|
|
110
|
+
"""Process incoming message and optionally enqueue responses."""
|
|
111
|
+
...
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class ClientIdExtractor(Protocol[TMessage]):
|
|
115
|
+
"""
|
|
116
|
+
Protocol for extracting client ID from incoming gRPC messages.
|
|
117
|
+
|
|
118
|
+
Different services may store client IDs in different message fields.
|
|
119
|
+
This protocol allows type-safe client ID extraction.
|
|
120
|
+
|
|
121
|
+
**Type Parameters**:
|
|
122
|
+
TMessage: Type of incoming messages
|
|
123
|
+
|
|
124
|
+
**Signature**:
|
|
125
|
+
def(message: TMessage) -> str
|
|
126
|
+
|
|
127
|
+
**Example Implementation**:
|
|
128
|
+
```python
|
|
129
|
+
def extract_bot_client_id(message: BotCommand) -> str:
|
|
130
|
+
return str(message.bot_id)
|
|
131
|
+
|
|
132
|
+
def extract_signal_client_id(message: SignalCommand) -> str:
|
|
133
|
+
return message.client_id
|
|
134
|
+
```
|
|
135
|
+
"""
|
|
136
|
+
def __call__(self, message: TMessage) -> str:
|
|
137
|
+
"""Extract client ID from message."""
|
|
138
|
+
...
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class PingMessageCreator(Protocol[TCommand]):
|
|
142
|
+
"""
|
|
143
|
+
Protocol for creating ping/keepalive messages.
|
|
144
|
+
|
|
145
|
+
Bidirectional streams need periodic ping messages to keep connections alive.
|
|
146
|
+
This protocol allows type-safe ping message creation.
|
|
147
|
+
|
|
148
|
+
**Type Parameters**:
|
|
149
|
+
TCommand: Type of outgoing commands
|
|
150
|
+
|
|
151
|
+
**Signature**:
|
|
152
|
+
def() -> TCommand
|
|
153
|
+
|
|
154
|
+
**Example Implementation**:
|
|
155
|
+
```python
|
|
156
|
+
def create_bot_ping() -> BotResponse:
|
|
157
|
+
return BotResponse(
|
|
158
|
+
message_type=MessageType.PING,
|
|
159
|
+
timestamp=int(time.time())
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
def create_signal_ping() -> SignalMessage:
|
|
163
|
+
return SignalMessage(is_ping=True)
|
|
164
|
+
```
|
|
165
|
+
"""
|
|
166
|
+
def __call__(self) -> TCommand:
|
|
167
|
+
"""Create a ping message."""
|
|
168
|
+
...
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
# ============================================================================
|
|
172
|
+
# Connection Management Protocols
|
|
173
|
+
# ============================================================================
|
|
174
|
+
|
|
175
|
+
class ConnectionCallback(Protocol):
|
|
176
|
+
"""
|
|
177
|
+
Protocol for connection lifecycle callbacks.
|
|
178
|
+
|
|
179
|
+
**Signature**:
|
|
180
|
+
async def(client_id: str) -> None
|
|
181
|
+
|
|
182
|
+
**Use Cases**:
|
|
183
|
+
- on_connect: Initialize resources, log connection
|
|
184
|
+
- on_disconnect: Cleanup resources, update database
|
|
185
|
+
- on_error: Handle connection errors
|
|
186
|
+
|
|
187
|
+
**Example Implementation**:
|
|
188
|
+
```python
|
|
189
|
+
async def on_client_connected(client_id: str) -> None:
|
|
190
|
+
logger.info(f"Client {client_id} connected")
|
|
191
|
+
await db.mark_client_active(client_id)
|
|
192
|
+
|
|
193
|
+
async def on_client_disconnected(client_id: str) -> None:
|
|
194
|
+
logger.info(f"Client {client_id} disconnected")
|
|
195
|
+
await db.mark_client_inactive(client_id)
|
|
196
|
+
```
|
|
197
|
+
"""
|
|
198
|
+
async def __call__(self, client_id: str) -> None:
|
|
199
|
+
"""Handle connection lifecycle event."""
|
|
200
|
+
...
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class ErrorHandler(Protocol):
|
|
204
|
+
"""
|
|
205
|
+
Protocol for handling errors during streaming.
|
|
206
|
+
|
|
207
|
+
**Signature**:
|
|
208
|
+
async def(client_id: str, error: Exception) -> None
|
|
209
|
+
|
|
210
|
+
**Example Implementation**:
|
|
211
|
+
```python
|
|
212
|
+
async def handle_stream_error(client_id: str, error: Exception) -> None:
|
|
213
|
+
logger.error(f"Error for {client_id}: {error}")
|
|
214
|
+
|
|
215
|
+
if isinstance(error, asyncio.CancelledError):
|
|
216
|
+
# Normal cancellation, just log
|
|
217
|
+
pass
|
|
218
|
+
elif isinstance(error, grpc.RpcError):
|
|
219
|
+
# gRPC-specific error handling
|
|
220
|
+
await notify_admin(client_id, error)
|
|
221
|
+
else:
|
|
222
|
+
# Unexpected error, escalate
|
|
223
|
+
raise
|
|
224
|
+
```
|
|
225
|
+
"""
|
|
226
|
+
async def __call__(self, client_id: str, error: Exception) -> None:
|
|
227
|
+
"""Handle streaming error."""
|
|
228
|
+
...
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# ============================================================================
|
|
232
|
+
# Type Aliases for Common Patterns
|
|
233
|
+
# ============================================================================
|
|
234
|
+
|
|
235
|
+
MessageProcessorType = MessageProcessor[Any, Any]
|
|
236
|
+
"""Type alias for MessageProcessor without generic constraints."""
|
|
237
|
+
|
|
238
|
+
ClientIdExtractorType = ClientIdExtractor[Any]
|
|
239
|
+
"""Type alias for ClientIdExtractor without generic constraints."""
|
|
240
|
+
|
|
241
|
+
PingMessageCreatorType = PingMessageCreator[Any]
|
|
242
|
+
"""Type alias for PingMessageCreator without generic constraints."""
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# ============================================================================
|
|
246
|
+
# Type Guards and Validation
|
|
247
|
+
# ============================================================================
|
|
248
|
+
|
|
249
|
+
def is_valid_message_processor(func: Any) -> bool:
|
|
250
|
+
"""
|
|
251
|
+
Runtime check if function matches MessageProcessor protocol.
|
|
252
|
+
|
|
253
|
+
**Parameters**:
|
|
254
|
+
func: Function to validate
|
|
255
|
+
|
|
256
|
+
**Returns**:
|
|
257
|
+
True if function signature matches protocol
|
|
258
|
+
|
|
259
|
+
**Example**:
|
|
260
|
+
```python
|
|
261
|
+
async def my_processor(client_id: str, msg: Command, queue: Queue) -> None:
|
|
262
|
+
pass
|
|
263
|
+
|
|
264
|
+
assert is_valid_message_processor(my_processor) # ✅
|
|
265
|
+
```
|
|
266
|
+
"""
|
|
267
|
+
if not callable(func):
|
|
268
|
+
return False
|
|
269
|
+
|
|
270
|
+
import inspect
|
|
271
|
+
sig = inspect.signature(func)
|
|
272
|
+
params = list(sig.parameters.values())
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
len(params) == 3 and
|
|
276
|
+
params[0].annotation in (str, inspect.Parameter.empty) and
|
|
277
|
+
inspect.iscoroutinefunction(func)
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def is_valid_client_id_extractor(func: Any) -> bool:
|
|
282
|
+
"""
|
|
283
|
+
Runtime check if function matches ClientIdExtractor protocol.
|
|
284
|
+
|
|
285
|
+
**Parameters**:
|
|
286
|
+
func: Function to validate
|
|
287
|
+
|
|
288
|
+
**Returns**:
|
|
289
|
+
True if function signature matches protocol
|
|
290
|
+
|
|
291
|
+
**Example**:
|
|
292
|
+
```python
|
|
293
|
+
def extract_id(msg: Command) -> str:
|
|
294
|
+
return msg.client_id
|
|
295
|
+
|
|
296
|
+
assert is_valid_client_id_extractor(extract_id) # ✅
|
|
297
|
+
```
|
|
298
|
+
"""
|
|
299
|
+
if not callable(func):
|
|
300
|
+
return False
|
|
301
|
+
|
|
302
|
+
import inspect
|
|
303
|
+
sig = inspect.signature(func)
|
|
304
|
+
params = list(sig.parameters.values())
|
|
305
|
+
|
|
306
|
+
return (
|
|
307
|
+
len(params) == 1 and
|
|
308
|
+
sig.return_annotation in (str, inspect.Parameter.empty)
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def is_valid_ping_creator(func: Any) -> bool:
|
|
313
|
+
"""
|
|
314
|
+
Runtime check if function matches PingMessageCreator protocol.
|
|
315
|
+
|
|
316
|
+
**Parameters**:
|
|
317
|
+
func: Function to validate
|
|
318
|
+
|
|
319
|
+
**Returns**:
|
|
320
|
+
True if function signature matches protocol
|
|
321
|
+
|
|
322
|
+
**Example**:
|
|
323
|
+
```python
|
|
324
|
+
def create_ping() -> Message:
|
|
325
|
+
return Message(is_ping=True)
|
|
326
|
+
|
|
327
|
+
assert is_valid_ping_creator(create_ping) # ✅
|
|
328
|
+
```
|
|
329
|
+
"""
|
|
330
|
+
if not callable(func):
|
|
331
|
+
return False
|
|
332
|
+
|
|
333
|
+
import inspect
|
|
334
|
+
sig = inspect.signature(func)
|
|
335
|
+
params = list(sig.parameters.values())
|
|
336
|
+
|
|
337
|
+
return len(params) == 0
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
# ============================================================================
|
|
341
|
+
# Exports
|
|
342
|
+
# ============================================================================
|
|
343
|
+
|
|
344
|
+
__all__ = [
|
|
345
|
+
# Type variables
|
|
346
|
+
'TMessage',
|
|
347
|
+
'TCommand',
|
|
348
|
+
|
|
349
|
+
# Core protocols
|
|
350
|
+
'MessageProcessor',
|
|
351
|
+
'ClientIdExtractor',
|
|
352
|
+
'PingMessageCreator',
|
|
353
|
+
|
|
354
|
+
# Connection protocols
|
|
355
|
+
'ConnectionCallback',
|
|
356
|
+
'ErrorHandler',
|
|
357
|
+
|
|
358
|
+
# Type aliases
|
|
359
|
+
'MessageProcessorType',
|
|
360
|
+
'ClientIdExtractorType',
|
|
361
|
+
'PingMessageCreatorType',
|
|
362
|
+
|
|
363
|
+
# Validation
|
|
364
|
+
'is_valid_message_processor',
|
|
365
|
+
'is_valid_client_id_extractor',
|
|
366
|
+
'is_valid_ping_creator',
|
|
367
|
+
]
|
|
@@ -2,8 +2,65 @@
|
|
|
2
2
|
Utilities for gRPC Integration.
|
|
3
3
|
|
|
4
4
|
Reusable utilities for gRPC services in django-cfg.
|
|
5
|
+
|
|
6
|
+
**Available Modules**:
|
|
7
|
+
- streaming_logger: Rich logging for gRPC streams
|
|
8
|
+
- converters: Protobuf ↔ Python conversions (Pydantic configured)
|
|
9
|
+
- handlers: gRPC handler factory utilities
|
|
10
|
+
|
|
11
|
+
**Quick Imports**:
|
|
12
|
+
```python
|
|
13
|
+
from django_cfg.apps.integrations.grpc.utils import (
|
|
14
|
+
# Logging
|
|
15
|
+
setup_streaming_logger,
|
|
16
|
+
get_streaming_logger,
|
|
17
|
+
|
|
18
|
+
# Converters
|
|
19
|
+
ProtobufConverterMixin,
|
|
20
|
+
ConverterConfig,
|
|
21
|
+
|
|
22
|
+
# Handlers
|
|
23
|
+
create_grpc_handler,
|
|
24
|
+
)
|
|
25
|
+
```
|
|
5
26
|
"""
|
|
6
27
|
|
|
7
28
|
from .streaming_logger import setup_streaming_logger, get_streaming_logger
|
|
29
|
+
from .converters import (
|
|
30
|
+
ConverterConfig,
|
|
31
|
+
ProtobufConverterMixin,
|
|
32
|
+
datetime_to_timestamp,
|
|
33
|
+
timestamp_to_datetime,
|
|
34
|
+
dict_to_struct,
|
|
35
|
+
struct_to_dict,
|
|
36
|
+
)
|
|
37
|
+
from .handlers import (
|
|
38
|
+
create_grpc_handler,
|
|
39
|
+
create_multiple_grpc_handlers,
|
|
40
|
+
validate_grpc_handler,
|
|
41
|
+
validate_grpc_handlers,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
# Logging
|
|
46
|
+
"setup_streaming_logger",
|
|
47
|
+
"get_streaming_logger",
|
|
48
|
+
|
|
49
|
+
# Converters - Config
|
|
50
|
+
"ConverterConfig",
|
|
51
|
+
|
|
52
|
+
# Converters - Mixin
|
|
53
|
+
"ProtobufConverterMixin",
|
|
54
|
+
|
|
55
|
+
# Converters - Standalone functions
|
|
56
|
+
"datetime_to_timestamp",
|
|
57
|
+
"timestamp_to_datetime",
|
|
58
|
+
"dict_to_struct",
|
|
59
|
+
"struct_to_dict",
|
|
8
60
|
|
|
9
|
-
|
|
61
|
+
# Handlers
|
|
62
|
+
"create_grpc_handler",
|
|
63
|
+
"create_multiple_grpc_handlers",
|
|
64
|
+
"validate_grpc_handler",
|
|
65
|
+
"validate_grpc_handlers",
|
|
66
|
+
]
|