django-cfg 1.4.62__py3-none-any.whl → 1.4.64__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/accounts/services/otp_service.py +3 -14
- django_cfg/apps/centrifugo/__init__.py +57 -0
- django_cfg/apps/centrifugo/admin/__init__.py +13 -0
- django_cfg/apps/centrifugo/admin/centrifugo_log.py +249 -0
- django_cfg/apps/centrifugo/admin/config.py +82 -0
- django_cfg/apps/centrifugo/apps.py +31 -0
- django_cfg/apps/centrifugo/codegen/IMPLEMENTATION_SUMMARY.md +475 -0
- django_cfg/apps/centrifugo/codegen/README.md +242 -0
- django_cfg/apps/centrifugo/codegen/USAGE.md +616 -0
- django_cfg/apps/centrifugo/codegen/__init__.py +19 -0
- django_cfg/apps/centrifugo/codegen/discovery.py +246 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/__init__.py +5 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/generator.py +174 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/README.md.j2 +182 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/client.go.j2 +64 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/go.mod.j2 +10 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2 +300 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2.old +267 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/types.go.j2 +16 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/__init__.py +7 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/generator.py +241 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/README.md.j2 +128 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/__init__.py.j2 +22 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/client.py.j2 +73 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/models.py.j2 +19 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/requirements.txt.j2 +8 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/rpc_client.py.j2 +193 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/__init__.py +5 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/generator.py +124 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/README.md.j2 +38 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/client.ts.j2 +25 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/index.ts.j2 +12 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/package.json.j2 +13 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +137 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/tsconfig.json.j2 +14 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/types.ts.j2 +9 -0
- django_cfg/apps/centrifugo/codegen/utils/__init__.py +37 -0
- django_cfg/apps/centrifugo/codegen/utils/naming.py +155 -0
- django_cfg/apps/centrifugo/codegen/utils/type_converter.py +349 -0
- django_cfg/apps/centrifugo/decorators.py +137 -0
- django_cfg/apps/centrifugo/management/__init__.py +1 -0
- django_cfg/apps/centrifugo/management/commands/__init__.py +1 -0
- django_cfg/apps/centrifugo/management/commands/generate_centrifugo_clients.py +254 -0
- django_cfg/apps/centrifugo/managers/__init__.py +12 -0
- django_cfg/apps/centrifugo/managers/centrifugo_log.py +264 -0
- django_cfg/apps/centrifugo/migrations/0001_initial.py +164 -0
- django_cfg/apps/centrifugo/migrations/__init__.py +3 -0
- django_cfg/apps/centrifugo/models/__init__.py +11 -0
- django_cfg/apps/centrifugo/models/centrifugo_log.py +210 -0
- django_cfg/apps/centrifugo/registry.py +106 -0
- django_cfg/apps/centrifugo/router.py +125 -0
- django_cfg/apps/centrifugo/serializers/__init__.py +40 -0
- django_cfg/apps/centrifugo/serializers/admin_api.py +264 -0
- django_cfg/apps/centrifugo/serializers/channels.py +26 -0
- django_cfg/apps/centrifugo/serializers/health.py +17 -0
- django_cfg/apps/centrifugo/serializers/publishes.py +16 -0
- django_cfg/apps/centrifugo/serializers/stats.py +21 -0
- django_cfg/apps/centrifugo/services/__init__.py +12 -0
- django_cfg/apps/centrifugo/services/client/__init__.py +29 -0
- django_cfg/apps/centrifugo/services/client/client.py +582 -0
- django_cfg/apps/centrifugo/services/client/config.py +236 -0
- django_cfg/apps/centrifugo/services/client/exceptions.py +212 -0
- django_cfg/apps/centrifugo/services/config_helper.py +63 -0
- django_cfg/apps/centrifugo/services/dashboard_notifier.py +157 -0
- django_cfg/apps/centrifugo/services/logging.py +677 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +260 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +313 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +803 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +333 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +432 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +33 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +210 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +46 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +123 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +45 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +84 -0
- django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/stat_cards.html +23 -20
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +91 -0
- django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/tab_navigation.html +15 -15
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +415 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +61 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +58 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +48 -0
- django_cfg/apps/centrifugo/templatetags/__init__.py +1 -0
- django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +81 -0
- django_cfg/apps/centrifugo/urls.py +31 -0
- django_cfg/apps/{ipc → centrifugo}/urls_admin.py +4 -4
- django_cfg/apps/centrifugo/views/__init__.py +15 -0
- django_cfg/apps/centrifugo/views/admin_api.py +380 -0
- django_cfg/apps/centrifugo/views/dashboard.py +15 -0
- django_cfg/apps/centrifugo/views/monitoring.py +286 -0
- django_cfg/apps/centrifugo/views/testing_api.py +422 -0
- django_cfg/apps/support/utils/support_email_service.py +5 -18
- django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -2
- django_cfg/apps/urls.py +5 -5
- django_cfg/core/base/config_model.py +4 -44
- django_cfg/core/builders/apps_builder.py +2 -2
- django_cfg/core/generation/integration_generators/third_party.py +8 -8
- django_cfg/core/utils/__init__.py +5 -0
- django_cfg/core/utils/url_helpers.py +73 -0
- django_cfg/modules/base.py +7 -7
- django_cfg/modules/django_client/core/__init__.py +2 -1
- django_cfg/modules/django_client/core/config/config.py +8 -0
- django_cfg/modules/django_client/core/generator/__init__.py +42 -2
- django_cfg/modules/django_client/core/generator/go/__init__.py +14 -0
- django_cfg/modules/django_client/core/generator/go/client_generator.py +124 -0
- django_cfg/modules/django_client/core/generator/go/files_generator.py +133 -0
- django_cfg/modules/django_client/core/generator/go/generator.py +203 -0
- django_cfg/modules/django_client/core/generator/go/models_generator.py +304 -0
- django_cfg/modules/django_client/core/generator/go/naming.py +193 -0
- django_cfg/modules/django_client/core/generator/go/operations_generator.py +134 -0
- django_cfg/modules/django_client/core/generator/go/templates/Makefile.j2 +38 -0
- django_cfg/modules/django_client/core/generator/go/templates/README.md.j2 +55 -0
- django_cfg/modules/django_client/core/generator/go/templates/client.go.j2 +122 -0
- django_cfg/modules/django_client/core/generator/go/templates/enums.go.j2 +49 -0
- django_cfg/modules/django_client/core/generator/go/templates/errors.go.j2 +182 -0
- django_cfg/modules/django_client/core/generator/go/templates/go.mod.j2 +6 -0
- django_cfg/modules/django_client/core/generator/go/templates/main_client.go.j2 +60 -0
- django_cfg/modules/django_client/core/generator/go/templates/middleware.go.j2 +388 -0
- django_cfg/modules/django_client/core/generator/go/templates/models.go.j2 +28 -0
- django_cfg/modules/django_client/core/generator/go/templates/operations_client.go.j2 +142 -0
- django_cfg/modules/django_client/core/generator/go/templates/validation.go.j2 +217 -0
- django_cfg/modules/django_client/core/generator/go/type_mapper.py +380 -0
- django_cfg/modules/django_client/management/commands/generate_client.py +53 -3
- django_cfg/modules/django_client/system/generate_mjs_clients.py +3 -1
- django_cfg/modules/django_client/system/schema_parser.py +5 -1
- django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +1 -0
- django_cfg/modules/django_twilio/sendgrid_service.py +7 -4
- django_cfg/modules/django_unfold/dashboard.py +25 -19
- django_cfg/pyproject.toml +1 -1
- django_cfg/registry/core.py +2 -0
- django_cfg/registry/modules.py +2 -2
- django_cfg/static/js/api/centrifugo/client.mjs +164 -0
- django_cfg/static/js/api/centrifugo/index.mjs +13 -0
- django_cfg/static/js/api/index.mjs +5 -5
- django_cfg/static/js/api/types.mjs +89 -26
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/METADATA +1 -1
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/RECORD +142 -70
- django_cfg/apps/ipc/README.md +0 -346
- django_cfg/apps/ipc/RPC_LOGGING.md +0 -321
- django_cfg/apps/ipc/TESTING.md +0 -539
- django_cfg/apps/ipc/__init__.py +0 -60
- django_cfg/apps/ipc/admin.py +0 -232
- django_cfg/apps/ipc/apps.py +0 -98
- django_cfg/apps/ipc/migrations/0001_initial.py +0 -137
- django_cfg/apps/ipc/migrations/0002_rpclog_is_event.py +0 -23
- django_cfg/apps/ipc/migrations/__init__.py +0 -0
- django_cfg/apps/ipc/models.py +0 -229
- django_cfg/apps/ipc/serializers/__init__.py +0 -29
- django_cfg/apps/ipc/serializers/serializers.py +0 -343
- django_cfg/apps/ipc/services/__init__.py +0 -7
- django_cfg/apps/ipc/services/client/__init__.py +0 -23
- django_cfg/apps/ipc/services/client/client.py +0 -621
- django_cfg/apps/ipc/services/client/config.py +0 -214
- django_cfg/apps/ipc/services/client/exceptions.py +0 -201
- django_cfg/apps/ipc/services/logging.py +0 -239
- django_cfg/apps/ipc/services/monitor.py +0 -466
- django_cfg/apps/ipc/services/rpc_log_consumer.py +0 -330
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/main.mjs +0 -269
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/overview.mjs +0 -259
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/testing.mjs +0 -375
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs.old +0 -441
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/methods_content.html +0 -22
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/notifications_content.html +0 -9
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/overview_content.html +0 -9
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/requests_content.html +0 -23
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/system_status.html +0 -47
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/testing_tools.html +0 -184
- django_cfg/apps/ipc/templates/django_cfg_ipc/layout/base.html +0 -71
- django_cfg/apps/ipc/templates/django_cfg_ipc/pages/dashboard.html +0 -56
- django_cfg/apps/ipc/urls.py +0 -23
- django_cfg/apps/ipc/views/__init__.py +0 -13
- django_cfg/apps/ipc/views/dashboard.py +0 -15
- django_cfg/apps/ipc/views/monitoring.py +0 -251
- django_cfg/apps/ipc/views/testing.py +0 -285
- django_cfg/static/js/api/ipc/client.mjs +0 -114
- django_cfg/static/js/api/ipc/index.mjs +0 -13
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/licenses/LICENSE +0 -0
django_cfg/apps/ipc/admin.py
DELETED
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Django Admin for IPC/RPC models.
|
|
3
|
-
|
|
4
|
-
Uses PydanticAdmin with declarative configuration.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import json
|
|
8
|
-
|
|
9
|
-
from django.contrib import admin
|
|
10
|
-
from django_cfg.modules.django_admin import (
|
|
11
|
-
AdminConfig,
|
|
12
|
-
BadgeField,
|
|
13
|
-
DateTimeField,
|
|
14
|
-
Icons,
|
|
15
|
-
UserField,
|
|
16
|
-
computed_field,
|
|
17
|
-
)
|
|
18
|
-
from django_cfg.modules.django_admin.base import PydanticAdmin
|
|
19
|
-
|
|
20
|
-
from .models import RPCLog
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# Declarative configuration for RPCLog
|
|
24
|
-
rpclog_config = AdminConfig(
|
|
25
|
-
model=RPCLog,
|
|
26
|
-
|
|
27
|
-
# Performance optimization
|
|
28
|
-
select_related=["user"],
|
|
29
|
-
|
|
30
|
-
# List display
|
|
31
|
-
list_display=[
|
|
32
|
-
"method",
|
|
33
|
-
"type_badge", # NEW: Show RPC vs Event
|
|
34
|
-
"status",
|
|
35
|
-
"user",
|
|
36
|
-
"duration_ms",
|
|
37
|
-
"created_at",
|
|
38
|
-
"completed_at"
|
|
39
|
-
],
|
|
40
|
-
|
|
41
|
-
# Auto-generated display methods
|
|
42
|
-
display_fields=[
|
|
43
|
-
BadgeField(
|
|
44
|
-
name="method",
|
|
45
|
-
title="RPC Method",
|
|
46
|
-
variant="info",
|
|
47
|
-
icon=Icons.API
|
|
48
|
-
),
|
|
49
|
-
BadgeField(
|
|
50
|
-
name="status",
|
|
51
|
-
title="Status",
|
|
52
|
-
label_map={
|
|
53
|
-
"pending": "warning",
|
|
54
|
-
"success": "success",
|
|
55
|
-
"failed": "danger",
|
|
56
|
-
"timeout": "danger"
|
|
57
|
-
}
|
|
58
|
-
),
|
|
59
|
-
UserField(
|
|
60
|
-
name="user",
|
|
61
|
-
title="User",
|
|
62
|
-
header=True # Show with avatar
|
|
63
|
-
),
|
|
64
|
-
DateTimeField(
|
|
65
|
-
name="created_at",
|
|
66
|
-
title="Created",
|
|
67
|
-
ordering="created_at"
|
|
68
|
-
),
|
|
69
|
-
DateTimeField(
|
|
70
|
-
name="completed_at",
|
|
71
|
-
title="Completed",
|
|
72
|
-
ordering="completed_at"
|
|
73
|
-
),
|
|
74
|
-
],
|
|
75
|
-
|
|
76
|
-
# Filters
|
|
77
|
-
list_filter=["status", "is_event", "method", "created_at"],
|
|
78
|
-
search_fields=["method", "correlation_id", "user__username", "user__email", "error_message"],
|
|
79
|
-
|
|
80
|
-
# Autocomplete for user field
|
|
81
|
-
autocomplete_fields=["user"],
|
|
82
|
-
|
|
83
|
-
# Readonly fields (custom methods below)
|
|
84
|
-
readonly_fields=[
|
|
85
|
-
"id",
|
|
86
|
-
"correlation_id",
|
|
87
|
-
"created_at",
|
|
88
|
-
"completed_at",
|
|
89
|
-
"params_display",
|
|
90
|
-
"response_display",
|
|
91
|
-
"error_details_display"
|
|
92
|
-
],
|
|
93
|
-
|
|
94
|
-
# Date hierarchy
|
|
95
|
-
date_hierarchy="created_at",
|
|
96
|
-
|
|
97
|
-
# Per page
|
|
98
|
-
list_per_page=50,
|
|
99
|
-
)
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
@admin.register(RPCLog)
|
|
103
|
-
class RPCLogAdmin(PydanticAdmin):
|
|
104
|
-
"""
|
|
105
|
-
RPC log admin with analytics and filtering.
|
|
106
|
-
|
|
107
|
-
Features:
|
|
108
|
-
- Color-coded status badges
|
|
109
|
-
- Duration display with performance indicators
|
|
110
|
-
- Formatted JSON for params/response
|
|
111
|
-
- Error details with highlighted display
|
|
112
|
-
"""
|
|
113
|
-
config = rpclog_config
|
|
114
|
-
|
|
115
|
-
@computed_field("Type", ordering="is_event")
|
|
116
|
-
def type_badge(self, obj):
|
|
117
|
-
"""Display badge showing if this is an RPC call or server event."""
|
|
118
|
-
if obj.is_event:
|
|
119
|
-
return self.html.badge(
|
|
120
|
-
"EVENT",
|
|
121
|
-
variant="info",
|
|
122
|
-
icon=Icons.NOTIFICATION # or Icons.BROADCAST
|
|
123
|
-
)
|
|
124
|
-
else:
|
|
125
|
-
return self.html.badge(
|
|
126
|
-
"RPC",
|
|
127
|
-
variant="primary",
|
|
128
|
-
icon=Icons.API
|
|
129
|
-
)
|
|
130
|
-
|
|
131
|
-
@computed_field("Duration", ordering="duration_ms")
|
|
132
|
-
def duration_display(self, obj):
|
|
133
|
-
"""Display duration with color coding based on speed."""
|
|
134
|
-
if obj.duration_ms is None:
|
|
135
|
-
return self.html.empty()
|
|
136
|
-
|
|
137
|
-
# Color code based on duration
|
|
138
|
-
if obj.duration_ms < 100:
|
|
139
|
-
variant = "success" # Fast
|
|
140
|
-
icon = Icons.SPEED
|
|
141
|
-
elif obj.duration_ms < 500:
|
|
142
|
-
variant = "warning" # Moderate
|
|
143
|
-
icon = Icons.TIMER
|
|
144
|
-
else:
|
|
145
|
-
variant = "danger" # Slow
|
|
146
|
-
icon = Icons.ERROR
|
|
147
|
-
|
|
148
|
-
return self.html.badge(
|
|
149
|
-
f"{obj.duration_ms}ms",
|
|
150
|
-
variant=variant,
|
|
151
|
-
icon=icon
|
|
152
|
-
)
|
|
153
|
-
|
|
154
|
-
def params_display(self, obj):
|
|
155
|
-
"""Display formatted JSON params."""
|
|
156
|
-
if not obj.params:
|
|
157
|
-
return self.html.empty("No parameters")
|
|
158
|
-
|
|
159
|
-
try:
|
|
160
|
-
formatted = json.dumps(obj.params, indent=2)
|
|
161
|
-
return f'<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; max-height: 400px; overflow: auto; font-size: 12px; line-height: 1.5;">{formatted}</pre>'
|
|
162
|
-
except Exception:
|
|
163
|
-
return str(obj.params)
|
|
164
|
-
|
|
165
|
-
params_display.short_description = "Request Parameters"
|
|
166
|
-
|
|
167
|
-
def response_display(self, obj):
|
|
168
|
-
"""Display formatted JSON response."""
|
|
169
|
-
if not obj.response:
|
|
170
|
-
return self.html.empty("No response")
|
|
171
|
-
|
|
172
|
-
try:
|
|
173
|
-
formatted = json.dumps(obj.response, indent=2)
|
|
174
|
-
return f'<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; max-height: 400px; overflow: auto; font-size: 12px; line-height: 1.5;">{formatted}</pre>'
|
|
175
|
-
except Exception:
|
|
176
|
-
return str(obj.response)
|
|
177
|
-
|
|
178
|
-
response_display.short_description = "Response Data"
|
|
179
|
-
|
|
180
|
-
def error_details_display(self, obj):
|
|
181
|
-
"""Display error information if call failed."""
|
|
182
|
-
if not obj.is_failed:
|
|
183
|
-
return self.html.inline([
|
|
184
|
-
self.html.icon(Icons.CHECK_CIRCLE, size="sm"),
|
|
185
|
-
self.html.span("No errors", "text-green-600")
|
|
186
|
-
])
|
|
187
|
-
|
|
188
|
-
details = []
|
|
189
|
-
|
|
190
|
-
if obj.error_code:
|
|
191
|
-
details.append(self.html.inline([
|
|
192
|
-
self.html.span("Error Code:", "font-semibold"),
|
|
193
|
-
self.html.badge(obj.error_code, variant="danger", icon=Icons.ERROR)
|
|
194
|
-
], separator=" "))
|
|
195
|
-
|
|
196
|
-
if obj.error_message:
|
|
197
|
-
details.append(self.html.inline([
|
|
198
|
-
self.html.span("Message:", "font-semibold"),
|
|
199
|
-
self.html.span(obj.error_message, "text-red-600")
|
|
200
|
-
], separator=" "))
|
|
201
|
-
|
|
202
|
-
return "<br>".join(details) if details else self.html.empty()
|
|
203
|
-
|
|
204
|
-
error_details_display.short_description = "Error Details"
|
|
205
|
-
|
|
206
|
-
# Fieldsets for detail view
|
|
207
|
-
def get_fieldsets(self, request, obj=None):
|
|
208
|
-
"""Dynamic fieldsets based on object state."""
|
|
209
|
-
fieldsets = [
|
|
210
|
-
("RPC Call Information", {
|
|
211
|
-
'fields': ('id', 'correlation_id', 'method', 'user', 'status')
|
|
212
|
-
}),
|
|
213
|
-
("Request & Response", {
|
|
214
|
-
'fields': ('params_display', 'response_display'),
|
|
215
|
-
'classes': ('collapse',)
|
|
216
|
-
}),
|
|
217
|
-
("Performance", {
|
|
218
|
-
'fields': ('duration_ms', 'created_at', 'completed_at')
|
|
219
|
-
}),
|
|
220
|
-
("Metadata", {
|
|
221
|
-
'fields': ('caller_ip', 'user_agent'),
|
|
222
|
-
'classes': ('collapse',)
|
|
223
|
-
}),
|
|
224
|
-
]
|
|
225
|
-
|
|
226
|
-
# Add error section only if failed
|
|
227
|
-
if obj and obj.is_failed:
|
|
228
|
-
fieldsets.insert(2, ("Error Details", {
|
|
229
|
-
'fields': ('error_details_display', 'error_code', 'error_message')
|
|
230
|
-
}))
|
|
231
|
-
|
|
232
|
-
return fieldsets
|
django_cfg/apps/ipc/apps.py
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Django app configuration for IPC/RPC module.
|
|
3
|
-
|
|
4
|
-
Provides RPC client and monitoring dashboard.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import asyncio
|
|
8
|
-
from django.apps import AppConfig
|
|
9
|
-
from django.conf import settings
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class IPCConfig(AppConfig):
|
|
13
|
-
"""
|
|
14
|
-
IPC/RPC application configuration.
|
|
15
|
-
|
|
16
|
-
Provides:
|
|
17
|
-
- RPC client for inter-service communication
|
|
18
|
-
- Monitoring dashboard with real-time stats
|
|
19
|
-
- DRF API endpoints for dashboard
|
|
20
|
-
- RPC log consumer (Redis Stream -> ORM)
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
default_auto_field = 'django.db.models.BigAutoField'
|
|
24
|
-
name = 'django_cfg.apps.ipc'
|
|
25
|
-
label = 'django_cfg_ipc'
|
|
26
|
-
verbose_name = 'IPC/RPC System'
|
|
27
|
-
|
|
28
|
-
def ready(self):
|
|
29
|
-
"""Initialize app when Django starts."""
|
|
30
|
-
# Import monitor to ensure Redis connection is initialized
|
|
31
|
-
from .services import monitor # noqa: F401
|
|
32
|
-
|
|
33
|
-
# Start RPC Log Consumer in background (if enabled)
|
|
34
|
-
self._start_rpc_log_consumer()
|
|
35
|
-
|
|
36
|
-
def _start_rpc_log_consumer(self):
|
|
37
|
-
"""Start RPC Log Consumer to capture logs from WebSocket server."""
|
|
38
|
-
# Check if RPC logging consumer is enabled
|
|
39
|
-
enable_consumer = getattr(settings, 'DJANGO_CFG_RPC_LOG_CONSUMER_ENABLED', True)
|
|
40
|
-
|
|
41
|
-
if not enable_consumer:
|
|
42
|
-
return
|
|
43
|
-
|
|
44
|
-
# Check if we have RPC configuration
|
|
45
|
-
if not hasattr(settings, 'DJANGO_CFG_RPC'):
|
|
46
|
-
return
|
|
47
|
-
|
|
48
|
-
# Check if RPC is enabled (case-insensitive)
|
|
49
|
-
rpc_enabled = settings.DJANGO_CFG_RPC.get('ENABLED') or settings.DJANGO_CFG_RPC.get('enabled')
|
|
50
|
-
if not rpc_enabled:
|
|
51
|
-
return
|
|
52
|
-
|
|
53
|
-
try:
|
|
54
|
-
import threading
|
|
55
|
-
from .services.rpc_log_consumer import RPCLogConsumer
|
|
56
|
-
|
|
57
|
-
# Get Redis URL (case-insensitive)
|
|
58
|
-
redis_url = settings.DJANGO_CFG_RPC.get('REDIS_URL') or settings.DJANGO_CFG_RPC.get('redis_url', 'redis://localhost:6379/2')
|
|
59
|
-
|
|
60
|
-
consumer = RPCLogConsumer(
|
|
61
|
-
redis_url=redis_url,
|
|
62
|
-
stream_name="stream:rpc-logs",
|
|
63
|
-
consumer_group="django-rpc-loggers",
|
|
64
|
-
consumer_name="django-1",
|
|
65
|
-
)
|
|
66
|
-
|
|
67
|
-
# Run consumer in background thread with its own event loop
|
|
68
|
-
def run_consumer():
|
|
69
|
-
"""Run consumer in background thread."""
|
|
70
|
-
try:
|
|
71
|
-
# Create new event loop for this thread
|
|
72
|
-
loop = asyncio.new_event_loop()
|
|
73
|
-
asyncio.set_event_loop(loop)
|
|
74
|
-
|
|
75
|
-
# Initialize and start consumer
|
|
76
|
-
loop.run_until_complete(consumer.initialize())
|
|
77
|
-
loop.run_until_complete(consumer.start())
|
|
78
|
-
|
|
79
|
-
# Keep running
|
|
80
|
-
loop.run_forever()
|
|
81
|
-
|
|
82
|
-
except Exception as e:
|
|
83
|
-
from django_cfg.modules.django_logging import get_logger
|
|
84
|
-
logger = get_logger("ipc.consumer")
|
|
85
|
-
logger.error(f"RPC Log Consumer error: {e}", exc_info=True)
|
|
86
|
-
|
|
87
|
-
# Start in daemon thread (won't block Django shutdown)
|
|
88
|
-
thread = threading.Thread(target=run_consumer, daemon=True, name="rpc-log-consumer")
|
|
89
|
-
thread.start()
|
|
90
|
-
|
|
91
|
-
from django_cfg.modules.django_logging import get_logger
|
|
92
|
-
logger = get_logger("ipc.apps")
|
|
93
|
-
logger.info("✅ RPC Log Consumer started in background thread")
|
|
94
|
-
|
|
95
|
-
except Exception as e:
|
|
96
|
-
from django_cfg.modules.django_logging import get_logger
|
|
97
|
-
logger = get_logger("ipc.apps")
|
|
98
|
-
logger.warning(f"Failed to start RPC Log Consumer: {e}")
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
# Generated by Django 5.2.7 on 2025-10-23 12:12
|
|
2
|
-
|
|
3
|
-
import django.db.models.deletion
|
|
4
|
-
import django.utils.timezone
|
|
5
|
-
import uuid
|
|
6
|
-
from django.conf import settings
|
|
7
|
-
from django.db import migrations, models
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class Migration(migrations.Migration):
|
|
11
|
-
initial = True
|
|
12
|
-
|
|
13
|
-
dependencies = [
|
|
14
|
-
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
15
|
-
]
|
|
16
|
-
|
|
17
|
-
operations = [
|
|
18
|
-
migrations.CreateModel(
|
|
19
|
-
name="RPCLog",
|
|
20
|
-
fields=[
|
|
21
|
-
(
|
|
22
|
-
"id",
|
|
23
|
-
models.UUIDField(
|
|
24
|
-
default=uuid.uuid4, editable=False, primary_key=True, serialize=False
|
|
25
|
-
),
|
|
26
|
-
),
|
|
27
|
-
(
|
|
28
|
-
"correlation_id",
|
|
29
|
-
models.CharField(
|
|
30
|
-
db_index=True,
|
|
31
|
-
help_text="UUID from RPC request",
|
|
32
|
-
max_length=100,
|
|
33
|
-
verbose_name="Correlation ID",
|
|
34
|
-
),
|
|
35
|
-
),
|
|
36
|
-
(
|
|
37
|
-
"method",
|
|
38
|
-
models.CharField(
|
|
39
|
-
db_index=True,
|
|
40
|
-
help_text="e.g., send_notification, workspace.file_changed",
|
|
41
|
-
max_length=100,
|
|
42
|
-
verbose_name="RPC Method",
|
|
43
|
-
),
|
|
44
|
-
),
|
|
45
|
-
(
|
|
46
|
-
"params",
|
|
47
|
-
models.JSONField(
|
|
48
|
-
help_text="Parameters sent to RPC method", verbose_name="Request Params"
|
|
49
|
-
),
|
|
50
|
-
),
|
|
51
|
-
(
|
|
52
|
-
"response",
|
|
53
|
-
models.JSONField(
|
|
54
|
-
blank=True,
|
|
55
|
-
help_text="Result from RPC call",
|
|
56
|
-
null=True,
|
|
57
|
-
verbose_name="Response Data",
|
|
58
|
-
),
|
|
59
|
-
),
|
|
60
|
-
(
|
|
61
|
-
"status",
|
|
62
|
-
models.CharField(
|
|
63
|
-
choices=[
|
|
64
|
-
("pending", "Pending"),
|
|
65
|
-
("success", "Success"),
|
|
66
|
-
("failed", "Failed"),
|
|
67
|
-
("timeout", "Timeout"),
|
|
68
|
-
],
|
|
69
|
-
db_index=True,
|
|
70
|
-
default="pending",
|
|
71
|
-
max_length=20,
|
|
72
|
-
verbose_name="Status",
|
|
73
|
-
),
|
|
74
|
-
),
|
|
75
|
-
(
|
|
76
|
-
"error_code",
|
|
77
|
-
models.CharField(
|
|
78
|
-
blank=True, max_length=50, null=True, verbose_name="Error Code"
|
|
79
|
-
),
|
|
80
|
-
),
|
|
81
|
-
(
|
|
82
|
-
"error_message",
|
|
83
|
-
models.TextField(blank=True, null=True, verbose_name="Error Message"),
|
|
84
|
-
),
|
|
85
|
-
(
|
|
86
|
-
"duration_ms",
|
|
87
|
-
models.IntegerField(
|
|
88
|
-
blank=True,
|
|
89
|
-
help_text="Time taken for RPC call in milliseconds",
|
|
90
|
-
null=True,
|
|
91
|
-
verbose_name="Duration (ms)",
|
|
92
|
-
),
|
|
93
|
-
),
|
|
94
|
-
(
|
|
95
|
-
"caller_ip",
|
|
96
|
-
models.GenericIPAddressField(blank=True, null=True, verbose_name="Caller IP"),
|
|
97
|
-
),
|
|
98
|
-
("user_agent", models.TextField(blank=True, null=True, verbose_name="User Agent")),
|
|
99
|
-
(
|
|
100
|
-
"created_at",
|
|
101
|
-
models.DateTimeField(
|
|
102
|
-
db_index=True, default=django.utils.timezone.now, verbose_name="Created At"
|
|
103
|
-
),
|
|
104
|
-
),
|
|
105
|
-
(
|
|
106
|
-
"completed_at",
|
|
107
|
-
models.DateTimeField(blank=True, null=True, verbose_name="Completed At"),
|
|
108
|
-
),
|
|
109
|
-
(
|
|
110
|
-
"user",
|
|
111
|
-
models.ForeignKey(
|
|
112
|
-
blank=True,
|
|
113
|
-
null=True,
|
|
114
|
-
on_delete=django.db.models.deletion.SET_NULL,
|
|
115
|
-
related_name="rpc_logs",
|
|
116
|
-
to=settings.AUTH_USER_MODEL,
|
|
117
|
-
verbose_name="User",
|
|
118
|
-
),
|
|
119
|
-
),
|
|
120
|
-
],
|
|
121
|
-
options={
|
|
122
|
-
"verbose_name": "RPC Log",
|
|
123
|
-
"verbose_name_plural": "RPC Logs",
|
|
124
|
-
"ordering": ["-created_at"],
|
|
125
|
-
"indexes": [
|
|
126
|
-
models.Index(fields=["method", "status"], name="django_cfg__method_916fd9_idx"),
|
|
127
|
-
models.Index(
|
|
128
|
-
fields=["status", "created_at"], name="django_cfg__status_ee629e_idx"
|
|
129
|
-
),
|
|
130
|
-
models.Index(fields=["correlation_id"], name="django_cfg__correla_fc7bcf_idx"),
|
|
131
|
-
models.Index(
|
|
132
|
-
fields=["user", "created_at"], name="django_cfg__user_id_c33866_idx"
|
|
133
|
-
),
|
|
134
|
-
],
|
|
135
|
-
},
|
|
136
|
-
),
|
|
137
|
-
]
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Generated by Django 5.2.7 on 2025-10-24 07:41
|
|
2
|
-
|
|
3
|
-
from django.db import migrations, models
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Migration(migrations.Migration):
|
|
7
|
-
|
|
8
|
-
dependencies = [
|
|
9
|
-
("django_cfg_ipc", "0001_initial"),
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
operations = [
|
|
13
|
-
migrations.AddField(
|
|
14
|
-
model_name="rpclog",
|
|
15
|
-
name="is_event",
|
|
16
|
-
field=models.BooleanField(
|
|
17
|
-
db_index=True,
|
|
18
|
-
default=False,
|
|
19
|
-
help_text="True if this is a server-to-client event (not a request-response RPC call)",
|
|
20
|
-
verbose_name="Is Event",
|
|
21
|
-
),
|
|
22
|
-
),
|
|
23
|
-
]
|
|
File without changes
|