package explain import ( "crypto/tls" "crypto/x509" "errors" "fmt" "io" "io/fs" "net" "syscall" "ddc/internal/guard" ) var keptAsIs = []error{ guard.ErrBlockedAddress, guard.ErrBlockedPort, guard.ErrTooManyRedirects, guard.ErrUnsupportedScheme, } func Error(err error) string { if err == nil { return "" } for _, known := range keptAsIs { if errors.Is(err, known) { return capitalize(known.Error()) } } if message := networkMessage(err); message != "" { return message } if message := fileSystemMessage(err); message != "" { return message } return capitalize(err.Error()) } func networkMessage(err error) string { var dnsError *net.DNSError var certificateError *tls.CertificateVerificationError var unknownAuthority x509.UnknownAuthorityError var hostnameError x509.HostnameError var timeoutError net.Error switch { case errors.As(err, &dnsError): return fmt.Sprintf("Could not find the server %q. Check the link.", dnsError.Name) case errors.As(err, &certificateError), errors.As(err, &unknownAuthority), errors.As(err, &hostnameError): return "The server's security certificate is not valid." case errors.Is(err, syscall.ECONNREFUSED): return "The server refused the connection." case errors.Is(err, syscall.ECONNRESET), errors.Is(err, io.ErrUnexpectedEOF): return "The server closed the connection before the file was complete. Use Retry to continue." case errors.Is(err, syscall.ENETUNREACH), errors.Is(err, syscall.EHOSTUNREACH): return "The server could not be reached from this network." case errors.As(err, &timeoutError) && timeoutError.Timeout(): return "The server took too long to respond." default: return "" } } func fileSystemMessage(err error) string { switch { case errors.Is(err, syscall.ENOSPC): return "The disk is full." case errors.Is(err, fs.ErrPermission): return "The server does not have permission to write there. Check the folder owner and permissions." case errors.Is(err, syscall.EROFS): return "The destination is on a read-only file system." default: return "" } } func capitalize(message string) string { if message == "" { return message } first := message[0] if first >= 'a' && first <= 'z' { return string(first-'a'+'A') + message[1:] } return message }