mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Suppress benign broken pipe and context closed warnings (#2927)
This commit is contained in:
parent
5e97ecd260
commit
8efbcc1c4d
11 changed files with 172 additions and 105 deletions
|
|
@ -6,6 +6,7 @@ import (
|
|||
"net/http"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stashapp/stash/internal/manager"
|
||||
|
|
@ -84,11 +85,11 @@ func (rs imageRoutes) Thumbnail(w http.ResponseWriter, r *http.Request) {
|
|||
if manager.GetInstance().Config.IsWriteImageThumbnails() {
|
||||
logger.Debugf("writing thumbnail to disk: %s", img.Path)
|
||||
if err := fsutil.WriteFile(filepath, data); err != nil {
|
||||
logger.Errorf("error writing thumbnail for image %s: %s", img.Path, err)
|
||||
logger.Errorf("error writing thumbnail for image %s: %v", img.Path, err)
|
||||
}
|
||||
}
|
||||
if n, err := w.Write(data); err != nil {
|
||||
logger.Errorf("error writing thumbnail response. Wrote %v bytes: %v", n, err)
|
||||
if n, err := w.Write(data); err != nil && !errors.Is(err, syscall.EPIPE) {
|
||||
logger.Errorf("error serving thumbnail (wrote %v bytes out of %v): %v", n, len(data), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -114,7 +115,7 @@ func (rs imageRoutes) ImageCtx(next http.Handler) http.Handler {
|
|||
imageID, _ := strconv.Atoi(imageIdentifierQueryParam)
|
||||
|
||||
var image *models.Image
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
qb := rs.imageFinder
|
||||
if imageID == 0 {
|
||||
images, _ := qb.FindByChecksum(ctx, imageIdentifierQueryParam)
|
||||
|
|
@ -131,10 +132,6 @@ func (rs imageRoutes) ImageCtx(next http.Handler) http.Handler {
|
|||
|
||||
return nil
|
||||
})
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction failure while trying to read image by id: %v", readTxnErr)
|
||||
}
|
||||
|
||||
if image == nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package api
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
|
|
@ -40,12 +41,15 @@ func (rs movieRoutes) FrontImage(w http.ResponseWriter, r *http.Request) {
|
|||
defaultParam := r.URL.Query().Get("default")
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
image, _ = rs.movieFinder.GetFrontImage(ctx, movie.ID)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warnf("read transaction error while getting front image: %v", err)
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch movie front image: %v", readTxnErr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +58,7 @@ func (rs movieRoutes) FrontImage(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if err := utils.ServeImage(image, w, r); err != nil {
|
||||
logger.Warnf("error serving front image: %v", err)
|
||||
logger.Warnf("error serving movie front image: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,12 +67,15 @@ func (rs movieRoutes) BackImage(w http.ResponseWriter, r *http.Request) {
|
|||
defaultParam := r.URL.Query().Get("default")
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
image, _ = rs.movieFinder.GetBackImage(ctx, movie.ID)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warnf("read transaction error on fetch back image: %v", err)
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch movie back image: %v", readTxnErr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +84,7 @@ func (rs movieRoutes) BackImage(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if err := utils.ServeImage(image, w, r); err != nil {
|
||||
logger.Warnf("error while serving image: %v", err)
|
||||
logger.Warnf("error serving movie back image: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,11 +97,11 @@ func (rs movieRoutes) MovieCtx(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
var movie *models.Movie
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
movie, err = rs.movieFinder.Find(ctx, movieID)
|
||||
return err
|
||||
}); err != nil {
|
||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
movie, _ = rs.movieFinder.Find(ctx, movieID)
|
||||
return nil
|
||||
})
|
||||
if movie == nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package api
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
|
|
@ -44,8 +45,11 @@ func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
|||
image, _ = rs.performerFinder.GetImage(ctx, performer.ID)
|
||||
return nil
|
||||
})
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("couldn't execute getting a performer image from read transaction: %v", readTxnErr)
|
||||
logger.Warnf("read transaction error on fetch performer image: %v", readTxnErr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +58,7 @@ func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if err := utils.ServeImage(image, w, r); err != nil {
|
||||
logger.Warnf("error serving image: %v", err)
|
||||
logger.Warnf("error serving performer image: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,11 +71,12 @@ func (rs performerRoutes) PerformerCtx(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
var performer *models.Performer
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
performer, err = rs.performerFinder.Find(ctx, performerID)
|
||||
return err
|
||||
}); err != nil {
|
||||
})
|
||||
if performer == nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package api
|
|||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -253,12 +254,12 @@ func (rs sceneRoutes) Webp(w http.ResponseWriter, r *http.Request) {
|
|||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) getChapterVttTitle(ctx context.Context, marker *models.SceneMarker) string {
|
||||
func (rs sceneRoutes) getChapterVttTitle(ctx context.Context, marker *models.SceneMarker) (*string, error) {
|
||||
if marker.Title != "" {
|
||||
return marker.Title
|
||||
return &marker.Title, nil
|
||||
}
|
||||
|
||||
var ret string
|
||||
var title string
|
||||
if err := txn.WithTxn(ctx, rs.txnManager, func(ctx context.Context) error {
|
||||
qb := rs.tagFinder
|
||||
primaryTag, err := qb.Find(ctx, marker.PrimaryTagID)
|
||||
|
|
@ -266,7 +267,7 @@ func (rs sceneRoutes) getChapterVttTitle(ctx context.Context, marker *models.Sce
|
|||
return err
|
||||
}
|
||||
|
||||
ret = primaryTag.Name
|
||||
title = primaryTag.Name
|
||||
|
||||
tags, err := qb.FindBySceneMarkerID(ctx, marker.ID)
|
||||
if err != nil {
|
||||
|
|
@ -274,26 +275,31 @@ func (rs sceneRoutes) getChapterVttTitle(ctx context.Context, marker *models.Sce
|
|||
}
|
||||
|
||||
for _, t := range tags {
|
||||
ret += ", " + t.Name
|
||||
title += ", " + t.Name
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ret
|
||||
return &title, nil
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) ChapterVtt(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||
var sceneMarkers []*models.SceneMarker
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
sceneMarkers, err = rs.sceneMarkerFinder.FindBySceneID(ctx, scene.ID)
|
||||
return err
|
||||
}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
})
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch scene markers: %v", readTxnErr)
|
||||
http.Error(w, readTxnErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -302,7 +308,18 @@ func (rs sceneRoutes) ChapterVtt(w http.ResponseWriter, r *http.Request) {
|
|||
vttLines = append(vttLines, strconv.Itoa(i+1))
|
||||
time := utils.GetVTTTime(marker.Seconds)
|
||||
vttLines = append(vttLines, time+" --> "+time)
|
||||
vttLines = append(vttLines, rs.getChapterVttTitle(r.Context(), marker))
|
||||
|
||||
vttTitle, err := rs.getChapterVttTitle(r.Context(), marker)
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
logger.Warnf("read transaction error on fetch scene marker title: %v", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
vttLines = append(vttLines, *vttTitle)
|
||||
vttLines = append(vttLines, "")
|
||||
}
|
||||
vtt := strings.Join(vttLines, "\n")
|
||||
|
|
@ -327,35 +344,50 @@ func (rs sceneRoutes) InteractiveHeatmap(w http.ResponseWriter, r *http.Request)
|
|||
func (rs sceneRoutes) Caption(w http.ResponseWriter, r *http.Request, lang string, ext string) {
|
||||
s := r.Context().Value(sceneKey).(*models.Scene)
|
||||
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var captions []*models.VideoCaption
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
primaryFile := s.Files.Primary()
|
||||
if primaryFile == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
captions, err := rs.captionFinder.GetCaptions(ctx, primaryFile.Base().ID)
|
||||
for _, caption := range captions {
|
||||
if lang == caption.LanguageCode && ext == caption.CaptionType {
|
||||
sub, err := video.ReadSubs(caption.Path(s.Path))
|
||||
if err == nil {
|
||||
var b bytes.Buffer
|
||||
err = sub.WriteToWebVTT(&b)
|
||||
if err == nil {
|
||||
w.Header().Set("Content-Type", "text/vtt")
|
||||
w.Header().Add("Cache-Control", "no-cache")
|
||||
_, _ = b.WriteTo(w)
|
||||
}
|
||||
return err
|
||||
}
|
||||
logger.Debugf("Error while reading subs: %v", err)
|
||||
}
|
||||
}
|
||||
captions, err = rs.captionFinder.GetCaptions(ctx, primaryFile.Base().ID)
|
||||
|
||||
return err
|
||||
}); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
})
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch scene captions: %v", readTxnErr)
|
||||
http.Error(w, readTxnErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
for _, caption := range captions {
|
||||
if lang != caption.LanguageCode || ext != caption.CaptionType {
|
||||
return
|
||||
}
|
||||
|
||||
sub, err := video.ReadSubs(caption.Path(s.Path))
|
||||
if err != nil {
|
||||
logger.Warnf("error while reading subs: %v", err)
|
||||
http.Error(w, readTxnErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
err = sub.WriteToWebVTT(&b)
|
||||
if err != nil {
|
||||
http.Error(w, readTxnErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/vtt")
|
||||
w.Header().Add("Cache-Control", "no-cache")
|
||||
_, _ = b.WriteTo(w)
|
||||
}
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) CaptionLang(w http.ResponseWriter, r *http.Request) {
|
||||
|
|
@ -387,13 +419,17 @@ func (rs sceneRoutes) SceneMarkerStream(w http.ResponseWriter, r *http.Request)
|
|||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||
var sceneMarker *models.SceneMarker
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||
return err
|
||||
}); err != nil {
|
||||
logger.Warnf("Error when getting scene marker for stream: %s", err.Error())
|
||||
http.Error(w, http.StatusText(500), 500)
|
||||
})
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch scene marker: %v", readTxnErr)
|
||||
http.Error(w, readTxnErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -410,13 +446,17 @@ func (rs sceneRoutes) SceneMarkerPreview(w http.ResponseWriter, r *http.Request)
|
|||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||
var sceneMarker *models.SceneMarker
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||
return err
|
||||
}); err != nil {
|
||||
logger.Warnf("Error when getting scene marker for stream: %s", err.Error())
|
||||
http.Error(w, http.StatusText(500), 500)
|
||||
})
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch scene marker preview: %v", readTxnErr)
|
||||
http.Error(w, readTxnErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -443,13 +483,17 @@ func (rs sceneRoutes) SceneMarkerScreenshot(w http.ResponseWriter, r *http.Reque
|
|||
scene := r.Context().Value(sceneKey).(*models.Scene)
|
||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||
var sceneMarker *models.SceneMarker
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
sceneMarker, err = rs.sceneMarkerFinder.Find(ctx, sceneMarkerID)
|
||||
return err
|
||||
}); err != nil {
|
||||
logger.Warnf("Error when getting scene marker for stream: %s", err.Error())
|
||||
http.Error(w, http.StatusText(500), 500)
|
||||
})
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch scene marker screenshot: %v", readTxnErr)
|
||||
http.Error(w, readTxnErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -480,7 +524,7 @@ func (rs sceneRoutes) SceneCtx(next http.Handler) http.Handler {
|
|||
sceneID, _ := strconv.Atoi(sceneIdentifierQueryParam)
|
||||
|
||||
var scene *models.Scene
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
qb := rs.sceneFinder
|
||||
if sceneID == 0 {
|
||||
var scenes []*models.Scene
|
||||
|
|
@ -505,10 +549,6 @@ func (rs sceneRoutes) SceneCtx(next http.Handler) http.Handler {
|
|||
|
||||
return nil
|
||||
})
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("error executing SceneCtx transaction: %v", readTxnErr)
|
||||
}
|
||||
|
||||
if scene == nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import (
|
|||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
|
|
@ -42,12 +41,15 @@ func (rs studioRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
image, _ = rs.studioFinder.GetImage(ctx, studio.ID)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warnf("read transaction error while fetching studio image: %v", err)
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch studio image: %v", readTxnErr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,12 +58,7 @@ func (rs studioRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
if err := utils.ServeImage(image, w, r); err != nil {
|
||||
// Broken pipe errors are common when serving images and the remote
|
||||
// connection closes the connection. Filter them out of the error
|
||||
// messages, as they are benign.
|
||||
if !errors.Is(err, syscall.EPIPE) {
|
||||
logger.Warnf("cannot serve studio image: %v", err)
|
||||
}
|
||||
logger.Warnf("error serving studio image: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -74,11 +71,12 @@ func (rs studioRoutes) StudioCtx(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
var studio *models.Studio
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
studio, err = rs.studioFinder.Find(ctx, studioID)
|
||||
return err
|
||||
}); err != nil {
|
||||
})
|
||||
if studio == nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package api
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
|
|
@ -40,12 +41,15 @@ func (rs tagRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
var image []byte
|
||||
if defaultParam != "true" {
|
||||
err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
image, _ = rs.tagFinder.GetImage(ctx, tag.ID)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warnf("read transaction error while getting tag image: %v", err)
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch tag image: %v", readTxnErr)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -67,11 +71,12 @@ func (rs tagRoutes) TagCtx(next http.Handler) http.Handler {
|
|||
}
|
||||
|
||||
var tag *models.Tag
|
||||
if err := txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
_ = txn.WithTxn(r.Context(), rs.txnManager, func(ctx context.Context) error {
|
||||
var err error
|
||||
tag, err = rs.tagFinder.Find(ctx, tagID)
|
||||
return err
|
||||
}); err != nil {
|
||||
})
|
||||
if tag == nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package manager
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/stashapp/stash/internal/manager/config"
|
||||
|
|
@ -81,16 +82,21 @@ func (s *SceneServer) ServeScreenshot(scene *models.Scene, w http.ResponseWriter
|
|||
http.ServeFile(w, r, filepath)
|
||||
} else {
|
||||
var cover []byte
|
||||
err := txn.WithTxn(r.Context(), s.TxnManager, func(ctx context.Context) error {
|
||||
readTxnErr := txn.WithTxn(r.Context(), s.TxnManager, func(ctx context.Context) error {
|
||||
cover, _ = s.SceneCoverGetter.GetCover(ctx, scene.ID)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
logger.Warnf("read transaction failed while serving screenshot: %v", err)
|
||||
if errors.Is(readTxnErr, context.Canceled) {
|
||||
return
|
||||
}
|
||||
if readTxnErr != nil {
|
||||
logger.Warnf("read transaction error on fetch screenshot: %v", readTxnErr)
|
||||
http.Error(w, readTxnErr.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err = utils.ServeImage(cover, w, r); err != nil {
|
||||
logger.Warnf("unable to serve screenshot image: %v", err)
|
||||
if err := utils.ServeImage(cover, w, r); err != nil {
|
||||
logger.Warnf("error serving screenshot image: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ package ffmpeg
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
)
|
||||
|
|
@ -35,8 +37,8 @@ func (s *Stream) Serve(w http.ResponseWriter, r *http.Request) {
|
|||
// process killing should be handled by command context
|
||||
|
||||
_, err := io.Copy(w, s.Stdout)
|
||||
if err != nil {
|
||||
logger.Errorf("[stream] error serving transcoded video file: %s", err.Error())
|
||||
if err != nil && !errors.Is(err, syscall.EPIPE) {
|
||||
logger.Errorf("[stream] error serving transcoded video file: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@ package file
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/stashapp/stash/pkg/logger"
|
||||
|
|
@ -137,8 +139,9 @@ func (f *BaseFile) Serve(fs FS, w http.ResponseWriter, r *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
if k, err := w.Write(data); err != nil {
|
||||
logger.Warnf("failure while serving image (wrote %v bytes out of %v): %v", k, len(data), err)
|
||||
k, err := w.Write(data)
|
||||
if err != nil && !errors.Is(err, syscall.EPIPE) {
|
||||
logger.Warnf("error serving file (wrote %v bytes out of %v): %v", k, len(data), err)
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
|||
|
|
@ -84,14 +84,10 @@ func FileExists(path string) (bool, error) {
|
|||
func WriteFile(path string, file []byte) error {
|
||||
pathErr := EnsureDirAll(filepath.Dir(path))
|
||||
if pathErr != nil {
|
||||
return fmt.Errorf("cannot ensure path %s", pathErr)
|
||||
return fmt.Errorf("cannot ensure path exists: %w", pathErr)
|
||||
}
|
||||
|
||||
err := os.WriteFile(path, file, 0755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("write error for thumbnail %s: %s ", path, err)
|
||||
}
|
||||
return nil
|
||||
return os.WriteFile(path, file, 0755)
|
||||
}
|
||||
|
||||
// GetNameFromPath returns the name of a file from its path
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@ import (
|
|||
"crypto/md5"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
|
@ -127,5 +129,11 @@ func ServeImage(image []byte, w http.ResponseWriter, r *http.Request) error {
|
|||
w.Header().Add("Etag", etag)
|
||||
w.Header().Set("Cache-Control", "public, max-age=604800, immutable")
|
||||
_, err := w.Write(image)
|
||||
// Broken pipe errors are common when serving images and the remote
|
||||
// connection closes the connection. Filter them out of the error
|
||||
// messages, as they are benign.
|
||||
if errors.Is(err, syscall.EPIPE) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue