refac: decouple persistence and image storage behind driver registries
This commit is contained in:
1 parent
421cfafec3
commit
81e299f09a
46 files changed
+1036
-374
No files matched your search
@@ -1,11 +1,13 @@
|
||||
package staticimages
|
||||
|
||||
import (
|
||||
"RenewCMS/internal/domain/image"
|
||||
"RenewCMS/internal/infrastructure/useCases"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -24,13 +26,13 @@ var contentTypeExtensions = map[string]string{
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
uploadDir fs.FS
|
||||
openMedia *useCases.OpenMediaUseCase
|
||||
modTime time.Time
|
||||
}
|
||||
|
||||
func NewHandler(uploadDir string) *Handler {
|
||||
func NewHandler(openMedia *useCases.OpenMediaUseCase) *Handler {
|
||||
return &Handler{
|
||||
uploadDir: os.DirFS(uploadDir),
|
||||
openMedia: openMedia,
|
||||
modTime: time.Now(),
|
||||
}
|
||||
}
|
||||
@@ -39,18 +41,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
|
||||
cleaned := cleanPath(requestedPath(r))
|
||||
file, stat, ok := h.openFile(cleaned)
|
||||
if !ok {
|
||||
blob, err := h.openMedia.Open(cleaned)
|
||||
if errors.Is(err, image.ErrBlobNotFound) {
|
||||
http.NotFound(w, r)
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
content, ok := file.(io.ReadSeeker)
|
||||
if !ok {
|
||||
http.Error(w, "File not seekable", http.StatusInternalServerError)
|
||||
if err != nil {
|
||||
http.Error(w, "Unable to read the file", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer blob.Content.Close()
|
||||
|
||||
contentType := contentTypeFor(cleaned)
|
||||
w.Header().Set("Content-Type", contentType)
|
||||
@@ -59,7 +59,18 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Security-Policy", svgContentSecurityPolicy)
|
||||
}
|
||||
|
||||
http.ServeContent(w, r, cleaned, stat.ModTime(), content)
|
||||
if content, ok := blob.Content.(io.ReadSeeker); ok {
|
||||
http.ServeContent(w, r, cleaned, blob.ModTime, content)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Length", strconv.FormatInt(blob.Size, 10))
|
||||
if !blob.ModTime.IsZero() {
|
||||
w.Header().Set("Last-Modified", blob.ModTime.UTC().Format(http.TimeFormat))
|
||||
}
|
||||
w.WriteHeader(http.StatusOK)
|
||||
if r.Method != http.MethodHead {
|
||||
_, _ = io.Copy(w, blob.Content)
|
||||
}
|
||||
}
|
||||
|
||||
func requestedPath(r *http.Request) string {
|
||||
@@ -73,22 +84,6 @@ func cleanPath(p string) string {
|
||||
return strings.TrimPrefix(path.Clean("/"+p), "/")
|
||||
}
|
||||
|
||||
func (h *Handler) openFile(p string) (fs.File, fs.FileInfo, bool) {
|
||||
if p == "" || p == "." {
|
||||
return nil, nil, false
|
||||
}
|
||||
file, err := h.uploadDir.Open(p)
|
||||
if err != nil {
|
||||
return nil, nil, false
|
||||
}
|
||||
stat, err := file.Stat()
|
||||
if err != nil || stat.IsDir() {
|
||||
file.Close()
|
||||
return nil, nil, false
|
||||
}
|
||||
return file, stat, true
|
||||
}
|
||||
|
||||
func contentTypeFor(p string) string {
|
||||
ext := path.Ext(p)
|
||||
if contentType, ok := contentTypeExtensions[ext]; ok {
|
||||
|
||||
Reference in new issue
Block a user