File size: 5,838 Bytes
9853396 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 | package api
import (
"encoding/base64"
"errors"
"fmt"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
"go.uber.org/fx"
"github.com/looplj/axonhub/internal/build"
"github.com/looplj/axonhub/internal/log"
"github.com/looplj/axonhub/internal/server/assets"
"github.com/looplj/axonhub/internal/server/biz"
)
type SystemHandlersParams struct {
fx.In
SystemService *biz.SystemService
}
func NewSystemHandlers(params SystemHandlersParams) *SystemHandlers {
return &SystemHandlers{
SystemService: params.SystemService,
}
}
type SystemHandlers struct {
SystemService *biz.SystemService
}
// SystemStatusResponse 系统状态响应.
type SystemStatusResponse struct {
IsInitialized bool `json:"isInitialized"`
}
// HealthResponse 健康检查响应.
type HealthResponse struct {
Status string `json:"status"`
Timestamp time.Time `json:"timestamp"`
Version string `json:"version"`
Build build.Info `json:"build"`
Uptime string `json:"uptime"`
}
// InitializeSystemRequest 系统初始化请求.
type InitializeSystemRequest struct {
OwnerEmail string `json:"ownerEmail" binding:"required,email"`
OwnerPassword string `json:"ownerPassword" binding:"required,min=6"`
OwnerFirstName string `json:"ownerFirstName" binding:"required"`
OwnerLastName string `json:"ownerLastName" binding:"required"`
BrandName string `json:"brandName" binding:"required"`
}
// InitializeSystemResponse 系统初始化响应.
type InitializeSystemResponse struct {
Success bool `json:"success"`
Message string `json:"message"`
}
// GetSystemStatus returns the system initialization status.
func (h *SystemHandlers) GetSystemStatus(c *gin.Context) {
isInitialized, err := h.SystemService.IsInitialized(c.Request.Context())
if err != nil {
JSONError(c, http.StatusInternalServerError, errors.New("Failed to check system status"))
return
}
c.JSON(http.StatusOK, SystemStatusResponse{
IsInitialized: isInitialized,
})
}
// Health returns the application health status and build information.
func (h *SystemHandlers) Health(c *gin.Context) {
buildInfo := build.GetBuildInfo()
c.JSON(http.StatusOK, HealthResponse{
Status: "healthy",
Timestamp: time.Now(),
Version: build.Version,
Build: buildInfo,
Uptime: buildInfo.Uptime,
})
}
// InitializeSystem initializes the system with owner credentials.
func (h *SystemHandlers) InitializeSystem(c *gin.Context) {
var req InitializeSystemRequest
err := c.ShouldBindJSON(&req)
if err != nil {
c.JSON(http.StatusBadRequest, InitializeSystemResponse{
Success: false,
Message: "Invalid request format",
})
return
}
// Check if system is already initialized
isInitialized, err := h.SystemService.IsInitialized(c.Request.Context())
if err != nil {
JSONError(c, http.StatusInternalServerError, errors.New("Failed to check initialization status"))
return
}
if isInitialized {
c.JSON(http.StatusBadRequest, InitializeSystemResponse{
Success: false,
Message: "System is already initialized",
})
return
}
// Initialize system
err = h.SystemService.Initialize(c.Request.Context(), &biz.InitializeSystemParams{
OwnerEmail: req.OwnerEmail,
OwnerPassword: req.OwnerPassword,
OwnerFirstName: req.OwnerFirstName,
OwnerLastName: req.OwnerLastName,
BrandName: req.BrandName,
})
if err != nil {
c.JSON(http.StatusInternalServerError, InitializeSystemResponse{
Success: false,
Message: fmt.Sprintf("Failed to initialize system: %v", err),
})
return
}
c.JSON(http.StatusOK, InitializeSystemResponse{
Success: true,
Message: "System initialized successfully",
})
}
// GetFavicon returns the system brand logo as favicon.
func (h *SystemHandlers) GetFavicon(c *gin.Context) {
ctx := c.Request.Context()
brandLogo, err := h.SystemService.BrandLogo(ctx)
if err != nil {
log.Error(ctx, "Failed to get brand logo", log.Cause(err))
}
// 如果没有设置品牌标识,返回默认 favicon
if brandLogo == "" {
defaultFaviconData, err := assets.Favicon.ReadFile("favicon.ico")
if err != nil {
JSONError(c, http.StatusInternalServerError, errors.New("Failed to read default favicon"))
return
}
c.Header("Content-Type", "image/x-icon")
c.Header("Cache-Control", "public, max-age=3600")
c.Data(http.StatusOK, "image/x-icon", defaultFaviconData)
return
}
// 解析 base64 编码的图片数据
// 假设格式为 "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
if !strings.HasPrefix(brandLogo, "data:") {
JSONError(c, http.StatusBadRequest, errors.New("Invalid brand logo format"))
return
}
// 提取 MIME 类型和 base64 数据
parts := strings.Split(brandLogo, ",")
if len(parts) != 2 {
JSONError(c, http.StatusBadRequest, errors.New("Invalid brand logo format"))
return
}
// 提取 MIME 类型
headerPart := parts[0] // "data:image/png;base64"
mimeStart := strings.Index(headerPart, ":")
mimeEnd := strings.Index(headerPart, ";")
if mimeStart == -1 || mimeEnd == -1 {
JSONError(c, http.StatusBadRequest, errors.New("Invalid brand logo format"))
return
}
mimeType := headerPart[mimeStart+1 : mimeEnd]
// 解码 base64 数据
imageData, err := base64.StdEncoding.DecodeString(parts[1])
if err != nil {
JSONError(c, http.StatusBadRequest, errors.New("Failed to decode brand logo"))
return
}
// 设置响应头
c.Header("Content-Type", mimeType)
c.Header("Cache-Control", "public, max-age=3600") // 缓存 1 小时
c.Header("Content-Length", fmt.Sprintf("%d", len(imageData)))
// 返回图片数据
c.Data(http.StatusOK, mimeType, imageData)
}
|