- 新增多个源文件和目录,包括 app.rc、assets、build 脚本等 - 实现了与 MirrorChyan API 交互的客户端逻辑 - 添加了版本检查、更新检测和下载 URL 生成等功能 - 嵌入了配置模板和资源文件系统 - 提供了完整的构建和发布流程
219 lines
5.0 KiB
Go
219 lines
5.0 KiB
Go
package errors
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
)
|
|
|
|
// ErrorType 定义错误类型枚举
|
|
type ErrorType int
|
|
|
|
const (
|
|
NetworkError ErrorType = iota
|
|
APIError
|
|
FileError
|
|
ConfigError
|
|
InstallError
|
|
)
|
|
|
|
// String 返回错误类型的字符串表示
|
|
func (et ErrorType) String() string {
|
|
switch et {
|
|
case NetworkError:
|
|
return "NetworkError"
|
|
case APIError:
|
|
return "APIError"
|
|
case FileError:
|
|
return "FileError"
|
|
case ConfigError:
|
|
return "ConfigError"
|
|
case InstallError:
|
|
return "InstallError"
|
|
default:
|
|
return "UnknownError"
|
|
}
|
|
}
|
|
|
|
// UpdaterError 统一的错误结构体
|
|
type UpdaterError struct {
|
|
Type ErrorType
|
|
Message string
|
|
Cause error
|
|
Timestamp time.Time
|
|
Context map[string]interface{}
|
|
}
|
|
|
|
// Error 实现error接口
|
|
func (ue *UpdaterError) Error() string {
|
|
if ue.Cause != nil {
|
|
return fmt.Sprintf("[%s] %s: %v", ue.Type, ue.Message, ue.Cause)
|
|
}
|
|
return fmt.Sprintf("[%s] %s", ue.Type, ue.Message)
|
|
}
|
|
|
|
// Unwrap 支持错误链
|
|
func (ue *UpdaterError) Unwrap() error {
|
|
return ue.Cause
|
|
}
|
|
|
|
// NewUpdaterError 创建新的UpdaterError
|
|
func NewUpdaterError(errorType ErrorType, message string, cause error) *UpdaterError {
|
|
return &UpdaterError{
|
|
Type: errorType,
|
|
Message: message,
|
|
Cause: cause,
|
|
Timestamp: time.Now(),
|
|
Context: make(map[string]interface{}),
|
|
}
|
|
}
|
|
|
|
// WithContext 添加上下文信息
|
|
func (ue *UpdaterError) WithContext(key string, value interface{}) *UpdaterError {
|
|
ue.Context[key] = value
|
|
return ue
|
|
}
|
|
|
|
// GetUserFriendlyMessage 获取用户友好的错误消息
|
|
func (ue *UpdaterError) GetUserFriendlyMessage() string {
|
|
switch ue.Type {
|
|
case NetworkError:
|
|
return "网络连接失败,请检查网络连接后重试"
|
|
case APIError:
|
|
return "服务器响应异常,请稍后重试或联系技术支持"
|
|
case FileError:
|
|
return "文件操作失败,请检查文件权限和磁盘空间"
|
|
case ConfigError:
|
|
return "配置文件错误,程序将使用默认配置"
|
|
case InstallError:
|
|
return "安装过程中出现错误,程序将尝试回滚更改"
|
|
default:
|
|
return "发生未知错误,请联系技术支持"
|
|
}
|
|
}
|
|
|
|
// RetryConfig 重试配置
|
|
type RetryConfig struct {
|
|
MaxRetries int
|
|
InitialDelay time.Duration
|
|
MaxDelay time.Duration
|
|
BackoffFactor float64
|
|
RetryableErrors []ErrorType
|
|
}
|
|
|
|
// DefaultRetryConfig 默认重试配置
|
|
func DefaultRetryConfig() *RetryConfig {
|
|
return &RetryConfig{
|
|
MaxRetries: 3,
|
|
InitialDelay: time.Second,
|
|
MaxDelay: 30 * time.Second,
|
|
BackoffFactor: 2.0,
|
|
RetryableErrors: []ErrorType{NetworkError, APIError},
|
|
}
|
|
}
|
|
|
|
// IsRetryable 检查错误是否可重试
|
|
func (rc *RetryConfig) IsRetryable(err error) bool {
|
|
if ue, ok := err.(*UpdaterError); ok {
|
|
for _, retryableType := range rc.RetryableErrors {
|
|
if ue.Type == retryableType {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// CalculateDelay 计算重试延迟时间
|
|
func (rc *RetryConfig) CalculateDelay(attempt int) time.Duration {
|
|
delay := time.Duration(float64(rc.InitialDelay) * pow(rc.BackoffFactor, float64(attempt)))
|
|
if delay > rc.MaxDelay {
|
|
delay = rc.MaxDelay
|
|
}
|
|
return delay
|
|
}
|
|
|
|
// pow 简单的幂运算实现
|
|
func pow(base, exp float64) float64 {
|
|
result := 1.0
|
|
for i := 0; i < int(exp); i++ {
|
|
result *= base
|
|
}
|
|
return result
|
|
}
|
|
|
|
// RetryableOperation 可重试的操作函数类型
|
|
type RetryableOperation func() error
|
|
|
|
// ExecuteWithRetry 执行带重试的操作
|
|
func ExecuteWithRetry(operation RetryableOperation, config *RetryConfig) error {
|
|
var lastErr error
|
|
|
|
for attempt := 0; attempt <= config.MaxRetries; attempt++ {
|
|
err := operation()
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
lastErr = err
|
|
|
|
// 如果不是可重试的错误,直接返回
|
|
if !config.IsRetryable(err) {
|
|
return err
|
|
}
|
|
|
|
// 如果已经是最后一次尝试,不再等待
|
|
if attempt == config.MaxRetries {
|
|
break
|
|
}
|
|
|
|
// 计算延迟时间并等待
|
|
delay := config.CalculateDelay(attempt)
|
|
time.Sleep(delay)
|
|
}
|
|
|
|
return lastErr
|
|
}
|
|
|
|
// ErrorHandler 错误处理器接口
|
|
type ErrorHandler interface {
|
|
HandleError(err error) error
|
|
ShouldRetry(err error) bool
|
|
GetUserMessage(err error) string
|
|
}
|
|
|
|
// DefaultErrorHandler 默认错误处理器
|
|
type DefaultErrorHandler struct {
|
|
retryConfig *RetryConfig
|
|
}
|
|
|
|
// NewDefaultErrorHandler 创建默认错误处理器
|
|
func NewDefaultErrorHandler() *DefaultErrorHandler {
|
|
return &DefaultErrorHandler{
|
|
retryConfig: DefaultRetryConfig(),
|
|
}
|
|
}
|
|
|
|
// HandleError 处理错误
|
|
func (h *DefaultErrorHandler) HandleError(err error) error {
|
|
if ue, ok := err.(*UpdaterError); ok {
|
|
// 记录错误上下文
|
|
ue.WithContext("handled_at", time.Now())
|
|
return ue
|
|
}
|
|
|
|
// 将普通错误包装为UpdaterError
|
|
return NewUpdaterError(NetworkError, "未分类错误", err)
|
|
}
|
|
|
|
// ShouldRetry 判断是否应该重试
|
|
func (h *DefaultErrorHandler) ShouldRetry(err error) bool {
|
|
return h.retryConfig.IsRetryable(err)
|
|
}
|
|
|
|
// GetUserMessage 获取用户友好的错误消息
|
|
func (h *DefaultErrorHandler) GetUserMessage(err error) string {
|
|
if ue, ok := err.(*UpdaterError); ok {
|
|
return ue.GetUserFriendlyMessage()
|
|
}
|
|
return "发生未知错误,请联系技术支持"
|
|
} |