KairoCore 1.0.0__py3-none-any.whl → 1.2.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.

Potentially problematic release.


This version of KairoCore might be problematic. Click here for more details.

KairoCore/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from fastapi import APIRouter as kcRouter
2
2
  from .app import run_kairo
3
- from .utils.panic import Panic, QueryResponse
3
+ from .utils.panic import Panic, QueryResponse, exec_with_route_error
4
4
  from .utils.log import get_logger
5
5
  from .db_tools.kc_redis import RedisClient
6
6
  from .db_tools.kc_zookeeper import ZkClient
@@ -8,6 +8,9 @@ from .db_tools.kc_mysql import MysqlSession, AsyncMysqlSession
8
8
  from .utils.sql_tool import SqlTool
9
9
  from .utils.kc_timer import Ktimer
10
10
  from .utils.kc_re import KcReTool
11
+ from .utils.kc_http import KcHttpSession
12
+ from .utils.kc_upload import KcUploader
13
+ from .utils.auth import KairoAuth
11
14
 
12
15
  kQuery = QueryResponse()
13
16
 
@@ -15,6 +18,7 @@ __all__ = [
15
18
  "run_kairo",
16
19
  "kcRouter",
17
20
  "Panic",
21
+ "exec_with_route_error",
18
22
  "kQuery",
19
23
  "get_logger",
20
24
  "RedisClient",
@@ -23,5 +27,8 @@ __all__ = [
23
27
  "AsyncMysqlSession",
24
28
  "SqlTool",
25
29
  "Ktimer",
26
- "KcReTool"
30
+ "KcReTool",
31
+ "KcHttpSession",
32
+ "KcUploader",
33
+ "KairoAuth",
27
34
  ]
@@ -1,4 +1,5 @@
1
1
  from ..utils.panic import Panic
2
+ from .http import HttpStatusCode
2
3
 
3
4
  # mysql session 异常 业务代码 10010 ~ 10021
4
5
  MQSN_INIT_ERROR = Panic(10010, "Mysql配置异常,请检查env配置!")
@@ -23,4 +24,41 @@ KCR_USE_ERROR = Panic(10051, "redis使用异常,请检查!")
23
24
 
24
25
 
25
26
  # kc_re 异常 业务代码 10060 ~ 10069
26
- KCRE_USE_ERROR = Panic(10060, "正则校验异常,请检查!")
27
+ KCRE_USE_ERROR = Panic(10060, "正则校验异常,请检查!")
28
+
29
+
30
+ # kc_http 异常 业务代码 10070 ~ 10079
31
+ KCHT_INIT_ERROR = Panic(10070, "http配置异常,请检查!")
32
+ KCHT_REQUEST_ERROR = Panic(10071, "http请求异常,请检查!")
33
+ KCHT_TIMEOUT_ERROR = Panic(10072, "http请求超时,请检查!")
34
+ KCHT_STATUS_ERROR = Panic(10073, "http状态码异常,请检查!")
35
+ KCHT_PARSE_ERROR = Panic(10074, "http响应解析异常,请检查!")
36
+
37
+ # kc_upload 异常 业务代码 10080 ~ 10089
38
+ KCU_SAVE_DIR_EMPTY_ERROR = Panic(10080, "保存目录为空", HttpStatusCode.BAD_REQUEST)
39
+ KCU_MKDIR_ERROR = Panic(10081, "创建目录失败", HttpStatusCode.INTERNAL_SERVER_ERROR)
40
+ KCU_FILENAME_EMPTY_ERROR = Panic(10082, "文件名为空", HttpStatusCode.BAD_REQUEST)
41
+ KCU_PARAM_MISSING_ERROR = Panic(10083, "缺少必要参数", HttpStatusCode.BAD_REQUEST)
42
+ KCU_BASE64_PARSE_ERROR = Panic(10084, "Base64 内容解析失败", HttpStatusCode.UNPROCESSABLE_ENTITY)
43
+ KCU_UPLOAD_SAVE_ERROR = Panic(10085, "文件上传失败", HttpStatusCode.INTERNAL_SERVER_ERROR)
44
+ KCU_BASE64_SAVE_ERROR = Panic(10086, "Base64 上传失败", HttpStatusCode.INTERNAL_SERVER_ERROR)
45
+
46
+ # kc_file_upload_route 异常 业务代码 10090 ~ 10099
47
+ KCFU_UPLOAD_FAIL_ERROR = Panic(10090, "文件上传失败", HttpStatusCode.INTERNAL_SERVER_ERROR)
48
+ KCFU_BASE64_UPLOAD_FAIL_ERROR = Panic(10091, "Base64 上传失败", HttpStatusCode.INTERNAL_SERVER_ERROR)
49
+
50
+ # kc_panic 辅助方法异常 业务代码 10100 ~ 10109
51
+ KCP_EXEC_AWAITABLE_TYPE_ERROR = Panic(10100, "exec_with_route_error: awaitable 参数必须是可等待对象", HttpStatusCode.BAD_REQUEST)
52
+ KCP_EXEC_PANIC_CONST_TYPE_ERROR = Panic(10101, "exec_with_route_error: error_const 参数必须是 Panic 实例", HttpStatusCode.BAD_REQUEST)
53
+
54
+ # kc_auth 异常 业务代码 10110 ~ 10129
55
+ KCAUTH_LOGIN_FAILED = Panic(10110, "登录失败", HttpStatusCode.UNAUTHORIZED)
56
+ KCAUTH_TOKEN_INVALID = Panic(10111, "令牌无效", HttpStatusCode.UNAUTHORIZED)
57
+ KCAUTH_TOKEN_EXPIRED = Panic(10112, "令牌已过期", HttpStatusCode.UNAUTHORIZED)
58
+ KCAUTH_REFRESH_INVALID = Panic(10113, "刷新令牌无效", HttpStatusCode.UNAUTHORIZED)
59
+ KCAUTH_REFRESH_EXPIRED = Panic(10114, "刷新令牌已过期", HttpStatusCode.UNAUTHORIZED)
60
+ KCAUTH_TOKEN_REVOKED = Panic(10115, "令牌已撤销", HttpStatusCode.UNAUTHORIZED)
61
+ KCAUTH_PERMISSION_DENIED = Panic(10116, "权限不足", HttpStatusCode.FORBIDDEN)
62
+ KCAUTH_TENANT_REQUIRED = Panic(10117, "需要租户信息", HttpStatusCode.FORBIDDEN)
63
+ KCAUTH_ROLE_REQUIRED = Panic(10118, "需要角色权限", HttpStatusCode.FORBIDDEN)
64
+ KCAUTH_CONFIG_ERROR = Panic(10119, "认证配置错误,请检查环境变量", HttpStatusCode.INTERNAL_SERVER_ERROR)
@@ -0,0 +1,58 @@
1
+ # 🛠️ 代码生成器使用指南
2
+
3
+ KairoCore 提供了强大的代码生成器,可以一键生成完整的 CRUD 代码结构,大大提高开发效率。
4
+
5
+ ### 访问代码生成器
6
+
7
+ 启动应用后,访问 `/api/generator` 路径即可打开代码生成器页面。
8
+
9
+ ### 使用步骤
10
+
11
+ 1. **填写基本信息**:
12
+ - **路由名称(英文)**:必填,如 `user`,将用于生成文件名和类名
13
+ - **路由中文名称**:可选,如 `用户`,将用于生成注释和文档
14
+ - **数据库表名**:可选,默认为 `{路由名称}_info`,如 `user_info`
15
+
16
+ 2. **点击生成代码**:
17
+ 代码生成器将根据输入信息生成以下四个模块的代码:
18
+ - **Action 模块**:包含 API 路由和控制器逻辑
19
+ - **Schema 模块**:包含数据传输对象和验证规则
20
+ - **Domain 模块**:包含业务逻辑和领域模型
21
+ - **DAO 模块**:包含数据访问对象和数据库操作
22
+
23
+ 3. **查看和复制代码**:
24
+ 生成的代码将以文件形式展示,每个文件都有独立的复制按钮,可以一键复制到剪贴板。
25
+
26
+ ### 生成的代码结构
27
+
28
+ 代码生成器会生成完整的分层架构代码:
29
+
30
+ ```
31
+ {路由名称}/
32
+ ├── action/{路由名称}/{路由名称}.py # API 控制器
33
+ ├── schema/{路由名称}/{路由名称}.py # 数据传输对象
34
+ ├── domain/{路由名称}/{路由名称}.py # 领域模型和业务逻辑
35
+ └── dao/{路由名称}/{路由名称}.py # 数据访问对象
36
+ ```
37
+
38
+ ### 功能特性
39
+
40
+ - **完整的 CRUD 操作**:包含增删改查和分页查询功能
41
+ - **数据验证**:自动生成 Pydantic 验证规则
42
+ - **数据库操作**:包含常用的 SQL 操作封装
43
+ - **错误处理**:统一的异常处理机制
44
+ - **类型提示**:完整的类型注解支持
45
+ - **文档注释**:详细的函数和类文档
46
+
47
+ ### 注意事项
48
+
49
+ 1. 生成的代码可能需要根据实际业务需求进行调整
50
+ 2. 错误码和常量需要在 `common/errors.py`和 `common/consts.py`中定义
51
+ 3. 数据库表结构需要提前创建并与生成的代码匹配
52
+ 4. 生成的代码遵循 KairoCore 的分层架构规范
53
+
54
+ 通过代码生成器,您可以快速搭建业务模块的基础代码结构,专注于业务逻辑的实现而非重复的代码编写。
55
+
56
+ <div align="center">
57
+ <img src="https://github.com/Fatosy/KairoCore/blob/master/imgs/code_generator.png" alt="KairoCore Code Generator" />
58
+ </div>
@@ -0,0 +1,142 @@
1
+ # 📦 文件上传功能使用说明
2
+
3
+ 本说明文档介绍如何在 KairoCore 项目中使用文件上传功能,包含两种上传方式:multipart/form-data 上传和 Base64 字符串上传。内容简洁明了,开箱即用。😊
4
+
5
+ ---
6
+
7
+ ## ✨ 功能概览
8
+ - 支持两种上传方式:
9
+ - multipart 上传(UploadFile):POST `/example/api/file_upload/upload`
10
+ - Base64 上传(JSON):POST `/example/api/file_upload/upload_base64`
11
+ - 统一响应格式:`kQuery.to_response(...)`
12
+ - 签名约束:路由函数仅使用 `query/body/file` 参数名(由 `utils/router.enforce_signature` 强制),使接口更清晰规范。
13
+
14
+ ---
15
+
16
+ ## 📁 路径与入参
17
+
18
+ ### 1) multipart 上传
19
+ - 路径:`POST /example/api/file_upload/upload`
20
+ - 请求类型:`multipart/form-data`
21
+ - 表单字段:
22
+ - `file`:文件内容(必填)
23
+ - `target_dir`:保存目录(选填,默认 `/tmp`)
24
+ - `filename`:保存文件名(选填,默认使用原文件名)
25
+ - 代码片段:
26
+ ```python
27
+ @router.post("/upload")
28
+ async def upload_file(query: UploadQuery, file: UploadFile):
29
+ uploader = KcUploader(default_target_dir="/tmp")
30
+ result = await exec_with_route_error(
31
+ uploader.save_upload_file(file=file, target_dir=query.target_dir, filename=query.filename),
32
+ KCFU_UPLOAD_FAIL_ERROR,
33
+ )
34
+ return kQuery.to_response(data=result, msg="上传成功")
35
+ ```
36
+ - curl 示例:
37
+ ```bash
38
+ curl -X POST http://localhost:9140/example/api/file_upload/upload \
39
+ -F "file=@/path/to/local/file.png" \
40
+ -F "target_dir=/tmp" \
41
+ -F "filename=my_file.png"
42
+ ```
43
+ - 典型响应:
44
+ ```json
45
+ {
46
+ "data": {
47
+ "saved_path": "/tmp/my_file.png",
48
+ "filename": "my_file.png",
49
+ "size": 12345
50
+ },
51
+ "msg": "上传成功"
52
+ }
53
+ ```
54
+
55
+ ### 2) Base64 上传
56
+ - 路径:`POST /example/api/file_upload/upload_base64`
57
+ - 请求类型:`application/json`
58
+ - JSON 字段:
59
+ - `content_base64`:Base64 编码的文件内容(必填)
60
+ - `filename`:保存文件名(必填)
61
+ - `target_dir`:保存目录(选填,默认 `/tmp`)
62
+ - 代码片段:
63
+ ```python
64
+ @router.post("/upload_base64")
65
+ async def upload_base64(body: Base64Body):
66
+ uploader = KcUploader(default_target_dir="/tmp")
67
+ result = await exec_with_route_error(
68
+ uploader.save_base64(content_base64=body.content_base64, filename=body.filename, target_dir=body.target_dir),
69
+ KCFU_BASE64_UPLOAD_FAIL_ERROR,
70
+ )
71
+ return kQuery.to_response(data=result, msg="上传成功")
72
+ ```
73
+ - curl 示例:
74
+ ```bash
75
+ curl -X POST http://localhost:9140/example/api/file_upload/upload_base64 \
76
+ -H "Content-Type: application/json" \
77
+ -d '{
78
+ "content_base64": "iVBORw0KGgoAAAANSUhEUg...",
79
+ "filename": "my_file.png",
80
+ "target_dir": "/tmp"
81
+ }'
82
+ ```
83
+ - 典型响应:
84
+ ```json
85
+ {
86
+ "data": {
87
+ "saved_path": "/tmp/my_file.png",
88
+ "filename": "my_file.png",
89
+ "size": 12345
90
+ },
91
+ "msg": "上传成功"
92
+ }
93
+ ```
94
+
95
+ ---
96
+
97
+ ## 🧰 使用建议
98
+ - 大文件上传:根据实际场景调整 Nginx/网关的上传大小限制;后端也可设置合理的文件大小上限。
99
+ - 文件命名:建议前端传入明确的 `filename`,避免后端根据临时文件名生成不易识别的名称。
100
+ - 保存目录:默认 `/tmp`,可通过 `target_dir` 覆盖,请确保运行环境有写权限。
101
+ - 安全考虑:对上传内容进行扩展名/类型校验,避免执行型文件被误当资源保存;必要时放置到隔离目录并设置严格访问策略。
102
+
103
+ ---
104
+
105
+ ## 🚀 快速自测
106
+ 1) 启动示例服务:
107
+ ```bash
108
+ cd /home/Coding/KairoCore/example/your_project_name
109
+ python main.py
110
+ ```
111
+ 2) multipart 测试:
112
+ ```bash
113
+ curl -X POST http://localhost:9140/example/api/file_upload/upload \
114
+ -F "file=@/path/to/local/file.png" -F "target_dir=/tmp" -F "filename=test.png"
115
+ ```
116
+ 3) Base64 测试:
117
+ ```bash
118
+ curl -X POST http://localhost:9140/example/api/file_upload/upload_base64 \
119
+ -H "Content-Type: application/json" \
120
+ -d '{"content_base64":"iVBORw0KG...","filename":"test.png","target_dir":"/tmp"}'
121
+ ```
122
+ 4) 下载接口测试:
123
+ - 浏览器访问:
124
+ - `http://localhost:9140/example/api/file_upload/download?path=/tmp/test.png&name=my_download.png`
125
+ - curl(保存到本地并使用服务器文件名):
126
+ ```bash
127
+ curl -OJ "http://localhost:9140/example/api/file_upload/download?path=/tmp/test.png&name=my_download.png"
128
+ ```
129
+ - 说明:
130
+ - `path` 为服务器本地已保存的文件路径
131
+ - `name` 为浏览器下载展示的文件名(可选)
132
+ - 若需内联预览(如图片/PDF),可添加 `&inline=true`
133
+
134
+ ---
135
+
136
+ ## 📎 相关文件
137
+ - 路由:`example/your_project_name/action/file_upload.py`
138
+ - 上传工具:`utils/kc_upload.py`(KcUploader)
139
+ - 错误常量:`common/errors.py`(KCFU_UPLOAD_FAIL_ERROR、KCFU_BASE64_UPLOAD_FAIL_ERROR)
140
+ - 路由签名约束:`utils/router.py`(enforce_signature)
141
+
142
+ 祝你上传顺利!📤✨
@@ -0,0 +1,170 @@
1
+ # 🌐 HTTP 会话使用说明(KcHttpSession)
2
+
3
+ 本指南介绍如何使用项目内置的异步 HTTP 会话类 KcHttpSession,进行稳定可靠的外部接口调用。内容简洁明了,示例可直接复制运行。🚀
4
+
5
+ ---
6
+
7
+ ## ✨ 功能概览
8
+ - 统一的响应封装:`KcHttpResponse`(自动解析 JSON/Text/Bytes)
9
+ - 稳健的请求能力:超时、重试、退避、状态码检查、日志
10
+ - 连接池与性能:`httpx.AsyncClient` 连接复用与 keep-alive
11
+ - 可选参数:`base_url`、`headers`、`verify`、`proxies`、`timeout`、`retries`、`retry_backoff`
12
+ - 下载能力:`session.download(url, save_path)` 流式写入
13
+
14
+ ---
15
+
16
+ ## 📦 安装前提
17
+ 项目已内置依赖 `httpx`,直接使用即可。
18
+
19
+ ---
20
+
21
+ ## 🚀 快速上手
22
+ ```python
23
+ import asyncio
24
+ from KairoCore.utils.kc_http import KcHttpSession
25
+
26
+ async def main():
27
+ # 建议在应用范围内复用会话(保持连接池与性能)
28
+ async with KcHttpSession(base_url="https://api.example.com", timeout=10, retries=2) as session:
29
+ # GET 请求(自动拼接 base_url)
30
+ resp = await session.get("/v1/ping", params={"q": "hello"})
31
+ print(resp.status_code, resp.data)
32
+
33
+ # POST 请求(JSON)
34
+ resp2 = await session.post("/v1/items", json={"name": "demo"})
35
+ print(resp2.status_code, resp2.data)
36
+
37
+ asyncio.run(main())
38
+ ```
39
+
40
+ ---
41
+
42
+ ## 📄 响应结构:KcHttpResponse
43
+ - `status_code: int` —— HTTP 状态码
44
+ - `headers: Dict[str, str]` —— 响应头
45
+ - `data: Any` —— 自动解析:
46
+ - `application/json` → `resp.json()`(dict/list)
47
+ - `text/*` 或空 `Content-Type` → `resp.text`(str)
48
+ - 其他 → `resp.content`(bytes)
49
+ - `raw: httpx.Response` —— 原始响应对象
50
+ - `is_ok(): bool` —— 状态码是否在 2xx
51
+
52
+ 示例:
53
+ ```python
54
+ if resp.is_ok():
55
+ print("✅ OK", resp.data)
56
+ else:
57
+ print("❌ Bad status:", resp.status_code)
58
+ ```
59
+
60
+ ---
61
+
62
+ ## 🔧 常用请求示例
63
+ ```python
64
+ # 1) GET with params & 临时 headers 覆盖
65
+ resp = await session.get("/v1/search", params={"q": "kairo"}, headers={"X-Trace": "abc"})
66
+
67
+ # 2) POST: JSON 请求体
68
+ resp = await session.post("/v1/create", json={"title": "hello"})
69
+
70
+ # 3) POST: 表单或字符串/二进制数据
71
+ resp = await session.post("/v1/upload", data={"k": "v"})
72
+ # 或:resp = await session.post("/v1/raw", data=b"binary-data")
73
+
74
+ # 4) PUT / DELETE
75
+ await session.put("/v1/items/123", json={"name": "new"})
76
+ await session.delete("/v1/items/123")
77
+
78
+ # 5) 单次请求自定义超时(覆盖会话默认)
79
+ resp = await session.get("/v1/slow", timeout=3.0)
80
+ ```
81
+
82
+ ---
83
+
84
+ ## 📥 文件下载
85
+ ```python
86
+ save_path = await session.download("https://example.com/file.zip",
87
+ save_path="/tmp/file.zip",
88
+ chunk_size=1024*64)
89
+ print("已保存到:", save_path)
90
+ ```
91
+
92
+ ---
93
+
94
+ ## 🧯 错误处理
95
+ KcHttpSession 会在合适的时机抛出统一的错误类型,便于上层捕获与统一处理:
96
+ - `KCHT_INIT_ERROR` —— 会话初始化失败(参数/环境问题)
97
+ - `KCHT_TIMEOUT_ERROR` —— 请求超时
98
+ - `KCHT_STATUS_ERROR` —— 4xx/5xx 状态码错误(5xx可重试,4xx不重试)
99
+ - `KCHT_REQUEST_ERROR` —— 其他请求错误(网络/协议等)
100
+ - `KCHT_PARSE_ERROR` —— 响应解析失败(Content-Type 与内容不匹配等)
101
+
102
+ 示例:
103
+ ```python
104
+ from KairoCore.common.errors import (
105
+ KCHT_TIMEOUT_ERROR, KCHT_STATUS_ERROR, KCHT_REQUEST_ERROR, KCHT_PARSE_ERROR
106
+ )
107
+
108
+ try:
109
+ resp = await session.get("/v1/data")
110
+ print(resp.data)
111
+ except KCHT_TIMEOUT_ERROR as e:
112
+ print("⏳ 超时:", e)
113
+ except KCHT_STATUS_ERROR as e:
114
+ print("🔢 状态码异常:", e)
115
+ except KCHT_PARSE_ERROR as e:
116
+ print("🧩 解析失败:", e)
117
+ except KCHT_REQUEST_ERROR as e:
118
+ print("📡 请求错误:", e)
119
+ ```
120
+
121
+ ---
122
+
123
+ ## ⚙️ 参数说明与实践建议
124
+ - `base_url`:设置后可在请求中使用相对路径(如 `/v1/items`),更易维护。
125
+ - `timeout`:会话默认超时(秒)。可在单次请求中通过 `timeout=` 覆盖。
126
+ - `retries`:重试次数(默认 2)。服务器 5xx 会重试,客户端 4xx 不重试。
127
+ - `retry_backoff`:退避系数(默认 0.5),每次重试会 `await asyncio.sleep(backoff * attempt)`。
128
+ - `max_keepalive`:连接池并发上限(默认 10)。高并发场景可适当调大。
129
+ - `headers`:会话级公共 Header,可在每次请求 `headers` 临时覆盖/追加。
130
+ - `verify`:TLS 校验(True/False 或 CA 路径)。生产环境建议保持开启。
131
+ - `proxies`:代理(字符串或字典),如需通过网关访问外部服务。
132
+ - 日志:内置关键日志,便于排查(初始化、关闭、下载完成、重试等)。
133
+
134
+ 最佳实践:
135
+ - 复用会话实例(例如挂载到 `app.state`)以最大化连接池收益。
136
+ - 为慢接口设置单次请求 `timeout`,避免阻塞。
137
+ - 对关键外部依赖适度提高 `retries` 与 `max_keepalive`。
138
+
139
+ ---
140
+
141
+ ## 🔌 与 FastAPI 生命周期集成(可选)
142
+ 在 `app.py` 或 `example/your_project_name/main.py` 中:
143
+ ```python
144
+ from KairoCore.utils.kc_http import KcHttpSession
145
+
146
+ kc_http = KcHttpSession(base_url="https://api.example.com", timeout=10, retries=2)
147
+ app.state.kc_http = kc_http
148
+
149
+ @app.on_event("startup")
150
+ async def startup_event():
151
+ # 可在此进行健康检查或预热
152
+ pass
153
+
154
+ @app.on_event("shutdown")
155
+ async def shutdown_event():
156
+ await app.state.kc_http.close()
157
+ ```
158
+
159
+ ---
160
+
161
+ ## 📚 相关文件
162
+ - 会话实现:`utils/kc_http.py`
163
+ - 错误常量:`common/errors.py`
164
+
165
+ 如需将鉴权(API_KEY 或 Token)加入外部请求的 `headers`,也可在会话级统一设置,例如:
166
+ ```python
167
+ session = KcHttpSession(headers={"Authorization": "Bearer <token>", "X-API-Key": "<api_key>"})
168
+ ```
169
+
170
+ 祝你调用顺利!🌈