Пакет · sdk-s5w

Исключения

Всё, что бросает SDK, наследует S5wException. Класс исключения говорит, что случилось; текст сообщения предназначен для логов. Как обрабатывать на практике — в руководстве Обработка ошибок.

Корень Flytachi\Winter\SDK\S5w\S5wExceptionОстальные Flytachi\Winter\SDK\S5w\Exception

Иерархия

text
S5wException                         RuntimeException; корень всех ошибок SDK
├── TransportException                сервер не ответил: DNS, отказ соединения, таймаут
├── ResponseException                 ответ пришёл, но не в формате S5W
├── ApiException                      сервер ответил кодом ошибки
│   ├── UnauthorizedException   401   ключа нет или сервер его не знает
│   ├── ForbiddenException      403   ключ отключён, истёк или BASIC там, где нужен FULL
│   ├── NotFoundException       404   нет файла, папки или сессии
│   ├── ConflictException       409   имя занято; часть не продолжает загрузку
│   ├── PayloadTooLargeException 413  квота заполнена; часть слишком большая
│   ├── ValidationException     422   параметры не прошли проверку
│   └── ServerException         5xx   сбой на стороне сервера
├── UploadInterruptedException        загрузка частями прервана, сессию можно продолжить
└── UploadUnconfirmedException        сборка файла запрошена, но не подтверждена

S5wException

Корень иерархии, наследник RuntimeException. Поймав его, вы поймаете любую ошибку SDK.

Бросается и напрямую — для ошибок, которые SDK обнаруживает до запроса: неверная конфигурация, файл не читается с диска, файл изменился во время загрузки, размер файла не совпадает с сессией при resume().

Сообщение

Сообщения имеют вид S5W {путь}: {статус} {текст сервера}:

text
S5W v1/files/7CKEKbaV8AN6qTs1: 404 File does not exist
S5W v1/folders: 409 Folder "avatars" already exists
S5W v1/files: 422 Folder "no-such" does not exist
S5W v1/check: simulated: connection refused

Путь показывается раскодированным — кириллица в имени папки читается как есть.

ApiException

Сервер ответил статусом ошибки. Тело ответа — { code, message, errors? }. Для статусов из таблицы ниже бросается наследник; для остальных (например, 400) — сам ApiException.

Статус Класс Типичные причины
400 ApiException пустая часть или часть меньше 4 МиБ, но не последняя
401 UnauthorizedException ключа нет или он неизвестен
403 ForbiddenException ключ отключён или истёк; ключ BASIC для folders(), files(), uploads()
404 NotFoundException нет файла, папки, сессии; неверный формат id файла (без запроса)
409 ConflictException имя папки или файла занято; смещение части не совпало; complete() до получения всех байт
413 PayloadTooLargeException квота бакета заполнена; часть больше 16 МиБ или выходит за заявленный размер
422 ValidationException поле не прошло проверку; нет папки; опции картинки для не-картинки; хеш не совпал
5xx ServerException ошибка сервера; 507 — на диске сервера нет места

Методы

status(): int — HTTP-статус ответа.

errors(): array<string, list<string>> — ошибки по полям; заполнено только для 422 с ошибками валидации полей.

method(): string — HTTP-метод запроса, например "PUT".

path(): string — путь запроса относительно адреса сервера, например "v1/files/7CKEKbaV8AN6qTs1".

php
catch (ApiException $e) {
  $e->status();   // 409
  $e->method();   // "POST"
  $e->path();     // "v1/folders"
}

ValidationException

Дополнительный метод errorsOf(string $field): list<string> — ошибки одного поля.

php
catch (ValidationException $e) {
  $e->errors();          // ["name" => ["must not be blank", "size must be between 1 and 100"]]
  $e->errorsOf('name');  // ["must not be blank", "size must be between 1 and 100"]
  $e->errorsOf('other'); // []
}

Если ошибка относится ко всему запросу, а не к полю (нет папки, хеш не совпал), errors() пустой, а причина — в сообщении.

TransportException

Запрос не получил HTTP-ответа: сервер не найден, соединение отклонено, истёк таймаут. Единственный вид сбоя, который стоит повторять как есть.

Методы

isTimeout(): bool — true, если причина — истёкший таймаут, а не отказ соединения.

Исходное исключение HTTP-клиента доступно через getPrevious().

ResponseException

Ответ пришёл, но это не ответ S5W: не JSON, нет нужного поля, у поля не тот тип. Обычно адрес указывает не на S5W (например, на страницу ошибки прокси) или версии сервера и SDK не совпадают. В сообщении — путь к полю:

text
S5W v1/check: the answer is not JSON
S5W v1/check: bytes.quota must be int, got string

UploadInterruptedException

Загрузка частями остановилась на сбое сети или сервера после того, как все попытки (Uploads::ATTEMPTS) закончились. Сессия на сервере сохранена — её можно продолжить в течение 24 часов после последней полученной части.

Бросается методами uploads()->send(), sendContent(), resume(), а также files()->upload() и uploadContent() для файлов больше порога загрузки частями.

Методы

sessionId(): string — id сессии; передайте в uploads()->resume().

offset(): int — сколько байт, насколько известно SDK, уже на сервере.

size(): int — полный размер файла.

Причина — в getPrevious(): TransportException, ServerException или ConflictException.

php
catch (UploadInterruptedException $e) {
  $file = $s5w->uploads()->resume($e->sessionId(), $path);
}

UploadUnconfirmedException

Все байты переданы и сборка файла запрошена, но ответ не пришёл (обрыв связи, ошибка шлюза), а сессии на сервере уже нет. Файл мог быть создан — тогда его id неизвестен; мог и не быть. SDK не пытается угадать: поиск по имени мог бы найти чужой файл.

Методы

sessionId(): string — id сессии, которой больше нет.

name(): string — имя, с которым начиналась загрузка. Сохранённое имя может отличаться — например, name (1).ext, если имя было занято.

php
catch (UploadUnconfirmedException $e) {
  $logger->error("Загрузка {$e->name()} не подтверждена — проверьте папку вручную");
}

Что бросают методы

Метод Характерные исключения
S5w::check() UnauthorizedException, ForbiddenException
Folders::create(), rename(), update() ConflictException, ValidationException, NotFoundException
Folders::get(), delete() NotFoundException
Files::get(), delete() NotFoundException
Files::list() ValidationException (нет папки)
Files::rename(), move(), update() NotFoundException, ValidationException, ConflictException
Files::upload(), uploadContent() ValidationException, PayloadTooLargeException; для больших файлов — как у send()
Uploads::start() ValidationException, PayloadTooLargeException, ServerException (507)
Uploads::append() ConflictException, PayloadTooLargeException, ApiException (400), NotFoundException
Uploads::complete() ConflictException, ValidationException
Uploads::send(), sendContent() UploadInterruptedException, UploadUnconfirmedException, ApiException
Uploads::resume() как у send(), плюс NotFoundException и S5wException (другой файл)

Любой метод, который ходит на сервер, может также бросить TransportException, ResponseException, UnauthorizedException и ForbiddenException.