This commit is contained in:
2026-10-03 13:22:11 +07:00
parent 05090722a0
commit 2caa2c1a88
74 changed files with 44 additions and 676 deletions
@@ -9,8 +9,6 @@ import (
"strings"
)
// ErrFileNotFound — файл не найден в хранилище. Возвращается Get для
// отсутствующих объектов (маппинг smithy-ошибок NoSuchKey/NotFound).
var ErrFileNotFound = errors.New("файл не найден")
// File describes a stored file.
@@ -28,10 +26,6 @@ type IFileStorage interface {
MimeType(filename string) string
}
// FileType возвращает категорию файла по расширению имени: pdf → "pdf",
// jpg/jpeg/png/gif/webp → "image", mp3/ogg/wav → "audio", mp4/webm → "video", иначе "".
// Регистр расширения и query-параметры игнорируются.
// Используется для деривации file_type улик (см. storytelling.Application).
func FileType(filename string) string {
ext := strings.ToLower(extension(filename))
switch ext {
@@ -48,9 +42,6 @@ func FileType(filename string) string {
}
}
// NewName возвращает случайное имя файла в хранилище (hex-токен 16 байт
// без расширения): исключает коллизии в общем бакете. Расширение добавляет
// вызывающий код.
func NewName() (string, error) {
var b [16]byte
if _, err := rand.Read(b[:]); err != nil {
-10
View File
@@ -59,8 +59,6 @@ func (s *storage) Put(ctx context.Context, file *File) error {
func (s *storage) Get(ctx context.Context, filename string) (*File, error) {
data, err := s.client.GetObjectBytes(ctx, s.bucket, filename)
if err != nil {
// s3kit отдаёт сырые smithy-ошибки: маппим отсутствие объекта
// (NoSuchKey/NotFound) в sentinel для прикладного слоя.
var apiErr smithy.APIError
if errors.As(err, &apiErr) {
switch apiErr.ErrorCode() {
@@ -88,8 +86,6 @@ func (s *storage) MimeType(filename string) string {
return "application/octet-stream"
}
// mimeFor — Content-Type для Put: явный Mime файла приоритетнее вывода из
// расширения, чтобы объект в S3 соответствовал фактическому содержимому.
func mimeFor(f *File) string {
if f.Mime != "" {
return f.Mime
@@ -97,10 +93,6 @@ func mimeFor(f *File) string {
return mimeFromData(f.Data, f.Name)
}
// mimeFromData — Content-Type по содержимому (первые 512 байт) с запасным вариантом
// на расширение. text/* (например, HTML) трактуется как octet-stream и
// уходит в запасной вариант: при публичном скачивании не должно отдаваться как
// html с доверенного домена.
func mimeFromData(data []byte, filename string) string {
detected := http.DetectContentType(data)
if strings.HasPrefix(detected, "text/") || detected == "application/octet-stream" {
@@ -112,8 +104,6 @@ func mimeFromData(data []byte, filename string) string {
return detected
}
// extension — расширение имени файла в нижнем регистре, без query/fragment
// (например, "photo.PNG?v=2" → ".png").
func extension(filename string) string {
if i := strings.IndexAny(filename, "?#"); i >= 0 {
filename = filename[:i]
@@ -48,7 +48,6 @@ func TestNewName(t *testing.T) {
if a == b {
t.Errorf("NewName вернул одинаковые имена %q и %q", a, b)
}
// hex-токен 16 байт = 32 символа
if len(a) != 32 {
t.Errorf("длина имени = %d, want 32", len(a))
}