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.
- 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 +577 -0
- django_cfg/apps/centrifugo/services/client/config.py +228 -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 +374 -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.63.dist-info}/METADATA +1 -1
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.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.63.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.63.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
<!-- Testing Tools Tab -->
|
|
2
|
-
<div id="testing-tab" class="tab-panel hidden">
|
|
3
|
-
<!-- RPC Test Client -->
|
|
4
|
-
<div class="bg-white dark:bg-gray-800 rounded-lg p-6 border border-gray-200 dark:border-gray-700 mb-6">
|
|
5
|
-
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center">
|
|
6
|
-
<span class="material-icons mr-2 text-blue-500">send</span>
|
|
7
|
-
RPC Test Client
|
|
8
|
-
</h3>
|
|
9
|
-
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
|
10
|
-
Send individual RPC requests to test methods and inspect responses
|
|
11
|
-
</p>
|
|
12
|
-
|
|
13
|
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
|
|
14
|
-
<!-- Method Selection -->
|
|
15
|
-
<div>
|
|
16
|
-
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
17
|
-
RPC Method
|
|
18
|
-
</label>
|
|
19
|
-
<select id="test-rpc-method" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-blue-500 focus:border-blue-500">
|
|
20
|
-
<option value="">Select a method...</option>
|
|
21
|
-
<option value="notification.send">notification.send</option>
|
|
22
|
-
<option value="notification.broadcast">notification.broadcast</option>
|
|
23
|
-
<option value="workspace.file_changed">workspace.file_changed</option>
|
|
24
|
-
<option value="session.message">session.message</option>
|
|
25
|
-
</select>
|
|
26
|
-
</div>
|
|
27
|
-
|
|
28
|
-
<!-- Timeout -->
|
|
29
|
-
<div>
|
|
30
|
-
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
31
|
-
Timeout (seconds)
|
|
32
|
-
</label>
|
|
33
|
-
<input type="number" id="test-rpc-timeout" value="10" min="1" max="60" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-blue-500 focus:border-blue-500">
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
|
|
37
|
-
<!-- Params JSON Editor -->
|
|
38
|
-
<div class="mb-4">
|
|
39
|
-
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
40
|
-
Parameters (JSON)
|
|
41
|
-
</label>
|
|
42
|
-
<textarea id="test-rpc-params" rows="7" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white font-mono text-sm focus:ring-blue-5 focus:border-blue-500">{
|
|
43
|
-
"user_id": "test-123",
|
|
44
|
-
"type": "info",
|
|
45
|
-
"title": "Test Notification",
|
|
46
|
-
"message": "This is a test message",
|
|
47
|
-
"timestamp": "2025-10-23T12:00:00.000Z"
|
|
48
|
-
}</textarea>
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
<!-- Action Buttons -->
|
|
52
|
-
<div class="flex gap-3">
|
|
53
|
-
<button id="send-test-rpc-btn" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-md font-medium flex items-center gap-2 transition-colors">
|
|
54
|
-
<span class="material-icons text-sm">send</span>
|
|
55
|
-
Send Request
|
|
56
|
-
</button>
|
|
57
|
-
<button id="clear-test-rpc-btn" class="px-4 py-2 bg-gray-500 hover:bg-gray-600 text-white rounded-md font-medium flex items-center gap-2 transition-colors">
|
|
58
|
-
<span class="material-icons text-sm">clear</span>
|
|
59
|
-
Clear
|
|
60
|
-
</button>
|
|
61
|
-
</div>
|
|
62
|
-
|
|
63
|
-
<!-- Response Display -->
|
|
64
|
-
<div id="test-rpc-result" class="mt-4 hidden">
|
|
65
|
-
</div>
|
|
66
|
-
</div>
|
|
67
|
-
|
|
68
|
-
<!-- Load Testing Tool -->
|
|
69
|
-
<div class="bg-white dark:bg-gray-800 rounded-lg p-6 border border-gray-200 dark:border-gray-700">
|
|
70
|
-
<h3 class="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center">
|
|
71
|
-
<span class="material-icons mr-2 text-orange-500">speed</span>
|
|
72
|
-
Load Testing Tool
|
|
73
|
-
</h3>
|
|
74
|
-
<p class="text-sm text-gray-600 dark:text-gray-400 mb-4">
|
|
75
|
-
Emulate production load by sending multiple concurrent RPC requests
|
|
76
|
-
</p>
|
|
77
|
-
|
|
78
|
-
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
|
79
|
-
<!-- Total Requests -->
|
|
80
|
-
<div>
|
|
81
|
-
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
82
|
-
Total Requests
|
|
83
|
-
</label>
|
|
84
|
-
<input type="number" id="load-test-total" value="100" min="1" max="10000" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-blue-500 focus:border-blue-500">
|
|
85
|
-
</div>
|
|
86
|
-
|
|
87
|
-
<!-- Concurrency -->
|
|
88
|
-
<div>
|
|
89
|
-
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
90
|
-
Concurrent Requests
|
|
91
|
-
</label>
|
|
92
|
-
<input type="number" id="load-test-concurrency" value="10" min="1" max="100" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-blue-500 focus:border-blue-500">
|
|
93
|
-
</div>
|
|
94
|
-
|
|
95
|
-
<!-- Method -->
|
|
96
|
-
<div>
|
|
97
|
-
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
98
|
-
Test Method
|
|
99
|
-
</label>
|
|
100
|
-
<select id="load-test-method" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:ring-blue-500 focus:border-blue-500">
|
|
101
|
-
<option value="">Select a method...</option>
|
|
102
|
-
<option value="notification.send">notification.send</option>
|
|
103
|
-
<option value="notification.broadcast">notification.broadcast</option>
|
|
104
|
-
<option value="workspace.file_changed">workspace.file_changed</option>
|
|
105
|
-
<option value="session.message">session.message</option>
|
|
106
|
-
</select>
|
|
107
|
-
</div>
|
|
108
|
-
</div>
|
|
109
|
-
|
|
110
|
-
<!-- Load Test Params JSON Editor -->
|
|
111
|
-
<div class="mb-4">
|
|
112
|
-
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
113
|
-
Request Parameters (JSON)
|
|
114
|
-
</label>
|
|
115
|
-
<textarea id="load-test-params" rows="5" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md bg-white dark:bg-gray-700 text-gray-900 dark:text-white font-mono text-sm focus:ring-blue-500 focus:border-blue-500">{
|
|
116
|
-
"user_id": "load-test-user",
|
|
117
|
-
"type": "info",
|
|
118
|
-
"title": "Load Test Notification",
|
|
119
|
-
"message": "This is a load test message",
|
|
120
|
-
"timestamp": "2025-10-23T12:00:00.000Z"
|
|
121
|
-
}</textarea>
|
|
122
|
-
<p class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
|
123
|
-
Note: <code>_test_id</code> and <code>_index</code> will be automatically added to each request.
|
|
124
|
-
</p>
|
|
125
|
-
</div>
|
|
126
|
-
|
|
127
|
-
<!-- Action Buttons -->
|
|
128
|
-
<div class="flex gap-3 mb-4">
|
|
129
|
-
<button id="start-load-test-btn" class="px-4 py-2 bg-orange-600 hover:bg-orange-700 text-white rounded-md font-medium flex items-center gap-2 transition-colors">
|
|
130
|
-
<span class="material-icons text-sm">play_arrow</span>
|
|
131
|
-
Start Load Test
|
|
132
|
-
</button>
|
|
133
|
-
<button id="stop-load-test-btn" class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-md font-medium flex items-center gap-2 transition-colors opacity-50 cursor-not-allowed" disabled>
|
|
134
|
-
<span class="material-icons text-sm">stop</span>
|
|
135
|
-
Stop Test
|
|
136
|
-
</button>
|
|
137
|
-
</div>
|
|
138
|
-
|
|
139
|
-
<!-- Progress -->
|
|
140
|
-
<div class="mb-4">
|
|
141
|
-
<div class="mb-2 flex justify-between text-sm">
|
|
142
|
-
<span class="text-gray-700 dark:text-gray-300">Progress: <span id="load-test-progress-text">0/0</span></span>
|
|
143
|
-
</div>
|
|
144
|
-
<div class="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-2.5 mb-4">
|
|
145
|
-
<div id="load-test-progress" class="bg-orange-600 h-2.5 rounded-full transition-all" style="width: 0%"></div>
|
|
146
|
-
</div>
|
|
147
|
-
</div>
|
|
148
|
-
|
|
149
|
-
<!-- Statistics Cards -->
|
|
150
|
-
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
151
|
-
<div class="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800">
|
|
152
|
-
<div class="flex items-center justify-between mb-2">
|
|
153
|
-
<span class="material-icons text-xl text-blue-600 dark:text-blue-400">check_circle</span>
|
|
154
|
-
</div>
|
|
155
|
-
<div class="text-2xl font-bold text-gray-900 dark:text-white" id="load-test-success">0</div>
|
|
156
|
-
<div class="text-xs text-gray-600 dark:text-gray-400">Success</div>
|
|
157
|
-
</div>
|
|
158
|
-
|
|
159
|
-
<div class="bg-red-50 dark:bg-red-900/20 rounded-lg p-4 border border-red-200 dark:border-red-800">
|
|
160
|
-
<div class="flex items-center justify-between mb-2">
|
|
161
|
-
<span class="material-icons text-xl text-red-600 dark:text-red-400">error</span>
|
|
162
|
-
</div>
|
|
163
|
-
<div class="text-2xl font-bold text-gray-900 dark:text-white" id="load-test-failed">0</div>
|
|
164
|
-
<div class="text-xs text-gray-600 dark:text-gray-400">Failed</div>
|
|
165
|
-
</div>
|
|
166
|
-
|
|
167
|
-
<div class="bg-green-50 dark:bg-green-900/20 rounded-lg p-4 border border-green-200 dark:border-green-800">
|
|
168
|
-
<div class="flex items-center justify-between mb-2">
|
|
169
|
-
<span class="material-icons text-xl text-green-600 dark:text-green-400">timer</span>
|
|
170
|
-
</div>
|
|
171
|
-
<div class="text-2xl font-bold text-gray-900 dark:text-white"><span id="load-test-avg-time">0</span>ms</div>
|
|
172
|
-
<div class="text-xs text-gray-600 dark:text-gray-400">Avg Time</div>
|
|
173
|
-
</div>
|
|
174
|
-
|
|
175
|
-
<div class="bg-purple-50 dark:bg-purple-900/20 rounded-lg p-4 border border-purple-200 dark:border-purple-800">
|
|
176
|
-
<div class="flex items-center justify-between mb-2">
|
|
177
|
-
<span class="material-icons text-xl text-purple-600 dark:text-purple-400">trending_up</span>
|
|
178
|
-
</div>
|
|
179
|
-
<div class="text-2xl font-bold text-gray-900 dark:text-white" id="load-test-rps">0</div>
|
|
180
|
-
<div class="text-xs text-gray-600 dark:text-gray-400">RPS</div>
|
|
181
|
-
</div>
|
|
182
|
-
</div>
|
|
183
|
-
</div>
|
|
184
|
-
</div>
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
{% extends 'django_tailwind/app.html' %}
|
|
2
|
-
{% load static %}
|
|
3
|
-
|
|
4
|
-
{% block title %}{% block page_title_text %}RPC Monitor{% endblock %} - Django-CFG{% endblock %}
|
|
5
|
-
|
|
6
|
-
{# Navbar configuration #}
|
|
7
|
-
{% block header %}
|
|
8
|
-
{% with navbar_items=rpc_nav_items %}
|
|
9
|
-
{% include 'django_tailwind/components/navbar.html' with title="RPC Monitor" icon='<span class="material-icons text-3xl text-blue-400">insights</span>' nav_items=navbar_items full_width=True %}
|
|
10
|
-
{% endwith %}
|
|
11
|
-
|
|
12
|
-
{# RPC-specific header info #}
|
|
13
|
-
<div class="bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800">
|
|
14
|
-
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-3">
|
|
15
|
-
<div class="flex items-center justify-between text-sm">
|
|
16
|
-
<p class="text-gray-600 dark:text-gray-400">Real-time WebSocket & RPC Activity</p>
|
|
17
|
-
|
|
18
|
-
<div class="flex items-center space-x-4">
|
|
19
|
-
<!-- Health indicator -->
|
|
20
|
-
<div id="health-indicator" class="flex items-center space-x-2">
|
|
21
|
-
<span class="pulse-dot w-2 h-2 bg-green-500 rounded-full"></span>
|
|
22
|
-
<span class="text-gray-700 dark:text-gray-300">Connected</span>
|
|
23
|
-
</div>
|
|
24
|
-
|
|
25
|
-
<!-- Auto-refresh toggle -->
|
|
26
|
-
<label class="flex items-center space-x-2 cursor-pointer">
|
|
27
|
-
<span class="text-gray-700 dark:text-gray-300">Auto-refresh</span>
|
|
28
|
-
<input type="checkbox" id="auto-refresh-toggle" checked
|
|
29
|
-
class="toggle-checkbox rounded border-gray-400 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 dark:focus:ring-blue-400">
|
|
30
|
-
</label>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
</div>
|
|
34
|
-
</div>
|
|
35
|
-
{% endblock %}
|
|
36
|
-
|
|
37
|
-
{% block extra_head %}
|
|
38
|
-
{{ block.super }}
|
|
39
|
-
<!-- Material Icons -->
|
|
40
|
-
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
|
41
|
-
|
|
42
|
-
<style>
|
|
43
|
-
.stat-card {
|
|
44
|
-
transition: transform 0.2s, box-shadow 0.2s;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
.stat-card:hover {
|
|
48
|
-
transform: translateY(-2px);
|
|
49
|
-
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
.pulse-dot {
|
|
53
|
-
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
@keyframes pulse {
|
|
57
|
-
0%, 100% {
|
|
58
|
-
opacity: 1;
|
|
59
|
-
}
|
|
60
|
-
50% {
|
|
61
|
-
opacity: 0.5;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
</style>
|
|
65
|
-
|
|
66
|
-
{% block extra_css %}{% endblock %}
|
|
67
|
-
{% endblock %}
|
|
68
|
-
|
|
69
|
-
{% block body %}
|
|
70
|
-
{{ block.super }}
|
|
71
|
-
{% endblock %}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
{% extends 'django_cfg_ipc/layout/base.html' %}
|
|
2
|
-
{% load static %}
|
|
3
|
-
|
|
4
|
-
{% block title %}RPC Monitor Dashboard{% endblock %}
|
|
5
|
-
|
|
6
|
-
{% block content %}
|
|
7
|
-
<!-- Statistics Cards -->
|
|
8
|
-
{% include 'django_cfg_ipc/components/stat_cards.html' %}
|
|
9
|
-
|
|
10
|
-
<!-- System Status -->
|
|
11
|
-
{% include 'django_cfg_ipc/components/system_status.html' %}
|
|
12
|
-
|
|
13
|
-
<!-- Tab Navigation -->
|
|
14
|
-
{% include 'django_cfg_ipc/components/tab_navigation.html' %}
|
|
15
|
-
|
|
16
|
-
<!-- Tab Content -->
|
|
17
|
-
<div class="tab-content">
|
|
18
|
-
{% include 'django_cfg_ipc/components/overview_content.html' %}
|
|
19
|
-
{% include 'django_cfg_ipc/components/requests_content.html' %}
|
|
20
|
-
{% include 'django_cfg_ipc/components/notifications_content.html' %}
|
|
21
|
-
{% include 'django_cfg_ipc/components/methods_content.html' %}
|
|
22
|
-
{% include 'django_cfg_ipc/components/testing_tools.html' %}
|
|
23
|
-
</div>
|
|
24
|
-
{% endblock %}
|
|
25
|
-
|
|
26
|
-
{% block extra_js %}
|
|
27
|
-
{% load i18n %}
|
|
28
|
-
{% now "U" as current_timestamp %}
|
|
29
|
-
|
|
30
|
-
<!-- Load and initialize IPC API -->
|
|
31
|
-
<script type="module">
|
|
32
|
-
try {
|
|
33
|
-
console.log('🔄 Starting IpcAPI module import...');
|
|
34
|
-
const { loadAPI, showNotification } = await import('/static/js/api-loader.mjs');
|
|
35
|
-
|
|
36
|
-
// Load ipc API
|
|
37
|
-
const ipcAPI = await loadAPI('ipc');
|
|
38
|
-
console.log('✅ IpcAPI module imported successfully:', ipcAPI);
|
|
39
|
-
|
|
40
|
-
// Make it available globally as ipcAPI
|
|
41
|
-
window.ipcAPI = ipcAPI;
|
|
42
|
-
window.showNotification = showNotification;
|
|
43
|
-
|
|
44
|
-
console.log('✅ IpcAPI loaded from generated MJS client');
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.error('❌ Failed to load IpcAPI module:', error);
|
|
47
|
-
console.error('Error stack:', error.stack);
|
|
48
|
-
window.ipcAPI = null;
|
|
49
|
-
}
|
|
50
|
-
</script>
|
|
51
|
-
|
|
52
|
-
<!-- Dashboard Modules -->
|
|
53
|
-
<script type="module" src="{% static 'django_cfg_ipc/js/dashboard/overview.mjs' %}?v={{ current_timestamp }}"></script>
|
|
54
|
-
<script type="module" src="{% static 'django_cfg_ipc/js/dashboard/testing.mjs' %}?v={{ current_timestamp }}"></script>
|
|
55
|
-
<script type="module" src="{% static 'django_cfg_ipc/js/dashboard/main.mjs' %}?v={{ current_timestamp }}"></script>
|
|
56
|
-
{% endblock %}
|
django_cfg/apps/ipc/urls.py
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
URL patterns for IPC/RPC module.
|
|
3
|
-
|
|
4
|
-
Public API endpoints for RPC monitoring and testing using DRF router.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from django.urls import include, path
|
|
8
|
-
from rest_framework import routers
|
|
9
|
-
|
|
10
|
-
from .views.monitoring import RPCMonitorViewSet
|
|
11
|
-
from .views.testing import RPCTestingViewSet
|
|
12
|
-
|
|
13
|
-
app_name = 'django_cfg_ipc'
|
|
14
|
-
|
|
15
|
-
# Create router
|
|
16
|
-
router = routers.DefaultRouter()
|
|
17
|
-
router.register(r'monitor', RPCMonitorViewSet, basename='monitor')
|
|
18
|
-
router.register(r'test', RPCTestingViewSet, basename='test')
|
|
19
|
-
|
|
20
|
-
urlpatterns = [
|
|
21
|
-
# Include router URLs
|
|
22
|
-
path('', include(router.urls)),
|
|
23
|
-
]
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Dashboard view for IPC/RPC monitoring.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from django.contrib.admin.views.decorators import staff_member_required
|
|
6
|
-
from django.shortcuts import render
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@staff_member_required
|
|
10
|
-
def dashboard_view(request):
|
|
11
|
-
"""Render the IPC/RPC dashboard template."""
|
|
12
|
-
context = {
|
|
13
|
-
'page_title': 'IPC/RPC Monitor Dashboard',
|
|
14
|
-
}
|
|
15
|
-
return render(request, 'django_cfg_ipc/pages/dashboard.html', context)
|
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
RPC Monitoring ViewSet.
|
|
3
|
-
|
|
4
|
-
Provides REST API endpoints for monitoring RPC system health and statistics.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from django_cfg.modules.django_logging import get_logger
|
|
8
|
-
from drf_spectacular.types import OpenApiTypes
|
|
9
|
-
from drf_spectacular.utils import OpenApiParameter, extend_schema
|
|
10
|
-
from rest_framework import status, viewsets
|
|
11
|
-
from rest_framework.authentication import SessionAuthentication
|
|
12
|
-
from rest_framework.decorators import action
|
|
13
|
-
from rest_framework.permissions import IsAdminUser
|
|
14
|
-
from rest_framework.response import Response
|
|
15
|
-
|
|
16
|
-
from ..serializers import (
|
|
17
|
-
HealthCheckSerializer,
|
|
18
|
-
MethodStatsSerializer,
|
|
19
|
-
NotificationStatsSerializer,
|
|
20
|
-
OverviewStatsSerializer,
|
|
21
|
-
RecentRequestsSerializer,
|
|
22
|
-
)
|
|
23
|
-
from ..services import RPCMonitor
|
|
24
|
-
|
|
25
|
-
logger = get_logger("ipc.monitoring")
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
class RPCMonitorViewSet(viewsets.ViewSet):
|
|
29
|
-
"""
|
|
30
|
-
ViewSet for RPC monitoring and statistics.
|
|
31
|
-
|
|
32
|
-
Provides comprehensive monitoring data for the RPC system including:
|
|
33
|
-
- Health checks
|
|
34
|
-
- Overview statistics
|
|
35
|
-
- Recent requests
|
|
36
|
-
- Notification stats
|
|
37
|
-
- Method-level statistics
|
|
38
|
-
"""
|
|
39
|
-
|
|
40
|
-
authentication_classes = [SessionAuthentication]
|
|
41
|
-
permission_classes = [IsAdminUser]
|
|
42
|
-
|
|
43
|
-
@extend_schema(
|
|
44
|
-
tags=['IPC/RPC Monitoring'],
|
|
45
|
-
summary="Get RPC health status",
|
|
46
|
-
description="Returns the current health status of the RPC monitoring system.",
|
|
47
|
-
responses={
|
|
48
|
-
200: HealthCheckSerializer,
|
|
49
|
-
503: {"description": "Service unavailable"},
|
|
50
|
-
},
|
|
51
|
-
)
|
|
52
|
-
@action(detail=False, methods=['get'], url_path='health')
|
|
53
|
-
def health(self, request):
|
|
54
|
-
"""Get health status of RPC monitoring."""
|
|
55
|
-
try:
|
|
56
|
-
monitor = RPCMonitor()
|
|
57
|
-
health_data = monitor.health_check()
|
|
58
|
-
|
|
59
|
-
serializer = HealthCheckSerializer(data=health_data)
|
|
60
|
-
serializer.is_valid(raise_exception=True)
|
|
61
|
-
|
|
62
|
-
return Response(serializer.validated_data)
|
|
63
|
-
|
|
64
|
-
except ConnectionError as e:
|
|
65
|
-
logger.error(f"Health check connection error: {e}")
|
|
66
|
-
return Response(
|
|
67
|
-
{"error": "Redis connection unavailable"},
|
|
68
|
-
status=status.HTTP_503_SERVICE_UNAVAILABLE
|
|
69
|
-
)
|
|
70
|
-
except Exception as e:
|
|
71
|
-
logger.error(f"Health check error: {e}", exc_info=True)
|
|
72
|
-
return Response(
|
|
73
|
-
{"error": "Internal server error"},
|
|
74
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
@extend_schema(
|
|
78
|
-
tags=['IPC/RPC Monitoring'],
|
|
79
|
-
summary="Get overview statistics",
|
|
80
|
-
description="Returns overview statistics for RPC monitoring.",
|
|
81
|
-
responses={
|
|
82
|
-
200: OverviewStatsSerializer,
|
|
83
|
-
503: {"description": "Service unavailable"},
|
|
84
|
-
},
|
|
85
|
-
)
|
|
86
|
-
@action(detail=False, methods=['get'], url_path='overview')
|
|
87
|
-
def overview(self, request):
|
|
88
|
-
"""Get overview statistics for RPC monitoring."""
|
|
89
|
-
try:
|
|
90
|
-
monitor = RPCMonitor()
|
|
91
|
-
stats_data = monitor.get_overview_stats()
|
|
92
|
-
|
|
93
|
-
serializer = OverviewStatsSerializer(data=stats_data)
|
|
94
|
-
serializer.is_valid(raise_exception=True)
|
|
95
|
-
|
|
96
|
-
return Response(serializer.validated_data)
|
|
97
|
-
|
|
98
|
-
except ValueError as e:
|
|
99
|
-
logger.warning(f"Overview stats validation error: {e}")
|
|
100
|
-
return Response(
|
|
101
|
-
{"error": str(e)},
|
|
102
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
103
|
-
)
|
|
104
|
-
except ConnectionError as e:
|
|
105
|
-
logger.error(f"Overview stats connection error: {e}")
|
|
106
|
-
return Response(
|
|
107
|
-
{"error": "Redis connection unavailable"},
|
|
108
|
-
status=status.HTTP_503_SERVICE_UNAVAILABLE
|
|
109
|
-
)
|
|
110
|
-
except Exception as e:
|
|
111
|
-
logger.error(f"Overview stats error: {e}", exc_info=True)
|
|
112
|
-
return Response(
|
|
113
|
-
{"error": "Internal server error"},
|
|
114
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
@extend_schema(
|
|
118
|
-
tags=['IPC/RPC Monitoring'],
|
|
119
|
-
summary="Get recent RPC requests",
|
|
120
|
-
description="Returns a list of recent RPC requests with their details.",
|
|
121
|
-
parameters=[
|
|
122
|
-
OpenApiParameter(
|
|
123
|
-
name="count",
|
|
124
|
-
type=OpenApiTypes.INT,
|
|
125
|
-
location=OpenApiParameter.QUERY,
|
|
126
|
-
description="Number of requests to return (default: 50, max: 200)",
|
|
127
|
-
required=False,
|
|
128
|
-
),
|
|
129
|
-
],
|
|
130
|
-
responses={
|
|
131
|
-
200: RecentRequestsSerializer,
|
|
132
|
-
400: {"description": "Invalid parameters"},
|
|
133
|
-
503: {"description": "Service unavailable"},
|
|
134
|
-
},
|
|
135
|
-
)
|
|
136
|
-
@action(detail=False, methods=['get'], url_path='requests')
|
|
137
|
-
def requests(self, request):
|
|
138
|
-
"""Get recent RPC requests."""
|
|
139
|
-
try:
|
|
140
|
-
count = int(request.GET.get('count', 50))
|
|
141
|
-
count = min(count, 200) # Max 200
|
|
142
|
-
|
|
143
|
-
monitor = RPCMonitor()
|
|
144
|
-
requests_list = monitor.get_recent_requests(count=count)
|
|
145
|
-
|
|
146
|
-
response_data = {
|
|
147
|
-
'requests': requests_list,
|
|
148
|
-
'count': len(requests_list),
|
|
149
|
-
'total_available': monitor.get_total_requests_count()
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
serializer = RecentRequestsSerializer(data=response_data)
|
|
153
|
-
serializer.is_valid(raise_exception=True)
|
|
154
|
-
|
|
155
|
-
return Response(serializer.validated_data)
|
|
156
|
-
|
|
157
|
-
except ValueError as e:
|
|
158
|
-
logger.warning(f"Recent requests validation error: {e}")
|
|
159
|
-
return Response(
|
|
160
|
-
{"error": "Invalid count parameter"},
|
|
161
|
-
status=status.HTTP_400_BAD_REQUEST
|
|
162
|
-
)
|
|
163
|
-
except ConnectionError as e:
|
|
164
|
-
logger.error(f"Recent requests connection error: {e}")
|
|
165
|
-
return Response(
|
|
166
|
-
{"error": "Redis connection unavailable"},
|
|
167
|
-
status=status.HTTP_503_SERVICE_UNAVAILABLE
|
|
168
|
-
)
|
|
169
|
-
except Exception as e:
|
|
170
|
-
logger.error(f"Recent requests error: {e}", exc_info=True)
|
|
171
|
-
return Response(
|
|
172
|
-
{"error": "Internal server error"},
|
|
173
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
174
|
-
)
|
|
175
|
-
|
|
176
|
-
@extend_schema(
|
|
177
|
-
tags=['IPC/RPC Monitoring'],
|
|
178
|
-
summary="Get notification statistics",
|
|
179
|
-
description="Returns statistics about RPC notifications.",
|
|
180
|
-
responses={
|
|
181
|
-
200: NotificationStatsSerializer,
|
|
182
|
-
503: {"description": "Service unavailable"},
|
|
183
|
-
},
|
|
184
|
-
)
|
|
185
|
-
@action(detail=False, methods=['get'], url_path='notifications')
|
|
186
|
-
def notifications(self, request):
|
|
187
|
-
"""Get notification statistics."""
|
|
188
|
-
try:
|
|
189
|
-
monitor = RPCMonitor()
|
|
190
|
-
stats_data = monitor.get_notification_stats()
|
|
191
|
-
|
|
192
|
-
serializer = NotificationStatsSerializer(data=stats_data)
|
|
193
|
-
serializer.is_valid(raise_exception=True)
|
|
194
|
-
|
|
195
|
-
return Response(serializer.validated_data)
|
|
196
|
-
|
|
197
|
-
except ConnectionError as e:
|
|
198
|
-
logger.error(f"Notification stats connection error: {e}")
|
|
199
|
-
return Response(
|
|
200
|
-
{"error": "Redis connection unavailable"},
|
|
201
|
-
status=status.HTTP_503_SERVICE_UNAVAILABLE
|
|
202
|
-
)
|
|
203
|
-
except Exception as e:
|
|
204
|
-
logger.error(f"Notification stats error: {e}", exc_info=True)
|
|
205
|
-
return Response(
|
|
206
|
-
{"error": "Internal server error"},
|
|
207
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
208
|
-
)
|
|
209
|
-
|
|
210
|
-
@extend_schema(
|
|
211
|
-
tags=['IPC/RPC Monitoring'],
|
|
212
|
-
summary="Get method statistics",
|
|
213
|
-
description="Returns statistics grouped by RPC method.",
|
|
214
|
-
responses={
|
|
215
|
-
200: MethodStatsSerializer,
|
|
216
|
-
503: {"description": "Service unavailable"},
|
|
217
|
-
},
|
|
218
|
-
)
|
|
219
|
-
@action(detail=False, methods=['get'], url_path='methods')
|
|
220
|
-
def methods(self, request):
|
|
221
|
-
"""Get statistics grouped by RPC method."""
|
|
222
|
-
try:
|
|
223
|
-
monitor = RPCMonitor()
|
|
224
|
-
methods_list = monitor.get_method_stats()
|
|
225
|
-
|
|
226
|
-
# Calculate total calls
|
|
227
|
-
total_calls = sum(method.get('count', 0) for method in methods_list)
|
|
228
|
-
|
|
229
|
-
response_data = {
|
|
230
|
-
'methods': methods_list,
|
|
231
|
-
'count': len(methods_list),
|
|
232
|
-
'total_calls': total_calls
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
serializer = MethodStatsSerializer(data=response_data)
|
|
236
|
-
serializer.is_valid(raise_exception=True)
|
|
237
|
-
|
|
238
|
-
return Response(serializer.validated_data)
|
|
239
|
-
|
|
240
|
-
except ConnectionError as e:
|
|
241
|
-
logger.error(f"Method stats connection error: {e}")
|
|
242
|
-
return Response(
|
|
243
|
-
{"error": "Redis connection unavailable"},
|
|
244
|
-
status=status.HTTP_503_SERVICE_UNAVAILABLE
|
|
245
|
-
)
|
|
246
|
-
except Exception as e:
|
|
247
|
-
logger.error(f"Method stats error: {e}", exc_info=True)
|
|
248
|
-
return Response(
|
|
249
|
-
{"error": "Internal server error"},
|
|
250
|
-
status=status.HTTP_500_INTERNAL_SERVER_ERROR
|
|
251
|
-
)
|