whoissdk/errors.go

125 lines
3.1 KiB
Go
Raw Permalink Normal View History

2026-03-19 11:53:07 +08:00
package whois
import (
"errors"
"fmt"
"strings"
)
// ErrorCode represents a typed SDK error category.
type ErrorCode string
const (
ErrorCodeOK ErrorCode = "ok"
ErrorCodeNoWhoisServer ErrorCode = "no-whois-server"
ErrorCodeAccessDenied ErrorCode = "access-denied"
ErrorCodeNotFound ErrorCode = "not-found"
ErrorCodeEmptyResponse ErrorCode = "empty-response"
ErrorCodeParseWeak ErrorCode = "parse-weak"
ErrorCodeNetwork ErrorCode = "network"
)
// WhoisError is the typed error model used by this SDK.
type WhoisError struct {
Code ErrorCode
Domain string
Server string
Reason string
Err error
}
func (e *WhoisError) Error() string {
if e == nil {
return "whois: unknown error"
}
parts := make([]string, 0, 5)
parts = append(parts, "whois")
if e.Code != "" {
parts = append(parts, string(e.Code))
}
if strings.TrimSpace(e.Domain) != "" {
parts = append(parts, "domain="+strings.TrimSpace(e.Domain))
}
if strings.TrimSpace(e.Server) != "" {
parts = append(parts, "server="+strings.TrimSpace(e.Server))
}
if strings.TrimSpace(e.Reason) != "" {
parts = append(parts, strings.TrimSpace(e.Reason))
}
if e.Err != nil {
parts = append(parts, e.Err.Error())
}
return strings.Join(parts, ": ")
}
func (e *WhoisError) Unwrap() error {
if e == nil {
return nil
}
return e.Err
}
func (e *WhoisError) Is(target error) bool {
t, ok := target.(*WhoisError)
if !ok {
return false
}
return e.Code == t.Code
}
var (
ErrNoWhoisServer = &WhoisError{Code: ErrorCodeNoWhoisServer}
ErrAccessDenied = &WhoisError{Code: ErrorCodeAccessDenied}
ErrNotFound = &WhoisError{Code: ErrorCodeNotFound}
ErrEmptyResponse = &WhoisError{Code: ErrorCodeEmptyResponse}
ErrParseWeak = &WhoisError{Code: ErrorCodeParseWeak}
)
func newWhoisError(code ErrorCode, domain, server, reason string, cause error) error {
return &WhoisError{
Code: code,
Domain: strings.TrimSpace(domain),
Server: strings.TrimSpace(server),
Reason: strings.TrimSpace(reason),
Err: cause,
}
}
func reasonErrorFromMeta(domain string, m ResultMeta) error {
switch m.ReasonCode {
case ErrorCodeAccessDenied:
return newWhoisError(ErrorCodeAccessDenied, domain, m.Server, m.Reason, ErrAccessDenied)
case ErrorCodeNotFound:
return newWhoisError(ErrorCodeNotFound, domain, m.Server, m.Reason, ErrNotFound)
case ErrorCodeEmptyResponse:
return newWhoisError(ErrorCodeEmptyResponse, domain, m.Server, m.Reason, ErrEmptyResponse)
case ErrorCodeParseWeak:
return newWhoisError(ErrorCodeParseWeak, domain, m.Server, m.Reason, ErrParseWeak)
default:
return nil
}
}
// IsCode reports whether err is a typed SDK error with the given code.
func IsCode(err error, code ErrorCode) bool {
if err == nil {
return false
}
var we *WhoisError
if !errors.As(err, &we) {
return false
}
return we.Code == code
}
func wrapNetworkError(domain, server string, err error, op string) error {
reason := strings.TrimSpace(op)
if reason == "" {
reason = "network error"
}
if err == nil {
err = fmt.Errorf("whois: %s", reason)
}
return newWhoisError(ErrorCodeNetwork, domain, server, reason, err)
}