Files
summercms/lagoon/attach/bucket.go
Jakub Zych ba9c99246e feat(05-04): implement attach File, Thumb, blob bucket, system_files migration
- Winter-exact thumb filename and 3x3 partition with lazy imaging resize
- gocloud.dev/blob fileblob/memblob; empty bucket_url fails boot
- lagoon.Migrate runs system_files before every plugin set
2026-09-18 19:55:15 +02:00

96 lines
2.3 KiB
Go

package attach
import (
"context"
"fmt"
"net/url"
"strings"
"sync"
"git.golem15.com/golem15/summercms/backpack"
"git.golem15.com/golem15/summercms/compass"
"gocloud.dev/blob"
_ "gocloud.dev/blob/fileblob"
_ "gocloud.dev/blob/memblob"
)
const defaultPublicPathPrefix = "/storage/uploads"
var (
prefixMu sync.RWMutex
publicPathPrefix = defaultPublicPathPrefix
)
func setPublicPathPrefix(prefix string) {
prefixMu.Lock()
publicPathPrefix = prefix
prefixMu.Unlock()
}
// PublicPathPrefix is the URL prefix prepended to partition+filename.
func PublicPathPrefix() string {
prefixMu.RLock()
defer prefixMu.RUnlock()
return publicPathPrefix
}
func normalizeBucketURL(raw string) (string, error) {
u, err := url.Parse(raw)
if err != nil {
return "", fmt.Errorf("attach: bucket_url: %w", err)
}
switch strings.ToLower(u.Scheme) {
case "mem", "memory":
return "mem://", nil
case "fileblob":
u.Scheme = "file"
fallthrough
case "file":
q := u.Query()
if q.Get("create_dir") == "" {
q.Set("create_dir", "true")
u.RawQuery = q.Encode()
}
return u.String(), nil
default:
return raw, nil
}
}
// OpenBucket opens storage.uploads.bucket_url (file:// or mem://) and
// records storage.uploads.public_path_prefix. An empty bucket_url fails boot.
func OpenBucket(ctx context.Context, cfg *compass.Config) (*blob.Bucket, error) {
if cfg == nil {
return nil, fmt.Errorf("attach: config is nil")
}
raw := strings.TrimSpace(cfg.String("storage.uploads.bucket_url"))
if raw == "" {
return nil, fmt.Errorf("attach: storage.uploads.bucket_url is empty (set SUMMER_STORAGE__UPLOADS__BUCKET_URL)")
}
bucketURL, err := normalizeBucketURL(raw)
if err != nil {
return nil, err
}
bucket, err := blob.OpenBucket(ctx, bucketURL)
if err != nil {
return nil, fmt.Errorf("attach: open bucket %q: %w", raw, err)
}
prefix := strings.TrimSpace(cfg.String("storage.uploads.public_path_prefix"))
if prefix == "" {
prefix = defaultPublicPathPrefix
}
setPublicPathPrefix(prefix)
return bucket, nil
}
// Publish stores the opened bucket once on the app, matching lagoon.Publish.
func Publish(app *backpack.App, bucket *blob.Bucket) error {
if app == nil {
return fmt.Errorf("attach: app is nil")
}
if bucket == nil {
return fmt.Errorf("attach: bucket is nil")
}
return app.Publish(bucket)
}