fix(media): proxy ContainerFileOpener through fallback storage provider

The fallback provider introduced in 5aeb2fd3 wrapped containerfs but did
not implement storage.ContainerFileOpener, causing IngestContainerFile to
fail with "provider does not support container file reading". This broke
outbound file attachments on all IM channels (Telegram, Discord, etc.)
because container paths like /data/xxx.xlsx were passed as-is to the
platform API instead of being ingested into the media store first.
This commit is contained in:
Acbox
2026-04-03 01:14:20 +08:00
parent 5aeb2fd3fc
commit 3fa311c6cb
3 changed files with 23 additions and 1 deletions
+1 -1
View File
@@ -148,7 +148,7 @@ func (s *Service) IngestContainerFile(ctx context.Context, botID, containerPath
}
opener, ok := s.provider.(storage.ContainerFileOpener)
if !ok {
return Asset{}, errors.New("provider does not support container file reading")
return Asset{}, storage.ErrContainerFileNotSupported
}
f, err := opener.OpenContainerFile(ctx, botID, containerPath)
if err != nil {
@@ -10,6 +10,8 @@ import (
"github.com/memohai/memoh/internal/storage"
)
var _ storage.ContainerFileOpener = (*Provider)(nil)
// Provider delegates to primary and falls back to secondary on write errors.
type Provider struct {
primary storage.Provider
@@ -79,3 +81,18 @@ func tryListPrefix(ctx context.Context, p storage.Provider, prefix string) ([]st
}
return nil, nil
}
// OpenContainerFile delegates to whichever inner provider implements
// storage.ContainerFileOpener, trying the primary first.
func (p *Provider) OpenContainerFile(ctx context.Context, botID, containerPath string) (io.ReadCloser, error) {
if opener, ok := p.primary.(storage.ContainerFileOpener); ok {
rc, err := opener.OpenContainerFile(ctx, botID, containerPath)
if err == nil {
return rc, nil
}
}
if opener, ok := p.secondary.(storage.ContainerFileOpener); ok {
return opener.OpenContainerFile(ctx, botID, containerPath)
}
return nil, storage.ErrContainerFileNotSupported
}
+5
View File
@@ -3,9 +3,14 @@ package storage
import (
"context"
"errors"
"io"
)
// ErrContainerFileNotSupported is returned when no underlying provider
// implements ContainerFileOpener.
var ErrContainerFileNotSupported = errors.New("provider does not support container file reading")
// Provider abstracts object storage operations.
type Provider interface {
// Put writes data to storage under the given key.