// Package apierr defines the bilingual error response type used across all API modules. // Error messages follow the desensitisation rules: no "VPN" / "翻墙" / "科学上网" wording. package apierr import ( "encoding/json" "net/http" ) // Error is the canonical API error body: {code, message_zh, message_en}. type Error struct { Code string `json:"code"` MessageZH string `json:"message_zh"` MessageEn string `json:"message_en"` } func (e *Error) Error() string { return e.Code + ": " + e.MessageEn } // Standard code-module errors. var ( ErrInvalidCode = &Error{ Code: "INVALID_CODE", MessageZH: "激活码格式无效,请检查后重试", MessageEn: "Invalid code format, please verify and try again", } ErrCodeNotFound = &Error{ Code: "CODE_NOT_FOUND", MessageZH: "激活码无效或已使用", MessageEn: "Code not found or already used", } ErrCodeRedeemed = &Error{ Code: "CODE_REDEEMED", MessageZH: "该激活码已被其他账户使用", MessageEn: "This code has already been redeemed by another account", } ErrCodeVoid = &Error{ Code: "CODE_VOID", MessageZH: "该激活码已失效", MessageEn: "This code is no longer valid", } ErrRateLimited = &Error{ Code: "RATE_LIMITED", MessageZH: "操作过于频繁,请稍后再试", MessageEn: "Too many attempts, please try again later", } ErrLocked = &Error{ Code: "ACCOUNT_LOCKED", MessageZH: "账户已临时锁定,请1小时后重试", MessageEn: "Account temporarily locked, please retry in 1 hour", } ErrInternal = &Error{ Code: "INTERNAL_ERROR", MessageZH: "服务器内部错误,请稍后重试", MessageEn: "Internal server error, please try again later", } ErrBadRequest = &Error{ Code: "BAD_REQUEST", MessageZH: "请求参数有误", MessageEn: "Invalid request parameters", } // Webhook-specific errors. ErrWebhookSignature = &Error{ Code: "WEBHOOK_INVALID_SIGNATURE", MessageZH: "签名校验失败", MessageEn: "Invalid webhook signature", } ErrWebhookTimestamp = &Error{ Code: "WEBHOOK_TIMESTAMP_EXPIRED", MessageZH: "请求时间戳超出允许窗口", MessageEn: "Webhook timestamp outside allowed window", } ErrWebhookReplay = &Error{ Code: "WEBHOOK_REPLAY", MessageZH: "重复请求已忽略", MessageEn: "Duplicate webhook request ignored", } ) // WriteJSON writes the given status code and error body as JSON. func WriteJSON(w http.ResponseWriter, status int, e *Error) { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(e) }