package httpapi import ( "errors" "net/http" "strings" "time" "data-terminal-cloud/internal/concurrency" "data-terminal-cloud/internal/hardwarelicense" ) func ListOpsHardwareLicensesHandler(service *hardwarelicense.Service) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { principal, tenantID, ok := opsDevicePrincipal(w, r) if !ok { return } items, err := service.List(r.Context(), principal, tenantID) if err != nil { writeHardwareLicenseError(w, r, err) return } w.Header().Set("Cache-Control", "no-store") WriteJSON(w, r, http.StatusOK, map[string]any{"items": items}) }) } func ImportOpsHardwareLicenseHandler(service *hardwarelicense.Service) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { principal, tenantID, ok := opsDevicePrincipal(w, r) if !ok { return } var body struct { LicenseRef string `json:"license_ref"` License string `json:"license"` InstanceID string `json:"instance_id"` ProductKey string `json:"product_key"` ExpiresAt time.Time `json:"expires_at"` } if !decodeWebJSON(w, r, &body, "License导入参数不正确") { return } item, err := service.Import(r.Context(), principal, tenantID, RequestID(r.Context()), hardwarelicense.ImportInput{LicenseRef: body.LicenseRef, Payload: body.License, InstanceID: body.InstanceID, ProductKey: body.ProductKey, ExpiresAt: body.ExpiresAt}) if err != nil { writeHardwareLicenseError(w, r, err) return } w.Header().Set("Cache-Control", "no-store") w.Header().Set("ETag", concurrency.FormatETag(item.Version)) WriteJSON(w, r, http.StatusCreated, item) }) } func TransitionOpsHardwareLicenseHandler(service *hardwarelicense.Service, action string) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { principal, tenantID, ok := opsDevicePrincipal(w, r) if !ok { return } if !validUUID(r.PathValue("id")) { writeValidation(w, r, "License编号不正确", FieldError{Field: "id", Message: "必须是UUID"}) return } expected, err := concurrency.ParseIfMatch(r) if err != nil { writeETagError(w, r, err) return } var item hardwarelicense.Item if action == "release" { item, err = service.Release(r.Context(), principal, tenantID, r.PathValue("id"), RequestID(r.Context()), expected) } else { item, err = service.Revoke(r.Context(), principal, tenantID, r.PathValue("id"), RequestID(r.Context()), expected) } if err != nil { writeHardwareLicenseError(w, r, err) return } w.Header().Set("Cache-Control", "no-store") w.Header().Set("ETag", concurrency.FormatETag(item.Version)) WriteJSON(w, r, http.StatusOK, item) }) } func writeHardwareLicenseError(w http.ResponseWriter, r *http.Request, err error) { switch { case errors.Is(err, hardwarelicense.ErrInvalid): writeValidation(w, r, "License参数不正确", FieldError{Field: "license", Message: "引用、密文、产品或到期时间不正确"}) case errors.Is(err, hardwarelicense.ErrAccessDenied): WriteError(w, r, http.StatusForbidden, "OPS_ACCESS_DENIED", "仅独立运维账号可以管理License") case errors.Is(err, hardwarelicense.ErrNotFound): WriteError(w, r, http.StatusNotFound, "RESOURCE_NOT_FOUND", "License不存在") case errors.Is(err, hardwarelicense.ErrVersionConflict): WriteError(w, r, http.StatusPreconditionFailed, "VERSION_CONFLICT", "License信息已变化,请刷新后重试") case errors.Is(err, hardwarelicense.ErrAssignment): WriteError(w, r, http.StatusConflict, "HARDWARE_LICENSE_STATE_CONFLICT", "License当前状态不允许执行该操作") default: if strings.Contains(strings.ToLower(err.Error()), "duplicate") { WriteError(w, r, http.StatusConflict, "HARDWARE_LICENSE_ALREADY_EXISTS", "License引用已经存在") return } WriteError(w, r, http.StatusInternalServerError, "INTERNAL_ERROR", "License管理操作失败") } }