Files
HostKeeper/v1/internal/errors/connection_errors.go
T
swanadiva 847989df75 refactor: move V1 code into v1/ subdirectory
- git mv cmd/ internal/ pkg/ test/ go.mod go.sum Makefile build.sh docs/ v1/
- Create v1/README.md with V1 documentation
- Update root README for V1 + V2 structure
- V1 still builds (cd v1 && go build ./cmd/hostkeeper) and 105 tests pass
- Root is now clean for V2 development
2026-07-07 11:56:27 +07:00

105 lines
3.0 KiB
Go

package errors
import (
"fmt"
"strings"
)
// ConnectionError represents SSH connection errors with helpful hints
type ConnectionError struct {
Type string // "auth", "network", "timeout", "config", "unknown"
Message string
Details string
Hints []string
}
// Error implements the error interface
func (e *ConnectionError) Error() string {
return fmt.Sprintf("Connection Error (%s): %s\nDetails: %s", e.Type, e.Message, e.Details)
}
// NewConnectionError creates a new ConnectionError
func NewConnectionError(errType, message, details string, hints []string) *ConnectionError {
return &ConnectionError{
Type: errType,
Message: message,
Details: details,
Hints: hints,
}
}
// HandleSSHError processes SSH errors and returns user-friendly errors
func HandleSSHError(err error) *ConnectionError {
if err == nil {
return nil
}
errStr := err.Error()
switch {
case strings.Contains(errStr, "connection refused"):
return &ConnectionError{
Type: "network",
Message: "Cannot connect to server",
Details: errStr,
Hints: []string{"Check if server is running", "Verify firewall rules", "Confirm hostname and port"},
}
case strings.Contains(errStr, "authentication failed"), strings.Contains(errStr, "unable to authenticate"):
return &ConnectionError{
Type: "auth",
Message: "Authentication failed",
Details: errStr,
Hints: []string{"Verify username and password", "Check SSH key is loaded", "Test with native SSH client"},
}
case strings.Contains(errStr, "timeout"), strings.Contains(errStr, "timed out"):
return &ConnectionError{
Type: "timeout",
Message: "Connection timeout",
Details: errStr,
Hints: []string{"Check network connectivity", "Try increasing timeout", "Verify server is reachable"},
}
case strings.Contains(errStr, "no such host"), strings.Contains(errStr, "hostname"):
return &ConnectionError{
Type: "config",
Message: "Invalid hostname",
Details: errStr,
Hints: []string{"Verify hostname spelling", "Check DNS resolution", "Try IP address instead"},
}
case strings.Contains(errStr, "permission denied"):
return &ConnectionError{
Type: "auth",
Message: "Permission denied",
Details: errStr,
Hints: []string{"Check user permissions on server", "Verify account is not locked", "Check authentication method"},
}
default:
return &ConnectionError{
Type: "unknown",
Message: "Connection failed",
Details: errStr,
Hints: []string{"Check host configuration", "Verify network settings", "Test with standard SSH client"},
}
}
}
// FormatConnectionError formats connection error for user-friendly display
func FormatConnectionError(err *ConnectionError) string {
var output strings.Builder
output.WriteString(fmt.Sprintf("❌ Connection Error: %s\n\n", err.Message))
output.WriteString(fmt.Sprintf("Details: %s\n\n", err.Details))
if len(err.Hints) > 0 {
output.WriteString("Possible solutions:\n")
for i, hint := range err.Hints {
output.WriteString(fmt.Sprintf(" %d. %s\n", i+1, hint))
}
}
return output.String()
}