crackerjack 0.32.0__py3-none-any.whl → 0.33.1__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 crackerjack might be problematic. Click here for more details.

Files changed (200) hide show
  1. crackerjack/__main__.py +1350 -34
  2. crackerjack/adapters/__init__.py +17 -0
  3. crackerjack/adapters/lsp_client.py +358 -0
  4. crackerjack/adapters/rust_tool_adapter.py +194 -0
  5. crackerjack/adapters/rust_tool_manager.py +193 -0
  6. crackerjack/adapters/skylos_adapter.py +231 -0
  7. crackerjack/adapters/zuban_adapter.py +560 -0
  8. crackerjack/agents/base.py +7 -3
  9. crackerjack/agents/coordinator.py +271 -33
  10. crackerjack/agents/documentation_agent.py +9 -15
  11. crackerjack/agents/dry_agent.py +3 -15
  12. crackerjack/agents/formatting_agent.py +1 -1
  13. crackerjack/agents/import_optimization_agent.py +36 -180
  14. crackerjack/agents/performance_agent.py +17 -98
  15. crackerjack/agents/performance_helpers.py +7 -31
  16. crackerjack/agents/proactive_agent.py +1 -3
  17. crackerjack/agents/refactoring_agent.py +16 -85
  18. crackerjack/agents/refactoring_helpers.py +7 -42
  19. crackerjack/agents/security_agent.py +9 -48
  20. crackerjack/agents/test_creation_agent.py +356 -513
  21. crackerjack/agents/test_specialist_agent.py +0 -4
  22. crackerjack/api.py +6 -25
  23. crackerjack/cli/cache_handlers.py +204 -0
  24. crackerjack/cli/cache_handlers_enhanced.py +683 -0
  25. crackerjack/cli/facade.py +100 -0
  26. crackerjack/cli/handlers.py +224 -9
  27. crackerjack/cli/interactive.py +6 -4
  28. crackerjack/cli/options.py +642 -55
  29. crackerjack/cli/utils.py +2 -1
  30. crackerjack/code_cleaner.py +58 -117
  31. crackerjack/config/global_lock_config.py +8 -48
  32. crackerjack/config/hooks.py +53 -62
  33. crackerjack/core/async_workflow_orchestrator.py +24 -34
  34. crackerjack/core/autofix_coordinator.py +3 -17
  35. crackerjack/core/enhanced_container.py +64 -6
  36. crackerjack/core/file_lifecycle.py +12 -89
  37. crackerjack/core/performance.py +2 -2
  38. crackerjack/core/performance_monitor.py +15 -55
  39. crackerjack/core/phase_coordinator.py +257 -218
  40. crackerjack/core/resource_manager.py +14 -90
  41. crackerjack/core/service_watchdog.py +62 -95
  42. crackerjack/core/session_coordinator.py +149 -0
  43. crackerjack/core/timeout_manager.py +14 -72
  44. crackerjack/core/websocket_lifecycle.py +13 -78
  45. crackerjack/core/workflow_orchestrator.py +558 -240
  46. crackerjack/docs/INDEX.md +11 -0
  47. crackerjack/docs/generated/api/API_REFERENCE.md +10895 -0
  48. crackerjack/docs/generated/api/CLI_REFERENCE.md +109 -0
  49. crackerjack/docs/generated/api/CROSS_REFERENCES.md +1755 -0
  50. crackerjack/docs/generated/api/PROTOCOLS.md +3 -0
  51. crackerjack/docs/generated/api/SERVICES.md +1252 -0
  52. crackerjack/documentation/__init__.py +31 -0
  53. crackerjack/documentation/ai_templates.py +756 -0
  54. crackerjack/documentation/dual_output_generator.py +765 -0
  55. crackerjack/documentation/mkdocs_integration.py +518 -0
  56. crackerjack/documentation/reference_generator.py +977 -0
  57. crackerjack/dynamic_config.py +55 -50
  58. crackerjack/executors/async_hook_executor.py +10 -15
  59. crackerjack/executors/cached_hook_executor.py +117 -43
  60. crackerjack/executors/hook_executor.py +8 -34
  61. crackerjack/executors/hook_lock_manager.py +26 -183
  62. crackerjack/executors/individual_hook_executor.py +13 -11
  63. crackerjack/executors/lsp_aware_hook_executor.py +270 -0
  64. crackerjack/executors/tool_proxy.py +417 -0
  65. crackerjack/hooks/lsp_hook.py +79 -0
  66. crackerjack/intelligence/adaptive_learning.py +25 -10
  67. crackerjack/intelligence/agent_orchestrator.py +2 -5
  68. crackerjack/intelligence/agent_registry.py +34 -24
  69. crackerjack/intelligence/agent_selector.py +5 -7
  70. crackerjack/interactive.py +17 -6
  71. crackerjack/managers/async_hook_manager.py +0 -1
  72. crackerjack/managers/hook_manager.py +79 -1
  73. crackerjack/managers/publish_manager.py +66 -13
  74. crackerjack/managers/test_command_builder.py +5 -17
  75. crackerjack/managers/test_executor.py +1 -3
  76. crackerjack/managers/test_manager.py +109 -7
  77. crackerjack/managers/test_manager_backup.py +10 -9
  78. crackerjack/mcp/cache.py +2 -2
  79. crackerjack/mcp/client_runner.py +1 -1
  80. crackerjack/mcp/context.py +191 -68
  81. crackerjack/mcp/dashboard.py +7 -5
  82. crackerjack/mcp/enhanced_progress_monitor.py +31 -28
  83. crackerjack/mcp/file_monitor.py +30 -23
  84. crackerjack/mcp/progress_components.py +31 -21
  85. crackerjack/mcp/progress_monitor.py +50 -53
  86. crackerjack/mcp/rate_limiter.py +6 -6
  87. crackerjack/mcp/server_core.py +161 -32
  88. crackerjack/mcp/service_watchdog.py +2 -1
  89. crackerjack/mcp/state.py +4 -7
  90. crackerjack/mcp/task_manager.py +11 -9
  91. crackerjack/mcp/tools/core_tools.py +174 -33
  92. crackerjack/mcp/tools/error_analyzer.py +3 -2
  93. crackerjack/mcp/tools/execution_tools.py +15 -12
  94. crackerjack/mcp/tools/execution_tools_backup.py +42 -30
  95. crackerjack/mcp/tools/intelligence_tool_registry.py +7 -5
  96. crackerjack/mcp/tools/intelligence_tools.py +5 -2
  97. crackerjack/mcp/tools/monitoring_tools.py +33 -70
  98. crackerjack/mcp/tools/proactive_tools.py +24 -11
  99. crackerjack/mcp/tools/progress_tools.py +5 -8
  100. crackerjack/mcp/tools/utility_tools.py +20 -14
  101. crackerjack/mcp/tools/workflow_executor.py +62 -40
  102. crackerjack/mcp/websocket/app.py +8 -0
  103. crackerjack/mcp/websocket/endpoints.py +352 -357
  104. crackerjack/mcp/websocket/jobs.py +40 -57
  105. crackerjack/mcp/websocket/monitoring_endpoints.py +2935 -0
  106. crackerjack/mcp/websocket/server.py +7 -25
  107. crackerjack/mcp/websocket/websocket_handler.py +6 -17
  108. crackerjack/mixins/__init__.py +3 -0
  109. crackerjack/mixins/error_handling.py +145 -0
  110. crackerjack/models/config.py +21 -1
  111. crackerjack/models/config_adapter.py +49 -1
  112. crackerjack/models/protocols.py +176 -107
  113. crackerjack/models/resource_protocols.py +55 -210
  114. crackerjack/models/task.py +3 -0
  115. crackerjack/monitoring/ai_agent_watchdog.py +13 -13
  116. crackerjack/monitoring/metrics_collector.py +426 -0
  117. crackerjack/monitoring/regression_prevention.py +8 -8
  118. crackerjack/monitoring/websocket_server.py +643 -0
  119. crackerjack/orchestration/advanced_orchestrator.py +11 -6
  120. crackerjack/orchestration/coverage_improvement.py +3 -3
  121. crackerjack/orchestration/execution_strategies.py +26 -6
  122. crackerjack/orchestration/test_progress_streamer.py +8 -5
  123. crackerjack/plugins/base.py +2 -2
  124. crackerjack/plugins/hooks.py +7 -0
  125. crackerjack/plugins/managers.py +11 -8
  126. crackerjack/security/__init__.py +0 -1
  127. crackerjack/security/audit.py +90 -105
  128. crackerjack/services/anomaly_detector.py +392 -0
  129. crackerjack/services/api_extractor.py +615 -0
  130. crackerjack/services/backup_service.py +2 -2
  131. crackerjack/services/bounded_status_operations.py +15 -152
  132. crackerjack/services/cache.py +127 -1
  133. crackerjack/services/changelog_automation.py +395 -0
  134. crackerjack/services/config.py +18 -11
  135. crackerjack/services/config_merge.py +30 -85
  136. crackerjack/services/config_template.py +506 -0
  137. crackerjack/services/contextual_ai_assistant.py +48 -22
  138. crackerjack/services/coverage_badge_service.py +171 -0
  139. crackerjack/services/coverage_ratchet.py +41 -17
  140. crackerjack/services/debug.py +3 -3
  141. crackerjack/services/dependency_analyzer.py +460 -0
  142. crackerjack/services/dependency_monitor.py +14 -11
  143. crackerjack/services/documentation_generator.py +491 -0
  144. crackerjack/services/documentation_service.py +675 -0
  145. crackerjack/services/enhanced_filesystem.py +6 -5
  146. crackerjack/services/enterprise_optimizer.py +865 -0
  147. crackerjack/services/error_pattern_analyzer.py +676 -0
  148. crackerjack/services/file_hasher.py +1 -1
  149. crackerjack/services/git.py +41 -45
  150. crackerjack/services/health_metrics.py +10 -8
  151. crackerjack/services/heatmap_generator.py +735 -0
  152. crackerjack/services/initialization.py +30 -33
  153. crackerjack/services/input_validator.py +5 -97
  154. crackerjack/services/intelligent_commit.py +327 -0
  155. crackerjack/services/log_manager.py +15 -12
  156. crackerjack/services/logging.py +4 -3
  157. crackerjack/services/lsp_client.py +628 -0
  158. crackerjack/services/memory_optimizer.py +409 -0
  159. crackerjack/services/metrics.py +42 -33
  160. crackerjack/services/parallel_executor.py +416 -0
  161. crackerjack/services/pattern_cache.py +1 -1
  162. crackerjack/services/pattern_detector.py +6 -6
  163. crackerjack/services/performance_benchmarks.py +250 -576
  164. crackerjack/services/performance_cache.py +382 -0
  165. crackerjack/services/performance_monitor.py +565 -0
  166. crackerjack/services/predictive_analytics.py +510 -0
  167. crackerjack/services/quality_baseline.py +234 -0
  168. crackerjack/services/quality_baseline_enhanced.py +646 -0
  169. crackerjack/services/quality_intelligence.py +785 -0
  170. crackerjack/services/regex_patterns.py +605 -524
  171. crackerjack/services/regex_utils.py +43 -123
  172. crackerjack/services/secure_path_utils.py +5 -164
  173. crackerjack/services/secure_status_formatter.py +30 -141
  174. crackerjack/services/secure_subprocess.py +11 -92
  175. crackerjack/services/security.py +61 -30
  176. crackerjack/services/security_logger.py +18 -22
  177. crackerjack/services/server_manager.py +124 -16
  178. crackerjack/services/status_authentication.py +16 -159
  179. crackerjack/services/status_security_manager.py +4 -131
  180. crackerjack/services/terminal_utils.py +0 -0
  181. crackerjack/services/thread_safe_status_collector.py +19 -125
  182. crackerjack/services/unified_config.py +21 -13
  183. crackerjack/services/validation_rate_limiter.py +5 -54
  184. crackerjack/services/version_analyzer.py +459 -0
  185. crackerjack/services/version_checker.py +1 -1
  186. crackerjack/services/websocket_resource_limiter.py +10 -144
  187. crackerjack/services/zuban_lsp_service.py +390 -0
  188. crackerjack/slash_commands/__init__.py +2 -7
  189. crackerjack/slash_commands/run.md +2 -2
  190. crackerjack/tools/validate_input_validator_patterns.py +14 -40
  191. crackerjack/tools/validate_regex_patterns.py +19 -48
  192. {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/METADATA +197 -26
  193. crackerjack-0.33.1.dist-info/RECORD +229 -0
  194. crackerjack/CLAUDE.md +0 -207
  195. crackerjack/RULES.md +0 -380
  196. crackerjack/py313.py +0 -234
  197. crackerjack-0.32.0.dist-info/RECORD +0 -180
  198. {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/WHEEL +0 -0
  199. {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/entry_points.txt +0 -0
  200. {crackerjack-0.32.0.dist-info → crackerjack-0.33.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,11 +1,3 @@
1
- """
2
- WebSocket Resource Limiter to prevent resource exhaustion attacks.
3
-
4
- Provides comprehensive resource monitoring and limiting for WebSocket
5
- connections, including connection limits, message limits, memory usage
6
- tracking, and DoS prevention.
7
- """
8
-
9
1
  import asyncio
10
2
  import time
11
3
  import typing as t
@@ -18,8 +10,6 @@ from .security_logger import SecurityEventLevel, SecurityEventType, get_security
18
10
 
19
11
  @dataclass
20
12
  class ConnectionMetrics:
21
- """Metrics for individual WebSocket connections."""
22
-
23
13
  client_id: str
24
14
  connect_time: float = field(default_factory=time.time)
25
15
  message_count: int = 0
@@ -29,70 +19,44 @@ class ConnectionMetrics:
29
19
 
30
20
  @property
31
21
  def connection_duration(self) -> float:
32
- """Get connection duration in seconds."""
33
22
  return time.time() - self.connect_time
34
23
 
35
24
  @property
36
25
  def idle_time(self) -> float:
37
- """Get idle time since last activity."""
38
26
  return time.time() - self.last_activity
39
27
 
40
28
 
41
29
  @dataclass
42
30
  class ResourceLimits:
43
- """Resource limits configuration."""
44
-
45
31
  max_connections: int = 50
46
32
  max_connections_per_ip: int = 10
47
- max_message_size: int = 64 * 1024 # 64KB
33
+ max_message_size: int = 64 * 1024
48
34
  max_messages_per_minute: int = 100
49
35
  max_messages_per_connection: int = 10000
50
- max_connection_duration: float = 3600.0 # 1 hour
51
- max_idle_time: float = 300.0 # 5 minutes
36
+ max_connection_duration: float = 3600.0
37
+ max_idle_time: float = 300.0
52
38
  max_memory_usage_mb: int = 100
53
39
  connection_timeout: float = 30.0
54
40
  message_timeout: float = 10.0
55
41
 
56
42
 
57
43
  class ResourceExhaustedError(Exception):
58
- """Raised when resource limits are exceeded."""
59
-
60
44
  pass
61
45
 
62
46
 
63
47
  class WebSocketResourceLimiter:
64
- """
65
- Resource limiter for WebSocket connections.
66
-
67
- Features:
68
- - Connection count and per-IP limits
69
- - Message size and rate limiting
70
- - Memory usage monitoring
71
- - Connection duration limits
72
- - Idle connection cleanup
73
- - DoS attack prevention
74
- """
75
-
76
48
  def __init__(self, limits: ResourceLimits | None = None):
77
- """
78
- Initialize WebSocket resource limiter.
79
-
80
- Args:
81
- limits: Resource limits configuration
82
- """
83
49
  self.limits = limits or ResourceLimits()
84
50
  self.security_logger = get_security_logger()
85
51
 
86
52
  self._setup_limiter_components()
87
53
 
88
54
  def _setup_limiter_components(self) -> None:
89
- """Set up all limiter components in initialization."""
90
55
  self._initialize_connection_tracking()
91
56
  self._initialize_metrics_tracking()
92
57
  self._initialize_cleanup_system()
93
58
 
94
59
  def _initialize_connection_tracking(self) -> None:
95
- """Initialize thread-safe connection tracking structures."""
96
60
  self._lock = RLock()
97
61
  self._connections: dict[str, ConnectionMetrics] = {}
98
62
  self._ip_connections: dict[str, set[str]] = defaultdict(set)
@@ -102,20 +66,16 @@ class WebSocketResourceLimiter:
102
66
  self._blocked_ips: dict[str, float] = {}
103
67
 
104
68
  def _initialize_metrics_tracking(self) -> None:
105
- """Initialize metrics tracking with proper typing."""
106
69
  self._connection_metrics: dict[str, ConnectionMetrics] = {}
107
70
  self._message_queues: dict[str, deque[bytes]] = defaultdict(deque)
108
71
  self._resource_usage: dict[str, dict[str, t.Any]] = {}
109
72
  self._memory_usage: int = 0
110
73
 
111
74
  def _initialize_cleanup_system(self) -> None:
112
- """Initialize the background cleanup system."""
113
75
  self._cleanup_task: asyncio.Task[t.Any] | None = None
114
76
  self._shutdown_event = asyncio.Event()
115
77
 
116
78
  async def start(self) -> None:
117
- """Start the resource limiter with background cleanup."""
118
-
119
79
  if self._cleanup_task is None:
120
80
  self._cleanup_task = asyncio.create_task(self._cleanup_loop())
121
81
 
@@ -127,8 +87,6 @@ class WebSocketResourceLimiter:
127
87
  )
128
88
 
129
89
  async def stop(self) -> None:
130
- """Stop the resource limiter and cleanup resources."""
131
-
132
90
  self._shutdown_event.set()
133
91
 
134
92
  if self._cleanup_task:
@@ -143,7 +101,6 @@ class WebSocketResourceLimiter:
143
101
 
144
102
  self._cleanup_task = None
145
103
 
146
- # Force cleanup all connections
147
104
  with self._lock:
148
105
  self._connections.clear()
149
106
  self._ip_connections.clear()
@@ -157,17 +114,6 @@ class WebSocketResourceLimiter:
157
114
  )
158
115
 
159
116
  def validate_new_connection(self, client_id: str, client_ip: str) -> None:
160
- """
161
- Validate if a new connection can be accepted.
162
-
163
- Args:
164
- client_id: Unique client identifier
165
- client_ip: Client IP address
166
-
167
- Raises:
168
- ResourceExhaustedError: If connection limits exceeded
169
- """
170
-
171
117
  with self._lock:
172
118
  current_time = time.time()
173
119
 
@@ -176,7 +122,6 @@ class WebSocketResourceLimiter:
176
122
  self._check_per_ip_connection_limit(client_id, client_ip, current_time)
177
123
 
178
124
  def _check_ip_blocking_status(self, client_ip: str, current_time: float) -> None:
179
- """Check if IP is currently blocked."""
180
125
  if client_ip in self._blocked_ips:
181
126
  if current_time < self._blocked_ips[client_ip]:
182
127
  raise ResourceExhaustedError(f"IP {client_ip} is temporarily blocked")
@@ -184,7 +129,6 @@ class WebSocketResourceLimiter:
184
129
  del self._blocked_ips[client_ip]
185
130
 
186
131
  def _check_total_connection_limit(self, client_id: str, client_ip: str) -> None:
187
- """Check if total connection limit is exceeded."""
188
132
  if len(self._connections) >= self.limits.max_connections:
189
133
  self.security_logger.log_security_event(
190
134
  event_type=SecurityEventType.RATE_LIMIT_EXCEEDED,
@@ -201,7 +145,6 @@ class WebSocketResourceLimiter:
201
145
  def _check_per_ip_connection_limit(
202
146
  self, client_id: str, client_ip: str, current_time: float
203
147
  ) -> None:
204
- """Check if per-IP connection limit is exceeded."""
205
148
  ip_connection_count = len(self._ip_connections[client_ip])
206
149
  if ip_connection_count >= self.limits.max_connections_per_ip:
207
150
  self.security_logger.log_security_event(
@@ -213,22 +156,13 @@ class WebSocketResourceLimiter:
213
156
  additional_data={"client_ip": client_ip},
214
157
  )
215
158
 
216
- # Block IP temporarily for repeated violations
217
- self._blocked_ips[client_ip] = current_time + 300.0 # 5 minute block
159
+ self._blocked_ips[client_ip] = current_time + 300.0
218
160
 
219
161
  raise ResourceExhaustedError(
220
162
  f"Maximum connections per IP exceeded: {ip_connection_count}"
221
163
  )
222
164
 
223
165
  def register_connection(self, client_id: str, client_ip: str) -> None:
224
- """
225
- Register a new WebSocket connection.
226
-
227
- Args:
228
- client_id: Unique client identifier
229
- client_ip: Client IP address
230
- """
231
-
232
166
  with self._lock:
233
167
  metrics = ConnectionMetrics(client_id=client_id)
234
168
  self._connections[client_id] = metrics
@@ -244,14 +178,6 @@ class WebSocketResourceLimiter:
244
178
  )
245
179
 
246
180
  def unregister_connection(self, client_id: str, client_ip: str) -> None:
247
- """
248
- Unregister a WebSocket connection.
249
-
250
- Args:
251
- client_id: Unique client identifier
252
- client_ip: Client IP address
253
- """
254
-
255
181
  with self._lock:
256
182
  if client_id in self._connections:
257
183
  metrics = self._connections[client_id]
@@ -272,28 +198,15 @@ class WebSocketResourceLimiter:
272
198
  },
273
199
  )
274
200
 
275
- # Remove from IP tracking
276
201
  if client_ip in self._ip_connections:
277
202
  self._ip_connections[client_ip].discard(client_id)
278
203
  if not self._ip_connections[client_ip]:
279
204
  del self._ip_connections[client_ip]
280
205
 
281
- # Clear message history
282
206
  if client_id in self._message_history:
283
207
  del self._message_history[client_id]
284
208
 
285
209
  def validate_message(self, client_id: str, message_size: int) -> None:
286
- """
287
- Validate if a message can be processed.
288
-
289
- Args:
290
- client_id: Client identifier
291
- message_size: Size of the message in bytes
292
-
293
- Raises:
294
- ResourceExhaustedError: If message limits exceeded
295
- """
296
-
297
210
  with self._lock:
298
211
  self._check_message_size(client_id, message_size)
299
212
  metrics = self._get_connection_metrics(client_id)
@@ -301,7 +214,6 @@ class WebSocketResourceLimiter:
301
214
  self._check_message_rate(client_id)
302
215
 
303
216
  def _check_message_size(self, client_id: str, message_size: int) -> None:
304
- """Check if message size exceeds limits."""
305
217
  if message_size > self.limits.max_message_size:
306
218
  self.security_logger.log_security_event(
307
219
  event_type=SecurityEventType.RATE_LIMIT_EXCEEDED,
@@ -313,13 +225,11 @@ class WebSocketResourceLimiter:
313
225
  raise ResourceExhaustedError(f"Message too large: {message_size} bytes")
314
226
 
315
227
  def _get_connection_metrics(self, client_id: str) -> ConnectionMetrics:
316
- """Get connection metrics, raising error if connection doesn't exist."""
317
228
  if client_id not in self._connections:
318
229
  raise ResourceExhaustedError(f"Connection not registered: {client_id}")
319
230
  return self._connections[client_id]
320
231
 
321
232
  def _check_message_count(self, client_id: str, metrics: ConnectionMetrics) -> None:
322
- """Check if total message count per connection exceeds limits."""
323
233
  if metrics.message_count >= self.limits.max_messages_per_connection:
324
234
  self.security_logger.log_security_event(
325
235
  event_type=SecurityEventType.RATE_LIMIT_EXCEEDED,
@@ -333,11 +243,9 @@ class WebSocketResourceLimiter:
333
243
  )
334
244
 
335
245
  def _check_message_rate(self, client_id: str) -> None:
336
- """Check if message rate exceeds per-minute limits."""
337
246
  current_time = time.time()
338
247
  message_times = self._message_history[client_id]
339
248
 
340
- # Remove old messages (older than 1 minute)
341
249
  while message_times and current_time - message_times[0] > 60.0:
342
250
  message_times.popleft()
343
251
 
@@ -356,15 +264,6 @@ class WebSocketResourceLimiter:
356
264
  def track_message(
357
265
  self, client_id: str, message_size: int, is_sent: bool = True
358
266
  ) -> None:
359
- """
360
- Track a processed message.
361
-
362
- Args:
363
- client_id: Client identifier
364
- message_size: Size of the message in bytes
365
- is_sent: True if message was sent, False if received
366
- """
367
-
368
267
  with self._lock:
369
268
  current_time = time.time()
370
269
 
@@ -378,20 +277,9 @@ class WebSocketResourceLimiter:
378
277
  else:
379
278
  metrics.bytes_received += message_size
380
279
 
381
- # Track message timing for rate limiting
382
280
  self._message_history[client_id].append(current_time)
383
281
 
384
282
  async def check_connection_limits(self, client_id: str) -> None:
385
- """
386
- Check if connection has exceeded limits.
387
-
388
- Args:
389
- client_id: Client identifier
390
-
391
- Raises:
392
- ResourceExhaustedError: If connection limits exceeded
393
- """
394
-
395
283
  with self._lock:
396
284
  if client_id not in self._connections:
397
285
  return
@@ -399,45 +287,40 @@ class WebSocketResourceLimiter:
399
287
  metrics = self._connections[client_id]
400
288
  time.time()
401
289
 
402
- # Check connection duration
403
290
  if metrics.connection_duration > self.limits.max_connection_duration:
404
291
  self.security_logger.log_security_event(
405
292
  event_type=SecurityEventType.CONNECTION_TIMEOUT,
406
293
  level=SecurityEventLevel.WARNING,
407
- message=f"Connection duration exceeded: {metrics.connection_duration:.1f}s",
294
+ message=f"Connection duration exceeded: {metrics.connection_duration: .1f}s",
408
295
  client_id=client_id,
409
296
  operation="connection_limit_check",
410
297
  )
411
298
  raise ResourceExhaustedError(
412
- f"Connection duration exceeded: {metrics.connection_duration:.1f}s"
299
+ f"Connection duration exceeded: {metrics.connection_duration: .1f}s"
413
300
  )
414
301
 
415
- # Check idle time
416
302
  if metrics.idle_time > self.limits.max_idle_time:
417
303
  self.security_logger.log_security_event(
418
304
  event_type=SecurityEventType.CONNECTION_IDLE,
419
305
  level=SecurityEventLevel.INFO,
420
- message=f"Connection idle timeout: {metrics.idle_time:.1f}s",
306
+ message=f"Connection idle timeout: {metrics.idle_time: .1f}s",
421
307
  client_id=client_id,
422
308
  operation="connection_limit_check",
423
309
  )
424
310
  raise ResourceExhaustedError(
425
- f"Connection idle timeout: {metrics.idle_time:.1f}s"
311
+ f"Connection idle timeout: {metrics.idle_time: .1f}s"
426
312
  )
427
313
 
428
314
  async def _cleanup_loop(self) -> None:
429
- """Background cleanup loop for expired connections and resources."""
430
-
431
315
  while not self._shutdown_event.is_set():
432
316
  try:
433
317
  await asyncio.wait_for(
434
318
  self._shutdown_event.wait(),
435
- timeout=30.0, # Cleanup every 30 seconds
319
+ timeout=30.0,
436
320
  )
437
- break # Shutdown requested
321
+ break
438
322
 
439
323
  except TimeoutError:
440
- # Perform cleanup
441
324
  await self._perform_cleanup()
442
325
 
443
326
  self.security_logger.log_security_event(
@@ -448,7 +331,6 @@ class WebSocketResourceLimiter:
448
331
  )
449
332
 
450
333
  async def _perform_cleanup(self) -> None:
451
- """Perform resource cleanup."""
452
334
  current_time = time.time()
453
335
 
454
336
  with self._lock:
@@ -459,7 +341,6 @@ class WebSocketResourceLimiter:
459
341
  self._log_cleanup_results(cleanup_count)
460
342
 
461
343
  def _cleanup_expired_connections(self, current_time: float) -> int:
462
- """Clean up expired connections and return count of cleaned connections."""
463
344
  expired_connections = self._find_expired_connections()
464
345
  cleanup_count = 0
465
346
 
@@ -470,7 +351,6 @@ class WebSocketResourceLimiter:
470
351
  return cleanup_count
471
352
 
472
353
  def _find_expired_connections(self) -> list[str]:
473
- """Find connections that have exceeded duration or idle time limits."""
474
354
  return [
475
355
  client_id
476
356
  for client_id, metrics in self._connections.items()
@@ -481,31 +361,25 @@ class WebSocketResourceLimiter:
481
361
  ]
482
362
 
483
363
  def _remove_expired_connection(self, client_id: str) -> bool:
484
- """Remove a specific expired connection and its associated data."""
485
364
  if client_id not in self._connections:
486
365
  return False
487
366
 
488
- # Remove connection metrics
489
367
  del self._connections[client_id]
490
368
 
491
- # Clean up IP tracking
492
369
  for client_set in self._ip_connections.values():
493
370
  client_set.discard(client_id)
494
371
 
495
- # Clean up message history
496
372
  if client_id in self._message_history:
497
373
  del self._message_history[client_id]
498
374
 
499
375
  return True
500
376
 
501
377
  def _cleanup_empty_ip_entries(self) -> None:
502
- """Remove IP entries that no longer have any connections."""
503
378
  empty_ips = [ip for ip, clients in self._ip_connections.items() if not clients]
504
379
  for ip in empty_ips:
505
380
  del self._ip_connections[ip]
506
381
 
507
382
  def _cleanup_expired_ip_blocks(self, current_time: float) -> None:
508
- """Remove IP blocks that have expired."""
509
383
  expired_blocks = [
510
384
  ip
511
385
  for ip, block_until in self._blocked_ips.items()
@@ -515,7 +389,6 @@ class WebSocketResourceLimiter:
515
389
  del self._blocked_ips[ip]
516
390
 
517
391
  def _log_cleanup_results(self, cleanup_count: int) -> None:
518
- """Log cleanup results if any connections were cleaned up."""
519
392
  if cleanup_count > 0:
520
393
  self.security_logger.log_security_event(
521
394
  event_type=SecurityEventType.RESOURCE_CLEANUP,
@@ -525,8 +398,6 @@ class WebSocketResourceLimiter:
525
398
  )
526
399
 
527
400
  def get_resource_status(self) -> dict[str, t.Any]:
528
- """Get current resource usage status."""
529
-
530
401
  with self._lock:
531
402
  return {
532
403
  "connections": {
@@ -551,21 +422,16 @@ class WebSocketResourceLimiter:
551
422
  }
552
423
 
553
424
  def get_connection_metrics(self, client_id: str) -> ConnectionMetrics | None:
554
- """Get metrics for a specific connection."""
555
-
556
425
  with self._lock:
557
426
  return self._connections.get(client_id)
558
427
 
559
428
 
560
- # Global singleton instance
561
429
  _resource_limiter: WebSocketResourceLimiter | None = None
562
430
 
563
431
 
564
432
  def get_websocket_resource_limiter(
565
433
  limits: ResourceLimits | None = None,
566
434
  ) -> WebSocketResourceLimiter:
567
- """Get the global WebSocket resource limiter instance."""
568
-
569
435
  global _resource_limiter
570
436
  if _resource_limiter is None:
571
437
  _resource_limiter = WebSocketResourceLimiter(limits)