implemented waiting for free thumb generator

Signed-off-by: Aleksandr Dubovikov <d.lexand@gmail.com>
This commit is contained in:
ad 2024-09-29 19:36:08 +02:00 committed by Aleksandr Dubovikov
parent 5845244aa9
commit 46473c1bf0

View file

@ -27,9 +27,12 @@ import (
"golang.org/x/net/html" "golang.org/x/net/html"
) )
var ErrorMissingUrl = errors.New("missing url") var (
var ErrorUnsupportedContentType = errors.New("unsupported content type") ErrorMissingUrl = errors.New("missing url")
var ErrorFileTooLarge = errors.New("file too large") ErrorUnsupportedContentType = errors.New("unsupported content type")
ErrorFileTooLarge = errors.New("file too large")
ErrorTimeoutThumbnailGenerator = errors.New("timeout waiting for thumbnail generator")
)
func makeUrlPreviewHandler( func makeUrlPreviewHandler(
cfg *config.MediaAPI, cfg *config.MediaAPI,
@ -138,16 +141,23 @@ func makeUrlPreviewHandler(
defer resp.Body.Close() defer resp.Body.Close()
var result *types.UrlPreview var result *types.UrlPreview
var err error
var imgUrl *url.URL
var imgReader *http.Response var imgReader *http.Response
var mediaData *types.MediaMetadata
if strings.HasPrefix(resp.Header.Get("Content-Type"), "text/html") { if strings.HasPrefix(resp.Header.Get("Content-Type"), "text/html") {
result, err = getPreviewFromHTML(resp, pUrl) result, err = getPreviewFromHTML(resp, pUrl)
if err == nil && result.ImageUrl != "" { if err == nil && result.ImageUrl != "" {
if imgUrl, err := url.Parse(result.ImageUrl); err == nil { if imgUrl, err = url.Parse(result.ImageUrl); err == nil {
imgReader, err = downloadUrl(result.ImageUrl, time.Duration(cfg.UrlPreviewTimeout)*time.Second) imgReader, err = downloadUrl(result.ImageUrl, time.Duration(cfg.UrlPreviewTimeout)*time.Second)
if err == nil { if err == nil {
mediaData, err := downloadAndStoreImage(imgUrl.Path, req.Context(), imgReader, cfg, device, db, activeThumbnailGeneration, logger) mediaData, err = downloadAndStoreImage(imgUrl.Path, req.Context(), imgReader, cfg, device, db, activeThumbnailGeneration, logger)
if err == nil { if err == nil {
result.ImageUrl = fmt.Sprintf("mxc://%s/%s", mediaData.Origin, mediaData.MediaID) result.ImageUrl = fmt.Sprintf("mxc://%s/%s", mediaData.Origin, mediaData.MediaID)
} else {
// We don't show the orginal URL as it is insecure for the room users
result.ImageUrl = ""
} }
} }
} }
@ -306,6 +316,22 @@ func downloadAndStoreImage(
// Create a thumbnail from the image // Create a thumbnail from the image
thumbnailPath := tmpFileName + ".thumbnail" thumbnailPath := tmpFileName + ".thumbnail"
// Check if we have too many thumbnail generators running
// If so, wait up to 30 seconds for one to finish
timeout := time.After(30 * time.Second)
for {
if len(activeThumbnailGeneration.PathToResult) < cfg.MaxThumbnailGenerators {
activeThumbnailGeneration.Lock()
activeThumbnailGeneration.PathToResult[string(hash)] = nil
activeThumbnailGeneration.Unlock()
defer func() {
activeThumbnailGeneration.Lock()
delete(activeThumbnailGeneration.PathToResult, string(hash))
activeThumbnailGeneration.Unlock()
}()
err = thumbnailer.CreateThumbnailFromFile(types.Path(tmpFileName), types.Path(thumbnailPath), types.ThumbnailSize(cfg.UrlPreviewThumbnailSize), logger) err = thumbnailer.CreateThumbnailFromFile(types.Path(tmpFileName), types.Path(thumbnailPath), types.ThumbnailSize(cfg.UrlPreviewThumbnailSize), logger)
if err != nil { if err != nil {
if errors.Is(err, thumbnailer.ErrThumbnailTooLarge) { if errors.Is(err, thumbnailer.ErrThumbnailTooLarge) {
@ -315,7 +341,18 @@ func downloadAndStoreImage(
return nil, err return nil, err
} }
} }
logger.Debug("thumbnail created", thumbnailPath) break
}
select {
case <-timeout:
logger.Error("timed out waiting for thumbnail generator")
return nil, ErrorTimeoutThumbnailGenerator
default:
time.Sleep(time.Second)
}
}
thumbnailFileInfo, err := os.Stat(string(thumbnailPath)) thumbnailFileInfo, err := os.Stat(string(thumbnailPath))
if err != nil { if err != nil {
logger.WithError(err).Error("unable to get thumbnail file info") logger.WithError(err).Error("unable to get thumbnail file info")
@ -345,7 +382,7 @@ func downloadAndStoreImage(
Base64Hash: hash, Base64Hash: hash,
UserID: userid, UserID: userid,
} }
fmt.Println("mediaMetaData", mediaMetaData)
finalPath, err := fileutils.GetPathFromBase64Hash(mediaMetaData.Base64Hash, cfg.AbsBasePath) finalPath, err := fileutils.GetPathFromBase64Hash(mediaMetaData.Base64Hash, cfg.AbsBasePath)
if err != nil { if err != nil {
logger.WithError(err).Error("unable to get path from base64 hash") logger.WithError(err).Error("unable to get path from base64 hash")