136 lines
3.1 KiB
Go
136 lines
3.1 KiB
Go
//go:build linux || freebsd
|
|
// +build linux freebsd
|
|
|
|
package core
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
)
|
|
|
|
// ErrorType defines the error type
|
|
type ErrorType string
|
|
|
|
const (
|
|
ErrNetwork ErrorType = "NETWORK"
|
|
ErrProtocol ErrorType = "PROTOCOL"
|
|
ErrFile ErrorType = "FILE"
|
|
ErrTimeout ErrorType = "TIMEOUT"
|
|
ErrAuth ErrorType = "AUTH"
|
|
ErrChecksum ErrorType = "CHECKSUM"
|
|
ErrUnsupported ErrorType = "UNSUPPORTED"
|
|
ErrCancelled ErrorType = "CANCELLED"
|
|
)
|
|
|
|
// GogetError is a structured error with context
|
|
type GogetError struct {
|
|
Type ErrorType
|
|
Message string
|
|
Cause error
|
|
URL string
|
|
Hint string // Actionable suggestion for the user
|
|
Details map[string]string
|
|
}
|
|
|
|
func (e *GogetError) Error() string {
|
|
var msg string
|
|
if e.Cause != nil {
|
|
msg = fmt.Sprintf("[%s] %s: %v", e.Type, e.Message, e.Cause)
|
|
} else {
|
|
msg = fmt.Sprintf("[%s] %s", e.Type, e.Message)
|
|
}
|
|
if e.Hint != "" {
|
|
msg += fmt.Sprintf(" (hint: %s)", e.Hint)
|
|
}
|
|
return msg
|
|
}
|
|
|
|
func (e *GogetError) Unwrap() error {
|
|
return e.Cause
|
|
}
|
|
|
|
// GetDetail returns a value from the Details map, or an empty string if the key is absent.
|
|
func (e *GogetError) GetDetail(key string) string {
|
|
if e.Details == nil {
|
|
return ""
|
|
}
|
|
return e.Details[key]
|
|
}
|
|
|
|
// NewNetworkError creates a network error
|
|
func NewNetworkError(msg string, cause error, url string) *GogetError {
|
|
return &GogetError{
|
|
Type: ErrNetwork,
|
|
Message: msg,
|
|
Cause: cause,
|
|
URL: url,
|
|
}
|
|
}
|
|
|
|
// NewProtocolError creates a protocol error
|
|
func NewProtocolError(msg string, cause error, url string) *GogetError {
|
|
return &GogetError{
|
|
Type: ErrProtocol,
|
|
Message: msg,
|
|
Cause: cause,
|
|
URL: url,
|
|
}
|
|
}
|
|
|
|
// NewFileError creates a file error
|
|
func NewFileError(msg string, cause error) *GogetError {
|
|
return &GogetError{
|
|
Type: ErrFile,
|
|
Message: msg,
|
|
Cause: cause,
|
|
}
|
|
}
|
|
|
|
// NewTimeoutError creates a timeout error
|
|
func NewTimeoutError(msg string, url string) *GogetError {
|
|
return &GogetError{
|
|
Type: ErrTimeout,
|
|
Message: msg,
|
|
URL: url,
|
|
Hint: "increase --max-time or --connect-timeout, or check network connectivity",
|
|
}
|
|
}
|
|
|
|
// NewChecksumError creates a checksum error
|
|
func NewChecksumError(expected, actual string) *GogetError {
|
|
return &GogetError{
|
|
Type: ErrChecksum,
|
|
Message: fmt.Sprintf("checksum mismatch: expected %s, got %s", expected, actual),
|
|
Hint: "verify the file integrity with an external checksum tool or re-download",
|
|
Details: map[string]string{
|
|
"expected": expected,
|
|
"actual": actual,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewUnsupportedError creates an unsupported operation error
|
|
func NewUnsupportedError(msg string) *GogetError {
|
|
return &GogetError{
|
|
Type: ErrUnsupported,
|
|
Message: msg,
|
|
}
|
|
}
|
|
|
|
// WithHint returns the error with the hint set. Use for adding contextual,
|
|
// actionable suggestions to an existing error without creating a new one.
|
|
func (e *GogetError) WithHint(hint string) *GogetError {
|
|
e.Hint = hint
|
|
return e
|
|
}
|
|
|
|
// SafeURL returns the URL string with credentials removed for safe error logging.
|
|
func SafeURL(u *url.URL) string {
|
|
if u == nil {
|
|
return ""
|
|
}
|
|
clean := *u
|
|
clean.User = nil
|
|
return clean.String()
|
|
}
|