diff --git a/Wavelet/docs/docs.go b/Wavelet/docs/docs.go index d553c93d..15720fbe 100644 --- a/Wavelet/docs/docs.go +++ b/Wavelet/docs/docs.go @@ -928,231 +928,6 @@ const docTemplate = `{ } } }, - "/api/v1/admin/logs": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "分页获取系统历史日志,cursor=0 获取最新日志,cursor\u003e0 获取更早日志", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取系统日志", - "parameters": [ - { - "type": "integer", - "default": 0, - "description": "日志游标,0=获取最新", - "name": "cursor", - "in": "query" - }, - { - "type": "integer", - "default": 200, - "description": "每页条数", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "日志列表", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/logs.logsResponse" - } - } - } - ] - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/logs/access": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "分页并按照用户、接口路径、时间范围等维度检索 ClickHouse 用户访问日志列表(需要管理员权限,ClickHouse 未启用时报错)", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取用户访问日志", - "parameters": [ - { - "type": "integer", - "default": 1, - "description": "页码", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "default": 20, - "description": "每页条数", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "用户名模糊搜索", - "name": "username", - "in": "query" - }, - { - "type": "string", - "description": "接口路径模糊搜索", - "name": "path", - "in": "query" - }, - { - "type": "string", - "description": "起始时间(RFC3339 或 YYYY-MM-DD HH:MM:SS)", - "name": "start_time", - "in": "query" - }, - { - "type": "string", - "description": "结束时间(RFC3339 或 YYYY-MM-DD HH:MM:SS)", - "name": "end_time", - "in": "query" - } - ], - "responses": { - "200": { - "description": "访问日志列表", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/logs.accessLogsResponse" - } - } - } - ] - } - }, - "400": { - "description": "ClickHouse 未启用或参数错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/logs/analytics": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "聚合统计最近 7 天的每日访问趋势、浏览器分布以及前 10 名最活跃用户排行(需要管理员权限,ClickHouse 未启用时报错)", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取访问日志分析数据", - "responses": { - "200": { - "description": "分析统计数据", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/logs.logsAnalyticsResponse" - } - } - } - ] - } - }, - "400": { - "description": "ClickHouse 未启用", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/logs/ws": { - "get": { - "description": "通过 WebSocket 实时推送系统日志,需要管理员权限", - "tags": [ - "admin" - ], - "summary": "系统日志实时推送", - "responses": {} - } - }, "/api/v1/admin/push/channels": { "get": { "security": [ @@ -3301,362 +3076,6 @@ const docTemplate = `{ } } }, - "/api/v1/admin/uploads": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "分页获取系统上传的文件列表,支持文件名关键词、业务类型、扩展名、上传用户ID过滤", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取文件列表", - "parameters": [ - { - "type": "integer", - "description": "页码(默认 1)", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "每页数量(默认 20,最大 100)", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "文件名关键词(模糊匹配)", - "name": "keyword", - "in": "query" - }, - { - "type": "string", - "description": "业务分类过滤", - "name": "type", - "in": "query" - }, - { - "type": "string", - "description": "扩展名过滤", - "name": "extension", - "in": "query" - }, - { - "type": "integer", - "format": "int64", - "description": "上传用户 ID", - "name": "user_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "查询成功", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handler.listFilesResponse" - } - } - } - ] - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/download/batch": { - "post": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "传入多个文件 ID,后台实时将其打包压缩为 ZIP 流并输出,自动处理文件名重复冲突", - "consumes": [ - "application/json" - ], - "produces": [ - "application/octet-stream" - ], - "tags": [ - "admin" - ], - "summary": "批量打包下载", - "parameters": [ - { - "description": "包含文件 ID 数组 of string 的请求体", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handler.batchDownloadRequest" - } - } - ], - "responses": { - "200": { - "description": "成功下载打包后的 ZIP", - "schema": { - "type": "file" - } - }, - "400": { - "description": "参数错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "打包失败", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/download/{id}": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "根据文件 ID 获取文件,以附件形式 (Attachment) 强制开启客户端浏览器下载", - "produces": [ - "application/octet-stream" - ], - "tags": [ - "admin" - ], - "summary": "下载单文件", - "parameters": [ - { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "图片质量 (low, medium, high, origin),默认为 origin", - "name": "quality", - "in": "query" - } - ], - "responses": { - "200": { - "description": "成功下载文件", - "schema": { - "type": "file" - } - }, - "400": { - "description": "参数错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "404": { - "description": "文件不存在", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "服务内部错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/stats": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "返回系统级的总文件数、占用大小、最近 7 天新增趋势、文件类型/格式分布等数据", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取文件统计数据", - "responses": { - "200": { - "description": "获取成功", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handler.fileStatsResponse" - } - } - } - ] - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "内部错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/types": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "返回数据库中所有已上传文件实际拥有的业务类型列表", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取文件业务类型列表", - "responses": { - "200": { - "description": "业务类型列表", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - ] - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "内部错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/{id}": { - "delete": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "将文件状态置为 deleted(软删除),不会立即清理底层存储对象", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "删除文件", - "parameters": [ - { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "删除成功", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无权操作", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "404": { - "description": "文件不存在", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, "/api/v1/admin/users": { "get": { "security": [ @@ -4054,6 +3473,375 @@ const docTemplate = `{ } } }, + "/api/v1/agent/apply-logs": { + "post": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "记录 Agent 配置下发与应用结果", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "上报配置应用日志", + "parameters": [ + { + "description": "应用日志", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/agent.ApplyLogPayload" + } + } + ], + "responses": { + "200": { + "description": "日志记录", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/model.OpenFlareApplyLog" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/config-versions/active": { + "get": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "返回当前生效的完整配置包,供 Agent 拉取并应用", + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "获取活跃配置版本", + "responses": { + "200": { + "description": "活跃配置", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/agent.ConfigResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/nodes/heartbeat": { + "post": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "上报节点状态、指标与健康事件,返回远程控制配置与活跃配置元信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "Agent 心跳上报", + "parameters": [ + { + "description": "心跳数据", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/agent.NodePayload" + } + } + ], + "responses": { + "200": { + "description": "心跳成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/agent.HeartbeatResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/nodes/register": { + "post": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "使用节点 access token 重新注册,或使用全局 discovery token 发现新节点;请求头需携带 X-Agent-Token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "注册或发现 Agent 节点", + "parameters": [ + { + "description": "节点上报数据", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/agent.NodePayload" + } + } + ], + "responses": { + "200": { + "description": "注册成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/agent.RegistrationResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/pages/deployments/{deployment_id}/package": { + "get": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "流式下载指定部署的静态资源压缩包,供 Agent 边缘分发", + "produces": [ + "application/octet-stream" + ], + "tags": [ + "openflare-agent" + ], + "summary": "下载 Pages 部署包", + "parameters": [ + { + "type": "integer", + "description": "部署 ID", + "name": "deployment_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "部署包文件", + "schema": { + "type": "file" + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/waf/ip-groups/sync": { + "post": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "按 ID 与校验和增量同步 WAF IP 组定义", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "同步 WAF IP 组", + "parameters": [ + { + "description": "同步请求", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/agent.WAFIPGroupSyncInput" + } + } + ], + "responses": { + "200": { + "description": "同步结果", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/agent.WAFIPGroupSyncResult" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/ws": { + "get": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "升级为 WebSocket 长连接,用于实时推送配置同步、WAF IP 组等指令;需携带 X-Agent-Token", + "tags": [ + "openflare-agent" + ], + "summary": "Agent WebSocket 连接", + "responses": { + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, "/api/v1/config/public": { "get": { "description": "返回系统配置表中 visibility 为 1 的配置键值集合", @@ -4205,8 +3993,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4280,8 +4068,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4397,8 +4185,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4520,8 +4308,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4625,8 +4413,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4718,8 +4506,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4779,12 +4567,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -5479,8 +5261,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5543,8 +5325,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5616,8 +5398,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5674,12 +5456,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -5762,12 +5538,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -5832,8 +5602,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5905,8 +5675,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5975,8 +5745,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -6033,12 +5803,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -6121,12 +5885,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -7011,8 +6769,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7085,8 +6843,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7160,8 +6918,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7223,8 +6981,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7286,8 +7044,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7679,8 +7437,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7752,8 +7510,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7825,12 +7583,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "部署不存在", "schema": { @@ -7901,12 +7653,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -7965,12 +7711,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -8044,12 +7784,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -8130,12 +7864,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -8213,12 +7941,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目或部署不存在", "schema": { @@ -8284,12 +8006,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目或部署不存在", "schema": { @@ -8372,12 +8088,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -8815,8 +8525,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -8888,8 +8598,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -8963,8 +8673,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9055,8 +8765,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9125,12 +8835,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9201,12 +8905,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9289,12 +8987,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9353,12 +9045,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9429,12 +9115,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9517,12 +9197,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9605,12 +9279,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9675,8 +9343,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9739,8 +9407,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9812,8 +9480,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9887,8 +9555,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9957,12 +9625,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10021,12 +9683,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10097,12 +9753,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10185,12 +9835,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10255,8 +9899,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -10328,8 +9972,8 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -10398,12 +10042,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10462,12 +10100,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10550,12 +10182,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10638,12 +10264,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10714,12 +10334,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10800,12 +10414,6 @@ const docTemplate = `{ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -11228,48 +10836,38 @@ const docTemplate = `{ } } }, - "/api/v1/upload": { + "/api/v1/relay/heartbeat": { "post": { "security": [ { - "SessionCookie": [] + "AgentTokenAuth": [] } ], - "description": "支持各种类型的通用文件上传,支持自动文件类型检测、哈希计算与“秒传”去重", + "description": "Relay 节点定期上报运行状态与 frps 观测数据,返回运行时配置", "consumes": [ - "multipart/form-data" + "application/json" ], "produces": [ "application/json" ], "tags": [ - "upload" + "openflare-relay" ], - "summary": "上传文件", + "summary": "上报 Relay 心跳", "parameters": [ { - "type": "file", - "description": "要上传的文件", - "name": "file", - "in": "formData", - "required": true - }, - { - "type": "string", - "description": "业务分类 (例如: avatar, attachment, doc,默认为 generic)", - "name": "type", - "in": "formData" - }, - { - "type": "string", - "description": "额外的 JSON 格式元数据", - "name": "metadata", - "in": "formData" + "description": "心跳载荷", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/relay.HeartbeatPayload" + } } ], "responses": { "200": { - "description": "上传成功", + "description": "心跳响应", "schema": { "allOf": [ { @@ -11279,7 +10877,7 @@ const docTemplate = `{ "type": "object", "properties": { "data": { - "$ref": "#/definitions/model.Upload" + "$ref": "#/definitions/relay.HeartbeatResponse" } } } @@ -11287,19 +10885,19 @@ const docTemplate = `{ } }, "400": { - "description": "请求参数错误或文件受限", + "description": "参数错误", "schema": { "$ref": "#/definitions/response.Any" } }, "401": { - "description": "未登录", + "description": "Agent Token 无效", "schema": { "$ref": "#/definitions/response.Any" } }, - "500": { - "description": "内部错误", + "403": { + "description": "节点类型不匹配", "schema": { "$ref": "#/definitions/response.Any" } @@ -11307,74 +10905,27 @@ const docTemplate = `{ } } }, - "/api/v1/upload/my": { + "/api/v1/relay/ws": { "get": { "security": [ { - "SessionCookie": [] + "AgentTokenAuth": [] } ], - "description": "分页获取当前登录用户上传的文件,支持文件名关键词、业务类型、扩展名过滤", - "produces": [ - "application/json" - ], + "description": "将已认证的 Relay 连接升级为 WebSocket 长连接,用于配置推送", "tags": [ - "upload" - ], - "summary": "获取我的文件列表", - "parameters": [ - { - "type": "integer", - "description": "页码(默认 1)", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "每页数量(默认 20,最大 100)", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "文件名关键词(模糊匹配)", - "name": "keyword", - "in": "query" - }, - { - "type": "string", - "description": "业务分类过滤", - "name": "type", - "in": "query" - }, - { - "type": "string", - "description": "扩展名过滤", - "name": "extension", - "in": "query" - } + "openflare-relay" ], + "summary": "升级 Relay WebSocket 连接", "responses": { - "200": { - "description": "查询成功", + "401": { + "description": "Agent Token 无效", "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handler.listMyFilesResponse" - } - } - } - ] + "$ref": "#/definitions/response.Any" } }, - "401": { - "description": "未登录", + "403": { + "description": "节点类型不匹配", "schema": { "$ref": "#/definitions/response.Any" } @@ -11382,14 +10933,14 @@ const docTemplate = `{ } } }, - "/api/v1/upload/{id}": { - "put": { + "/api/v1/tunnel/apply-log": { + "post": { "security": [ { - "SessionCookie": [] + "TunnelTokenAuth": [] } ], - "description": "更新当前用户本人的文件名或访问权限模式 (AccessMode)", + "description": "Tunnel 客户端上报配置应用结果,服务端记录下发日志", "consumes": [ "application/json" ], @@ -11397,30 +10948,23 @@ const docTemplate = `{ "application/json" ], "tags": [ - "upload" + "openflare-tunnel" ], - "summary": "更新我的文件信息", + "summary": "上报 Tunnel 配置下发结果", "parameters": [ { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "更新字段", - "name": "request", + "description": "下发结果载荷", + "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handler.updateMyFileRequest" + "$ref": "#/definitions/flared.ApplyLogPayload" } } ], "responses": { "200": { - "description": "更新成功", + "description": "下发日志记录", "schema": { "allOf": [ { @@ -11430,65 +10974,179 @@ const docTemplate = `{ "type": "object", "properties": { "data": { - "$ref": "#/definitions/model.Upload" + "$ref": "#/definitions/model.OpenFlareApplyLog" } } } ] } }, - "403": { - "description": "无权操作", + "400": { + "description": "参数错误", "schema": { "$ref": "#/definitions/response.Any" } }, - "404": { - "description": "文件不存在", + "401": { + "description": "Tunnel Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "403": { + "description": "节点类型不匹配", "schema": { "$ref": "#/definitions/response.Any" } } } - }, - "delete": { + } + }, + "/api/v1/tunnel/config/active": { + "get": { "security": [ { - "SessionCookie": [] + "TunnelTokenAuth": [] } ], - "description": "将当前用户本人的文件状态置为 deleted(软删除)", + "description": "返回 Tunnel 客户端当前应应用的完整路由配置(含中继列表与代理定义)", "produces": [ "application/json" ], "tags": [ - "upload" - ], - "summary": "删除我的文件", - "parameters": [ - { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - } + "openflare-tunnel" ], + "summary": "获取活跃隧道配置", "responses": { "200": { - "description": "删除成功", + "description": "隧道配置", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/flared.TunnelConfigResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Tunnel Token 无效", "schema": { "$ref": "#/definitions/response.Any" } }, "403": { - "description": "无权操作", + "description": "节点类型不匹配", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/tunnel/heartbeat": { + "post": { + "security": [ + { + "TunnelTokenAuth": [] + } + ], + "description": "Tunnel 客户端定期上报运行状态与中继连接信息,返回活跃配置元数据与隧道设置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-tunnel" + ], + "summary": "上报 Tunnel 心跳", + "parameters": [ + { + "description": "心跳载荷", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/flared.HeartbeatPayload" + } + } + ], + "responses": { + "200": { + "description": "心跳响应", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/flared.HeartbeatResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", "schema": { "$ref": "#/definitions/response.Any" } }, - "404": { - "description": "文件不存在", + "401": { + "description": "Tunnel Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "403": { + "description": "节点类型不匹配", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/tunnel/ws": { + "get": { + "security": [ + { + "TunnelTokenAuth": [] + } + ], + "description": "将已认证的 Tunnel 客户端连接升级为 WebSocket 长连接,用于配置推送", + "tags": [ + "openflare-tunnel" + ], + "summary": "升级 Tunnel WebSocket 连接", + "responses": { + "401": { + "description": "Tunnel Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "403": { + "description": "节点类型不匹配", "schema": { "$ref": "#/definitions/response.Any" } @@ -12102,65 +11760,6 @@ const docTemplate = `{ } } }, - "/f/{id}": { - "get": { - "description": "根据文件 ID 获取并提供已上传的临时或正式文件,若配置了缓存则优先走本地缓存,否则从 S3 等后端存储读取并流式返回", - "produces": [ - "application/octet-stream" - ], - "tags": [ - "upload" - ], - "summary": "获取已上传文件", - "parameters": [ - { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "图片质量 (low, medium, high, origin),默认为 origin", - "name": "quality", - "in": "query" - } - ], - "responses": { - "200": { - "description": "成功获取文件内容", - "schema": { - "type": "file" - } - }, - "400": { - "description": "文件 ID 格式错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "404": { - "description": "文件未找到", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "服务内部错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, "/robots.txt": { "get": { "description": "根据系统配置决定是否允许搜索引擎检索,并返回相应的 robots.txt 文件内容", @@ -12183,6 +11782,462 @@ const docTemplate = `{ } }, "definitions": { + "agent.ActiveConfigMeta": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "agent.ApplyLogPayload": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "main_config_checksum": { + "type": "string" + }, + "message": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "route_config_checksum": { + "type": "string" + }, + "support_file_count": { + "type": "integer" + }, + "version": { + "type": "string" + } + } + }, + "agent.BufferedObservabilityRecord": { + "type": "object", + "properties": { + "access_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.NodeAccessLog" + } + }, + "openresty_observation": { + "$ref": "#/definitions/agent.NodeOpenrestyObservation" + }, + "snapshot": { + "$ref": "#/definitions/agent.NodeMetricSnapshot" + }, + "traffic_report": { + "$ref": "#/definitions/agent.NodeTrafficReport" + }, + "window_started_at_unix": { + "type": "integer" + } + } + }, + "agent.ConfigResponse": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "source_config_json": { + "type": "string" + }, + "support_files": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.SupportFile" + } + }, + "version": { + "type": "string" + } + } + }, + "agent.HeartbeatResponse": { + "type": "object", + "properties": { + "active_config": { + "$ref": "#/definitions/agent.ActiveConfigMeta" + }, + "agent_settings": { + "$ref": "#/definitions/agent.Settings" + }, + "node": { + "$ref": "#/definitions/model.OpenFlareNode" + }, + "waf_ip_groups": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.WAFIPGroup" + } + } + } + }, + "agent.NodeAccessLog": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "logged_at_unix": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "remote_addr": { + "type": "string" + }, + "status_code": { + "type": "integer" + } + } + }, + "agent.NodeHealthEvent": { + "type": "object", + "properties": { + "event_type": { + "type": "string" + }, + "message": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "severity": { + "type": "string" + }, + "triggered_at_unix": { + "type": "integer" + } + } + }, + "agent.NodeMetricSnapshot": { + "type": "object", + "properties": { + "captured_at_unix": { + "type": "integer" + }, + "cpu_usage_percent": { + "type": "number" + }, + "disk_read_bytes": { + "type": "integer" + }, + "disk_write_bytes": { + "type": "integer" + }, + "memory_total_bytes": { + "type": "integer" + }, + "memory_used_bytes": { + "type": "integer" + }, + "network_rx_bytes": { + "type": "integer" + }, + "network_tx_bytes": { + "type": "integer" + }, + "storage_total_bytes": { + "type": "integer" + }, + "storage_used_bytes": { + "type": "integer" + } + } + }, + "agent.NodeOpenrestyObservation": { + "type": "object", + "properties": { + "captured_at_unix": { + "type": "integer" + }, + "openresty_connections": { + "type": "integer" + }, + "openresty_rx_bytes": { + "type": "integer" + }, + "openresty_tx_bytes": { + "type": "integer" + } + } + }, + "agent.NodePayload": { + "type": "object", + "properties": { + "access_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.NodeAccessLog" + } + }, + "buffered_observability": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.BufferedObservabilityRecord" + } + }, + "current_version": { + "type": "string" + }, + "ext_version": { + "type": "string" + }, + "health_events": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.NodeHealthEvent" + } + }, + "ip": { + "type": "string" + }, + "last_error": { + "type": "string" + }, + "name": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "openresty_message": { + "type": "string" + }, + "openresty_observation": { + "$ref": "#/definitions/agent.NodeOpenrestyObservation" + }, + "openresty_status": { + "type": "string" + }, + "profile": { + "$ref": "#/definitions/agent.NodeSystemProfile" + }, + "snapshot": { + "$ref": "#/definitions/agent.NodeMetricSnapshot" + }, + "traffic_report": { + "$ref": "#/definitions/agent.NodeTrafficReport" + }, + "version": { + "type": "string" + }, + "waf_ip_group_checksums": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "agent.NodeSystemProfile": { + "type": "object", + "properties": { + "architecture": { + "type": "string" + }, + "cpu_cores": { + "type": "integer" + }, + "cpu_model": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "kernel_version": { + "type": "string" + }, + "os_name": { + "type": "string" + }, + "os_version": { + "type": "string" + }, + "reported_at_unix": { + "type": "integer" + }, + "total_disk_bytes": { + "type": "integer" + }, + "total_memory_bytes": { + "type": "integer" + }, + "uptime_seconds": { + "type": "integer" + } + } + }, + "agent.NodeTrafficReport": { + "type": "object", + "properties": { + "error_count": { + "type": "integer" + }, + "request_count": { + "type": "integer" + }, + "source_countries": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + }, + "status_codes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + }, + "top_domains": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + }, + "unique_visitor_count": { + "type": "integer" + }, + "window_ended_at_unix": { + "type": "integer" + }, + "window_started_at_unix": { + "type": "integer" + } + } + }, + "agent.RegistrationResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "name": { + "type": "string" + }, + "node_id": { + "type": "string" + } + } + }, + "agent.Settings": { + "type": "object", + "properties": { + "auto_update": { + "type": "boolean" + }, + "heartbeat_interval": { + "type": "integer" + }, + "restart_openresty_now": { + "type": "boolean" + }, + "update_channel": { + "type": "string" + }, + "update_now": { + "type": "boolean" + }, + "update_repo": { + "type": "string" + }, + "update_tag": { + "type": "string" + }, + "websocket_upgrade_enabled": { + "type": "boolean" + } + } + }, + "agent.SupportFile": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "agent.WAFIPGroup": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "ip_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "agent.WAFIPGroupSyncInput": { + "type": "object", + "properties": { + "checksums": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "agent.WAFIPGroupSyncResult": { + "type": "object", + "properties": { + "groups": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.WAFIPGroup" + } + } + } + }, "apply_log.CleanupInput": { "type": "object", "properties": { @@ -12722,6 +12777,163 @@ const docTemplate = `{ } } }, + "flared.ActiveConfigMeta": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "flared.ApplyLogPayload": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "main_config_checksum": { + "type": "string" + }, + "message": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "route_config_checksum": { + "type": "string" + }, + "support_file_count": { + "type": "integer" + }, + "version": { + "type": "string" + } + } + }, + "flared.ConnectedRelay": { + "type": "object", + "properties": { + "proxy_count": { + "type": "integer" + }, + "relay_node_id": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "flared.HeartbeatPayload": { + "type": "object", + "properties": { + "client_version": { + "type": "string" + }, + "connected_relays": { + "type": "array", + "items": { + "$ref": "#/definitions/flared.ConnectedRelay" + } + }, + "current_checksum": { + "type": "string" + }, + "current_version": { + "type": "string" + }, + "frp_version": { + "type": "string" + }, + "ip": { + "type": "string" + }, + "tunnel_status": { + "type": "string" + } + } + }, + "flared.HeartbeatResponse": { + "type": "object", + "properties": { + "active_config": { + "$ref": "#/definitions/flared.ActiveConfigMeta" + }, + "tunnel_settings": { + "$ref": "#/definitions/relay.Settings" + } + } + }, + "flared.ProxyEntry": { + "type": "object", + "properties": { + "custom_domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "local_addr": { + "type": "string" + }, + "local_port": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "flared.RelayInfo": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "auth_token": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "relay_node_id": { + "type": "string" + } + } + }, + "flared.TunnelConfigResponse": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "proxies": { + "type": "array", + "items": { + "$ref": "#/definitions/flared.ProxyEntry" + } + }, + "relays": { + "type": "array", + "items": { + "$ref": "#/definitions/flared.RelayInfo" + } + }, + "version": { + "type": "string" + } + } + }, "github_com_Rain-kl_Wavelet_internal_apps_cap.RedeemResponse": { "type": "object", "properties": { @@ -12739,285 +12951,6 @@ const docTemplate = `{ } } }, - "handler.batchDownloadRequest": { - "type": "object", - "required": [ - "ids" - ], - "properties": { - "ids": { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - } - }, - "handler.distributionItem": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "size": { - "type": "integer" - } - } - }, - "handler.fileStatsResponse": { - "type": "object", - "properties": { - "categories": { - "type": "array", - "items": { - "$ref": "#/definitions/handler.distributionItem" - } - }, - "total_count": { - "type": "integer" - }, - "total_size": { - "type": "integer" - }, - "trend": { - "type": "array", - "items": { - "$ref": "#/definitions/handler.trendItem" - } - }, - "types": { - "type": "array", - "items": { - "$ref": "#/definitions/handler.distributionItem" - } - } - } - }, - "handler.listFilesResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Upload" - } - }, - "page": { - "type": "integer" - }, - "page_size": { - "type": "integer" - }, - "total": { - "type": "integer" - } - } - }, - "handler.listMyFilesResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Upload" - } - }, - "page": { - "type": "integer" - }, - "page_size": { - "type": "integer" - }, - "total": { - "type": "integer" - } - } - }, - "handler.trendItem": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "date": { - "type": "string" - }, - "size": { - "type": "integer" - } - } - }, - "handler.updateMyFileRequest": { - "type": "object", - "properties": { - "access_mode": { - "type": "integer", - "enum": [ - 0, - 1 - ] - }, - "file_name": { - "type": "string", - "maxLength": 255 - } - } - }, - "logger.LogEntry": { - "type": "object", - "properties": { - "data": { - "description": "一行日志原文(含换行符)", - "type": "string" - }, - "index": { - "description": "全局递增序号", - "type": "integer" - } - } - }, - "logs.accessLogItem": { - "type": "object", - "properties": { - "created_at": { - "type": "string" - }, - "headers": { - "type": "string" - }, - "id": { - "type": "string", - "example": "0" - }, - "ip": { - "type": "string" - }, - "latency": { - "type": "integer" - }, - "method": { - "type": "string" - }, - "nickname": { - "type": "string" - }, - "path": { - "type": "string" - }, - "status": { - "type": "integer" - }, - "user_agent": { - "type": "string" - }, - "user_id": { - "type": "string", - "example": "0" - }, - "username": { - "type": "string" - } - } - }, - "logs.accessLogsResponse": { - "type": "object", - "properties": { - "list": { - "type": "array", - "items": { - "$ref": "#/definitions/logs.accessLogItem" - } - }, - "total": { - "type": "integer" - } - } - }, - "logs.browserItem": { - "type": "object", - "properties": { - "browser": { - "type": "string" - }, - "count": { - "type": "integer" - } - } - }, - "logs.logsAnalyticsResponse": { - "type": "object", - "properties": { - "browsers": { - "type": "array", - "items": { - "$ref": "#/definitions/logs.browserItem" - } - }, - "top_users": { - "type": "array", - "items": { - "$ref": "#/definitions/logs.topUserItem" - } - }, - "trend": { - "type": "array", - "items": { - "$ref": "#/definitions/logs.trendItem" - } - } - } - }, - "logs.logsResponse": { - "type": "object", - "properties": { - "has_more": { - "type": "boolean" - }, - "lines": { - "type": "array", - "items": { - "$ref": "#/definitions/logger.LogEntry" - } - }, - "next_cursor": { - "description": "用于加载更早日志的 cursor", - "type": "integer" - } - } - }, - "logs.topUserItem": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "nickname": { - "type": "string" - }, - "user_id": { - "type": "string", - "example": "0" - }, - "username": { - "type": "string" - } - } - }, - "logs.trendItem": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "date": { - "type": "string" - } - } - }, "model.AccessToken": { "type": "object", "properties": { @@ -13361,6 +13294,110 @@ const docTemplate = `{ } } }, + "model.OpenFlareNode": { + "type": "object", + "properties": { + "auto_update_enabled": { + "type": "boolean" + }, + "capabilities_json": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "current_version": { + "type": "string" + }, + "ext_version": { + "type": "string" + }, + "geo_latitude": { + "type": "number" + }, + "geo_longitude": { + "type": "number" + }, + "geo_manual_override": { + "type": "boolean" + }, + "geo_name": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "ip": { + "type": "string" + }, + "ip_manual_override": { + "type": "boolean" + }, + "last_error": { + "type": "string" + }, + "last_seen_at": { + "type": "string" + }, + "name": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "node_type": { + "type": "string" + }, + "openresty_message": { + "type": "string" + }, + "openresty_status": { + "type": "string" + }, + "relay_agent_access_addr": { + "type": "string" + }, + "relay_bind_port": { + "type": "integer" + }, + "relay_client_access_addr": { + "type": "string" + }, + "relay_client_proxy_url": { + "type": "string" + }, + "relay_status": { + "type": "string" + }, + "relay_vhost_http_port": { + "type": "integer" + }, + "relay_web_server_enabled": { + "type": "boolean" + }, + "restart_openresty_requested": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "update_channel": { + "type": "string" + }, + "update_requested": { + "type": "boolean" + }, + "update_tag": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, "model.OpenFlareNodeSystemProfile": { "type": "object", "properties": { @@ -13817,133 +13854,6 @@ const docTemplate = `{ } } }, - "model.Upload": { - "type": "object", - "properties": { - "access_mode": { - "type": "integer" - }, - "created_at": { - "type": "string" - }, - "extension": { - "description": "文件后缀名 (不含点,如 png, pdf)", - "type": "string" - }, - "file_name": { - "description": "原始文件名 (例如: image.png)", - "type": "string" - }, - "file_path": { - "description": "文件相对路径 / S3 Key", - "type": "string" - }, - "file_size": { - "description": "文件大小(字节)", - "type": "integer" - }, - "hash": { - "description": "文件哈希 (SHA-256/MD5,可用于排重)", - "type": "string" - }, - "id": { - "type": "string", - "example": "0" - }, - "metadata": { - "description": "业务扩展元数据", - "allOf": [ - { - "$ref": "#/definitions/model.UploadMetadata" - } - ] - }, - "mime_type": { - "description": "媒体类型 (MIME, 如 image/png)", - "type": "string" - }, - "status": { - "description": "状态", - "allOf": [ - { - "$ref": "#/definitions/model.UploadStatus" - } - ] - }, - "type": { - "description": "业务标识类型 (如 avatar, doc, attachment)", - "type": "string" - }, - "updated_at": { - "type": "string" - }, - "user_id": { - "type": "string", - "example": "0" - } - } - }, - "model.UploadMetadata": { - "type": "object", - "properties": { - "bucket": { - "description": "存储桶名称 (适用于 S3 等)", - "type": "string" - }, - "client_ip": { - "description": "上传者 IP", - "type": "string" - }, - "duration": { - "description": "音视频时长 (s)", - "type": "number" - }, - "extra": { - "description": "其它任意业务自定义元数据", - "type": "object", - "additionalProperties": {} - }, - "height": { - "description": "图像/视频高度 (px)", - "type": "integer" - }, - "original_mime": { - "description": "原始 MIME 类型", - "type": "string" - }, - "user_agent": { - "description": "上传者的 UA", - "type": "string" - }, - "width": { - "description": "图像/视频宽度 (px)", - "type": "integer" - } - } - }, - "model.UploadStatus": { - "type": "string", - "enum": [ - "pending", - "used", - "deleted" - ], - "x-enum-comments": { - "UploadStatusDeleted": "已删除", - "UploadStatusPending": "待使用", - "UploadStatusUsed": "已使用" - }, - "x-enum-descriptions": [ - "待使用", - "已使用", - "已删除" - ], - "x-enum-varnames": [ - "UploadStatusPending", - "UploadStatusUsed", - "UploadStatusDeleted" - ] - }, "node.AgentReleaseInfo": { "type": "object", "properties": { @@ -15804,6 +15714,136 @@ const docTemplate = `{ } } }, + "relay.Config": { + "type": "object", + "properties": { + "auth_token": { + "type": "string" + }, + "bind_port": { + "type": "integer" + }, + "log_level": { + "type": "string" + }, + "vhost_http_port": { + "type": "integer" + }, + "web_server_enabled": { + "type": "boolean" + } + } + }, + "relay.HeartbeatPayload": { + "type": "object", + "properties": { + "frp_version": { + "type": "string" + }, + "frps_client_count": { + "type": "integer" + }, + "frps_connections": { + "type": "integer" + }, + "frps_proxies": { + "type": "array", + "items": { + "$ref": "#/definitions/relay.ProxyStat" + } + }, + "frps_proxy_count": { + "type": "integer" + }, + "health_events": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.NodeHealthEvent" + } + }, + "ip": { + "type": "string" + }, + "name": { + "type": "string" + }, + "profile": { + "$ref": "#/definitions/agent.NodeSystemProfile" + }, + "relay_status": { + "type": "string" + }, + "snapshot": { + "$ref": "#/definitions/agent.NodeMetricSnapshot" + }, + "version": { + "type": "string" + } + } + }, + "relay.HeartbeatResponse": { + "type": "object", + "properties": { + "relay_config": { + "$ref": "#/definitions/relay.Config" + }, + "relay_settings": { + "$ref": "#/definitions/relay.Settings" + } + } + }, + "relay.ProxyStat": { + "type": "object", + "properties": { + "client_addr": { + "type": "string" + }, + "client_version": { + "type": "string" + }, + "last_close_time": { + "type": "string" + }, + "last_start_time": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "relay.Settings": { + "type": "object", + "properties": { + "auto_update": { + "type": "boolean" + }, + "heartbeat_interval": { + "type": "integer" + }, + "update_channel": { + "type": "string" + }, + "update_now": { + "type": "boolean" + }, + "update_repo": { + "type": "string" + }, + "update_tag": { + "type": "string" + }, + "websocket_upgrade_enabled": { + "type": "boolean" + } + } + }, "response.Any": { "type": "object", "properties": { @@ -17126,10 +17166,20 @@ const docTemplate = `{ } }, "securityDefinitions": { + "AgentTokenAuth": { + "type": "apiKey", + "name": "X-Agent-Token", + "in": "header" + }, "SessionCookie": { "type": "apiKey", "name": "session", "in": "cookie" + }, + "TunnelTokenAuth": { + "type": "apiKey", + "name": "X-Tunnel-Token", + "in": "header" } } }` diff --git a/Wavelet/docs/swagger.json b/Wavelet/docs/swagger.json index ade96ab2..de8abe56 100644 --- a/Wavelet/docs/swagger.json +++ b/Wavelet/docs/swagger.json @@ -921,231 +921,6 @@ } } }, - "/api/v1/admin/logs": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "分页获取系统历史日志,cursor=0 获取最新日志,cursor\u003e0 获取更早日志", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取系统日志", - "parameters": [ - { - "type": "integer", - "default": 0, - "description": "日志游标,0=获取最新", - "name": "cursor", - "in": "query" - }, - { - "type": "integer", - "default": 200, - "description": "每页条数", - "name": "limit", - "in": "query" - } - ], - "responses": { - "200": { - "description": "日志列表", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/logs.logsResponse" - } - } - } - ] - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/logs/access": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "分页并按照用户、接口路径、时间范围等维度检索 ClickHouse 用户访问日志列表(需要管理员权限,ClickHouse 未启用时报错)", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取用户访问日志", - "parameters": [ - { - "type": "integer", - "default": 1, - "description": "页码", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "default": 20, - "description": "每页条数", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "用户名模糊搜索", - "name": "username", - "in": "query" - }, - { - "type": "string", - "description": "接口路径模糊搜索", - "name": "path", - "in": "query" - }, - { - "type": "string", - "description": "起始时间(RFC3339 或 YYYY-MM-DD HH:MM:SS)", - "name": "start_time", - "in": "query" - }, - { - "type": "string", - "description": "结束时间(RFC3339 或 YYYY-MM-DD HH:MM:SS)", - "name": "end_time", - "in": "query" - } - ], - "responses": { - "200": { - "description": "访问日志列表", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/logs.accessLogsResponse" - } - } - } - ] - } - }, - "400": { - "description": "ClickHouse 未启用或参数错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/logs/analytics": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "聚合统计最近 7 天的每日访问趋势、浏览器分布以及前 10 名最活跃用户排行(需要管理员权限,ClickHouse 未启用时报错)", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取访问日志分析数据", - "responses": { - "200": { - "description": "分析统计数据", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/logs.logsAnalyticsResponse" - } - } - } - ] - } - }, - "400": { - "description": "ClickHouse 未启用", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/logs/ws": { - "get": { - "description": "通过 WebSocket 实时推送系统日志,需要管理员权限", - "tags": [ - "admin" - ], - "summary": "系统日志实时推送", - "responses": {} - } - }, "/api/v1/admin/push/channels": { "get": { "security": [ @@ -3294,362 +3069,6 @@ } } }, - "/api/v1/admin/uploads": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "分页获取系统上传的文件列表,支持文件名关键词、业务类型、扩展名、上传用户ID过滤", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取文件列表", - "parameters": [ - { - "type": "integer", - "description": "页码(默认 1)", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "每页数量(默认 20,最大 100)", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "文件名关键词(模糊匹配)", - "name": "keyword", - "in": "query" - }, - { - "type": "string", - "description": "业务分类过滤", - "name": "type", - "in": "query" - }, - { - "type": "string", - "description": "扩展名过滤", - "name": "extension", - "in": "query" - }, - { - "type": "integer", - "format": "int64", - "description": "上传用户 ID", - "name": "user_id", - "in": "query" - } - ], - "responses": { - "200": { - "description": "查询成功", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handler.listFilesResponse" - } - } - } - ] - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/download/batch": { - "post": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "传入多个文件 ID,后台实时将其打包压缩为 ZIP 流并输出,自动处理文件名重复冲突", - "consumes": [ - "application/json" - ], - "produces": [ - "application/octet-stream" - ], - "tags": [ - "admin" - ], - "summary": "批量打包下载", - "parameters": [ - { - "description": "包含文件 ID 数组 of string 的请求体", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/handler.batchDownloadRequest" - } - } - ], - "responses": { - "200": { - "description": "成功下载打包后的 ZIP", - "schema": { - "type": "file" - } - }, - "400": { - "description": "参数错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "打包失败", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/download/{id}": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "根据文件 ID 获取文件,以附件形式 (Attachment) 强制开启客户端浏览器下载", - "produces": [ - "application/octet-stream" - ], - "tags": [ - "admin" - ], - "summary": "下载单文件", - "parameters": [ - { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "图片质量 (low, medium, high, origin),默认为 origin", - "name": "quality", - "in": "query" - } - ], - "responses": { - "200": { - "description": "成功下载文件", - "schema": { - "type": "file" - } - }, - "400": { - "description": "参数错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "404": { - "description": "文件不存在", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "服务内部错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/stats": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "返回系统级的总文件数、占用大小、最近 7 天新增趋势、文件类型/格式分布等数据", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取文件统计数据", - "responses": { - "200": { - "description": "获取成功", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handler.fileStatsResponse" - } - } - } - ] - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "内部错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/types": { - "get": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "返回数据库中所有已上传文件实际拥有的业务类型列表", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "获取文件业务类型列表", - "responses": { - "200": { - "description": "业务类型列表", - "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - ] - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "内部错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, - "/api/v1/admin/uploads/{id}": { - "delete": { - "security": [ - { - "SessionCookie": [] - } - ], - "description": "将文件状态置为 deleted(软删除),不会立即清理底层存储对象", - "produces": [ - "application/json" - ], - "tags": [ - "admin" - ], - "summary": "删除文件", - "parameters": [ - { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - } - ], - "responses": { - "200": { - "description": "删除成功", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "403": { - "description": "无权操作", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "404": { - "description": "文件不存在", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, "/api/v1/admin/users": { "get": { "security": [ @@ -4047,6 +3466,375 @@ } } }, + "/api/v1/agent/apply-logs": { + "post": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "记录 Agent 配置下发与应用结果", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "上报配置应用日志", + "parameters": [ + { + "description": "应用日志", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/agent.ApplyLogPayload" + } + } + ], + "responses": { + "200": { + "description": "日志记录", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/model.OpenFlareApplyLog" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/config-versions/active": { + "get": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "返回当前生效的完整配置包,供 Agent 拉取并应用", + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "获取活跃配置版本", + "responses": { + "200": { + "description": "活跃配置", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/agent.ConfigResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/nodes/heartbeat": { + "post": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "上报节点状态、指标与健康事件,返回远程控制配置与活跃配置元信息", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "Agent 心跳上报", + "parameters": [ + { + "description": "心跳数据", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/agent.NodePayload" + } + } + ], + "responses": { + "200": { + "description": "心跳成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/agent.HeartbeatResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/nodes/register": { + "post": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "使用节点 access token 重新注册,或使用全局 discovery token 发现新节点;请求头需携带 X-Agent-Token", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "注册或发现 Agent 节点", + "parameters": [ + { + "description": "节点上报数据", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/agent.NodePayload" + } + } + ], + "responses": { + "200": { + "description": "注册成功", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/agent.RegistrationResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/pages/deployments/{deployment_id}/package": { + "get": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "流式下载指定部署的静态资源压缩包,供 Agent 边缘分发", + "produces": [ + "application/octet-stream" + ], + "tags": [ + "openflare-agent" + ], + "summary": "下载 Pages 部署包", + "parameters": [ + { + "type": "integer", + "description": "部署 ID", + "name": "deployment_id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "部署包文件", + "schema": { + "type": "file" + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/waf/ip-groups/sync": { + "post": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "按 ID 与校验和增量同步 WAF IP 组定义", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-agent" + ], + "summary": "同步 WAF IP 组", + "parameters": [ + { + "description": "同步请求", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/agent.WAFIPGroupSyncInput" + } + } + ], + "responses": { + "200": { + "description": "同步结果", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/agent.WAFIPGroupSyncResult" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/agent/ws": { + "get": { + "security": [ + { + "AgentTokenAuth": [] + } + ], + "description": "升级为 WebSocket 长连接,用于实时推送配置同步、WAF IP 组等指令;需携带 X-Agent-Token", + "tags": [ + "openflare-agent" + ], + "summary": "Agent WebSocket 连接", + "responses": { + "401": { + "description": "Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, "/api/v1/config/public": { "get": { "description": "返回系统配置表中 visibility 为 1 的配置键值集合", @@ -4198,8 +3986,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4273,8 +4061,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4390,8 +4178,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4513,8 +4301,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4618,8 +4406,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4711,8 +4499,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -4772,12 +4560,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -5472,8 +5254,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5536,8 +5318,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5609,8 +5391,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5667,12 +5449,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -5755,12 +5531,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -5825,8 +5595,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5898,8 +5668,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -5968,8 +5738,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -6026,12 +5796,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -6114,12 +5878,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -7004,8 +6762,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7078,8 +6836,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7153,8 +6911,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7216,8 +6974,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7279,8 +7037,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7672,8 +7430,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7745,8 +7503,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -7818,12 +7576,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "部署不存在", "schema": { @@ -7894,12 +7646,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -7958,12 +7704,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -8037,12 +7777,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -8123,12 +7857,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -8206,12 +7934,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目或部署不存在", "schema": { @@ -8277,12 +7999,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目或部署不存在", "schema": { @@ -8365,12 +8081,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "项目不存在", "schema": { @@ -8808,8 +8518,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -8881,8 +8591,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -8956,8 +8666,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9048,8 +8758,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9118,12 +8828,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9194,12 +8898,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9282,12 +8980,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9346,12 +9038,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9422,12 +9108,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9510,12 +9190,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9598,12 +9272,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -9668,8 +9336,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9732,8 +9400,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9805,8 +9473,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9880,8 +9548,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -9950,12 +9618,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10014,12 +9676,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10090,12 +9746,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10178,12 +9828,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10248,8 +9892,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -10321,8 +9965,8 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", + "404": { + "description": "无权限或不存在", "schema": { "$ref": "#/definitions/response.Any" } @@ -10391,12 +10035,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10455,12 +10093,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10543,12 +10175,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10631,12 +10257,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10707,12 +10327,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -10793,12 +10407,6 @@ "$ref": "#/definitions/response.Any" } }, - "403": { - "description": "无管理员权限", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, "404": { "description": "记录不存在", "schema": { @@ -11221,48 +10829,38 @@ } } }, - "/api/v1/upload": { + "/api/v1/relay/heartbeat": { "post": { "security": [ { - "SessionCookie": [] + "AgentTokenAuth": [] } ], - "description": "支持各种类型的通用文件上传,支持自动文件类型检测、哈希计算与“秒传”去重", + "description": "Relay 节点定期上报运行状态与 frps 观测数据,返回运行时配置", "consumes": [ - "multipart/form-data" + "application/json" ], "produces": [ "application/json" ], "tags": [ - "upload" + "openflare-relay" ], - "summary": "上传文件", + "summary": "上报 Relay 心跳", "parameters": [ { - "type": "file", - "description": "要上传的文件", - "name": "file", - "in": "formData", - "required": true - }, - { - "type": "string", - "description": "业务分类 (例如: avatar, attachment, doc,默认为 generic)", - "name": "type", - "in": "formData" - }, - { - "type": "string", - "description": "额外的 JSON 格式元数据", - "name": "metadata", - "in": "formData" + "description": "心跳载荷", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/relay.HeartbeatPayload" + } } ], "responses": { "200": { - "description": "上传成功", + "description": "心跳响应", "schema": { "allOf": [ { @@ -11272,7 +10870,7 @@ "type": "object", "properties": { "data": { - "$ref": "#/definitions/model.Upload" + "$ref": "#/definitions/relay.HeartbeatResponse" } } } @@ -11280,19 +10878,19 @@ } }, "400": { - "description": "请求参数错误或文件受限", + "description": "参数错误", "schema": { "$ref": "#/definitions/response.Any" } }, "401": { - "description": "未登录", + "description": "Agent Token 无效", "schema": { "$ref": "#/definitions/response.Any" } }, - "500": { - "description": "内部错误", + "403": { + "description": "节点类型不匹配", "schema": { "$ref": "#/definitions/response.Any" } @@ -11300,74 +10898,27 @@ } } }, - "/api/v1/upload/my": { + "/api/v1/relay/ws": { "get": { "security": [ { - "SessionCookie": [] + "AgentTokenAuth": [] } ], - "description": "分页获取当前登录用户上传的文件,支持文件名关键词、业务类型、扩展名过滤", - "produces": [ - "application/json" - ], + "description": "将已认证的 Relay 连接升级为 WebSocket 长连接,用于配置推送", "tags": [ - "upload" - ], - "summary": "获取我的文件列表", - "parameters": [ - { - "type": "integer", - "description": "页码(默认 1)", - "name": "page", - "in": "query" - }, - { - "type": "integer", - "description": "每页数量(默认 20,最大 100)", - "name": "page_size", - "in": "query" - }, - { - "type": "string", - "description": "文件名关键词(模糊匹配)", - "name": "keyword", - "in": "query" - }, - { - "type": "string", - "description": "业务分类过滤", - "name": "type", - "in": "query" - }, - { - "type": "string", - "description": "扩展名过滤", - "name": "extension", - "in": "query" - } + "openflare-relay" ], + "summary": "升级 Relay WebSocket 连接", "responses": { - "200": { - "description": "查询成功", + "401": { + "description": "Agent Token 无效", "schema": { - "allOf": [ - { - "$ref": "#/definitions/response.Any" - }, - { - "type": "object", - "properties": { - "data": { - "$ref": "#/definitions/handler.listMyFilesResponse" - } - } - } - ] + "$ref": "#/definitions/response.Any" } }, - "401": { - "description": "未登录", + "403": { + "description": "节点类型不匹配", "schema": { "$ref": "#/definitions/response.Any" } @@ -11375,14 +10926,14 @@ } } }, - "/api/v1/upload/{id}": { - "put": { + "/api/v1/tunnel/apply-log": { + "post": { "security": [ { - "SessionCookie": [] + "TunnelTokenAuth": [] } ], - "description": "更新当前用户本人的文件名或访问权限模式 (AccessMode)", + "description": "Tunnel 客户端上报配置应用结果,服务端记录下发日志", "consumes": [ "application/json" ], @@ -11390,30 +10941,23 @@ "application/json" ], "tags": [ - "upload" + "openflare-tunnel" ], - "summary": "更新我的文件信息", + "summary": "上报 Tunnel 配置下发结果", "parameters": [ { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - }, - { - "description": "更新字段", - "name": "request", + "description": "下发结果载荷", + "name": "body", "in": "body", "required": true, "schema": { - "$ref": "#/definitions/handler.updateMyFileRequest" + "$ref": "#/definitions/flared.ApplyLogPayload" } } ], "responses": { "200": { - "description": "更新成功", + "description": "下发日志记录", "schema": { "allOf": [ { @@ -11423,65 +10967,179 @@ "type": "object", "properties": { "data": { - "$ref": "#/definitions/model.Upload" + "$ref": "#/definitions/model.OpenFlareApplyLog" } } } ] } }, - "403": { - "description": "无权操作", + "400": { + "description": "参数错误", "schema": { "$ref": "#/definitions/response.Any" } }, - "404": { - "description": "文件不存在", + "401": { + "description": "Tunnel Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "403": { + "description": "节点类型不匹配", "schema": { "$ref": "#/definitions/response.Any" } } } - }, - "delete": { + } + }, + "/api/v1/tunnel/config/active": { + "get": { "security": [ { - "SessionCookie": [] + "TunnelTokenAuth": [] } ], - "description": "将当前用户本人的文件状态置为 deleted(软删除)", + "description": "返回 Tunnel 客户端当前应应用的完整路由配置(含中继列表与代理定义)", "produces": [ "application/json" ], "tags": [ - "upload" - ], - "summary": "删除我的文件", - "parameters": [ - { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - } + "openflare-tunnel" ], + "summary": "获取活跃隧道配置", "responses": { "200": { - "description": "删除成功", + "description": "隧道配置", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/flared.TunnelConfigResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "401": { + "description": "Tunnel Token 无效", "schema": { "$ref": "#/definitions/response.Any" } }, "403": { - "description": "无权操作", + "description": "节点类型不匹配", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/tunnel/heartbeat": { + "post": { + "security": [ + { + "TunnelTokenAuth": [] + } + ], + "description": "Tunnel 客户端定期上报运行状态与中继连接信息,返回活跃配置元数据与隧道设置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "openflare-tunnel" + ], + "summary": "上报 Tunnel 心跳", + "parameters": [ + { + "description": "心跳载荷", + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/flared.HeartbeatPayload" + } + } + ], + "responses": { + "200": { + "description": "心跳响应", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Any" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/flared.HeartbeatResponse" + } + } + } + ] + } + }, + "400": { + "description": "参数错误", "schema": { "$ref": "#/definitions/response.Any" } }, - "404": { - "description": "文件不存在", + "401": { + "description": "Tunnel Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "403": { + "description": "节点类型不匹配", + "schema": { + "$ref": "#/definitions/response.Any" + } + } + } + } + }, + "/api/v1/tunnel/ws": { + "get": { + "security": [ + { + "TunnelTokenAuth": [] + } + ], + "description": "将已认证的 Tunnel 客户端连接升级为 WebSocket 长连接,用于配置推送", + "tags": [ + "openflare-tunnel" + ], + "summary": "升级 Tunnel WebSocket 连接", + "responses": { + "401": { + "description": "Tunnel Token 无效", + "schema": { + "$ref": "#/definitions/response.Any" + } + }, + "403": { + "description": "节点类型不匹配", "schema": { "$ref": "#/definitions/response.Any" } @@ -12095,65 +11753,6 @@ } } }, - "/f/{id}": { - "get": { - "description": "根据文件 ID 获取并提供已上传的临时或正式文件,若配置了缓存则优先走本地缓存,否则从 S3 等后端存储读取并流式返回", - "produces": [ - "application/octet-stream" - ], - "tags": [ - "upload" - ], - "summary": "获取已上传文件", - "parameters": [ - { - "type": "string", - "description": "文件 ID", - "name": "id", - "in": "path", - "required": true - }, - { - "type": "string", - "description": "图片质量 (low, medium, high, origin),默认为 origin", - "name": "quality", - "in": "query" - } - ], - "responses": { - "200": { - "description": "成功获取文件内容", - "schema": { - "type": "file" - } - }, - "400": { - "description": "文件 ID 格式错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "401": { - "description": "未登录", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "404": { - "description": "文件未找到", - "schema": { - "$ref": "#/definitions/response.Any" - } - }, - "500": { - "description": "服务内部错误", - "schema": { - "$ref": "#/definitions/response.Any" - } - } - } - } - }, "/robots.txt": { "get": { "description": "根据系统配置决定是否允许搜索引擎检索,并返回相应的 robots.txt 文件内容", @@ -12176,6 +11775,462 @@ } }, "definitions": { + "agent.ActiveConfigMeta": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "agent.ApplyLogPayload": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "main_config_checksum": { + "type": "string" + }, + "message": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "route_config_checksum": { + "type": "string" + }, + "support_file_count": { + "type": "integer" + }, + "version": { + "type": "string" + } + } + }, + "agent.BufferedObservabilityRecord": { + "type": "object", + "properties": { + "access_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.NodeAccessLog" + } + }, + "openresty_observation": { + "$ref": "#/definitions/agent.NodeOpenrestyObservation" + }, + "snapshot": { + "$ref": "#/definitions/agent.NodeMetricSnapshot" + }, + "traffic_report": { + "$ref": "#/definitions/agent.NodeTrafficReport" + }, + "window_started_at_unix": { + "type": "integer" + } + } + }, + "agent.ConfigResponse": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "source_config_json": { + "type": "string" + }, + "support_files": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.SupportFile" + } + }, + "version": { + "type": "string" + } + } + }, + "agent.HeartbeatResponse": { + "type": "object", + "properties": { + "active_config": { + "$ref": "#/definitions/agent.ActiveConfigMeta" + }, + "agent_settings": { + "$ref": "#/definitions/agent.Settings" + }, + "node": { + "$ref": "#/definitions/model.OpenFlareNode" + }, + "waf_ip_groups": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.WAFIPGroup" + } + } + } + }, + "agent.NodeAccessLog": { + "type": "object", + "properties": { + "host": { + "type": "string" + }, + "logged_at_unix": { + "type": "integer" + }, + "path": { + "type": "string" + }, + "remote_addr": { + "type": "string" + }, + "status_code": { + "type": "integer" + } + } + }, + "agent.NodeHealthEvent": { + "type": "object", + "properties": { + "event_type": { + "type": "string" + }, + "message": { + "type": "string" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "severity": { + "type": "string" + }, + "triggered_at_unix": { + "type": "integer" + } + } + }, + "agent.NodeMetricSnapshot": { + "type": "object", + "properties": { + "captured_at_unix": { + "type": "integer" + }, + "cpu_usage_percent": { + "type": "number" + }, + "disk_read_bytes": { + "type": "integer" + }, + "disk_write_bytes": { + "type": "integer" + }, + "memory_total_bytes": { + "type": "integer" + }, + "memory_used_bytes": { + "type": "integer" + }, + "network_rx_bytes": { + "type": "integer" + }, + "network_tx_bytes": { + "type": "integer" + }, + "storage_total_bytes": { + "type": "integer" + }, + "storage_used_bytes": { + "type": "integer" + } + } + }, + "agent.NodeOpenrestyObservation": { + "type": "object", + "properties": { + "captured_at_unix": { + "type": "integer" + }, + "openresty_connections": { + "type": "integer" + }, + "openresty_rx_bytes": { + "type": "integer" + }, + "openresty_tx_bytes": { + "type": "integer" + } + } + }, + "agent.NodePayload": { + "type": "object", + "properties": { + "access_logs": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.NodeAccessLog" + } + }, + "buffered_observability": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.BufferedObservabilityRecord" + } + }, + "current_version": { + "type": "string" + }, + "ext_version": { + "type": "string" + }, + "health_events": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.NodeHealthEvent" + } + }, + "ip": { + "type": "string" + }, + "last_error": { + "type": "string" + }, + "name": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "openresty_message": { + "type": "string" + }, + "openresty_observation": { + "$ref": "#/definitions/agent.NodeOpenrestyObservation" + }, + "openresty_status": { + "type": "string" + }, + "profile": { + "$ref": "#/definitions/agent.NodeSystemProfile" + }, + "snapshot": { + "$ref": "#/definitions/agent.NodeMetricSnapshot" + }, + "traffic_report": { + "$ref": "#/definitions/agent.NodeTrafficReport" + }, + "version": { + "type": "string" + }, + "waf_ip_group_checksums": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "agent.NodeSystemProfile": { + "type": "object", + "properties": { + "architecture": { + "type": "string" + }, + "cpu_cores": { + "type": "integer" + }, + "cpu_model": { + "type": "string" + }, + "hostname": { + "type": "string" + }, + "kernel_version": { + "type": "string" + }, + "os_name": { + "type": "string" + }, + "os_version": { + "type": "string" + }, + "reported_at_unix": { + "type": "integer" + }, + "total_disk_bytes": { + "type": "integer" + }, + "total_memory_bytes": { + "type": "integer" + }, + "uptime_seconds": { + "type": "integer" + } + } + }, + "agent.NodeTrafficReport": { + "type": "object", + "properties": { + "error_count": { + "type": "integer" + }, + "request_count": { + "type": "integer" + }, + "source_countries": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + }, + "status_codes": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + }, + "top_domains": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int64" + } + }, + "unique_visitor_count": { + "type": "integer" + }, + "window_ended_at_unix": { + "type": "integer" + }, + "window_started_at_unix": { + "type": "integer" + } + } + }, + "agent.RegistrationResponse": { + "type": "object", + "properties": { + "access_token": { + "type": "string" + }, + "name": { + "type": "string" + }, + "node_id": { + "type": "string" + } + } + }, + "agent.Settings": { + "type": "object", + "properties": { + "auto_update": { + "type": "boolean" + }, + "heartbeat_interval": { + "type": "integer" + }, + "restart_openresty_now": { + "type": "boolean" + }, + "update_channel": { + "type": "string" + }, + "update_now": { + "type": "boolean" + }, + "update_repo": { + "type": "string" + }, + "update_tag": { + "type": "string" + }, + "websocket_upgrade_enabled": { + "type": "boolean" + } + } + }, + "agent.SupportFile": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, + "agent.WAFIPGroup": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "ip_list": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "agent.WAFIPGroupSyncInput": { + "type": "object", + "properties": { + "checksums": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ids": { + "type": "array", + "items": { + "type": "integer" + } + } + } + }, + "agent.WAFIPGroupSyncResult": { + "type": "object", + "properties": { + "groups": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.WAFIPGroup" + } + } + } + }, "apply_log.CleanupInput": { "type": "object", "properties": { @@ -12715,6 +12770,163 @@ } } }, + "flared.ActiveConfigMeta": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, + "flared.ApplyLogPayload": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "main_config_checksum": { + "type": "string" + }, + "message": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "result": { + "type": "string" + }, + "route_config_checksum": { + "type": "string" + }, + "support_file_count": { + "type": "integer" + }, + "version": { + "type": "string" + } + } + }, + "flared.ConnectedRelay": { + "type": "object", + "properties": { + "proxy_count": { + "type": "integer" + }, + "relay_node_id": { + "type": "string" + }, + "status": { + "type": "string" + } + } + }, + "flared.HeartbeatPayload": { + "type": "object", + "properties": { + "client_version": { + "type": "string" + }, + "connected_relays": { + "type": "array", + "items": { + "$ref": "#/definitions/flared.ConnectedRelay" + } + }, + "current_checksum": { + "type": "string" + }, + "current_version": { + "type": "string" + }, + "frp_version": { + "type": "string" + }, + "ip": { + "type": "string" + }, + "tunnel_status": { + "type": "string" + } + } + }, + "flared.HeartbeatResponse": { + "type": "object", + "properties": { + "active_config": { + "$ref": "#/definitions/flared.ActiveConfigMeta" + }, + "tunnel_settings": { + "$ref": "#/definitions/relay.Settings" + } + } + }, + "flared.ProxyEntry": { + "type": "object", + "properties": { + "custom_domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "local_addr": { + "type": "string" + }, + "local_port": { + "type": "integer" + }, + "name": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "flared.RelayInfo": { + "type": "object", + "properties": { + "address": { + "type": "string" + }, + "auth_token": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "relay_node_id": { + "type": "string" + } + } + }, + "flared.TunnelConfigResponse": { + "type": "object", + "properties": { + "checksum": { + "type": "string" + }, + "proxies": { + "type": "array", + "items": { + "$ref": "#/definitions/flared.ProxyEntry" + } + }, + "relays": { + "type": "array", + "items": { + "$ref": "#/definitions/flared.RelayInfo" + } + }, + "version": { + "type": "string" + } + } + }, "github_com_Rain-kl_Wavelet_internal_apps_cap.RedeemResponse": { "type": "object", "properties": { @@ -12732,285 +12944,6 @@ } } }, - "handler.batchDownloadRequest": { - "type": "object", - "required": [ - "ids" - ], - "properties": { - "ids": { - "type": "array", - "minItems": 1, - "items": { - "type": "string" - } - } - } - }, - "handler.distributionItem": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "name": { - "type": "string" - }, - "size": { - "type": "integer" - } - } - }, - "handler.fileStatsResponse": { - "type": "object", - "properties": { - "categories": { - "type": "array", - "items": { - "$ref": "#/definitions/handler.distributionItem" - } - }, - "total_count": { - "type": "integer" - }, - "total_size": { - "type": "integer" - }, - "trend": { - "type": "array", - "items": { - "$ref": "#/definitions/handler.trendItem" - } - }, - "types": { - "type": "array", - "items": { - "$ref": "#/definitions/handler.distributionItem" - } - } - } - }, - "handler.listFilesResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Upload" - } - }, - "page": { - "type": "integer" - }, - "page_size": { - "type": "integer" - }, - "total": { - "type": "integer" - } - } - }, - "handler.listMyFilesResponse": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/definitions/model.Upload" - } - }, - "page": { - "type": "integer" - }, - "page_size": { - "type": "integer" - }, - "total": { - "type": "integer" - } - } - }, - "handler.trendItem": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "date": { - "type": "string" - }, - "size": { - "type": "integer" - } - } - }, - "handler.updateMyFileRequest": { - "type": "object", - "properties": { - "access_mode": { - "type": "integer", - "enum": [ - 0, - 1 - ] - }, - "file_name": { - "type": "string", - "maxLength": 255 - } - } - }, - "logger.LogEntry": { - "type": "object", - "properties": { - "data": { - "description": "一行日志原文(含换行符)", - "type": "string" - }, - "index": { - "description": "全局递增序号", - "type": "integer" - } - } - }, - "logs.accessLogItem": { - "type": "object", - "properties": { - "created_at": { - "type": "string" - }, - "headers": { - "type": "string" - }, - "id": { - "type": "string", - "example": "0" - }, - "ip": { - "type": "string" - }, - "latency": { - "type": "integer" - }, - "method": { - "type": "string" - }, - "nickname": { - "type": "string" - }, - "path": { - "type": "string" - }, - "status": { - "type": "integer" - }, - "user_agent": { - "type": "string" - }, - "user_id": { - "type": "string", - "example": "0" - }, - "username": { - "type": "string" - } - } - }, - "logs.accessLogsResponse": { - "type": "object", - "properties": { - "list": { - "type": "array", - "items": { - "$ref": "#/definitions/logs.accessLogItem" - } - }, - "total": { - "type": "integer" - } - } - }, - "logs.browserItem": { - "type": "object", - "properties": { - "browser": { - "type": "string" - }, - "count": { - "type": "integer" - } - } - }, - "logs.logsAnalyticsResponse": { - "type": "object", - "properties": { - "browsers": { - "type": "array", - "items": { - "$ref": "#/definitions/logs.browserItem" - } - }, - "top_users": { - "type": "array", - "items": { - "$ref": "#/definitions/logs.topUserItem" - } - }, - "trend": { - "type": "array", - "items": { - "$ref": "#/definitions/logs.trendItem" - } - } - } - }, - "logs.logsResponse": { - "type": "object", - "properties": { - "has_more": { - "type": "boolean" - }, - "lines": { - "type": "array", - "items": { - "$ref": "#/definitions/logger.LogEntry" - } - }, - "next_cursor": { - "description": "用于加载更早日志的 cursor", - "type": "integer" - } - } - }, - "logs.topUserItem": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "nickname": { - "type": "string" - }, - "user_id": { - "type": "string", - "example": "0" - }, - "username": { - "type": "string" - } - } - }, - "logs.trendItem": { - "type": "object", - "properties": { - "count": { - "type": "integer" - }, - "date": { - "type": "string" - } - } - }, "model.AccessToken": { "type": "object", "properties": { @@ -13354,6 +13287,110 @@ } } }, + "model.OpenFlareNode": { + "type": "object", + "properties": { + "auto_update_enabled": { + "type": "boolean" + }, + "capabilities_json": { + "type": "string" + }, + "created_at": { + "type": "string" + }, + "current_version": { + "type": "string" + }, + "ext_version": { + "type": "string" + }, + "geo_latitude": { + "type": "number" + }, + "geo_longitude": { + "type": "number" + }, + "geo_manual_override": { + "type": "boolean" + }, + "geo_name": { + "type": "string" + }, + "id": { + "type": "integer" + }, + "ip": { + "type": "string" + }, + "ip_manual_override": { + "type": "boolean" + }, + "last_error": { + "type": "string" + }, + "last_seen_at": { + "type": "string" + }, + "name": { + "type": "string" + }, + "node_id": { + "type": "string" + }, + "node_type": { + "type": "string" + }, + "openresty_message": { + "type": "string" + }, + "openresty_status": { + "type": "string" + }, + "relay_agent_access_addr": { + "type": "string" + }, + "relay_bind_port": { + "type": "integer" + }, + "relay_client_access_addr": { + "type": "string" + }, + "relay_client_proxy_url": { + "type": "string" + }, + "relay_status": { + "type": "string" + }, + "relay_vhost_http_port": { + "type": "integer" + }, + "relay_web_server_enabled": { + "type": "boolean" + }, + "restart_openresty_requested": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "update_channel": { + "type": "string" + }, + "update_requested": { + "type": "boolean" + }, + "update_tag": { + "type": "string" + }, + "updated_at": { + "type": "string" + }, + "version": { + "type": "string" + } + } + }, "model.OpenFlareNodeSystemProfile": { "type": "object", "properties": { @@ -13810,133 +13847,6 @@ } } }, - "model.Upload": { - "type": "object", - "properties": { - "access_mode": { - "type": "integer" - }, - "created_at": { - "type": "string" - }, - "extension": { - "description": "文件后缀名 (不含点,如 png, pdf)", - "type": "string" - }, - "file_name": { - "description": "原始文件名 (例如: image.png)", - "type": "string" - }, - "file_path": { - "description": "文件相对路径 / S3 Key", - "type": "string" - }, - "file_size": { - "description": "文件大小(字节)", - "type": "integer" - }, - "hash": { - "description": "文件哈希 (SHA-256/MD5,可用于排重)", - "type": "string" - }, - "id": { - "type": "string", - "example": "0" - }, - "metadata": { - "description": "业务扩展元数据", - "allOf": [ - { - "$ref": "#/definitions/model.UploadMetadata" - } - ] - }, - "mime_type": { - "description": "媒体类型 (MIME, 如 image/png)", - "type": "string" - }, - "status": { - "description": "状态", - "allOf": [ - { - "$ref": "#/definitions/model.UploadStatus" - } - ] - }, - "type": { - "description": "业务标识类型 (如 avatar, doc, attachment)", - "type": "string" - }, - "updated_at": { - "type": "string" - }, - "user_id": { - "type": "string", - "example": "0" - } - } - }, - "model.UploadMetadata": { - "type": "object", - "properties": { - "bucket": { - "description": "存储桶名称 (适用于 S3 等)", - "type": "string" - }, - "client_ip": { - "description": "上传者 IP", - "type": "string" - }, - "duration": { - "description": "音视频时长 (s)", - "type": "number" - }, - "extra": { - "description": "其它任意业务自定义元数据", - "type": "object", - "additionalProperties": {} - }, - "height": { - "description": "图像/视频高度 (px)", - "type": "integer" - }, - "original_mime": { - "description": "原始 MIME 类型", - "type": "string" - }, - "user_agent": { - "description": "上传者的 UA", - "type": "string" - }, - "width": { - "description": "图像/视频宽度 (px)", - "type": "integer" - } - } - }, - "model.UploadStatus": { - "type": "string", - "enum": [ - "pending", - "used", - "deleted" - ], - "x-enum-comments": { - "UploadStatusDeleted": "已删除", - "UploadStatusPending": "待使用", - "UploadStatusUsed": "已使用" - }, - "x-enum-descriptions": [ - "待使用", - "已使用", - "已删除" - ], - "x-enum-varnames": [ - "UploadStatusPending", - "UploadStatusUsed", - "UploadStatusDeleted" - ] - }, "node.AgentReleaseInfo": { "type": "object", "properties": { @@ -15797,6 +15707,136 @@ } } }, + "relay.Config": { + "type": "object", + "properties": { + "auth_token": { + "type": "string" + }, + "bind_port": { + "type": "integer" + }, + "log_level": { + "type": "string" + }, + "vhost_http_port": { + "type": "integer" + }, + "web_server_enabled": { + "type": "boolean" + } + } + }, + "relay.HeartbeatPayload": { + "type": "object", + "properties": { + "frp_version": { + "type": "string" + }, + "frps_client_count": { + "type": "integer" + }, + "frps_connections": { + "type": "integer" + }, + "frps_proxies": { + "type": "array", + "items": { + "$ref": "#/definitions/relay.ProxyStat" + } + }, + "frps_proxy_count": { + "type": "integer" + }, + "health_events": { + "type": "array", + "items": { + "$ref": "#/definitions/agent.NodeHealthEvent" + } + }, + "ip": { + "type": "string" + }, + "name": { + "type": "string" + }, + "profile": { + "$ref": "#/definitions/agent.NodeSystemProfile" + }, + "relay_status": { + "type": "string" + }, + "snapshot": { + "$ref": "#/definitions/agent.NodeMetricSnapshot" + }, + "version": { + "type": "string" + } + } + }, + "relay.HeartbeatResponse": { + "type": "object", + "properties": { + "relay_config": { + "$ref": "#/definitions/relay.Config" + }, + "relay_settings": { + "$ref": "#/definitions/relay.Settings" + } + } + }, + "relay.ProxyStat": { + "type": "object", + "properties": { + "client_addr": { + "type": "string" + }, + "client_version": { + "type": "string" + }, + "last_close_time": { + "type": "string" + }, + "last_start_time": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "type": { + "type": "string" + } + } + }, + "relay.Settings": { + "type": "object", + "properties": { + "auto_update": { + "type": "boolean" + }, + "heartbeat_interval": { + "type": "integer" + }, + "update_channel": { + "type": "string" + }, + "update_now": { + "type": "boolean" + }, + "update_repo": { + "type": "string" + }, + "update_tag": { + "type": "string" + }, + "websocket_upgrade_enabled": { + "type": "boolean" + } + } + }, "response.Any": { "type": "object", "properties": { @@ -17119,10 +17159,20 @@ } }, "securityDefinitions": { + "AgentTokenAuth": { + "type": "apiKey", + "name": "X-Agent-Token", + "in": "header" + }, "SessionCookie": { "type": "apiKey", "name": "session", "in": "cookie" + }, + "TunnelTokenAuth": { + "type": "apiKey", + "name": "X-Tunnel-Token", + "in": "header" } } } \ No newline at end of file diff --git a/Wavelet/docs/swagger.yaml b/Wavelet/docs/swagger.yaml index a29730ad..c4002318 100644 --- a/Wavelet/docs/swagger.yaml +++ b/Wavelet/docs/swagger.yaml @@ -1,5 +1,304 @@ basePath: / definitions: + agent.ActiveConfigMeta: + properties: + checksum: + type: string + version: + type: string + type: object + agent.ApplyLogPayload: + properties: + checksum: + type: string + main_config_checksum: + type: string + message: + type: string + node_id: + type: string + result: + type: string + route_config_checksum: + type: string + support_file_count: + type: integer + version: + type: string + type: object + agent.BufferedObservabilityRecord: + properties: + access_logs: + items: + $ref: '#/definitions/agent.NodeAccessLog' + type: array + openresty_observation: + $ref: '#/definitions/agent.NodeOpenrestyObservation' + snapshot: + $ref: '#/definitions/agent.NodeMetricSnapshot' + traffic_report: + $ref: '#/definitions/agent.NodeTrafficReport' + window_started_at_unix: + type: integer + type: object + agent.ConfigResponse: + properties: + checksum: + type: string + created_at: + type: string + source_config_json: + type: string + support_files: + items: + $ref: '#/definitions/agent.SupportFile' + type: array + version: + type: string + type: object + agent.HeartbeatResponse: + properties: + active_config: + $ref: '#/definitions/agent.ActiveConfigMeta' + agent_settings: + $ref: '#/definitions/agent.Settings' + node: + $ref: '#/definitions/model.OpenFlareNode' + waf_ip_groups: + items: + $ref: '#/definitions/agent.WAFIPGroup' + type: array + type: object + agent.NodeAccessLog: + properties: + host: + type: string + logged_at_unix: + type: integer + path: + type: string + remote_addr: + type: string + status_code: + type: integer + type: object + agent.NodeHealthEvent: + properties: + event_type: + type: string + message: + type: string + metadata: + additionalProperties: + type: string + type: object + severity: + type: string + triggered_at_unix: + type: integer + type: object + agent.NodeMetricSnapshot: + properties: + captured_at_unix: + type: integer + cpu_usage_percent: + type: number + disk_read_bytes: + type: integer + disk_write_bytes: + type: integer + memory_total_bytes: + type: integer + memory_used_bytes: + type: integer + network_rx_bytes: + type: integer + network_tx_bytes: + type: integer + storage_total_bytes: + type: integer + storage_used_bytes: + type: integer + type: object + agent.NodeOpenrestyObservation: + properties: + captured_at_unix: + type: integer + openresty_connections: + type: integer + openresty_rx_bytes: + type: integer + openresty_tx_bytes: + type: integer + type: object + agent.NodePayload: + properties: + access_logs: + items: + $ref: '#/definitions/agent.NodeAccessLog' + type: array + buffered_observability: + items: + $ref: '#/definitions/agent.BufferedObservabilityRecord' + type: array + current_version: + type: string + ext_version: + type: string + health_events: + items: + $ref: '#/definitions/agent.NodeHealthEvent' + type: array + ip: + type: string + last_error: + type: string + name: + type: string + node_id: + type: string + openresty_message: + type: string + openresty_observation: + $ref: '#/definitions/agent.NodeOpenrestyObservation' + openresty_status: + type: string + profile: + $ref: '#/definitions/agent.NodeSystemProfile' + snapshot: + $ref: '#/definitions/agent.NodeMetricSnapshot' + traffic_report: + $ref: '#/definitions/agent.NodeTrafficReport' + version: + type: string + waf_ip_group_checksums: + additionalProperties: + type: string + type: object + type: object + agent.NodeSystemProfile: + properties: + architecture: + type: string + cpu_cores: + type: integer + cpu_model: + type: string + hostname: + type: string + kernel_version: + type: string + os_name: + type: string + os_version: + type: string + reported_at_unix: + type: integer + total_disk_bytes: + type: integer + total_memory_bytes: + type: integer + uptime_seconds: + type: integer + type: object + agent.NodeTrafficReport: + properties: + error_count: + type: integer + request_count: + type: integer + source_countries: + additionalProperties: + format: int64 + type: integer + type: object + status_codes: + additionalProperties: + format: int64 + type: integer + type: object + top_domains: + additionalProperties: + format: int64 + type: integer + type: object + unique_visitor_count: + type: integer + window_ended_at_unix: + type: integer + window_started_at_unix: + type: integer + type: object + agent.RegistrationResponse: + properties: + access_token: + type: string + name: + type: string + node_id: + type: string + type: object + agent.Settings: + properties: + auto_update: + type: boolean + heartbeat_interval: + type: integer + restart_openresty_now: + type: boolean + update_channel: + type: string + update_now: + type: boolean + update_repo: + type: string + update_tag: + type: string + websocket_upgrade_enabled: + type: boolean + type: object + agent.SupportFile: + properties: + content: + type: string + path: + type: string + type: object + agent.WAFIPGroup: + properties: + checksum: + type: string + enabled: + type: boolean + id: + type: integer + ip_list: + items: + type: string + type: array + name: + type: string + type: + type: string + type: object + agent.WAFIPGroupSyncInput: + properties: + checksums: + additionalProperties: + type: string + type: object + ids: + items: + type: integer + type: array + type: object + agent.WAFIPGroupSyncResult: + properties: + groups: + items: + $ref: '#/definitions/agent.WAFIPGroup' + type: array + type: object apply_log.CleanupInput: properties: delete_all: @@ -356,6 +655,108 @@ definitions: ttl_minutes: type: integer type: object + flared.ActiveConfigMeta: + properties: + checksum: + type: string + version: + type: string + type: object + flared.ApplyLogPayload: + properties: + checksum: + type: string + main_config_checksum: + type: string + message: + type: string + node_id: + type: string + result: + type: string + route_config_checksum: + type: string + support_file_count: + type: integer + version: + type: string + type: object + flared.ConnectedRelay: + properties: + proxy_count: + type: integer + relay_node_id: + type: string + status: + type: string + type: object + flared.HeartbeatPayload: + properties: + client_version: + type: string + connected_relays: + items: + $ref: '#/definitions/flared.ConnectedRelay' + type: array + current_checksum: + type: string + current_version: + type: string + frp_version: + type: string + ip: + type: string + tunnel_status: + type: string + type: object + flared.HeartbeatResponse: + properties: + active_config: + $ref: '#/definitions/flared.ActiveConfigMeta' + tunnel_settings: + $ref: '#/definitions/relay.Settings' + type: object + flared.ProxyEntry: + properties: + custom_domains: + items: + type: string + type: array + local_addr: + type: string + local_port: + type: integer + name: + type: string + type: + type: string + type: object + flared.RelayInfo: + properties: + address: + type: string + auth_token: + type: string + proxy_url: + type: string + relay_node_id: + type: string + type: object + flared.TunnelConfigResponse: + properties: + checksum: + type: string + proxies: + items: + $ref: '#/definitions/flared.ProxyEntry' + type: array + relays: + items: + $ref: '#/definitions/flared.RelayInfo' + type: array + version: + type: string + type: object github_com_Rain-kl_Wavelet_internal_apps_cap.RedeemResponse: properties: error: @@ -367,190 +768,6 @@ definitions: token: type: string type: object - handler.batchDownloadRequest: - properties: - ids: - items: - type: string - minItems: 1 - type: array - required: - - ids - type: object - handler.distributionItem: - properties: - count: - type: integer - name: - type: string - size: - type: integer - type: object - handler.fileStatsResponse: - properties: - categories: - items: - $ref: '#/definitions/handler.distributionItem' - type: array - total_count: - type: integer - total_size: - type: integer - trend: - items: - $ref: '#/definitions/handler.trendItem' - type: array - types: - items: - $ref: '#/definitions/handler.distributionItem' - type: array - type: object - handler.listFilesResponse: - properties: - items: - items: - $ref: '#/definitions/model.Upload' - type: array - page: - type: integer - page_size: - type: integer - total: - type: integer - type: object - handler.listMyFilesResponse: - properties: - items: - items: - $ref: '#/definitions/model.Upload' - type: array - page: - type: integer - page_size: - type: integer - total: - type: integer - type: object - handler.trendItem: - properties: - count: - type: integer - date: - type: string - size: - type: integer - type: object - handler.updateMyFileRequest: - properties: - access_mode: - enum: - - 0 - - 1 - type: integer - file_name: - maxLength: 255 - type: string - type: object - logger.LogEntry: - properties: - data: - description: 一行日志原文(含换行符) - type: string - index: - description: 全局递增序号 - type: integer - type: object - logs.accessLogItem: - properties: - created_at: - type: string - headers: - type: string - id: - example: "0" - type: string - ip: - type: string - latency: - type: integer - method: - type: string - nickname: - type: string - path: - type: string - status: - type: integer - user_agent: - type: string - user_id: - example: "0" - type: string - username: - type: string - type: object - logs.accessLogsResponse: - properties: - list: - items: - $ref: '#/definitions/logs.accessLogItem' - type: array - total: - type: integer - type: object - logs.browserItem: - properties: - browser: - type: string - count: - type: integer - type: object - logs.logsAnalyticsResponse: - properties: - browsers: - items: - $ref: '#/definitions/logs.browserItem' - type: array - top_users: - items: - $ref: '#/definitions/logs.topUserItem' - type: array - trend: - items: - $ref: '#/definitions/logs.trendItem' - type: array - type: object - logs.logsResponse: - properties: - has_more: - type: boolean - lines: - items: - $ref: '#/definitions/logger.LogEntry' - type: array - next_cursor: - description: 用于加载更早日志的 cursor - type: integer - type: object - logs.topUserItem: - properties: - count: - type: integer - nickname: - type: string - user_id: - example: "0" - type: string - username: - type: string - type: object - logs.trendItem: - properties: - count: - type: integer - date: - type: string - type: object model.AccessToken: properties: created_at: @@ -776,6 +993,75 @@ definitions: storage_used_bytes: type: integer type: object + model.OpenFlareNode: + properties: + auto_update_enabled: + type: boolean + capabilities_json: + type: string + created_at: + type: string + current_version: + type: string + ext_version: + type: string + geo_latitude: + type: number + geo_longitude: + type: number + geo_manual_override: + type: boolean + geo_name: + type: string + id: + type: integer + ip: + type: string + ip_manual_override: + type: boolean + last_error: + type: string + last_seen_at: + type: string + name: + type: string + node_id: + type: string + node_type: + type: string + openresty_message: + type: string + openresty_status: + type: string + relay_agent_access_addr: + type: string + relay_bind_port: + type: integer + relay_client_access_addr: + type: string + relay_client_proxy_url: + type: string + relay_status: + type: string + relay_vhost_http_port: + type: integer + relay_web_server_enabled: + type: boolean + restart_openresty_requested: + type: boolean + status: + type: string + update_channel: + type: string + update_requested: + type: boolean + update_tag: + type: string + updated_at: + type: string + version: + type: string + type: object model.OpenFlareNodeSystemProfile: properties: architecture: @@ -1084,96 +1370,6 @@ definitions: updated_at: type: string type: object - model.Upload: - properties: - access_mode: - type: integer - created_at: - type: string - extension: - description: 文件后缀名 (不含点,如 png, pdf) - type: string - file_name: - description: '原始文件名 (例如: image.png)' - type: string - file_path: - description: 文件相对路径 / S3 Key - type: string - file_size: - description: 文件大小(字节) - type: integer - hash: - description: 文件哈希 (SHA-256/MD5,可用于排重) - type: string - id: - example: "0" - type: string - metadata: - allOf: - - $ref: '#/definitions/model.UploadMetadata' - description: 业务扩展元数据 - mime_type: - description: 媒体类型 (MIME, 如 image/png) - type: string - status: - allOf: - - $ref: '#/definitions/model.UploadStatus' - description: 状态 - type: - description: 业务标识类型 (如 avatar, doc, attachment) - type: string - updated_at: - type: string - user_id: - example: "0" - type: string - type: object - model.UploadMetadata: - properties: - bucket: - description: 存储桶名称 (适用于 S3 等) - type: string - client_ip: - description: 上传者 IP - type: string - duration: - description: 音视频时长 (s) - type: number - extra: - additionalProperties: {} - description: 其它任意业务自定义元数据 - type: object - height: - description: 图像/视频高度 (px) - type: integer - original_mime: - description: 原始 MIME 类型 - type: string - user_agent: - description: 上传者的 UA - type: string - width: - description: 图像/视频宽度 (px) - type: integer - type: object - model.UploadStatus: - enum: - - pending - - used - - deleted - type: string - x-enum-comments: - UploadStatusDeleted: 已删除 - UploadStatusPending: 待使用 - UploadStatusUsed: 已使用 - x-enum-descriptions: - - 待使用 - - 已使用 - - 已删除 - x-enum-varnames: - - UploadStatusPending - - UploadStatusUsed - - UploadStatusDeleted node.AgentReleaseInfo: properties: body: @@ -2399,6 +2595,91 @@ definitions: total: type: integer type: object + relay.Config: + properties: + auth_token: + type: string + bind_port: + type: integer + log_level: + type: string + vhost_http_port: + type: integer + web_server_enabled: + type: boolean + type: object + relay.HeartbeatPayload: + properties: + frp_version: + type: string + frps_client_count: + type: integer + frps_connections: + type: integer + frps_proxies: + items: + $ref: '#/definitions/relay.ProxyStat' + type: array + frps_proxy_count: + type: integer + health_events: + items: + $ref: '#/definitions/agent.NodeHealthEvent' + type: array + ip: + type: string + name: + type: string + profile: + $ref: '#/definitions/agent.NodeSystemProfile' + relay_status: + type: string + snapshot: + $ref: '#/definitions/agent.NodeMetricSnapshot' + version: + type: string + type: object + relay.HeartbeatResponse: + properties: + relay_config: + $ref: '#/definitions/relay.Config' + relay_settings: + $ref: '#/definitions/relay.Settings' + type: object + relay.ProxyStat: + properties: + client_addr: + type: string + client_version: + type: string + last_close_time: + type: string + last_start_time: + type: string + name: + type: string + status: + type: string + type: + type: string + type: object + relay.Settings: + properties: + auto_update: + type: boolean + heartbeat_interval: + type: integer + update_channel: + type: string + update_now: + type: boolean + update_repo: + type: string + update_tag: + type: string + websocket_upgrade_enabled: + type: boolean + type: object response.Any: properties: data: {} @@ -3841,143 +4122,6 @@ paths: summary: 获取数据库所有表名 tags: - admin - /api/v1/admin/logs: - get: - description: 分页获取系统历史日志,cursor=0 获取最新日志,cursor>0 获取更早日志 - parameters: - - default: 0 - description: 日志游标,0=获取最新 - in: query - name: cursor - type: integer - - default: 200 - description: 每页条数 - in: query - name: limit - type: integer - produces: - - application/json - responses: - "200": - description: 日志列表 - schema: - allOf: - - $ref: '#/definitions/response.Any' - - properties: - data: - $ref: '#/definitions/logs.logsResponse' - type: object - "401": - description: 未登录 - schema: - $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 获取系统日志 - tags: - - admin - /api/v1/admin/logs/access: - get: - description: 分页并按照用户、接口路径、时间范围等维度检索 ClickHouse 用户访问日志列表(需要管理员权限,ClickHouse 未启用时报错) - parameters: - - default: 1 - description: 页码 - in: query - name: page - type: integer - - default: 20 - description: 每页条数 - in: query - name: page_size - type: integer - - description: 用户名模糊搜索 - in: query - name: username - type: string - - description: 接口路径模糊搜索 - in: query - name: path - type: string - - description: 起始时间(RFC3339 或 YYYY-MM-DD HH:MM:SS) - in: query - name: start_time - type: string - - description: 结束时间(RFC3339 或 YYYY-MM-DD HH:MM:SS) - in: query - name: end_time - type: string - produces: - - application/json - responses: - "200": - description: 访问日志列表 - schema: - allOf: - - $ref: '#/definitions/response.Any' - - properties: - data: - $ref: '#/definitions/logs.accessLogsResponse' - type: object - "400": - description: ClickHouse 未启用或参数错误 - schema: - $ref: '#/definitions/response.Any' - "401": - description: 未登录 - schema: - $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 获取用户访问日志 - tags: - - admin - /api/v1/admin/logs/analytics: - get: - description: 聚合统计最近 7 天的每日访问趋势、浏览器分布以及前 10 名最活跃用户排行(需要管理员权限,ClickHouse 未启用时报错) - produces: - - application/json - responses: - "200": - description: 分析统计数据 - schema: - allOf: - - $ref: '#/definitions/response.Any' - - properties: - data: - $ref: '#/definitions/logs.logsAnalyticsResponse' - type: object - "400": - description: ClickHouse 未启用 - schema: - $ref: '#/definitions/response.Any' - "401": - description: 未登录 - schema: - $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 获取访问日志分析数据 - tags: - - admin - /api/v1/admin/logs/ws: - get: - description: 通过 WebSocket 实时推送系统日志,需要管理员权限 - responses: {} - summary: 系统日志实时推送 - tags: - - admin /api/v1/admin/push/channels: get: description: 返回系统配置的所有消息通道列表,需要管理员权限 @@ -5252,224 +5396,6 @@ paths: summary: 下载并应用应用更新 tags: - admin - /api/v1/admin/uploads: - get: - description: 分页获取系统上传的文件列表,支持文件名关键词、业务类型、扩展名、上传用户ID过滤 - parameters: - - description: 页码(默认 1) - in: query - name: page - type: integer - - description: 每页数量(默认 20,最大 100) - in: query - name: page_size - type: integer - - description: 文件名关键词(模糊匹配) - in: query - name: keyword - type: string - - description: 业务分类过滤 - in: query - name: type - type: string - - description: 扩展名过滤 - in: query - name: extension - type: string - - description: 上传用户 ID - format: int64 - in: query - name: user_id - type: integer - produces: - - application/json - responses: - "200": - description: 查询成功 - schema: - allOf: - - $ref: '#/definitions/response.Any' - - properties: - data: - $ref: '#/definitions/handler.listFilesResponse' - type: object - "401": - description: 未登录 - schema: - $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 获取文件列表 - tags: - - admin - /api/v1/admin/uploads/{id}: - delete: - description: 将文件状态置为 deleted(软删除),不会立即清理底层存储对象 - parameters: - - description: 文件 ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: 删除成功 - schema: - $ref: '#/definitions/response.Any' - "403": - description: 无权操作 - schema: - $ref: '#/definitions/response.Any' - "404": - description: 文件不存在 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 删除文件 - tags: - - admin - /api/v1/admin/uploads/download/{id}: - get: - description: 根据文件 ID 获取文件,以附件形式 (Attachment) 强制开启客户端浏览器下载 - parameters: - - description: 文件 ID - in: path - name: id - required: true - type: string - - description: 图片质量 (low, medium, high, origin),默认为 origin - in: query - name: quality - type: string - produces: - - application/octet-stream - responses: - "200": - description: 成功下载文件 - schema: - type: file - "400": - description: 参数错误 - schema: - $ref: '#/definitions/response.Any' - "404": - description: 文件不存在 - schema: - $ref: '#/definitions/response.Any' - "500": - description: 服务内部错误 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 下载单文件 - tags: - - admin - /api/v1/admin/uploads/download/batch: - post: - consumes: - - application/json - description: 传入多个文件 ID,后台实时将其打包压缩为 ZIP 流并输出,自动处理文件名重复冲突 - parameters: - - description: 包含文件 ID 数组 of string 的请求体 - in: body - name: request - required: true - schema: - $ref: '#/definitions/handler.batchDownloadRequest' - produces: - - application/octet-stream - responses: - "200": - description: 成功下载打包后的 ZIP - schema: - type: file - "400": - description: 参数错误 - schema: - $ref: '#/definitions/response.Any' - "500": - description: 打包失败 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 批量打包下载 - tags: - - admin - /api/v1/admin/uploads/stats: - get: - description: 返回系统级的总文件数、占用大小、最近 7 天新增趋势、文件类型/格式分布等数据 - produces: - - application/json - responses: - "200": - description: 获取成功 - schema: - allOf: - - $ref: '#/definitions/response.Any' - - properties: - data: - $ref: '#/definitions/handler.fileStatsResponse' - type: object - "401": - description: 未登录 - schema: - $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' - "500": - description: 内部错误 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 获取文件统计数据 - tags: - - admin - /api/v1/admin/uploads/types: - get: - description: 返回数据库中所有已上传文件实际拥有的业务类型列表 - produces: - - application/json - responses: - "200": - description: 业务类型列表 - schema: - allOf: - - $ref: '#/definitions/response.Any' - - properties: - data: - items: - type: string - type: array - type: object - "401": - description: 未登录 - schema: - $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' - "500": - description: 内部错误 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 获取文件业务类型列表 - tags: - - admin /api/v1/admin/users: get: description: 分页返回用户列表,支持按用户 ID 和用户名筛选,需要管理员权限 @@ -5711,6 +5637,224 @@ paths: summary: 更新用户状态 tags: - admin + /api/v1/agent/apply-logs: + post: + consumes: + - application/json + description: 记录 Agent 配置下发与应用结果 + parameters: + - description: 应用日志 + in: body + name: body + required: true + schema: + $ref: '#/definitions/agent.ApplyLogPayload' + produces: + - application/json + responses: + "200": + description: 日志记录 + schema: + allOf: + - $ref: '#/definitions/response.Any' + - properties: + data: + $ref: '#/definitions/model.OpenFlareApplyLog' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Token 无效 + schema: + $ref: '#/definitions/response.Any' + security: + - AgentTokenAuth: [] + summary: 上报配置应用日志 + tags: + - openflare-agent + /api/v1/agent/config-versions/active: + get: + description: 返回当前生效的完整配置包,供 Agent 拉取并应用 + produces: + - application/json + responses: + "200": + description: 活跃配置 + schema: + allOf: + - $ref: '#/definitions/response.Any' + - properties: + data: + $ref: '#/definitions/agent.ConfigResponse' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Token 无效 + schema: + $ref: '#/definitions/response.Any' + security: + - AgentTokenAuth: [] + summary: 获取活跃配置版本 + tags: + - openflare-agent + /api/v1/agent/nodes/heartbeat: + post: + consumes: + - application/json + description: 上报节点状态、指标与健康事件,返回远程控制配置与活跃配置元信息 + parameters: + - description: 心跳数据 + in: body + name: body + required: true + schema: + $ref: '#/definitions/agent.NodePayload' + produces: + - application/json + responses: + "200": + description: 心跳成功 + schema: + allOf: + - $ref: '#/definitions/response.Any' + - properties: + data: + $ref: '#/definitions/agent.HeartbeatResponse' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Token 无效 + schema: + $ref: '#/definitions/response.Any' + security: + - AgentTokenAuth: [] + summary: Agent 心跳上报 + tags: + - openflare-agent + /api/v1/agent/nodes/register: + post: + consumes: + - application/json + description: 使用节点 access token 重新注册,或使用全局 discovery token 发现新节点;请求头需携带 X-Agent-Token + parameters: + - description: 节点上报数据 + in: body + name: body + required: true + schema: + $ref: '#/definitions/agent.NodePayload' + produces: + - application/json + responses: + "200": + description: 注册成功 + schema: + allOf: + - $ref: '#/definitions/response.Any' + - properties: + data: + $ref: '#/definitions/agent.RegistrationResponse' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Token 无效 + schema: + $ref: '#/definitions/response.Any' + security: + - AgentTokenAuth: [] + summary: 注册或发现 Agent 节点 + tags: + - openflare-agent + /api/v1/agent/pages/deployments/{deployment_id}/package: + get: + description: 流式下载指定部署的静态资源压缩包,供 Agent 边缘分发 + parameters: + - description: 部署 ID + in: path + name: deployment_id + required: true + type: integer + produces: + - application/octet-stream + responses: + "200": + description: 部署包文件 + schema: + type: file + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Token 无效 + schema: + $ref: '#/definitions/response.Any' + security: + - AgentTokenAuth: [] + summary: 下载 Pages 部署包 + tags: + - openflare-agent + /api/v1/agent/waf/ip-groups/sync: + post: + consumes: + - application/json + description: 按 ID 与校验和增量同步 WAF IP 组定义 + parameters: + - description: 同步请求 + in: body + name: body + required: true + schema: + $ref: '#/definitions/agent.WAFIPGroupSyncInput' + produces: + - application/json + responses: + "200": + description: 同步结果 + schema: + allOf: + - $ref: '#/definitions/response.Any' + - properties: + data: + $ref: '#/definitions/agent.WAFIPGroupSyncResult' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Token 无效 + schema: + $ref: '#/definitions/response.Any' + security: + - AgentTokenAuth: [] + summary: 同步 WAF IP 组 + tags: + - openflare-agent + /api/v1/agent/ws: + get: + description: 升级为 WebSocket 长连接,用于实时推送配置同步、WAF IP 组等指令;需携带 X-Agent-Token + responses: + "401": + description: Token 无效 + schema: + $ref: '#/definitions/response.Any' + security: + - AgentTokenAuth: [] + summary: Agent WebSocket 连接 + tags: + - openflare-agent /api/v1/config/public: get: consumes: @@ -5800,8 +5944,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -5845,8 +5989,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -5918,8 +6062,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -5995,8 +6139,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -6060,8 +6204,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -6117,8 +6261,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -6153,10 +6297,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -6567,8 +6707,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -6605,8 +6745,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -6649,8 +6789,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -6686,10 +6826,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -6740,10 +6876,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -6782,8 +6914,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -6826,8 +6958,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -6863,10 +6995,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -6917,10 +7045,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -6963,8 +7087,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -7488,8 +7612,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -7532,8 +7656,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -7577,8 +7701,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -7617,8 +7741,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -7657,8 +7781,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -7891,8 +8015,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -7935,8 +8059,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -7977,10 +8101,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 项目不存在 schema: @@ -8018,10 +8138,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 项目不存在 schema: @@ -8066,10 +8182,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 项目不存在 schema: @@ -8117,10 +8229,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 项目或部署不存在 schema: @@ -8163,10 +8271,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 项目或部署不存在 schema: @@ -8216,10 +8320,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 项目不存在 schema: @@ -8270,10 +8370,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 项目不存在 schema: @@ -8318,10 +8414,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 部署不存在 schema: @@ -8582,8 +8674,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -8626,8 +8718,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -8668,10 +8760,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -8714,10 +8802,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -8768,10 +8852,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -8809,10 +8889,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -8855,10 +8931,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -8909,10 +8981,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -8963,10 +9031,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9012,8 +9076,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -9069,8 +9133,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -9107,8 +9171,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -9145,8 +9209,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -9189,8 +9253,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -9231,10 +9295,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9272,10 +9332,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9318,10 +9374,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9372,10 +9424,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9421,8 +9469,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -9459,8 +9507,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -9503,8 +9551,8 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 + "404": + description: 无权限或不存在 schema: $ref: '#/definitions/response.Any' "500": @@ -9545,10 +9593,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9586,10 +9630,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9640,10 +9680,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9694,10 +9730,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9740,10 +9772,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -9793,10 +9821,6 @@ paths: description: 未登录 schema: $ref: '#/definitions/response.Any' - "403": - description: 无管理员权限 - schema: - $ref: '#/definitions/response.Any' "404": description: 记录不存在 schema: @@ -10049,169 +10073,195 @@ paths: summary: 获取当前登录用户信息 tags: - oauth - /api/v1/upload: + /api/v1/relay/heartbeat: post: consumes: - - multipart/form-data - description: 支持各种类型的通用文件上传,支持自动文件类型检测、哈希计算与“秒传”去重 - parameters: - - description: 要上传的文件 - in: formData - name: file - required: true - type: file - - description: '业务分类 (例如: avatar, attachment, doc,默认为 generic)' - in: formData - name: type - type: string - - description: 额外的 JSON 格式元数据 - in: formData - name: metadata - type: string - produces: - application/json - responses: - "200": - description: 上传成功 - schema: - allOf: - - $ref: '#/definitions/response.Any' - - properties: - data: - $ref: '#/definitions/model.Upload' - type: object - "400": - description: 请求参数错误或文件受限 - schema: - $ref: '#/definitions/response.Any' - "401": - description: 未登录 - schema: - $ref: '#/definitions/response.Any' - "500": - description: 内部错误 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 上传文件 - tags: - - upload - /api/v1/upload/{id}: - delete: - description: 将当前用户本人的文件状态置为 deleted(软删除) + description: Relay 节点定期上报运行状态与 frps 观测数据,返回运行时配置 parameters: - - description: 文件 ID - in: path - name: id - required: true - type: string - produces: - - application/json - responses: - "200": - description: 删除成功 - schema: - $ref: '#/definitions/response.Any' - "403": - description: 无权操作 - schema: - $ref: '#/definitions/response.Any' - "404": - description: 文件不存在 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 删除我的文件 - tags: - - upload - put: - consumes: - - application/json - description: 更新当前用户本人的文件名或访问权限模式 (AccessMode) - parameters: - - description: 文件 ID - in: path - name: id - required: true - type: string - - description: 更新字段 + - description: 心跳载荷 in: body - name: request + name: body required: true schema: - $ref: '#/definitions/handler.updateMyFileRequest' + $ref: '#/definitions/relay.HeartbeatPayload' produces: - application/json responses: "200": - description: 更新成功 + description: 心跳响应 schema: allOf: - $ref: '#/definitions/response.Any' - properties: data: - $ref: '#/definitions/model.Upload' + $ref: '#/definitions/relay.HeartbeatResponse' type: object - "403": - description: 无权操作 + "400": + description: 参数错误 schema: $ref: '#/definitions/response.Any' - "404": - description: 文件不存在 - schema: - $ref: '#/definitions/response.Any' - security: - - SessionCookie: [] - summary: 更新我的文件信息 - tags: - - upload - /api/v1/upload/my: - get: - description: 分页获取当前登录用户上传的文件,支持文件名关键词、业务类型、扩展名过滤 - parameters: - - description: 页码(默认 1) - in: query - name: page - type: integer - - description: 每页数量(默认 20,最大 100) - in: query - name: page_size - type: integer - - description: 文件名关键词(模糊匹配) - in: query - name: keyword - type: string - - description: 业务分类过滤 - in: query - name: type - type: string - - description: 扩展名过滤 - in: query - name: extension - type: string - produces: - - application/json - responses: - "200": - description: 查询成功 - schema: - allOf: - - $ref: '#/definitions/response.Any' - - properties: - data: - $ref: '#/definitions/handler.listMyFilesResponse' - type: object "401": - description: 未登录 + description: Agent Token 无效 + schema: + $ref: '#/definitions/response.Any' + "403": + description: 节点类型不匹配 schema: $ref: '#/definitions/response.Any' security: - - SessionCookie: [] - summary: 获取我的文件列表 + - AgentTokenAuth: [] + summary: 上报 Relay 心跳 tags: - - upload + - openflare-relay + /api/v1/relay/ws: + get: + description: 将已认证的 Relay 连接升级为 WebSocket 长连接,用于配置推送 + responses: + "401": + description: Agent Token 无效 + schema: + $ref: '#/definitions/response.Any' + "403": + description: 节点类型不匹配 + schema: + $ref: '#/definitions/response.Any' + security: + - AgentTokenAuth: [] + summary: 升级 Relay WebSocket 连接 + tags: + - openflare-relay + /api/v1/tunnel/apply-log: + post: + consumes: + - application/json + description: Tunnel 客户端上报配置应用结果,服务端记录下发日志 + parameters: + - description: 下发结果载荷 + in: body + name: body + required: true + schema: + $ref: '#/definitions/flared.ApplyLogPayload' + produces: + - application/json + responses: + "200": + description: 下发日志记录 + schema: + allOf: + - $ref: '#/definitions/response.Any' + - properties: + data: + $ref: '#/definitions/model.OpenFlareApplyLog' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Tunnel Token 无效 + schema: + $ref: '#/definitions/response.Any' + "403": + description: 节点类型不匹配 + schema: + $ref: '#/definitions/response.Any' + security: + - TunnelTokenAuth: [] + summary: 上报 Tunnel 配置下发结果 + tags: + - openflare-tunnel + /api/v1/tunnel/config/active: + get: + description: 返回 Tunnel 客户端当前应应用的完整路由配置(含中继列表与代理定义) + produces: + - application/json + responses: + "200": + description: 隧道配置 + schema: + allOf: + - $ref: '#/definitions/response.Any' + - properties: + data: + $ref: '#/definitions/flared.TunnelConfigResponse' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Tunnel Token 无效 + schema: + $ref: '#/definitions/response.Any' + "403": + description: 节点类型不匹配 + schema: + $ref: '#/definitions/response.Any' + security: + - TunnelTokenAuth: [] + summary: 获取活跃隧道配置 + tags: + - openflare-tunnel + /api/v1/tunnel/heartbeat: + post: + consumes: + - application/json + description: Tunnel 客户端定期上报运行状态与中继连接信息,返回活跃配置元数据与隧道设置 + parameters: + - description: 心跳载荷 + in: body + name: body + required: true + schema: + $ref: '#/definitions/flared.HeartbeatPayload' + produces: + - application/json + responses: + "200": + description: 心跳响应 + schema: + allOf: + - $ref: '#/definitions/response.Any' + - properties: + data: + $ref: '#/definitions/flared.HeartbeatResponse' + type: object + "400": + description: 参数错误 + schema: + $ref: '#/definitions/response.Any' + "401": + description: Tunnel Token 无效 + schema: + $ref: '#/definitions/response.Any' + "403": + description: 节点类型不匹配 + schema: + $ref: '#/definitions/response.Any' + security: + - TunnelTokenAuth: [] + summary: 上报 Tunnel 心跳 + tags: + - openflare-tunnel + /api/v1/tunnel/ws: + get: + description: 将已认证的 Tunnel 客户端连接升级为 WebSocket 长连接,用于配置推送 + responses: + "401": + description: Tunnel Token 无效 + schema: + $ref: '#/definitions/response.Any' + "403": + description: 节点类型不匹配 + schema: + $ref: '#/definitions/response.Any' + security: + - TunnelTokenAuth: [] + summary: 升级 Tunnel WebSocket 连接 + tags: + - openflare-tunnel /api/v1/user-info: get: description: 返回当前登录用户的基本信息及余额数据,需要登录。包括用户 ID、用户名、信任等级、各类余额信息等。 @@ -10568,45 +10618,6 @@ paths: summary: 发送邮箱验证码 tags: - user - /f/{id}: - get: - description: 根据文件 ID 获取并提供已上传的临时或正式文件,若配置了缓存则优先走本地缓存,否则从 S3 等后端存储读取并流式返回 - parameters: - - description: 文件 ID - in: path - name: id - required: true - type: string - - description: 图片质量 (low, medium, high, origin),默认为 origin - in: query - name: quality - type: string - produces: - - application/octet-stream - responses: - "200": - description: 成功获取文件内容 - schema: - type: file - "400": - description: 文件 ID 格式错误 - schema: - $ref: '#/definitions/response.Any' - "401": - description: 未登录 - schema: - $ref: '#/definitions/response.Any' - "404": - description: 文件未找到 - schema: - $ref: '#/definitions/response.Any' - "500": - description: 服务内部错误 - schema: - $ref: '#/definitions/response.Any' - summary: 获取已上传文件 - tags: - - upload /robots.txt: get: description: 根据系统配置决定是否允许搜索引擎检索,并返回相应的 robots.txt 文件内容 @@ -10621,8 +10632,16 @@ paths: tags: - config securityDefinitions: + AgentTokenAuth: + in: header + name: X-Agent-Token + type: apiKey SessionCookie: in: cookie name: session type: apiKey + TunnelTokenAuth: + in: header + name: X-Tunnel-Token + type: apiKey swagger: "2.0" diff --git a/Wavelet/internal/apps/openflare/agent/routers.go b/Wavelet/internal/apps/openflare/agent/routers.go index c6618d68..50b921ab 100644 --- a/Wavelet/internal/apps/openflare/agent/routers.go +++ b/Wavelet/internal/apps/openflare/agent/routers.go @@ -15,6 +15,17 @@ import ( ) // RegisterHandler registers or discovers an agent node. +// @Summary 注册或发现 Agent 节点 +// @Description 使用节点 access token 重新注册,或使用全局 discovery token 发现新节点;请求头需携带 X-Agent-Token +// @Tags openflare-agent +// @Accept json +// @Produce json +// @Security AgentTokenAuth +// @Param body body agent.NodePayload true "节点上报数据" +// @Success 200 {object} response.Any{data=agent.RegistrationResponse} "注册成功" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Token 无效" +// @Router /api/v1/agent/nodes/register [post] func RegisterHandler(c *gin.Context) { var payload NodePayload if !apiutil.BindJSON(c, &payload) { @@ -38,6 +49,17 @@ func RegisterHandler(c *gin.Context) { } // HeartbeatHandler records agent heartbeat state. +// @Summary Agent 心跳上报 +// @Description 上报节点状态、指标与健康事件,返回远程控制配置与活跃配置元信息 +// @Tags openflare-agent +// @Accept json +// @Produce json +// @Security AgentTokenAuth +// @Param body body agent.NodePayload true "心跳数据" +// @Success 200 {object} response.Any{data=agent.HeartbeatResponse} "心跳成功" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Token 无效" +// @Router /api/v1/agent/nodes/heartbeat [post] func HeartbeatHandler(c *gin.Context) { var payload NodePayload if !apiutil.BindJSON(c, &payload) { @@ -59,6 +81,15 @@ func HeartbeatHandler(c *gin.Context) { } // GetActiveConfigHandler returns the active configuration version. +// @Summary 获取活跃配置版本 +// @Description 返回当前生效的完整配置包,供 Agent 拉取并应用 +// @Tags openflare-agent +// @Produce json +// @Security AgentTokenAuth +// @Success 200 {object} response.Any{data=agent.ConfigResponse} "活跃配置" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Token 无效" +// @Router /api/v1/agent/config-versions/active [get] func GetActiveConfigHandler(c *gin.Context) { if _, ok := AgentNodeFromContext(c); !ok { response.AbortUnauthorized(c, errNodeMissingFromContext) @@ -72,6 +103,17 @@ func GetActiveConfigHandler(c *gin.Context) { } // SyncWAFIPGroupsHandler syncs WAF IP groups for an agent. +// @Summary 同步 WAF IP 组 +// @Description 按 ID 与校验和增量同步 WAF IP 组定义 +// @Tags openflare-agent +// @Accept json +// @Produce json +// @Security AgentTokenAuth +// @Param body body agent.WAFIPGroupSyncInput true "同步请求" +// @Success 200 {object} response.Any{data=agent.WAFIPGroupSyncResult} "同步结果" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Token 无效" +// @Router /api/v1/agent/waf/ip-groups/sync [post] func SyncWAFIPGroupsHandler(c *gin.Context) { var input WAFIPGroupSyncInput if !apiutil.BindJSON(c, &input) { @@ -85,6 +127,17 @@ func SyncWAFIPGroupsHandler(c *gin.Context) { } // ReportApplyLogHandler records an agent apply log entry. +// @Summary 上报配置应用日志 +// @Description 记录 Agent 配置下发与应用结果 +// @Tags openflare-agent +// @Accept json +// @Produce json +// @Security AgentTokenAuth +// @Param body body agent.ApplyLogPayload true "应用日志" +// @Success 200 {object} response.Any{data=model.OpenFlareApplyLog} "日志记录" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Token 无效" +// @Router /api/v1/agent/apply-logs [post] func ReportApplyLogHandler(c *gin.Context) { var payload ApplyLogPayload if !apiutil.BindJSON(c, &payload) { @@ -101,6 +154,16 @@ func ReportApplyLogHandler(c *gin.Context) { } // DownloadPagesPackageHandler streams the Pages deployment artifact to an authenticated agent. +// @Summary 下载 Pages 部署包 +// @Description 流式下载指定部署的静态资源压缩包,供 Agent 边缘分发 +// @Tags openflare-agent +// @Produce application/octet-stream +// @Security AgentTokenAuth +// @Param deployment_id path int true "部署 ID" +// @Success 200 {file} binary "部署包文件" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Token 无效" +// @Router /api/v1/agent/pages/deployments/{deployment_id}/package [get] func DownloadPagesPackageHandler(c *gin.Context) { deploymentID, ok := pagesDeploymentIDParam(c) if !ok { @@ -133,6 +196,12 @@ func pagesDeploymentIDParam(c *gin.Context) (uint, bool) { } // AgentWebSocketHandler upgrades an authenticated agent websocket connection. +// @Summary Agent WebSocket 连接 +// @Description 升级为 WebSocket 长连接,用于实时推送配置同步、WAF IP 组等指令;需携带 X-Agent-Token +// @Tags openflare-agent +// @Security AgentTokenAuth +// @Failure 401 {object} response.Any "Token 无效" +// @Router /api/v1/agent/ws [get] func AgentWebSocketHandler(c *gin.Context) { authNode, ok := AgentNodeFromContext(c) if !ok { diff --git a/Wavelet/internal/apps/openflare/dashboard/routers.go b/Wavelet/internal/apps/openflare/dashboard/routers.go index e226d308..ff5ea931 100644 --- a/Wavelet/internal/apps/openflare/dashboard/routers.go +++ b/Wavelet/internal/apps/openflare/dashboard/routers.go @@ -20,7 +20,7 @@ import ( // @Success 200 {object} response.Any{data=dashboard.OverviewPayload} "仪表盘概览" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/dashboard/overview [get] func GetOverviewHandler(c *gin.Context) { diff --git a/Wavelet/internal/apps/openflare/flared/routers.go b/Wavelet/internal/apps/openflare/flared/routers.go index 6c27b0ba..3091c9ae 100644 --- a/Wavelet/internal/apps/openflare/flared/routers.go +++ b/Wavelet/internal/apps/openflare/flared/routers.go @@ -14,6 +14,18 @@ import ( ) // PostHeartbeat handles POST /tunnel/heartbeat. +// @Summary 上报 Tunnel 心跳 +// @Description Tunnel 客户端定期上报运行状态与中继连接信息,返回活跃配置元数据与隧道设置 +// @Tags openflare-tunnel +// @Accept json +// @Produce json +// @Security TunnelTokenAuth +// @Param body body flared.HeartbeatPayload true "心跳载荷" +// @Success 200 {object} response.Any{data=flared.HeartbeatResponse} "心跳响应" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Tunnel Token 无效" +// @Failure 403 {object} response.Any "节点类型不匹配" +// @Router /api/v1/tunnel/heartbeat [post] func PostHeartbeat(c *gin.Context) { var payload HeartbeatPayload if !apiutil.BindJSON(c, &payload) { @@ -35,6 +47,16 @@ func PostHeartbeat(c *gin.Context) { } // GetActiveConfig handles GET /tunnel/config/active. +// @Summary 获取活跃隧道配置 +// @Description 返回 Tunnel 客户端当前应应用的完整路由配置(含中继列表与代理定义) +// @Tags openflare-tunnel +// @Produce json +// @Security TunnelTokenAuth +// @Success 200 {object} response.Any{data=flared.TunnelConfigResponse} "隧道配置" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Tunnel Token 无效" +// @Failure 403 {object} response.Any "节点类型不匹配" +// @Router /api/v1/tunnel/config/active [get] func GetActiveConfig(c *gin.Context) { authNode, ok := c.Get(ctxFlaredNodeKey) if !ok { @@ -51,6 +73,18 @@ func GetActiveConfig(c *gin.Context) { } // PostApplyLog handles POST /tunnel/apply-log. +// @Summary 上报 Tunnel 配置下发结果 +// @Description Tunnel 客户端上报配置应用结果,服务端记录下发日志 +// @Tags openflare-tunnel +// @Accept json +// @Produce json +// @Security TunnelTokenAuth +// @Param body body flared.ApplyLogPayload true "下发结果载荷" +// @Success 200 {object} response.Any{data=model.OpenFlareApplyLog} "下发日志记录" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Tunnel Token 无效" +// @Failure 403 {object} response.Any "节点类型不匹配" +// @Router /api/v1/tunnel/apply-log [post] func PostApplyLog(c *gin.Context) { var payload ApplyLogPayload if !apiutil.BindJSON(c, &payload) { @@ -68,6 +102,13 @@ func PostApplyLog(c *gin.Context) { } // GetWebSocket handles GET /tunnel/ws. +// @Summary 升级 Tunnel WebSocket 连接 +// @Description 将已认证的 Tunnel 客户端连接升级为 WebSocket 长连接,用于配置推送 +// @Tags openflare-tunnel +// @Security TunnelTokenAuth +// @Failure 401 {object} response.Any "Tunnel Token 无效" +// @Failure 403 {object} response.Any "节点类型不匹配" +// @Router /api/v1/tunnel/ws [get] func GetWebSocket(c *gin.Context) { authNode, ok := c.Get(ctxFlaredNodeKey) if !ok { diff --git a/Wavelet/internal/apps/openflare/observability/routers.go b/Wavelet/internal/apps/openflare/observability/routers.go index 500a209d..c3c06816 100644 --- a/Wavelet/internal/apps/openflare/observability/routers.go +++ b/Wavelet/internal/apps/openflare/observability/routers.go @@ -29,7 +29,7 @@ import ( // @Success 200 {object} response.Any{data=observability.AccessLogList} "访问日志列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/access-logs [get] func GetAccessLogsHandler(c *gin.Context) { @@ -58,7 +58,7 @@ func GetAccessLogsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=observability.FoldedAccessLogList} "折叠访问日志列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/access-logs/folds [get] func GetFoldedAccessLogsHandler(c *gin.Context) { @@ -90,7 +90,7 @@ func GetFoldedAccessLogsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=observability.FoldedAccessLogIPList} "折叠 IP 汇总列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/access-logs/folds/ip-summary [get] func GetFoldedAccessLogIPsHandler(c *gin.Context) { @@ -128,7 +128,7 @@ func GetFoldedAccessLogIPsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=observability.AccessLogIPSummaryList} "IP 汇总列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/access-logs/ip-summary [get] func GetAccessLogIPSummariesHandler(c *gin.Context) { @@ -161,7 +161,7 @@ func GetAccessLogIPSummariesHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=observability.AccessLogIPTrendView} "IP 访问趋势" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/access-logs/ip-summary/trend [get] func GetAccessLogIPTrendHandler(c *gin.Context) { @@ -189,7 +189,7 @@ func GetAccessLogIPTrendHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=observability.AccessLogCleanupResult} "清理结果" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/access-logs/cleanup [post] func CleanupAccessLogsHandler(c *gin.Context) { diff --git a/Wavelet/internal/apps/openflare/option/routers.go b/Wavelet/internal/apps/openflare/option/routers.go index d6052edb..a4a8c2b0 100644 --- a/Wavelet/internal/apps/openflare/option/routers.go +++ b/Wavelet/internal/apps/openflare/option/routers.go @@ -59,7 +59,7 @@ func GetNoticeHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=[]model.OpenFlareOption} "配置项列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/option [get] // ListOptionsHandler lists OpenFlare options. @@ -82,7 +82,7 @@ func ListOptionsHandler(c *gin.Context) { // @Success 200 {object} response.Any "更新成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/option/update [post] // UpdateOptionHandler updates a single option. @@ -108,7 +108,7 @@ func UpdateOptionHandler(c *gin.Context) { // @Success 200 {object} response.Any "更新成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/option/update-batch [post] // UpdateOptionsBatchHandler updates options in batch. @@ -134,7 +134,7 @@ func UpdateOptionsBatchHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=option.geoIPLookupView} "GeoIP 查询结果" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/option/geoip/lookup [post] // LookupGeoIPHandler performs a GeoIP lookup. @@ -161,7 +161,7 @@ func LookupGeoIPHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=option.databaseCleanupResult} "清理结果" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/option/database/cleanup [post] // CleanupDatabaseHandler cleans up observability data. @@ -188,7 +188,7 @@ func CleanupDatabaseHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=string} "同步成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/uptimekuma/sync [post] // SyncUptimeKumaHandler triggers UptimeKuma sync. diff --git a/Wavelet/internal/apps/openflare/pages/routers.go b/Wavelet/internal/apps/openflare/pages/routers.go index 11a68f59..07e83e89 100644 --- a/Wavelet/internal/apps/openflare/pages/routers.go +++ b/Wavelet/internal/apps/openflare/pages/routers.go @@ -43,7 +43,7 @@ func deploymentIDParam(c *gin.Context) (uint, bool) { // @Success 200 {object} response.Any{data=[]pages.View} "Pages 项目列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages [get] func ListProjectsHandler(c *gin.Context) { @@ -64,7 +64,7 @@ func ListProjectsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=pages.View} "Pages 项目详情" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "项目不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages/{id} [get] @@ -91,7 +91,7 @@ func GetProjectHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=pages.View} "创建成功的项目" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages [post] func CreateProjectHandler(c *gin.Context) { @@ -118,7 +118,7 @@ func CreateProjectHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=pages.View} "更新后的项目" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "项目不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages/{id}/update [post] @@ -148,7 +148,7 @@ func UpdateProjectHandler(c *gin.Context) { // @Success 200 {object} response.Any "删除成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "项目不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages/{id}/delete [post] @@ -173,7 +173,7 @@ func DeleteProjectHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=[]pages.DeploymentView} "部署列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "项目不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages/{id}/deployments [get] @@ -201,7 +201,7 @@ func ListDeploymentsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=pages.DeploymentView} "部署记录" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "项目不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages/{id}/deployments/upload [post] @@ -233,7 +233,7 @@ func UploadDeploymentHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=pages.View} "激活后的项目" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "项目或部署不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages/{id}/deployments/{deployment_id}/activate [post] @@ -264,7 +264,7 @@ func ActivateDeploymentHandler(c *gin.Context) { // @Success 200 {object} response.Any "删除成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "项目或部署不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages/{id}/deployments/{deployment_id}/delete [post] @@ -293,7 +293,7 @@ func DeleteDeploymentHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=[]pages.DeploymentFileView} "部署文件列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "部署不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/pages/deployments/{deployment_id}/files [get] diff --git a/Wavelet/internal/apps/openflare/relay/routers.go b/Wavelet/internal/apps/openflare/relay/routers.go index 9db05d68..4dc70c03 100644 --- a/Wavelet/internal/apps/openflare/relay/routers.go +++ b/Wavelet/internal/apps/openflare/relay/routers.go @@ -14,6 +14,18 @@ import ( ) // PostHeartbeat handles POST /relay/heartbeat. +// @Summary 上报 Relay 心跳 +// @Description Relay 节点定期上报运行状态与 frps 观测数据,返回运行时配置 +// @Tags openflare-relay +// @Accept json +// @Produce json +// @Security AgentTokenAuth +// @Param body body relay.HeartbeatPayload true "心跳载荷" +// @Success 200 {object} response.Any{data=relay.HeartbeatResponse} "心跳响应" +// @Failure 400 {object} response.Any "参数错误" +// @Failure 401 {object} response.Any "Agent Token 无效" +// @Failure 403 {object} response.Any "节点类型不匹配" +// @Router /api/v1/relay/heartbeat [post] func PostHeartbeat(c *gin.Context) { var payload HeartbeatPayload if !apiutil.BindJSON(c, &payload) { @@ -36,6 +48,13 @@ func PostHeartbeat(c *gin.Context) { } // GetWebSocket handles GET /relay/ws. +// @Summary 升级 Relay WebSocket 连接 +// @Description 将已认证的 Relay 连接升级为 WebSocket 长连接,用于配置推送 +// @Tags openflare-relay +// @Security AgentTokenAuth +// @Failure 401 {object} response.Any "Agent Token 无效" +// @Failure 403 {object} response.Any "节点类型不匹配" +// @Router /api/v1/relay/ws [get] func GetWebSocket(c *gin.Context) { authNode, ok := c.Get(ctxRelayNodeKey) if !ok { diff --git a/Wavelet/internal/apps/openflare/tls/routers.go b/Wavelet/internal/apps/openflare/tls/routers.go index 7b19e664..1095df59 100644 --- a/Wavelet/internal/apps/openflare/tls/routers.go +++ b/Wavelet/internal/apps/openflare/tls/routers.go @@ -29,7 +29,7 @@ func handleLogicError(c *gin.Context, err error) bool { // @Success 200 {object} response.Any{data=[]model.TLSCertificate} "证书列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates [get] func GetCertificates(c *gin.Context) { @@ -50,7 +50,7 @@ func GetCertificates(c *gin.Context) { // @Success 200 {object} response.Any{data=model.TLSCertificate} "证书详情" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/{id} [get] @@ -76,7 +76,7 @@ func GetCertificateDetail(c *gin.Context) { // @Success 200 {object} response.Any{data=tls.CertificateContent} "证书 PEM 内容" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/{id}/content [get] @@ -103,7 +103,7 @@ func GetCertificateContentHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.TLSCertificate} "创建成功的证书" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates [post] func CreateCertificateHandler(c *gin.Context) { @@ -130,7 +130,7 @@ func CreateCertificateHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.TLSCertificate} "更新后的证书" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/{id}/update [post] @@ -164,7 +164,7 @@ func UpdateCertificateHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.TLSCertificate} "导入成功的证书" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/import-file [post] func ImportCertificateFile(c *gin.Context) { @@ -197,7 +197,7 @@ func ImportCertificateFile(c *gin.Context) { // @Success 200 {object} response.Any "删除成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/{id}/delete [post] @@ -223,7 +223,7 @@ func DeleteCertificateHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.TLSCertificate} "申请中的证书" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/apply [post] func ApplyCertificateHandler(c *gin.Context) { @@ -250,7 +250,7 @@ func ApplyCertificateHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.TLSCertificate} "更新后的证书" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/{id}/update-acme [post] @@ -282,7 +282,7 @@ func UpdateACMECertificateHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.TLSCertificate} "转换后的证书" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/{id}/convert-acme [post] @@ -312,7 +312,7 @@ func ConvertCertificateToACMEHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.TLSCertificate} "续期后的证书" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/tls-certificates/{id}/renew [post] @@ -337,7 +337,7 @@ func RenewCertificateHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=[]model.ManagedDomain} "托管域名列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/managed-domains [get] func GetManagedDomains(c *gin.Context) { @@ -359,7 +359,7 @@ func GetManagedDomains(c *gin.Context) { // @Success 200 {object} response.Any{data=model.ManagedDomain} "创建成功的托管域名" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/managed-domains [post] func CreateManagedDomainHandler(c *gin.Context) { @@ -386,7 +386,7 @@ func CreateManagedDomainHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.ManagedDomain} "更新后的托管域名" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/managed-domains/{id}/update [post] @@ -416,7 +416,7 @@ func UpdateManagedDomainHandler(c *gin.Context) { // @Success 200 {object} response.Any "删除成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/managed-domains/{id}/delete [post] @@ -441,7 +441,7 @@ func DeleteManagedDomainHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=tls.ManagedDomainMatchResult} "证书匹配结果" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/managed-domains/match [get] func MatchManagedDomainCertificateHandler(c *gin.Context) { @@ -462,7 +462,7 @@ func MatchManagedDomainCertificateHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=[]model.DNSAccount} "DNS 账号列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/dns-accounts [get] func GetDNSAccounts(c *gin.Context) { @@ -484,7 +484,7 @@ func GetDNSAccounts(c *gin.Context) { // @Success 200 {object} response.Any{data=model.DNSAccount} "创建成功的 DNS 账号" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/dns-accounts [post] func CreateDNSAccountHandler(c *gin.Context) { @@ -511,7 +511,7 @@ func CreateDNSAccountHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.DNSAccount} "更新后的 DNS 账号" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/dns-accounts/{id}/update [post] @@ -541,7 +541,7 @@ func UpdateDNSAccountHandler(c *gin.Context) { // @Success 200 {object} response.Any "删除成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/dns-accounts/{id}/delete [post] @@ -565,7 +565,7 @@ func DeleteDNSAccountHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=model.AcmeAccount} "默认 ACME 账号" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/acme-accounts/default [get] diff --git a/Wavelet/internal/apps/openflare/waf/routers.go b/Wavelet/internal/apps/openflare/waf/routers.go index 738c117a..ab121de0 100644 --- a/Wavelet/internal/apps/openflare/waf/routers.go +++ b/Wavelet/internal/apps/openflare/waf/routers.go @@ -43,7 +43,7 @@ func routeIDParam(c *gin.Context) (uint, bool) { // @Success 200 {object} response.Any{data=[]waf.RuleGroupView} "规则组列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/rule-groups [get] func ListRuleGroupsHandler(c *gin.Context) { @@ -64,7 +64,7 @@ func ListRuleGroupsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.RuleGroupView} "规则组详情" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/rule-groups/{id} [get] @@ -91,7 +91,7 @@ func GetRuleGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.RuleGroupView} "创建成功的规则组" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/rule-groups [post] func CreateRuleGroupHandler(c *gin.Context) { @@ -118,7 +118,7 @@ func CreateRuleGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.RuleGroupView} "更新后的规则组" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/rule-groups/{id}/update [post] @@ -148,7 +148,7 @@ func UpdateRuleGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any "删除成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/rule-groups/{id}/delete [post] @@ -175,7 +175,7 @@ func DeleteRuleGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.RuleGroupView} "更新后的规则组" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/rule-groups/{id}/sites [post] @@ -205,7 +205,7 @@ func ReplaceRuleGroupSitesHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.SiteRuleGroupsView} "站点规则组绑定" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/sites/{route_id}/rule-groups [get] @@ -233,7 +233,7 @@ func GetSiteRuleGroupsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.SiteRuleGroupsView} "更新后的站点规则组绑定" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/sites/{route_id}/rule-groups [post] @@ -262,7 +262,7 @@ func ReplaceSiteRuleGroupsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=[]waf.IPGroupView} "IP 组列表" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/ip-groups [get] func ListIPGroupsHandler(c *gin.Context) { @@ -283,7 +283,7 @@ func ListIPGroupsHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.IPGroupView} "IP 组详情" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/ip-groups/{id} [get] @@ -310,7 +310,7 @@ func GetIPGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.IPGroupView} "创建成功的 IP 组" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/ip-groups [post] func CreateIPGroupHandler(c *gin.Context) { @@ -337,7 +337,7 @@ func CreateIPGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.IPGroupView} "更新后的 IP 组" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/ip-groups/{id}/update [post] @@ -367,7 +367,7 @@ func UpdateIPGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any "删除成功" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/ip-groups/{id}/delete [post] @@ -392,7 +392,7 @@ func DeleteIPGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.IPGroupSyncResult} "同步结果" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 404 {object} response.Any "记录不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/ip-groups/{id}/sync [post] @@ -419,7 +419,7 @@ func SyncIPGroupHandler(c *gin.Context) { // @Success 200 {object} response.Any{data=waf.IPGroupAutoTestResult} "测试结果" // @Failure 400 {object} response.Any "参数错误" // @Failure 401 {object} response.Any "未登录" -// @Failure 403 {object} response.Any "无管理员权限" +// @Failure 404 {object} response.Any "无权限或不存在" // @Failure 500 {object} response.Any "内部错误" // @Router /api/v1/d/waf/ip-groups/test [post] func TestIPGroupAutoConfigHandler(c *gin.Context) { diff --git a/Wavelet/main.go b/Wavelet/main.go index deddacd5..e71674f2 100644 --- a/Wavelet/main.go +++ b/Wavelet/main.go @@ -17,6 +17,12 @@ import "github.com/Rain-kl/Wavelet/internal/cmd" // @securityDefinitions.apikey SessionCookie // @in cookie // @name session +// @securityDefinitions.apikey AgentTokenAuth +// @in header +// @name X-Agent-Token +// @securityDefinitions.apikey TunnelTokenAuth +// @in header +// @name X-Tunnel-Token func main() { cmd.Execute() } diff --git a/docs/changelog/index.md b/docs/changelog/index.md index a2fbaafc..3eb2f295 100644 --- a/docs/changelog/index.md +++ b/docs/changelog/index.md @@ -72,6 +72,7 @@ sidebar: false ### 变更 +- 补齐 OpenFlare Swagger 文档:新增 Agent/Relay/Tunnel 协议端点(13 个 `/api/v1/agent|relay|tunnel/*`)注解与安全定义(`AgentTokenAuth`、`TunnelTokenAuth`);管理端注解将权限不足响应由 403 统一为 404。 - Wavelet API 路径统一:管理端由 `/api/v1/openflare/*` 调整为 `/api/v1/d/*`;Agent/Relay/Tunnel 协议路由分别迁移至 `/api/v1/agent/*`、`/api/v1/relay/*`、`/api/v1/tunnel/*`(原 `/api/flared/*`)。同步更新 Wavelet 前端服务层与 `openflare-agent`、`openflare-relay`、`openflared` 客户端连接端点。 - Agent/Relay/Tunnel 协议 API 响应格式对齐 Wavelet `{error_msg, data}`:服务端移除 `compat` 包,业务错误改为 HTTP 4xx + `error_msg`;同步更新 `openflare-agent`、`openflare-relay`、`openflared` HTTP 客户端解析逻辑。 - OpenFlare 管理端权限模型对齐 Wavelet:取消旧系统 Admin/Root 三级角色区分,统一以 `user.IsAdmin` 为管理门槛;Access Token 访问敏感接口(Option、Update 等)须 `token_admin=true`;权限不足返回 HTTP 404 + `error_msg`,参数错误返回 HTTP 400 + `error_msg`(`apiutil.AdminMiddlewares` = `oauth.LoginRequired` + `admin.LoginAdminRequired`)。