mirror of
https://github.com/bestnite/sub2clash.git
synced 2025-06-17 20:53:18 +08:00
Refactor error handling
This commit is contained in:
192
common/errors.go
Normal file
192
common/errors.go
Normal file
@ -0,0 +1,192 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// CommonError represents a structured error type for the common package
|
||||
type CommonError struct {
|
||||
Code ErrorCode
|
||||
Message string
|
||||
Cause error
|
||||
}
|
||||
|
||||
// ErrorCode represents different types of errors
|
||||
type ErrorCode string
|
||||
|
||||
const (
|
||||
// Directory operation errors
|
||||
ErrDirCreation ErrorCode = "DIRECTORY_CREATION_FAILED"
|
||||
ErrDirAccess ErrorCode = "DIRECTORY_ACCESS_FAILED"
|
||||
|
||||
// File operation errors
|
||||
ErrFileNotFound ErrorCode = "FILE_NOT_FOUND"
|
||||
ErrFileRead ErrorCode = "FILE_READ_FAILED"
|
||||
ErrFileWrite ErrorCode = "FILE_WRITE_FAILED"
|
||||
ErrFileCreate ErrorCode = "FILE_CREATE_FAILED"
|
||||
|
||||
// Network operation errors
|
||||
ErrNetworkRequest ErrorCode = "NETWORK_REQUEST_FAILED"
|
||||
ErrNetworkResponse ErrorCode = "NETWORK_RESPONSE_FAILED"
|
||||
|
||||
// Template and configuration errors
|
||||
ErrTemplateLoad ErrorCode = "TEMPLATE_LOAD_FAILED"
|
||||
ErrTemplateParse ErrorCode = "TEMPLATE_PARSE_FAILED"
|
||||
ErrConfigInvalid ErrorCode = "CONFIG_INVALID"
|
||||
|
||||
// Subscription errors
|
||||
ErrSubscriptionLoad ErrorCode = "SUBSCRIPTION_LOAD_FAILED"
|
||||
ErrSubscriptionParse ErrorCode = "SUBSCRIPTION_PARSE_FAILED"
|
||||
|
||||
// Regex errors
|
||||
ErrRegexCompile ErrorCode = "REGEX_COMPILE_FAILED"
|
||||
ErrRegexInvalid ErrorCode = "REGEX_INVALID"
|
||||
|
||||
// Database errors
|
||||
ErrDatabaseConnect ErrorCode = "DATABASE_CONNECTION_FAILED"
|
||||
ErrDatabaseQuery ErrorCode = "DATABASE_QUERY_FAILED"
|
||||
ErrRecordNotFound ErrorCode = "RECORD_NOT_FOUND"
|
||||
|
||||
// Validation errors
|
||||
ErrValidation ErrorCode = "VALIDATION_FAILED"
|
||||
ErrInvalidInput ErrorCode = "INVALID_INPUT"
|
||||
)
|
||||
|
||||
// Error returns the string representation of the error
|
||||
func (e *CommonError) Error() string {
|
||||
if e.Cause != nil {
|
||||
return fmt.Sprintf("[%s] %s: %v", e.Code, e.Message, e.Cause)
|
||||
}
|
||||
return fmt.Sprintf("[%s] %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
// Unwrap returns the underlying error
|
||||
func (e *CommonError) Unwrap() error {
|
||||
return e.Cause
|
||||
}
|
||||
|
||||
// Is allows error comparison
|
||||
func (e *CommonError) Is(target error) bool {
|
||||
if t, ok := target.(*CommonError); ok {
|
||||
return e.Code == t.Code
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// NewError creates a new CommonError
|
||||
func NewError(code ErrorCode, message string, cause error) *CommonError {
|
||||
return &CommonError{
|
||||
Code: code,
|
||||
Message: message,
|
||||
Cause: cause,
|
||||
}
|
||||
}
|
||||
|
||||
// NewSimpleError creates a new CommonError without a cause
|
||||
func NewSimpleError(code ErrorCode, message string) *CommonError {
|
||||
return &CommonError{
|
||||
Code: code,
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience constructors for common error types
|
||||
|
||||
// Directory errors
|
||||
func NewDirCreationError(dirPath string, cause error) *CommonError {
|
||||
return NewError(ErrDirCreation, fmt.Sprintf("failed to create directory: %s", dirPath), cause)
|
||||
}
|
||||
|
||||
func NewDirAccessError(dirPath string, cause error) *CommonError {
|
||||
return NewError(ErrDirAccess, fmt.Sprintf("failed to access directory: %s", dirPath), cause)
|
||||
}
|
||||
|
||||
// File errors
|
||||
func NewFileNotFoundError(filePath string) *CommonError {
|
||||
return NewSimpleError(ErrFileNotFound, fmt.Sprintf("file not found: %s", filePath))
|
||||
}
|
||||
|
||||
func NewFileReadError(filePath string, cause error) *CommonError {
|
||||
return NewError(ErrFileRead, fmt.Sprintf("failed to read file: %s", filePath), cause)
|
||||
}
|
||||
|
||||
func NewFileWriteError(filePath string, cause error) *CommonError {
|
||||
return NewError(ErrFileWrite, fmt.Sprintf("failed to write file: %s", filePath), cause)
|
||||
}
|
||||
|
||||
func NewFileCreateError(filePath string, cause error) *CommonError {
|
||||
return NewError(ErrFileCreate, fmt.Sprintf("failed to create file: %s", filePath), cause)
|
||||
}
|
||||
|
||||
// Network errors
|
||||
func NewNetworkRequestError(url string, cause error) *CommonError {
|
||||
return NewError(ErrNetworkRequest, fmt.Sprintf("network request failed for URL: %s", url), cause)
|
||||
}
|
||||
|
||||
func NewNetworkResponseError(message string, cause error) *CommonError {
|
||||
return NewError(ErrNetworkResponse, message, cause)
|
||||
}
|
||||
|
||||
// Template errors
|
||||
func NewTemplateLoadError(template string, cause error) *CommonError {
|
||||
return NewError(ErrTemplateLoad, fmt.Sprintf("failed to load template: %s", template), cause)
|
||||
}
|
||||
|
||||
func NewTemplateParseError(cause error) *CommonError {
|
||||
return NewError(ErrTemplateParse, "failed to parse template", cause)
|
||||
}
|
||||
|
||||
// Subscription errors
|
||||
func NewSubscriptionLoadError(url string, cause error) *CommonError {
|
||||
return NewError(ErrSubscriptionLoad, fmt.Sprintf("failed to load subscription: %s", url), cause)
|
||||
}
|
||||
|
||||
func NewSubscriptionParseError(cause error) *CommonError {
|
||||
return NewError(ErrSubscriptionParse, "failed to parse subscription", cause)
|
||||
}
|
||||
|
||||
// Regex errors
|
||||
func NewRegexCompileError(pattern string, cause error) *CommonError {
|
||||
return NewError(ErrRegexCompile, fmt.Sprintf("failed to compile regex pattern: %s", pattern), cause)
|
||||
}
|
||||
|
||||
func NewRegexInvalidError(paramName string, cause error) *CommonError {
|
||||
return NewError(ErrRegexInvalid, fmt.Sprintf("invalid regex in parameter: %s", paramName), cause)
|
||||
}
|
||||
|
||||
// Database errors
|
||||
func NewDatabaseConnectError(cause error) *CommonError {
|
||||
return NewError(ErrDatabaseConnect, "failed to connect to database", cause)
|
||||
}
|
||||
|
||||
func NewRecordNotFoundError(recordType string, id string) *CommonError {
|
||||
return NewSimpleError(ErrRecordNotFound, fmt.Sprintf("%s not found: %s", recordType, id))
|
||||
}
|
||||
|
||||
// Validation errors
|
||||
func NewValidationError(field string, message string) *CommonError {
|
||||
return NewSimpleError(ErrValidation, fmt.Sprintf("validation failed for %s: %s", field, message))
|
||||
}
|
||||
|
||||
func NewInvalidInputError(paramName string, value string) *CommonError {
|
||||
return NewSimpleError(ErrInvalidInput, fmt.Sprintf("invalid input for parameter %s: %s", paramName, value))
|
||||
}
|
||||
|
||||
// IsErrorCode checks if an error has a specific error code
|
||||
func IsErrorCode(err error, code ErrorCode) bool {
|
||||
var commonErr *CommonError
|
||||
if errors.As(err, &commonErr) {
|
||||
return commonErr.Code == code
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetErrorCode extracts the error code from an error
|
||||
func GetErrorCode(err error) (ErrorCode, bool) {
|
||||
var commonErr *CommonError
|
||||
if errors.As(err, &commonErr) {
|
||||
return commonErr.Code, true
|
||||
}
|
||||
return "", false
|
||||
}
|
Reference in New Issue
Block a user