repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

commit
0c80ce2
parent
b60f3d1
author
Eric Bower
date
2025-01-15 12:53:16 -0500 EST
fix(imgproxy): properly handle missing last-modified
15 files changed,  +50, -39
M cmd/scripts/clean-object-store/clean.go
+1, -1
1@@ -45,7 +45,7 @@ func main() {
2 
3 	var st storage.StorageServe
4 	var err error
5-	st, err = storage.NewStorageMinio(picoCfg.MinioURL, picoCfg.MinioUser, picoCfg.MinioPass)
6+	st, err = storage.NewStorageMinio(logger, picoCfg.MinioURL, picoCfg.MinioUser, picoCfg.MinioPass)
7 	bail(err)
8 
9 	logger.Info("fetching all users")
M feeds/api.go
+2, -2
 1@@ -81,9 +81,9 @@ func StartApiServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
M feeds/ssh.go
+2, -2
 1@@ -68,9 +68,9 @@ func StartSshServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
M imgs/api.go
+2, -2
 1@@ -313,9 +313,9 @@ func StartApiServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
M imgs/ssh.go
+1, -1
1@@ -265,7 +265,7 @@ func StartSshServer() {
2 	logger := shared.CreateLogger("imgs")
3 	logger.Info("bootup", "registry", registryUrl, "minio", minioUrl)
4 	dbh := postgres.NewDB(dbUrl, logger)
5-	st, err := storage.NewStorageMinio(minioUrl, minioUser, minioPass)
6+	st, err := storage.NewStorageMinio(logger, minioUrl, minioUser, minioPass)
7 	if err != nil {
8 		panic(err)
9 	}
M pastes/api.go
+2, -2
 1@@ -373,9 +373,9 @@ func StartApiServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
M pastes/ssh.go
+2, -2
 1@@ -67,9 +67,9 @@ func StartSshServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
M pgs/ssh.go
+2, -2
 1@@ -64,9 +64,9 @@ func StartSshServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
M pgs/web.go
+5, -5
 1@@ -53,9 +53,9 @@ func StartApiServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
13@@ -472,8 +472,8 @@ func (web *WebRouter) ServeAsset(fname string, opts *storage.ImgProcessOpts, fro
14 		bucket, err = web.Storage.GetBucket(shared.GetImgsBucketName(user.ID))
15 	} else {
16 		bucket, err = web.Storage.GetBucket(shared.GetAssetBucketName(user.ID))
17-		project, err := web.Dbpool.FindProjectByName(user.ID, props.ProjectName)
18-		if err != nil {
19+		project, perr := web.Dbpool.FindProjectByName(user.ID, props.ProjectName)
20+		if perr != nil {
21 			logger.Info("project not found")
22 			http.Error(w, "project not found", http.StatusNotFound)
23 			return
24@@ -499,7 +499,7 @@ func (web *WebRouter) ServeAsset(fname string, opts *storage.ImgProcessOpts, fro
25 	}
26 
27 	if err != nil {
28-		logger.Info("bucket not found")
29+		logger.Error("bucket not found", "err", err)
30 		http.Error(w, "bucket not found", http.StatusNotFound)
31 		return
32 	}
M pgs/web_asset_handler.go
+8, -4
 1@@ -131,15 +131,19 @@ func (h *ApiAssetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 2 			return
 3 		}
 4 
 5-		attempts = append(attempts, fp.Filepath)
 6-		logger = logger.With("filename", fp.Filepath)
 7 		var c io.ReadCloser
 8+		fpath := fp.Filepath
 9+		attempts = append(attempts, fpath)
10+		logger = logger.With("object", fpath)
11+		logger.Info("serving object")
12 		c, info, err = h.Storage.ServeObject(
13 			h.Bucket,
14-			fp.Filepath,
15+			fpath,
16 			h.ImgProcessOpts,
17 		)
18-		if err == nil {
19+		if err != nil {
20+			logger.Error("serving object", "err", err)
21+		} else {
22 			contents = c
23 			assetFilepath = fp.Filepath
24 			status = fp.Status
M prose/api.go
+2, -2
 1@@ -898,9 +898,9 @@ func StartApiServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
M prose/ssh.go
+2, -2
 1@@ -69,9 +69,9 @@ func StartSshServer() {
 2 	var st storage.StorageServe
 3 	var err error
 4 	if cfg.MinioURL == "" {
 5-		st, err = storage.NewStorageFS(cfg.StorageDir)
 6+		st, err = storage.NewStorageFS(cfg.Logger, cfg.StorageDir)
 7 	} else {
 8-		st, err = storage.NewStorageMinio(cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
 9+		st, err = storage.NewStorageMinio(cfg.Logger, cfg.MinioURL, cfg.MinioUser, cfg.MinioPass)
10 	}
11 
12 	if err != nil {
M shared/storage/fs.go
+5, -3
 1@@ -3,6 +3,7 @@ package storage
 2 import (
 3 	"fmt"
 4 	"io"
 5+	"log/slog"
 6 	"os"
 7 	"path/filepath"
 8 	"strings"
 9@@ -12,14 +13,15 @@ import (
10 
11 type StorageFS struct {
12 	*sst.StorageFS
13+	Logger *slog.Logger
14 }
15 
16-func NewStorageFS(dir string) (*StorageFS, error) {
17+func NewStorageFS(logger *slog.Logger, dir string) (*StorageFS, error) {
18 	st, err := sst.NewStorageFS(dir)
19 	if err != nil {
20 		return nil, err
21 	}
22-	return &StorageFS{st}, nil
23+	return &StorageFS{st, logger}, nil
24 }
25 
26 func (s *StorageFS) ServeObject(bucket sst.Bucket, fpath string, opts *ImgProcessOpts) (io.ReadCloser, *sst.ObjectInfo, error) {
27@@ -37,7 +39,7 @@ func (s *StorageFS) ServeObject(bucket sst.Bucket, fpath string, opts *ImgProces
28 	} else {
29 		filePath := filepath.Join(bucket.Name, fpath)
30 		dataURL := fmt.Sprintf("s3://%s", filePath)
31-		rc, info, err = HandleProxy(dataURL, opts)
32+		rc, info, err = HandleProxy(s.Logger, dataURL, opts)
33 	}
34 	if err != nil {
35 		return nil, nil, err
M shared/storage/minio.go
+5, -3
 1@@ -3,6 +3,7 @@ package storage
 2 import (
 3 	"fmt"
 4 	"io"
 5+	"log/slog"
 6 	"os"
 7 	"path/filepath"
 8 	"strings"
 9@@ -12,14 +13,15 @@ import (
10 
11 type StorageMinio struct {
12 	*sst.StorageMinio
13+	Logger *slog.Logger
14 }
15 
16-func NewStorageMinio(address, user, pass string) (*StorageMinio, error) {
17+func NewStorageMinio(logger *slog.Logger, address, user, pass string) (*StorageMinio, error) {
18 	st, err := sst.NewStorageMinio(address, user, pass)
19 	if err != nil {
20 		return nil, err
21 	}
22-	return &StorageMinio{st}, nil
23+	return &StorageMinio{st, logger}, nil
24 }
25 
26 func (s *StorageMinio) ServeObject(bucket sst.Bucket, fpath string, opts *ImgProcessOpts) (io.ReadCloser, *sst.ObjectInfo, error) {
27@@ -37,7 +39,7 @@ func (s *StorageMinio) ServeObject(bucket sst.Bucket, fpath string, opts *ImgPro
28 	} else {
29 		filePath := filepath.Join(bucket.Name, fpath)
30 		dataURL := fmt.Sprintf("s3://%s", filePath)
31-		rc, info, err = HandleProxy(dataURL, opts)
32+		rc, info, err = HandleProxy(s.Logger, dataURL, opts)
33 	}
34 	if err != nil {
35 		return nil, nil, err
M shared/storage/proxy.go
+9, -6
 1@@ -7,6 +7,7 @@ import (
 2 	"encoding/hex"
 3 	"fmt"
 4 	"io"
 5+	"log/slog"
 6 	"net/http"
 7 	"os"
 8 	"path/filepath"
 9@@ -202,7 +203,7 @@ func (img *ImgProcessOpts) String() string {
10 	return processOpts
11 }
12 
13-func HandleProxy(dataURL string, opts *ImgProcessOpts) (io.ReadCloser, *storage.ObjectInfo, error) {
14+func HandleProxy(logger *slog.Logger, dataURL string, opts *ImgProcessOpts) (io.ReadCloser, *storage.ObjectInfo, error) {
15 	imgProxyURL := os.Getenv("IMGPROXY_URL")
16 	imgProxySalt := os.Getenv("IMGPROXY_SALT")
17 	imgProxyKey := os.Getenv("IMGPROXY_KEY")
18@@ -242,13 +243,15 @@ func HandleProxy(dataURL string, opts *ImgProcessOpts) (io.ReadCloser, *storage.
19 	lastModified := res.Header.Get("Last-Modified")
20 	parsedTime, err := time.Parse(time.RFC1123, lastModified)
21 	if err != nil {
22-		return nil, nil, fmt.Errorf("decoding last-modified: %w", err)
23+		logger.Error("decoding last-modified", "err", err)
24 	}
25 	info := &storage.ObjectInfo{
26-		Size:         res.ContentLength,
27-		LastModified: parsedTime,
28-		ETag:         trimEtag(res.Header.Get("etag")),
29-		Metadata:     res.Header,
30+		Size:     res.ContentLength,
31+		ETag:     trimEtag(res.Header.Get("etag")),
32+		Metadata: res.Header,
33+	}
34+	if !parsedTime.IsZero() {
35+		info.LastModified = parsedTime
36 	}
37 
38 	return res.Body, info, nil