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) }