package attach import ( "context" "fmt" "net/url" "strings" "sync" "git.golem15.com/golem15/summercms/modules/backpack" "git.golem15.com/golem15/summercms/modules/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) }