django-cfg 1.4.62__py3-none-any.whl → 1.4.63__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.

Files changed (181) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/services/otp_service.py +3 -14
  3. django_cfg/apps/centrifugo/__init__.py +57 -0
  4. django_cfg/apps/centrifugo/admin/__init__.py +13 -0
  5. django_cfg/apps/centrifugo/admin/centrifugo_log.py +249 -0
  6. django_cfg/apps/centrifugo/admin/config.py +82 -0
  7. django_cfg/apps/centrifugo/apps.py +31 -0
  8. django_cfg/apps/centrifugo/codegen/IMPLEMENTATION_SUMMARY.md +475 -0
  9. django_cfg/apps/centrifugo/codegen/README.md +242 -0
  10. django_cfg/apps/centrifugo/codegen/USAGE.md +616 -0
  11. django_cfg/apps/centrifugo/codegen/__init__.py +19 -0
  12. django_cfg/apps/centrifugo/codegen/discovery.py +246 -0
  13. django_cfg/apps/centrifugo/codegen/generators/go_thin/__init__.py +5 -0
  14. django_cfg/apps/centrifugo/codegen/generators/go_thin/generator.py +174 -0
  15. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/README.md.j2 +182 -0
  16. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/client.go.j2 +64 -0
  17. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/go.mod.j2 +10 -0
  18. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2 +300 -0
  19. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2.old +267 -0
  20. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/types.go.j2 +16 -0
  21. django_cfg/apps/centrifugo/codegen/generators/python_thin/__init__.py +7 -0
  22. django_cfg/apps/centrifugo/codegen/generators/python_thin/generator.py +241 -0
  23. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/README.md.j2 +128 -0
  24. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/__init__.py.j2 +22 -0
  25. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/client.py.j2 +73 -0
  26. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/models.py.j2 +19 -0
  27. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/requirements.txt.j2 +8 -0
  28. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/rpc_client.py.j2 +193 -0
  29. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/__init__.py +5 -0
  30. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/generator.py +124 -0
  31. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/README.md.j2 +38 -0
  32. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/client.ts.j2 +25 -0
  33. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/index.ts.j2 +12 -0
  34. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/package.json.j2 +13 -0
  35. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +137 -0
  36. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/tsconfig.json.j2 +14 -0
  37. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/types.ts.j2 +9 -0
  38. django_cfg/apps/centrifugo/codegen/utils/__init__.py +37 -0
  39. django_cfg/apps/centrifugo/codegen/utils/naming.py +155 -0
  40. django_cfg/apps/centrifugo/codegen/utils/type_converter.py +349 -0
  41. django_cfg/apps/centrifugo/decorators.py +137 -0
  42. django_cfg/apps/centrifugo/management/__init__.py +1 -0
  43. django_cfg/apps/centrifugo/management/commands/__init__.py +1 -0
  44. django_cfg/apps/centrifugo/management/commands/generate_centrifugo_clients.py +254 -0
  45. django_cfg/apps/centrifugo/managers/__init__.py +12 -0
  46. django_cfg/apps/centrifugo/managers/centrifugo_log.py +264 -0
  47. django_cfg/apps/centrifugo/migrations/0001_initial.py +164 -0
  48. django_cfg/apps/centrifugo/migrations/__init__.py +3 -0
  49. django_cfg/apps/centrifugo/models/__init__.py +11 -0
  50. django_cfg/apps/centrifugo/models/centrifugo_log.py +210 -0
  51. django_cfg/apps/centrifugo/registry.py +106 -0
  52. django_cfg/apps/centrifugo/router.py +125 -0
  53. django_cfg/apps/centrifugo/serializers/__init__.py +40 -0
  54. django_cfg/apps/centrifugo/serializers/admin_api.py +264 -0
  55. django_cfg/apps/centrifugo/serializers/channels.py +26 -0
  56. django_cfg/apps/centrifugo/serializers/health.py +17 -0
  57. django_cfg/apps/centrifugo/serializers/publishes.py +16 -0
  58. django_cfg/apps/centrifugo/serializers/stats.py +21 -0
  59. django_cfg/apps/centrifugo/services/__init__.py +12 -0
  60. django_cfg/apps/centrifugo/services/client/__init__.py +29 -0
  61. django_cfg/apps/centrifugo/services/client/client.py +577 -0
  62. django_cfg/apps/centrifugo/services/client/config.py +228 -0
  63. django_cfg/apps/centrifugo/services/client/exceptions.py +212 -0
  64. django_cfg/apps/centrifugo/services/config_helper.py +63 -0
  65. django_cfg/apps/centrifugo/services/dashboard_notifier.py +157 -0
  66. django_cfg/apps/centrifugo/services/logging.py +677 -0
  67. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +260 -0
  68. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +313 -0
  69. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +803 -0
  70. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +333 -0
  71. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +432 -0
  72. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +33 -0
  73. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +210 -0
  74. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +46 -0
  75. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +123 -0
  76. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +45 -0
  77. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +84 -0
  78. django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/stat_cards.html +23 -20
  79. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +91 -0
  80. django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/tab_navigation.html +15 -15
  81. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +415 -0
  82. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +61 -0
  83. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +58 -0
  84. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +48 -0
  85. django_cfg/apps/centrifugo/templatetags/__init__.py +1 -0
  86. django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +81 -0
  87. django_cfg/apps/centrifugo/urls.py +31 -0
  88. django_cfg/apps/{ipc → centrifugo}/urls_admin.py +4 -4
  89. django_cfg/apps/centrifugo/views/__init__.py +15 -0
  90. django_cfg/apps/centrifugo/views/admin_api.py +374 -0
  91. django_cfg/apps/centrifugo/views/dashboard.py +15 -0
  92. django_cfg/apps/centrifugo/views/monitoring.py +286 -0
  93. django_cfg/apps/centrifugo/views/testing_api.py +422 -0
  94. django_cfg/apps/support/utils/support_email_service.py +5 -18
  95. django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -2
  96. django_cfg/apps/urls.py +5 -5
  97. django_cfg/core/base/config_model.py +4 -44
  98. django_cfg/core/builders/apps_builder.py +2 -2
  99. django_cfg/core/generation/integration_generators/third_party.py +8 -8
  100. django_cfg/core/utils/__init__.py +5 -0
  101. django_cfg/core/utils/url_helpers.py +73 -0
  102. django_cfg/modules/base.py +7 -7
  103. django_cfg/modules/django_client/core/__init__.py +2 -1
  104. django_cfg/modules/django_client/core/config/config.py +8 -0
  105. django_cfg/modules/django_client/core/generator/__init__.py +42 -2
  106. django_cfg/modules/django_client/core/generator/go/__init__.py +14 -0
  107. django_cfg/modules/django_client/core/generator/go/client_generator.py +124 -0
  108. django_cfg/modules/django_client/core/generator/go/files_generator.py +133 -0
  109. django_cfg/modules/django_client/core/generator/go/generator.py +203 -0
  110. django_cfg/modules/django_client/core/generator/go/models_generator.py +304 -0
  111. django_cfg/modules/django_client/core/generator/go/naming.py +193 -0
  112. django_cfg/modules/django_client/core/generator/go/operations_generator.py +134 -0
  113. django_cfg/modules/django_client/core/generator/go/templates/Makefile.j2 +38 -0
  114. django_cfg/modules/django_client/core/generator/go/templates/README.md.j2 +55 -0
  115. django_cfg/modules/django_client/core/generator/go/templates/client.go.j2 +122 -0
  116. django_cfg/modules/django_client/core/generator/go/templates/enums.go.j2 +49 -0
  117. django_cfg/modules/django_client/core/generator/go/templates/errors.go.j2 +182 -0
  118. django_cfg/modules/django_client/core/generator/go/templates/go.mod.j2 +6 -0
  119. django_cfg/modules/django_client/core/generator/go/templates/main_client.go.j2 +60 -0
  120. django_cfg/modules/django_client/core/generator/go/templates/middleware.go.j2 +388 -0
  121. django_cfg/modules/django_client/core/generator/go/templates/models.go.j2 +28 -0
  122. django_cfg/modules/django_client/core/generator/go/templates/operations_client.go.j2 +142 -0
  123. django_cfg/modules/django_client/core/generator/go/templates/validation.go.j2 +217 -0
  124. django_cfg/modules/django_client/core/generator/go/type_mapper.py +380 -0
  125. django_cfg/modules/django_client/management/commands/generate_client.py +53 -3
  126. django_cfg/modules/django_client/system/generate_mjs_clients.py +3 -1
  127. django_cfg/modules/django_client/system/schema_parser.py +5 -1
  128. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +1 -0
  129. django_cfg/modules/django_twilio/sendgrid_service.py +7 -4
  130. django_cfg/modules/django_unfold/dashboard.py +25 -19
  131. django_cfg/pyproject.toml +1 -1
  132. django_cfg/registry/core.py +2 -0
  133. django_cfg/registry/modules.py +2 -2
  134. django_cfg/static/js/api/centrifugo/client.mjs +164 -0
  135. django_cfg/static/js/api/centrifugo/index.mjs +13 -0
  136. django_cfg/static/js/api/index.mjs +5 -5
  137. django_cfg/static/js/api/types.mjs +89 -26
  138. {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/METADATA +1 -1
  139. {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/RECORD +142 -70
  140. django_cfg/apps/ipc/README.md +0 -346
  141. django_cfg/apps/ipc/RPC_LOGGING.md +0 -321
  142. django_cfg/apps/ipc/TESTING.md +0 -539
  143. django_cfg/apps/ipc/__init__.py +0 -60
  144. django_cfg/apps/ipc/admin.py +0 -232
  145. django_cfg/apps/ipc/apps.py +0 -98
  146. django_cfg/apps/ipc/migrations/0001_initial.py +0 -137
  147. django_cfg/apps/ipc/migrations/0002_rpclog_is_event.py +0 -23
  148. django_cfg/apps/ipc/migrations/__init__.py +0 -0
  149. django_cfg/apps/ipc/models.py +0 -229
  150. django_cfg/apps/ipc/serializers/__init__.py +0 -29
  151. django_cfg/apps/ipc/serializers/serializers.py +0 -343
  152. django_cfg/apps/ipc/services/__init__.py +0 -7
  153. django_cfg/apps/ipc/services/client/__init__.py +0 -23
  154. django_cfg/apps/ipc/services/client/client.py +0 -621
  155. django_cfg/apps/ipc/services/client/config.py +0 -214
  156. django_cfg/apps/ipc/services/client/exceptions.py +0 -201
  157. django_cfg/apps/ipc/services/logging.py +0 -239
  158. django_cfg/apps/ipc/services/monitor.py +0 -466
  159. django_cfg/apps/ipc/services/rpc_log_consumer.py +0 -330
  160. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/main.mjs +0 -269
  161. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/overview.mjs +0 -259
  162. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/testing.mjs +0 -375
  163. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs.old +0 -441
  164. django_cfg/apps/ipc/templates/django_cfg_ipc/components/methods_content.html +0 -22
  165. django_cfg/apps/ipc/templates/django_cfg_ipc/components/notifications_content.html +0 -9
  166. django_cfg/apps/ipc/templates/django_cfg_ipc/components/overview_content.html +0 -9
  167. django_cfg/apps/ipc/templates/django_cfg_ipc/components/requests_content.html +0 -23
  168. django_cfg/apps/ipc/templates/django_cfg_ipc/components/system_status.html +0 -47
  169. django_cfg/apps/ipc/templates/django_cfg_ipc/components/testing_tools.html +0 -184
  170. django_cfg/apps/ipc/templates/django_cfg_ipc/layout/base.html +0 -71
  171. django_cfg/apps/ipc/templates/django_cfg_ipc/pages/dashboard.html +0 -56
  172. django_cfg/apps/ipc/urls.py +0 -23
  173. django_cfg/apps/ipc/views/__init__.py +0 -13
  174. django_cfg/apps/ipc/views/dashboard.py +0 -15
  175. django_cfg/apps/ipc/views/monitoring.py +0 -251
  176. django_cfg/apps/ipc/views/testing.py +0 -285
  177. django_cfg/static/js/api/ipc/client.mjs +0 -114
  178. django_cfg/static/js/api/ipc/index.mjs +0 -13
  179. {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/WHEEL +0 -0
  180. {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/entry_points.txt +0 -0
  181. {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,616 @@
1
+ # Centrifugo Client Code Generation - Usage Guide
2
+
3
+ ## Overview
4
+
5
+ Автоматическая генерация type-safe клиентов для Centrifugo WebSocket RPC из Python обработчиков.
6
+
7
+ **Архитектура:**
8
+ - Используется Pydantic как единый источник правды
9
+ - Декоратор `@websocket_rpc` регистрирует обработчики
10
+ - Discovery извлекает типы из сигнатур функций
11
+ - Генераторы создают тонкие обёртки над базовыми RPC клиентами
12
+
13
+ ## Quick Start
14
+
15
+ ### 1. Создайте RPC Handler
16
+
17
+ ```python
18
+ # myapp/handlers.py
19
+ from pydantic import BaseModel, Field
20
+ from django_cfg.apps.centrifugo.decorators import websocket_rpc
21
+
22
+ class TaskStatsParams(BaseModel):
23
+ user_id: str = Field(..., description="User ID")
24
+ limit: int = Field(10, description="Max results")
25
+
26
+ class TaskStatsResult(BaseModel):
27
+ total: int = Field(..., description="Total tasks")
28
+ completed: int = Field(..., description="Completed tasks")
29
+
30
+ @websocket_rpc("tasks.get_stats")
31
+ async def get_task_stats(conn, params: TaskStatsParams) -> TaskStatsResult:
32
+ """Get task statistics for user."""
33
+ # Ваша бизнес-логика
34
+ return TaskStatsResult(total=100, completed=75)
35
+ ```
36
+
37
+ ### 2. Импортируйте Handlers в AppConfig
38
+
39
+ ```python
40
+ # myapp/apps.py
41
+ class MyAppConfig(AppConfig):
42
+ def ready(self):
43
+ # Импортируйте handlers чтобы декораторы сработали
44
+ from . import handlers
45
+ ```
46
+
47
+ ### 3. Сгенерируйте Клиенты
48
+
49
+ ```bash
50
+ # Все языки
51
+ python manage.py generate_centrifugo_clients --output ./clients --all
52
+
53
+ # Только Python
54
+ python manage.py generate_centrifugo_clients --output ./clients --python
55
+
56
+ # Только TypeScript
57
+ python manage.py generate_centrifugo_clients --output ./clients --typescript
58
+
59
+ # Только Go
60
+ python manage.py generate_centrifugo_clients --output ./clients --go
61
+
62
+ # С verbose выводом
63
+ python manage.py generate_centrifugo_clients --output ./clients --all --verbose
64
+ ```
65
+
66
+ ### 4. Используйте Сгенерированные Клиенты
67
+
68
+ **Python:**
69
+ ```python
70
+ from clients.python import CentrifugoRPCClient, APIClient
71
+ from clients.python.models import TaskStatsParams
72
+
73
+ async def main():
74
+ rpc = CentrifugoRPCClient(
75
+ url='ws://localhost:8000/connection/websocket',
76
+ token='jwt-token',
77
+ user_id='user-123'
78
+ )
79
+ await rpc.connect()
80
+
81
+ api = APIClient(rpc)
82
+ result = await api.tasks_get_stats(
83
+ TaskStatsParams(user_id='user-123', limit=10)
84
+ )
85
+ print(f"Total: {result.total}, Completed: {result.completed}")
86
+
87
+ await rpc.disconnect()
88
+ ```
89
+
90
+ **TypeScript:**
91
+ ```typescript
92
+ import { CentrifugoRPCClient, APIClient } from './clients/typescript';
93
+ import type { TaskStatsParams } from './clients/typescript';
94
+
95
+ const rpc = new CentrifugoRPCClient(
96
+ 'ws://localhost:8000/connection/websocket',
97
+ 'jwt-token',
98
+ 'user-123'
99
+ );
100
+ await rpc.connect();
101
+
102
+ const api = new APIClient(rpc);
103
+ const result = await api.tasksGetStats({
104
+ user_id: 'user-123',
105
+ limit: 10
106
+ });
107
+ console.log(`Total: ${result.total}, Completed: ${result.completed}`);
108
+
109
+ await rpc.disconnect();
110
+ ```
111
+
112
+ **Go:**
113
+ ```go
114
+ import (
115
+ "context"
116
+ client "path/to/clients/go"
117
+ )
118
+
119
+ func main() {
120
+ ctx := context.Background()
121
+ api := client.NewAPIClient(
122
+ "ws://localhost:8000/connection/websocket",
123
+ "jwt-token",
124
+ "user-123",
125
+ )
126
+
127
+ if err := api.Connect(ctx); err != nil {
128
+ log.Fatal(err)
129
+ }
130
+ defer api.Disconnect()
131
+
132
+ result, err := api.TasksGetStats(ctx, client.TaskStatsParams{
133
+ UserId: "user-123",
134
+ Limit: 10,
135
+ })
136
+ if err != nil {
137
+ log.Fatal(err)
138
+ }
139
+
140
+ fmt.Printf("Total: %d, Completed: %d\n", result.Total, result.Completed)
141
+ }
142
+ ```
143
+
144
+ ## Декоратор @websocket_rpc
145
+
146
+ ### Базовое Использование
147
+
148
+ ```python
149
+ from django_cfg.apps.centrifugo.decorators import websocket_rpc
150
+ from pydantic import BaseModel
151
+
152
+ class MyParams(BaseModel):
153
+ name: str
154
+
155
+ class MyResult(BaseModel):
156
+ message: str
157
+
158
+ @websocket_rpc("my.method")
159
+ async def my_handler(conn, params: MyParams) -> MyResult:
160
+ """Handler docstring (будет в генерируемых клиентах)."""
161
+ return MyResult(message=f"Hello {params.name}")
162
+ ```
163
+
164
+ ### Регистрация
165
+
166
+ Декоратор автоматически регистрирует обработчик в:
167
+ 1. **MessageRouter** - для runtime обработки сообщений
168
+ 2. **RPCRegistry** - для code generation (discovery)
169
+
170
+ ### Type Hints
171
+
172
+ Обязательно указывайте типы:
173
+ - `params: YourParamsModel` - Pydantic модель параметров
174
+ - `-> YourResultModel` - Pydantic модель результата
175
+
176
+ Discovery извлекает эти типы для генерации клиентов.
177
+
178
+ ## Архитектура Генераторов
179
+
180
+ ### Thin Wrapper Pattern
181
+
182
+ Генерируется 2 слоя:
183
+
184
+ 1. **Base RPC Client** (`rpc_client.py/ts/go`)
185
+ - Управляет WebSocket соединением
186
+ - Реализует correlation ID pattern
187
+ - Отправляет запросы на канал `rpc.requests`
188
+ - Получает ответы на канал `user#{user_id}`
189
+ - Мэтчит ответы по correlation_id
190
+
191
+ 2. **Typed API Client** (`client.py/ts/go`)
192
+ - Тонкая обёртка над base client
193
+ - Type-safe методы для каждого RPC endpoint
194
+ - Автоматическая сериализация/десериализация
195
+ - IDE autocomplete, type checking
196
+
197
+ ### Correlation ID Pattern
198
+
199
+ ```
200
+ Client Centrifugo Server
201
+ | | |
202
+ |-- publish('rpc.requests') ------->| |
203
+ | { | |
204
+ | method: 'tasks.get_stats', | |
205
+ | params: {...}, | |
206
+ | correlation_id: 'uuid-123', | |
207
+ | reply_to: 'user#123' | |
208
+ | } | |
209
+ | |-- subscribe to channel -->|
210
+ | | |
211
+ | |<-- publish to user#123 ---|
212
+ |<-- receive on user#123 -----------| { |
213
+ | { | correlation_id: ... |
214
+ | correlation_id: 'uuid-123', | result: {...} |
215
+ | result: {...} | } |
216
+ | } | |
217
+ ```
218
+
219
+ ## Структура Сгенерированных Файлов
220
+
221
+ ### Python Client
222
+
223
+ ```
224
+ clients/python/
225
+ ├── __init__.py # Exports: CentrifugoRPCClient, APIClient, models
226
+ ├── models.py # Pydantic models
227
+ ├── rpc_client.py # CentrifugoRPCClient (base)
228
+ ├── client.py # APIClient (thin wrapper)
229
+ ├── requirements.txt # Dependencies: centrifuge, pydantic
230
+ └── README.md # Usage documentation
231
+ ```
232
+
233
+ ### TypeScript Client
234
+
235
+ ```
236
+ clients/typescript/
237
+ ├── index.ts # Exports: CentrifugoRPCClient, APIClient, types
238
+ ├── types.ts # TypeScript interfaces
239
+ ├── rpc-client.ts # CentrifugoRPCClient (base)
240
+ ├── client.ts # APIClient (thin wrapper)
241
+ ├── package.json # Dependencies: centrifuge
242
+ ├── tsconfig.json # TypeScript config
243
+ └── README.md # Usage documentation
244
+ ```
245
+
246
+ ### Go Client
247
+
248
+ ```
249
+ clients/go/
250
+ ├── types.go # Go structs
251
+ ├── rpc_client.go # CentrifugoRPCClient (base)
252
+ ├── client.go # APIClient (thin wrapper)
253
+ ├── go.mod # Dependencies: centrifuge-go
254
+ └── README.md # Usage documentation
255
+ ```
256
+
257
+ ## Management Command
258
+
259
+ ### Опции
260
+
261
+ ```bash
262
+ python manage.py generate_centrifugo_clients \
263
+ --output ./clients \ # Директория для клиентов (обязательно)
264
+ --python \ # Генерировать Python клиент
265
+ --typescript \ # Генерировать TypeScript клиент
266
+ --go \ # Генерировать Go клиент
267
+ --all \ # Генерировать все клиенты
268
+ --router-path myapp.router \ # Кастомный router (опционально)
269
+ --verbose # Verbose вывод
270
+ ```
271
+
272
+ ### Примеры
273
+
274
+ ```bash
275
+ # Все языки с verbose
276
+ python manage.py generate_centrifugo_clients -o ./sdk --all --verbose
277
+
278
+ # Только Python и TypeScript
279
+ python manage.py generate_centrifugo_clients -o ./sdk --python --typescript
280
+
281
+ # Кастомный router
282
+ python manage.py generate_centrifugo_clients \
283
+ -o ./sdk \
284
+ --all \
285
+ --router-path myapp.custom_router.router
286
+ ```
287
+
288
+ ### Вывод
289
+
290
+ ```
291
+ Centrifugo Client Code Generation
292
+ ============================================================
293
+ Using global MessageRouter
294
+
295
+ Discovering RPC methods...
296
+ Found 3 RPC methods
297
+ - tasks.get_stats: TaskStatsParams -> TaskStats
298
+ - users.get_profile: UserProfileParams -> UserProfile
299
+ - notifications.send: NotificationParams -> NotificationResult
300
+
301
+ Output directory: ./clients
302
+
303
+ Generating Python client...
304
+ ✓ Generated at: ./clients/python
305
+
306
+ Generating TypeScript client...
307
+ ✓ Generated at: ./clients/typescript
308
+
309
+ Generating Go client...
310
+ ✓ Generated at: ./clients/go
311
+
312
+ ============================================================
313
+ Successfully generated 3 client(s): Python, TypeScript, Go
314
+
315
+ Next steps:
316
+ cd ./clients/python && pip install -r requirements.txt
317
+ cd ./clients/typescript && npm install
318
+ cd ./clients/go && go mod tidy
319
+ ```
320
+
321
+ ## Advanced Usage
322
+
323
+ ### Кастомный Router
324
+
325
+ ```python
326
+ # myapp/routers.py
327
+ from django_cfg.apps.centrifugo.router import MessageRouter
328
+
329
+ custom_router = MessageRouter()
330
+
331
+ @custom_router.register("custom.method")
332
+ async def custom_handler(conn, params):
333
+ return {"result": "custom"}
334
+ ```
335
+
336
+ Затем:
337
+ ```bash
338
+ python manage.py generate_centrifugo_clients \
339
+ --output ./clients \
340
+ --all \
341
+ --router-path myapp.routers.custom_router
342
+ ```
343
+
344
+ ### Optional Fields
345
+
346
+ Pydantic опциональные поля → nullable в клиентах:
347
+
348
+ ```python
349
+ class Params(BaseModel):
350
+ required: str
351
+ optional: Optional[str] = None
352
+ ```
353
+
354
+ TypeScript:
355
+ ```typescript
356
+ interface Params {
357
+ required: string;
358
+ optional?: string | null;
359
+ }
360
+ ```
361
+
362
+ Go:
363
+ ```go
364
+ type Params struct {
365
+ Required string `json:"required"`
366
+ Optional *string `json:"optional"`
367
+ }
368
+ ```
369
+
370
+ ### Nested Models
371
+
372
+ ```python
373
+ class Address(BaseModel):
374
+ city: str
375
+ country: str
376
+
377
+ class User(BaseModel):
378
+ name: str
379
+ address: Address
380
+ ```
381
+
382
+ Автоматически генерируются все nested модели.
383
+
384
+ ### List/Dict Fields
385
+
386
+ ```python
387
+ class Data(BaseModel):
388
+ tags: List[str]
389
+ metadata: Dict[str, Any]
390
+ ```
391
+
392
+ TypeScript:
393
+ ```typescript
394
+ interface Data {
395
+ tags: string[];
396
+ metadata: { [key: string]: any };
397
+ }
398
+ ```
399
+
400
+ Go:
401
+ ```go
402
+ type Data struct {
403
+ Tags []string `json:"tags"`
404
+ Metadata map[string]interface{} `json:"metadata"`
405
+ }
406
+ ```
407
+
408
+ ## Type Conversion
409
+
410
+ ### Python → TypeScript
411
+
412
+ | Python | TypeScript |
413
+ |-----------------------|-------------------------|
414
+ | `str` | `string` |
415
+ | `int`, `float` | `number` |
416
+ | `bool` | `boolean` |
417
+ | `List[T]` | `T[]` |
418
+ | `Dict[str, T]` | `{ [key: string]: T }` |
419
+ | `Optional[T]` | `T \| null` |
420
+ | `datetime` | `string` (ISO 8601) |
421
+ | `BaseModel` | `interface` |
422
+
423
+ ### Python → Go
424
+
425
+ | Python | Go |
426
+ |-----------------------|-------------------------|
427
+ | `str` | `string` |
428
+ | `int` | `int64` |
429
+ | `float` | `float64` |
430
+ | `bool` | `bool` |
431
+ | `List[T]` | `[]T` |
432
+ | `Dict[str, T]` | `map[string]T` |
433
+ | `Optional[T]` | `*T` |
434
+ | `datetime` | `time.Time` |
435
+ | `BaseModel` | `struct` |
436
+
437
+ ## Best Practices
438
+
439
+ ### 1. Используйте Field с description
440
+
441
+ ```python
442
+ class Params(BaseModel):
443
+ user_id: str = Field(..., description="User ID to fetch")
444
+ limit: int = Field(10, description="Maximum results")
445
+ ```
446
+
447
+ Генерирует комментарии в клиентах:
448
+ ```typescript
449
+ interface Params {
450
+ /** User ID to fetch */
451
+ user_id: string;
452
+ /** Maximum results */
453
+ limit?: number;
454
+ }
455
+ ```
456
+
457
+ ### 2. Добавляйте Docstrings
458
+
459
+ ```python
460
+ @websocket_rpc("users.get")
461
+ async def get_user(conn, params: GetUserParams) -> User:
462
+ """
463
+ Get user by ID.
464
+
465
+ Retrieves full user profile including permissions and settings.
466
+ """
467
+ ...
468
+ ```
469
+
470
+ Docstring попадает в README клиентов.
471
+
472
+ ### 3. Версионирование API
473
+
474
+ ```python
475
+ @websocket_rpc("users.v2.get")
476
+ async def get_user_v2(conn, params: GetUserParamsV2) -> UserV2:
477
+ """Get user (API v2)."""
478
+ ...
479
+ ```
480
+
481
+ ### 4. Namespace Methods
482
+
483
+ ```python
484
+ @websocket_rpc("tasks.list")
485
+ @websocket_rpc("tasks.create")
486
+ @websocket_rpc("tasks.update")
487
+ @websocket_rpc("tasks.delete")
488
+ ```
489
+
490
+ Генерирует:
491
+ ```python
492
+ api.tasks_list(...)
493
+ api.tasks_create(...)
494
+ api.tasks_update(...)
495
+ api.tasks_delete(...)
496
+ ```
497
+
498
+ ### 5. Error Handling
499
+
500
+ ```python
501
+ class ErrorResult(BaseModel):
502
+ error: str
503
+ code: str
504
+
505
+ @websocket_rpc("tasks.get")
506
+ async def get_task(conn, params: GetTaskParams) -> TaskResult:
507
+ if not task_exists(params.task_id):
508
+ raise ValueError("Task not found")
509
+ return TaskResult(...)
510
+ ```
511
+
512
+ Клиент получит exception:
513
+ ```python
514
+ try:
515
+ result = await api.tasks_get(params)
516
+ except Exception as e:
517
+ print(f"Error: {e}")
518
+ ```
519
+
520
+ ## Troubleshooting
521
+
522
+ ### No RPC methods found
523
+
524
+ Проблема: `Found 0 RPC methods`
525
+
526
+ Решение:
527
+ 1. Проверьте что handlers импортированы в `AppConfig.ready()`
528
+ 2. Проверьте что используется `@websocket_rpc` декоратор
529
+ 3. Проверьте type hints на параметрах и return
530
+
531
+ ### Type conversion errors
532
+
533
+ Проблема: Неправильная конвертация типов
534
+
535
+ Решение:
536
+ - Используйте только Pydantic BaseModel для params/result
537
+ - Избегайте Union types (кроме Optional)
538
+ - Используйте стандартные типы (str, int, float, bool, List, Dict)
539
+
540
+ ### Import errors in generated code
541
+
542
+ Проблема: Generated code не импортирует правильно
543
+
544
+ Решение:
545
+ - Убедитесь что все Pydantic модели имеют уникальные имена
546
+ - Проверьте что nested модели тоже BaseModel
547
+ - Regenerate clients после изменения моделей
548
+
549
+ ## Примеры
550
+
551
+ ### Real-Time Notifications
552
+
553
+ ```python
554
+ # Handler
555
+ @websocket_rpc("notifications.subscribe")
556
+ async def subscribe_notifications(conn, params: SubscribeParams) -> SubscriptionResult:
557
+ """Subscribe to user notifications."""
558
+ # Subscribe logic
559
+ return SubscriptionResult(subscription_id="sub-123")
560
+
561
+ # Python client
562
+ result = await api.notifications_subscribe(
563
+ SubscribeParams(user_id="user-123", topics=["orders", "messages"])
564
+ )
565
+ print(f"Subscribed: {result.subscription_id}")
566
+ ```
567
+
568
+ ### Batch Operations
569
+
570
+ ```python
571
+ # Handler
572
+ class BatchTaskParams(BaseModel):
573
+ task_ids: List[str]
574
+
575
+ class BatchTaskResult(BaseModel):
576
+ results: List[TaskStatus]
577
+
578
+ @websocket_rpc("tasks.batch_status")
579
+ async def batch_task_status(conn, params: BatchTaskParams) -> BatchTaskResult:
580
+ """Get status for multiple tasks."""
581
+ statuses = [get_task_status(tid) for tid in params.task_ids]
582
+ return BatchTaskResult(results=statuses)
583
+
584
+ # TypeScript client
585
+ const result = await api.tasksBatchStatus({
586
+ task_ids: ['task-1', 'task-2', 'task-3']
587
+ });
588
+ result.results.forEach(status => console.log(status));
589
+ ```
590
+
591
+ ### Streaming Data
592
+
593
+ ```python
594
+ # Handler
595
+ @websocket_rpc("data.stream")
596
+ async def stream_data(conn, params: StreamParams) -> StreamResult:
597
+ """Start data stream."""
598
+ # Initialize stream
599
+ return StreamResult(stream_id="stream-123", channel="data.stream.123")
600
+
601
+ # Go client
602
+ result, err := api.DataStream(ctx, StreamParams{
603
+ Source: "sensors",
604
+ Limit: 1000,
605
+ })
606
+ if err != nil {
607
+ log.Fatal(err)
608
+ }
609
+ fmt.Printf("Stream ID: %s, Channel: %s\n", result.StreamId, result.Channel)
610
+ ```
611
+
612
+ ## См. также
613
+
614
+ - [Centrifugo Documentation](https://centrifugal.dev/)
615
+ - [Pydantic Documentation](https://docs.pydantic.dev/)
616
+ - [django-ipc (original inspiration)](../../../django-ipc/)
@@ -0,0 +1,19 @@
1
+ """
2
+ Centrifugo WebSocket Client Code Generation.
3
+
4
+ Generates type-safe Python, TypeScript, and Go clients from Pydantic models.
5
+ """
6
+
7
+ from .discovery import (
8
+ RPCMethodInfo,
9
+ discover_rpc_methods_from_router,
10
+ extract_all_models,
11
+ get_method_summary,
12
+ )
13
+
14
+ __all__ = [
15
+ "RPCMethodInfo",
16
+ "discover_rpc_methods_from_router",
17
+ "extract_all_models",
18
+ "get_method_summary",
19
+ ]