springbootAI 1.8.0__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.
- spring/__init__.py +66 -0
- spring/ai/__init__.py +78 -0
- spring/ai/advisors.py +139 -0
- spring/ai/annotations.py +74 -0
- spring/ai/autoconfig.py +481 -0
- spring/ai/core.py +391 -0
- spring/ai/etl.py +188 -0
- spring/ai/memory.py +109 -0
- spring/ai/observability.py +129 -0
- spring/ai/providers.py +789 -0
- spring/ai/resilience.py +258 -0
- spring/ai/tools.py +106 -0
- spring/ai/vectorstore.py +303 -0
- spring/annotations/__init__.py +188 -0
- spring/annotations/cache.py +126 -0
- spring/annotations/cloud.py +207 -0
- spring/annotations/conditional.py +272 -0
- spring/annotations/core.py +864 -0
- spring/annotations/messaging.py +107 -0
- spring/aop/__init__.py +4 -0
- spring/aop/cloud_aop.py +404 -0
- spring/aop/comprehensive_aop.py +1015 -0
- spring/aop/method_interceptor.py +19 -0
- spring/aop/proxy_factory.py +55 -0
- spring/cloud/__init__.py +76 -0
- spring/cloud/discovery.py +364 -0
- spring/cloud/feign.py +469 -0
- spring/cloud/gateway.py +452 -0
- spring/cloud/load_balancer.py +149 -0
- spring/cloud/seata.py +557 -0
- spring/cloud/sentinel.py +525 -0
- spring/cloud/tracer.py +337 -0
- spring/config/__init__.py +21 -0
- spring/config/binding.py +206 -0
- spring/config/config_loader.py +405 -0
- spring/context/__init__.py +13 -0
- spring/context/application_context.py +589 -0
- spring/context/bean_definition.py +70 -0
- spring/context/bean_factory.py +1052 -0
- spring/context/registry.py +58 -0
- spring/context/scanner.py +106 -0
- spring/core/__init__.py +3 -0
- spring/core/graceful_shutdown.py +196 -0
- spring/core/typing_utils.py +50 -0
- spring/csv/__init__.py +52 -0
- spring/csv/annotations.py +402 -0
- spring/csv/converters.py +69 -0
- spring/csv/easy_csv.py +95 -0
- spring/csv/exceptions.py +27 -0
- spring/csv/reader.py +195 -0
- spring/csv/writer.py +155 -0
- spring/data/__init__.py +54 -0
- spring/data/page.py +181 -0
- spring/data/repository.py +274 -0
- spring/data/specification.py +228 -0
- spring/datasource/__init__.py +66 -0
- spring/datasource/annotations.py +133 -0
- spring/datasource/context.py +69 -0
- spring/datasource/dynamic.py +148 -0
- spring/event/__init__.py +7 -0
- spring/event/publisher.py +69 -0
- spring/excel/__init__.py +51 -0
- spring/excel/annotations.py +405 -0
- spring/excel/converters.py +231 -0
- spring/excel/easy_excel.py +94 -0
- spring/excel/exceptions.py +31 -0
- spring/excel/reader.py +254 -0
- spring/excel/style.py +95 -0
- spring/excel/writer.py +197 -0
- spring/i18n/__init__.py +97 -0
- spring/i18n/accessor.py +94 -0
- spring/i18n/auto_config.py +177 -0
- spring/i18n/holder.py +106 -0
- spring/i18n/locale.py +152 -0
- spring/i18n/locale_resolver.py +367 -0
- spring/i18n/message_source.py +250 -0
- spring/i18n/middleware.py +79 -0
- spring/i18n/properties.py +168 -0
- spring/i18n/sources.py +255 -0
- spring/logging/__init__.py +1 -0
- spring/logging/loguru_logger.py +228 -0
- spring/main.py +378 -0
- spring/messaging/__init__.py +1 -0
- spring/messaging/rabbitmq.py +302 -0
- spring/monitoring/__init__.py +1 -0
- spring/monitoring/prometheus.py +199 -0
- spring/orm/__init__.py +258 -0
- spring/orm/database.py +222 -0
- spring/orm/ddl_auto.py +1217 -0
- spring/orm/migration.py +419 -0
- spring/orm/mybatis_integration.py +400 -0
- spring/orm/pymybatis/__init__.py +86 -0
- spring/orm/pymybatis/annotations/__init__.py +30 -0
- spring/orm/pymybatis/annotations/annotations.py +332 -0
- spring/orm/pymybatis/cache/__init__.py +47 -0
- spring/orm/pymybatis/cache/cache.py +371 -0
- spring/orm/pymybatis/cache/redis_cache.py +434 -0
- spring/orm/pymybatis/circuit_breaker/__init__.py +21 -0
- spring/orm/pymybatis/circuit_breaker/circuit_breaker.py +424 -0
- spring/orm/pymybatis/configuration.py +525 -0
- spring/orm/pymybatis/core/__init__.py +10 -0
- spring/orm/pymybatis/core/sql_session.py +1382 -0
- spring/orm/pymybatis/core/sql_session_factory.py +76 -0
- spring/orm/pymybatis/dialect/__init__.py +9 -0
- spring/orm/pymybatis/dialect/dialect.py +445 -0
- spring/orm/pymybatis/dynamic_sql/__init__.py +9 -0
- spring/orm/pymybatis/dynamic_sql/dynamic_sql.py +900 -0
- spring/orm/pymybatis/interceptor/__init__.py +31 -0
- spring/orm/pymybatis/interceptor/interceptor.py +427 -0
- spring/orm/pymybatis/mapper/__init__.py +9 -0
- spring/orm/pymybatis/mapper/mapper.py +540 -0
- spring/orm/pymybatis/metrics/__init__.py +41 -0
- spring/orm/pymybatis/metrics/metrics.py +595 -0
- spring/orm/pymybatis/pool/__init__.py +9 -0
- spring/orm/pymybatis/pool/connection_pool.py +711 -0
- spring/orm/pymybatis/security/__init__.py +19 -0
- spring/orm/pymybatis/security/access_control.py +415 -0
- spring/orm/pymybatis/security/password_encoder.py +293 -0
- spring/orm/pymybatis/security/sensitive_data_masker.py +326 -0
- spring/orm/pymybatis/security/sql_injection_detector.py +675 -0
- spring/orm/pymybatis/transaction/__init__.py +9 -0
- spring/orm/pymybatis/transaction/transaction.py +288 -0
- spring/orm/pymybatis/type_handler/__init__.py +37 -0
- spring/orm/pymybatis/type_handler/type_handler.py +473 -0
- spring/orm/pymybatis/version.py +9 -0
- spring/orm/pymybatis/xml_parser/__init__.py +9 -0
- spring/orm/pymybatis/xml_parser/xml_parser.py +761 -0
- spring/retry/__init__.py +12 -0
- spring/retry/retry_annotations.py +71 -0
- spring/retry/retry_decorator.py +155 -0
- spring/scheduling/__init__.py +3 -0
- spring/scheduling/scheduler.py +389 -0
- spring/security/__init__.py +39 -0
- spring/security/jwt_utils.py +281 -0
- spring/security/replay_protection.py +206 -0
- spring/security/secret_manager.py +226 -0
- spring/security/security_aop.py +248 -0
- spring/security/security_context.py +172 -0
- spring/test/__init__.py +45 -0
- spring/test/slicing.py +341 -0
- spring/tracing/__init__.py +11 -0
- spring/tracing/skywalking.py +229 -0
- spring/tx/__init__.py +52 -0
- spring/tx/events.py +172 -0
- spring/tx/synchronization.py +143 -0
- spring/utils/__init__.py +5 -0
- spring/utils/banner.py +32 -0
- spring/utils/logger.py +73 -0
- spring/utils/redis_client.py +526 -0
- spring/validation/__init__.py +55 -0
- spring/validation/aop.py +141 -0
- spring/validation/constraints.py +357 -0
- spring/validation/exceptions.py +55 -0
- spring/validation/validator.py +139 -0
- spring/web/__init__.py +12 -0
- spring/web/actuator.py +319 -0
- spring/web/exception_handler.py +61 -0
- spring/web/health.py +399 -0
- spring/web/interceptor.py +91 -0
- spring/web/result.py +44 -0
- spring/web/swagger.py +601 -0
- spring/web/web_context.py +755 -0
- spring/websocket/__init__.py +86 -0
- spring/websocket/annotations.py +169 -0
- spring/websocket/broker.py +238 -0
- spring/websocket/exceptions.py +26 -0
- spring/websocket/handler.py +243 -0
- spring/websocket/router.py +526 -0
- spring/websocket/session.py +216 -0
- springbootai-1.8.0.dist-info/METADATA +2796 -0
- springbootai-1.8.0.dist-info/RECORD +175 -0
- springbootai-1.8.0.dist-info/WHEEL +5 -0
- springbootai-1.8.0.dist-info/entry_points.txt +2 -0
- springbootai-1.8.0.dist-info/licenses/LICENSE +7 -0
- springbootai-1.8.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"""WebSocket Handler 接口与 ``@ServerEndpoint`` 类级注解(对齐 Spring
|
|
2
|
+
``WebSocketHandler`` + JSR-356 ``@ServerEndpoint``)。
|
|
3
|
+
|
|
4
|
+
两种使用范式:
|
|
5
|
+
|
|
6
|
+
1. **接口风格**(对齐 Spring ``WebSocketHandler``)::
|
|
7
|
+
|
|
8
|
+
class EchoHandler(WebSocketHandler):
|
|
9
|
+
async def after_connection_established(self, session):
|
|
10
|
+
await session.send_text("welcome")
|
|
11
|
+
async def handle_message(self, session, message):
|
|
12
|
+
await session.send_text("echo: " + message)
|
|
13
|
+
|
|
14
|
+
或更便捷的 ``TextWebSocketHandler`` / ``BinaryWebSocketHandler``。
|
|
15
|
+
|
|
16
|
+
2. **JSR-356 注解风格**(``@ServerEndpoint``)::
|
|
17
|
+
|
|
18
|
+
@ServerEndpoint("/ws/echo")
|
|
19
|
+
class EchoEndpoint:
|
|
20
|
+
async def on_open(self, session): ...
|
|
21
|
+
async def on_message(self, session, message): ...
|
|
22
|
+
async def on_close(self, session, reason): ...
|
|
23
|
+
async def on_error(self, session, error): ...
|
|
24
|
+
|
|
25
|
+
``@ServerEndpoint`` 只注册元数据(路径 + 生命周期方法名),实际方法包装由
|
|
26
|
+
``AnnotatedEndpointHandler`` 完成(适配到 ``WebSocketHandler`` 接口)。
|
|
27
|
+
``discover_server_endpoints`` 扫描模块/类列表,返回 ``{path: endpoint_cls}`` 字典,
|
|
28
|
+
供 ``WebSocketRouter`` 挂载路由。
|
|
29
|
+
"""
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
import inspect
|
|
33
|
+
import logging
|
|
34
|
+
from typing import Any, Awaitable, Callable, Dict, Iterable, List, Optional, Type, Union
|
|
35
|
+
|
|
36
|
+
from spring.annotations.core import SpringAnnotation
|
|
37
|
+
|
|
38
|
+
from .exceptions import WebSocketHandlerException
|
|
39
|
+
from .session import WebSocketSession, global_session_registry
|
|
40
|
+
|
|
41
|
+
logger = logging.getLogger("Spring.WebSocket.Handler")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ==================== WebSocketHandler 接口 ====================
|
|
45
|
+
|
|
46
|
+
class WebSocketHandler:
|
|
47
|
+
"""WebSocket 处理器接口(对齐 Spring ``WebSocketHandler``)。
|
|
48
|
+
|
|
49
|
+
子类覆盖以下方法:
|
|
50
|
+
- ``after_connection_established(session)``:连接建立后调用。
|
|
51
|
+
- ``handle_text_message(session, message)``:处理文本消息(默认调用 ``handle_message``)。
|
|
52
|
+
- ``handle_binary_message(session, data)``:处理二进制消息(默认调用 ``handle_message``)。
|
|
53
|
+
- ``handle_message(session, message)``:通用消息处理(默认 no-op)。
|
|
54
|
+
- ``handle_transport_error(session, exception)``:传输错误。
|
|
55
|
+
- ``after_connection_closed(session, reason)``:连接关闭后调用。
|
|
56
|
+
- ``supports_partial_messages()``:是否支持分片消息,默认 False。
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
async def after_connection_established(self, session: WebSocketSession) -> None:
|
|
60
|
+
"""连接建立后调用(默认 no-op)。"""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
async def handle_text_message(self, session: WebSocketSession, message: str) -> None:
|
|
64
|
+
await self.handle_message(session, message)
|
|
65
|
+
|
|
66
|
+
async def handle_binary_message(self, session: WebSocketSession, data: bytes) -> None:
|
|
67
|
+
await self.handle_message(session, data)
|
|
68
|
+
|
|
69
|
+
async def handle_message(self, session: WebSocketSession, message: Any) -> None:
|
|
70
|
+
"""通用消息处理(默认 no-op,子类覆盖)。"""
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
async def handle_transport_error(self, session: WebSocketSession, exception: Exception) -> None:
|
|
74
|
+
logger.warning("WebSocket transport error on session %s: %s", session.id, exception)
|
|
75
|
+
|
|
76
|
+
async def after_connection_closed(self, session: WebSocketSession, reason: str) -> None:
|
|
77
|
+
"""连接关闭后调用(默认 no-op)。"""
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
def supports_partial_messages(self) -> bool:
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class TextWebSocketHandler(WebSocketHandler):
|
|
85
|
+
"""文本消息便捷基类(对齐 Spring ``TextWebSocketHandler``)。
|
|
86
|
+
|
|
87
|
+
子类只需覆盖 ``handle_text_message`` 即可处理文本消息。
|
|
88
|
+
二进制消息默认拒绝(抛 ``WebSocketHandlerException``)。
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
async def handle_binary_message(self, session: WebSocketSession, data: bytes) -> None:
|
|
92
|
+
raise WebSocketHandlerException(
|
|
93
|
+
f"{type(self).__name__} 不支持二进制消息(覆盖 handle_binary_message 以启用)"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class BinaryWebSocketHandler(WebSocketHandler):
|
|
98
|
+
"""二进制消息便捷基类(对齐 Spring ``BinaryWebSocketHandler``)。
|
|
99
|
+
|
|
100
|
+
子类只需覆盖 ``handle_binary_message`` 即可处理二进制消息。
|
|
101
|
+
文本消息默认拒绝。
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
async def handle_text_message(self, session: WebSocketSession, message: str) -> None:
|
|
105
|
+
raise WebSocketHandlerException(
|
|
106
|
+
f"{type(self).__name__} 不支持文本消息(覆盖 handle_text_message 以启用)"
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
# ==================== @ServerEndpoint 注解 ====================
|
|
111
|
+
|
|
112
|
+
class ServerEndpoint(SpringAnnotation):
|
|
113
|
+
"""``@ServerEndpoint("/ws/echo")`` 类级注解(JSR-356 风格)。
|
|
114
|
+
|
|
115
|
+
标注的类作为 WebSocket 端点,可定义以下生命周期方法(均为 ``async``):
|
|
116
|
+
- ``on_open(session)``:连接建立后调用。
|
|
117
|
+
- ``on_message(session, message)``:收到消息时调用(文本/二进制备用同名方法)。
|
|
118
|
+
- ``on_close(session, reason)``:连接关闭后调用。
|
|
119
|
+
- ``on_error(session, error)``:异常时调用。
|
|
120
|
+
|
|
121
|
+
用法::
|
|
122
|
+
|
|
123
|
+
@ServerEndpoint("/ws/echo")
|
|
124
|
+
class EchoEndpoint:
|
|
125
|
+
async def on_open(self, session):
|
|
126
|
+
await session.send_text("welcome")
|
|
127
|
+
async def on_message(self, session, message):
|
|
128
|
+
await session.send_text("echo: " + message)
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
_annotation_type = "server_endpoint"
|
|
132
|
+
|
|
133
|
+
def __init__(self, value: str = "", subprotocols: Optional[List[str]] = None):
|
|
134
|
+
super().__init__(value=value, subprotocols=subprotocols or [])
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# ==================== AnnotatedEndpointHandler ====================
|
|
138
|
+
|
|
139
|
+
class AnnotatedEndpointHandler(WebSocketHandler):
|
|
140
|
+
"""把 ``@ServerEndpoint`` 标注的类适配到 ``WebSocketHandler`` 接口。
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
endpoint_cls: ``@ServerEndpoint`` 标注的类。
|
|
144
|
+
instance: 可选的预构造实例(用于 IoC 注入依赖);为 None 时用 ``endpoint_cls()``。
|
|
145
|
+
"""
|
|
146
|
+
|
|
147
|
+
def __init__(self, endpoint_cls: Type, instance: Optional[Any] = None):
|
|
148
|
+
self._endpoint_cls = endpoint_cls
|
|
149
|
+
self._instance = instance # 延迟构造,按需创建
|
|
150
|
+
|
|
151
|
+
def _get_instance(self) -> Any:
|
|
152
|
+
if self._instance is None:
|
|
153
|
+
self._instance = self._endpoint_cls()
|
|
154
|
+
return self._instance
|
|
155
|
+
|
|
156
|
+
async def after_connection_established(self, session: WebSocketSession) -> None:
|
|
157
|
+
await self._call_lifecycle("on_open", session)
|
|
158
|
+
|
|
159
|
+
async def handle_text_message(self, session: WebSocketSession, message: str) -> None:
|
|
160
|
+
await self._call_lifecycle("on_message", session, message)
|
|
161
|
+
|
|
162
|
+
async def handle_binary_message(self, session: WebSocketSession, data: bytes) -> None:
|
|
163
|
+
# 优先 on_bytes,否则复用 on_message
|
|
164
|
+
instance = self._get_instance()
|
|
165
|
+
on_bytes = getattr(instance, "on_bytes", None)
|
|
166
|
+
if callable(on_bytes):
|
|
167
|
+
await self._invoke(on_bytes, session, data)
|
|
168
|
+
else:
|
|
169
|
+
await self._call_lifecycle("on_message", session, data)
|
|
170
|
+
|
|
171
|
+
async def handle_transport_error(self, session: WebSocketSession, exception: Exception) -> None:
|
|
172
|
+
await self._call_lifecycle("on_error", session, exception)
|
|
173
|
+
|
|
174
|
+
async def after_connection_closed(self, session: WebSocketSession, reason: str) -> None:
|
|
175
|
+
await self._call_lifecycle("on_close", session, reason)
|
|
176
|
+
|
|
177
|
+
async def _call_lifecycle(self, method_name: str, *args) -> None:
|
|
178
|
+
instance = self._get_instance()
|
|
179
|
+
method = getattr(instance, method_name, None)
|
|
180
|
+
if not callable(method):
|
|
181
|
+
return # 钩子未定义,跳过
|
|
182
|
+
await self._invoke(method, *args)
|
|
183
|
+
|
|
184
|
+
async def _invoke(self, method: Callable, *args) -> None:
|
|
185
|
+
try:
|
|
186
|
+
result = method(*args)
|
|
187
|
+
if inspect.isawaitable(result):
|
|
188
|
+
await result
|
|
189
|
+
except Exception as exc:
|
|
190
|
+
logger.warning(
|
|
191
|
+
"ServerEndpoint %s.%s 抛异常: %s",
|
|
192
|
+
self._endpoint_cls.__name__, method.__name__, exc
|
|
193
|
+
)
|
|
194
|
+
raise WebSocketHandlerException(str(exc)) from exc
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
# ==================== 端点发现 ====================
|
|
198
|
+
|
|
199
|
+
def discover_server_endpoints(
|
|
200
|
+
classes: Optional[Iterable[Type]] = None,
|
|
201
|
+
modules: Optional[Iterable[Any]] = None,
|
|
202
|
+
) -> Dict[str, Type]:
|
|
203
|
+
"""扫描 ``@ServerEndpoint`` 标注的类,返回 ``{path: endpoint_cls}``。
|
|
204
|
+
|
|
205
|
+
Args:
|
|
206
|
+
classes: 显式传入的类列表。
|
|
207
|
+
modules: 模块对象列表,扫描其 ``__dict__`` 中的类。
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
``{path: endpoint_cls}``;路径冲突时后者覆盖前者(最后声明者胜出)。
|
|
211
|
+
"""
|
|
212
|
+
result: Dict[str, Type] = {}
|
|
213
|
+
candidates: List[Type] = []
|
|
214
|
+
if classes:
|
|
215
|
+
candidates.extend(classes)
|
|
216
|
+
if modules:
|
|
217
|
+
for mod in modules:
|
|
218
|
+
if mod is None:
|
|
219
|
+
continue
|
|
220
|
+
for attr in vars(mod).values():
|
|
221
|
+
if isinstance(attr, type) and getattr(attr, "__module__", "") == mod.__name__:
|
|
222
|
+
candidates.append(attr)
|
|
223
|
+
seen_ids = set()
|
|
224
|
+
for cls in candidates:
|
|
225
|
+
if id(cls) in seen_ids:
|
|
226
|
+
continue
|
|
227
|
+
seen_ids.add(id(cls))
|
|
228
|
+
annotations = getattr(cls, "__spring_annotations__", []) or []
|
|
229
|
+
for ann in annotations:
|
|
230
|
+
if isinstance(ann, ServerEndpoint) and ann.value:
|
|
231
|
+
result[ann.value] = cls
|
|
232
|
+
break
|
|
233
|
+
return result
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
__all__ = [
|
|
237
|
+
"WebSocketHandler",
|
|
238
|
+
"TextWebSocketHandler",
|
|
239
|
+
"BinaryWebSocketHandler",
|
|
240
|
+
"ServerEndpoint",
|
|
241
|
+
"AnnotatedEndpointHandler",
|
|
242
|
+
"discover_server_endpoints",
|
|
243
|
+
]
|