diff --git a/docs/docs.go b/docs/docs.go index ca07dda..5921b2f 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -1069,6 +1069,49 @@ const docTemplate = `{ } } } + }, + "/api/health": { + "get": { + "security": [ + { + "APITokenAuth": [] + } + ], + "description": "检查服务运行状态,需要有效的 API Token 或管理员 JWT 进行鉴权。", + "produces": [ + "application/json" + ], + "tags": [ + "Public" + ], + "summary": "健康检查", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/model.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/public.HealthResponse" + } + } + } + ] + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } } }, "definitions": { @@ -1584,6 +1627,27 @@ const docTemplate = `{ } } }, + "public.HealthResponse": { + "type": "object", + "properties": { + "database": { + "type": "string", + "example": "ok" + }, + "go_version": { + "type": "string", + "example": "go1.21.0" + }, + "status": { + "type": "string", + "example": "ok" + }, + "uptime": { + "type": "string", + "example": "2h30m15s" + } + } + }, "public.PickupResponse": { "type": "object", "properties": { diff --git a/docs/swagger.json b/docs/swagger.json index bf837ef..ea4ea31 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -1062,6 +1062,49 @@ } } } + }, + "/api/health": { + "get": { + "security": [ + { + "APITokenAuth": [] + } + ], + "description": "检查服务运行状态,需要有效的 API Token 或管理员 JWT 进行鉴权。", + "produces": [ + "application/json" + ], + "tags": [ + "Public" + ], + "summary": "健康检查", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/model.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/public.HealthResponse" + } + } + } + ] + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/model.Response" + } + } + } + } } }, "definitions": { @@ -1577,6 +1620,27 @@ } } }, + "public.HealthResponse": { + "type": "object", + "properties": { + "database": { + "type": "string", + "example": "ok" + }, + "go_version": { + "type": "string", + "example": "go1.21.0" + }, + "status": { + "type": "string", + "example": "ok" + }, + "uptime": { + "type": "string", + "example": "2h30m15s" + } + } + }, "public.PickupResponse": { "type": "object", "properties": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 0065702..f0e09b6 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -340,6 +340,21 @@ definitions: max_downloads: type: integer type: object + public.HealthResponse: + properties: + database: + example: ok + type: string + go_version: + example: go1.21.0 + type: string + status: + example: ok + type: string + uptime: + example: 2h30m15s + type: string + type: object public.PickupResponse: properties: content: @@ -1060,6 +1075,30 @@ paths: summary: 下载单个文件 tags: - Public + /api/health: + get: + description: 检查服务运行状态,需要有效的 API Token 或管理员 JWT 进行鉴权。 + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/model.Response' + - properties: + data: + $ref: '#/definitions/public.HealthResponse' + type: object + "401": + description: Unauthorized + schema: + $ref: '#/definitions/model.Response' + security: + - APITokenAuth: [] + summary: 健康检查 + tags: + - Public securityDefinitions: APITokenAuth: description: Type "Bearer " to authenticate. Required scope depends diff --git a/internal/api/public/health.go b/internal/api/public/health.go new file mode 100644 index 0000000..2053155 --- /dev/null +++ b/internal/api/public/health.go @@ -0,0 +1,55 @@ +package public + +import ( + "FileRelay/internal/bootstrap" + "FileRelay/internal/model" + "net/http" + "runtime" + "time" + + "github.com/gin-gonic/gin" +) + +var startTime = time.Now() + +type HealthHandler struct{} + +func NewHealthHandler() *HealthHandler { + return &HealthHandler{} +} + +type HealthResponse struct { + Status string `json:"status" example:"ok"` + Uptime string `json:"uptime" example:"2h30m15s"` + Database string `json:"database" example:"ok"` + GoVer string `json:"go_version" example:"go1.21.0"` +} + +// Health 健康检查 +// @Summary 健康检查 +// @Description 检查服务运行状态,需要有效的 API Token 或管理员 JWT 进行鉴权。 +// @Tags Public +// @Produce json +// @Security APITokenAuth +// @Success 200 {object} model.Response{data=HealthResponse} +// @Failure 401 {object} model.Response +// @Router /api/health [get] +func (h *HealthHandler) Health(c *gin.Context) { + dbStatus := "ok" + sqlDB, err := bootstrap.DB.DB() + if err != nil || sqlDB.Ping() != nil { + dbStatus = "unavailable" + } + + status := "ok" + if dbStatus != "ok" { + status = "degraded" + } + + c.JSON(http.StatusOK, model.SuccessResponse(HealthResponse{ + Status: status, + Uptime: time.Since(startTime).Round(time.Second).String(), + Database: dbStatus, + GoVer: runtime.Version(), + })) +} diff --git a/main.go b/main.go index c2bf514..3739d7b 100644 --- a/main.go +++ b/main.go @@ -141,9 +141,12 @@ func main() { pickupHandler := public.NewPickupHandler() publicConfigHandler := public.NewConfigHandler() + healthHandler := public.NewHealthHandler() + api := r.Group("/api") { api.GET("/config", publicConfigHandler.GetPublicConfig) + api.GET("/health", middleware.APITokenAuth("", false), healthHandler.Health) // 统一使用 /batches 作为资源路径 api.POST("/batches", middleware.UploadAuth(), uploadHandler.Upload) api.POST("/batches/text", middleware.UploadAuth(), uploadHandler.UploadText)