package handler import ( "errors" "fmt" "strconv" "awesome_cli/internal/service" "awesome_cli/pkg/ui" libErr "code.linberg.su/linberg/awesome-back/pkg/errors" ) type CoffeeHandler struct { coffeeService *service.CoffeeService } func NewCoffeeHandler(coffeeService *service.CoffeeService) *CoffeeHandler { return &CoffeeHandler{ coffeeService: coffeeService, } } func (h *CoffeeHandler) HandleList() error { coffees, err := h.coffeeService.GetAllCoffees() if err != nil { return h.handleError(err, "Failed to list coffees") } h.printCoffeesTable(coffees) return nil } func (h *CoffeeHandler) HandleGet(coffeeID string) error { id, err := strconv.Atoi(coffeeID) if err != nil { return libErr.NewInvalidError("coffee ID must be a number") } coffee, err := h.coffeeService.GetCoffeeByID(id) if err != nil { return h.handleError(err, fmt.Sprintf("Failed to get coffee with ID %d", id)) } h.printCoffeeDetail(coffee) return nil } func (h *CoffeeHandler) HandleGetWithRetry(coffeeID string, maxRetries int) error { id, err := strconv.Atoi(coffeeID) if err != nil { return libErr.NewInvalidError("coffee ID must be a number") } fmt.Printf("Fetching coffee with ID %d (max retries: %d)...\n", id, maxRetries) coffee, err := h.coffeeService.GetCoffeeByIDWithRetry(id, maxRetries) if err != nil { return h.handleError(err, fmt.Sprintf("Failed to get coffee with ID %d after retries", id)) } h.printCoffeeDetail(coffee) return nil } func (h *CoffeeHandler) printCoffeesTable(coffees []service.Coffee) { t := ui.NewTableBuilder() t.AddTableHeader("ID", "Name", "Price", "Size", "Description") for _, coffee := range coffees { t.AddRow( strconv.FormatInt(int64(coffee.ID), 10), coffee.Name, strconv.FormatInt(int64(coffee.Price), 10), coffee.Size, coffee.Description, ) } fmt.Println(t.CreateTable()) } func (h *CoffeeHandler) printCoffeeDetail(coffee *service.Coffee) { fmt.Printf("ID: %s\n", ui.SetColor(ui.Green, strconv.FormatInt(int64(coffee.ID), 10))) fmt.Printf("Name: %s\n", ui.SetColor(ui.Green, coffee.Name)) fmt.Printf("Price: %s\n", ui.SetColor(ui.Green, fmt.Sprintf("%.2f ₽", coffee.Price))) fmt.Printf("Size: %s\n", ui.SetColor(ui.Green, coffee.Size)) fmt.Printf("Description: %s\n", ui.SetColor(ui.Green, coffee.Description)) fmt.Println() } // handleError демонстрирует продвинутую обработку ошибок func (h *CoffeeHandler) handleError(err error, message string) error { red := func(s string) string { return ui.SetColor(ui.Red, s) } fmt.Printf("%s: %s\n", red("Error"), message) // Демонстрация использования errors.Is и errors.As switch { case libErr.IsNotFound(err): fmt.Printf("%s: Resource not found\n", red("Type")) fmt.Printf("%s: %v\n", red("Details"), err) case libErr.IsInvalid(err): fmt.Printf("%s: Invalid request\n", red("Type")) fmt.Printf("%s: %v\n", red("Details"), err) case libErr.IsNetworkError(err): fmt.Printf("%s: Network error\n", red("Type")) fmt.Printf("%s: Please check your connection and try again\n", red("Details")) default: // Используем errors.As для получения дополнительной информации var appErr *libErr.AppError if errors.As(err, &appErr) { fmt.Printf("%s: %s\n", red("Type"), string(appErr.Type)) fmt.Printf("%s: %s\n", red("Message"), appErr.Message) // Демонстрация unwrap цепочки ошибок if appErr.Err != nil { fmt.Printf("%s: %v\n", red("Underlying error"), appErr.Err) } } else { fmt.Printf("%s: %v\n", red("Unknown error"), err) } } fmt.Println() // Пустая строка для читабельности return err }