Менеджер загрузки картинок по URL без повторной заливки

ЗадачаMiddle40 минпроверка — Спринтнапиши код10-t056

По нормализованной ссылке нужно скопировать картинку во внутреннее хранилище и вернуть внутренний id. Если эта ссылка уже загружалась — вернуть существующий id без повторной заливки. Коды ошибок: 400 — некорректная ссылка, 409 — конфликт параллельных запросов на одну ссылку, 500 — ошибка на стороне сервера. Используя готовый клиент заливки, спроектируйте интерфейс вспомогательной БД (без реализации) для отслеживания уже загруженных ссылок и реализуйте на нём логику менеджера. (Вариант 1 условия: вместо StorageClient дан Store{Put(url) (string, error); Get(id)} и пустой Manager — суть та же.)

main.gogo
1package main2 3import (4	"context"5	"errors"6	"fmt"7	"net/http"8)9 10var ErrBadURL = errors.New("invalid url")11 12type StorageClient interface {13	// загружает по URL, возвращает внутренний ID14	// ErrBadURL при невалидном URL, иначе внутренняя ошибка15	Put(ctx context.Context, url string) (int, error)16}17 18type ManagerRow struct {19	...20}21 22type ManagerTable interface {23	Insert(ctx context.Context, row ManagerRow) error24	...25}26 27type RequestError struct {28	Code int29	Err  error30}31 32func (e *RequestError) Error() string {33	return fmt.Sprintf("HTTP error %d: %w", e.Code, e.Err)34}35 36func NewRequestError(code int, err error) *RequestError {37	return &RequestError{Code: code, Err: err}38}39 40type UploadManager struct {41	client StorageClient42	table  ManagerTable43}44 45func NewUploadManager(client StorageClient, table ManagerTable) *UploadManager {46	return &UploadManager{client: client, table: table}47}48 49func (m *UploadManager) Upload(ctx context.Context, url string) (int, error) {50	...51}
⌘ Enter — проверить