Benny a7b5992662
Metadata (#251)
* recover middleware

* simplify Atoi

* metadata data prototype

* InterestingAttention

* resize itself

* Bump version to 0.9.4
Added some comments
Removed String() for Extraparams

* Add metadata test

* Fix CI

* Remove unnecessary tests

* Update file count

* use t.Run to get test case

---------

Co-authored-by: n0vad3v <n0vad3v@riseup.net>
2023-07-11 19:08:32 +02:00

115 lines
3.0 KiB
Go

package handler
import (
"bytes"
"net/http"
"os"
"path"
"path/filepath"
"strings"
"webp_server_go/config"
"webp_server_go/helper"
"github.com/gofiber/fiber/v2"
"github.com/h2non/filetype"
log "github.com/sirupsen/logrus"
)
// Given /path/to/node.png
// Delete /path/to/node.png*
func cleanProxyCache(cacheImagePath string) {
// Delete /node.png*
files, err := filepath.Glob(cacheImagePath + "*")
if err != nil {
log.Infoln(err)
}
for _, f := range files {
if err := os.Remove(f); err != nil {
log.Info(err)
}
}
}
func downloadFile(filepath string, url string) {
resp, err := http.Get(url)
if err != nil {
log.Errorln("Connection to remote error when downloadFile!")
return
}
defer resp.Body.Close()
if resp.StatusCode != fiber.StatusOK {
log.Errorf("remote returned %s when fetching remote image", resp.Status)
return
}
// Copy bytes here
bodyBytes := new(bytes.Buffer)
_, err = bodyBytes.ReadFrom(resp.Body)
if err != nil {
return
}
// Check if remote content-type is image using check by filetype instead of content-type returned by origin
kind, _ := filetype.Match(bodyBytes.Bytes())
mime := kind.MIME.Value
if !strings.Contains(mime, "image") {
log.Errorf("remote file %s is not image, remote content has MIME type of %s", url, mime)
return
}
_ = os.MkdirAll(path.Dir(filepath), 0755)
// Create Cache here as a lock, so we can prevent incomplete file from being read
// Key: filepath, Value: true
config.WriteLock.Set(filepath, true, -1)
err = os.WriteFile(filepath, bodyBytes.Bytes(), 0600)
if err != nil {
// not likely to happen
return
}
// Delete lock here
config.WriteLock.Delete(filepath)
}
func fetchRemoteImg(url string) config.MetaFile {
// url is https://test.webp.sh/mypic/123.jpg?someother=200&somebugs=200
// How do we know if the remote img is changed? we're using hash(etag+length)
log.Infof("Remote Addr is %s, pinging for info...", url)
etag := pingURL(url)
metadata := helper.ReadMetadata(url, etag)
localRawImagePath := path.Join(config.RemoteRaw, metadata.Id)
if !helper.ImageExists(localRawImagePath) || metadata.Checksum != helper.HashString(etag) {
// remote file has changed or local file not exists
log.Info("Remote file not found in remote-raw, re-fetching...")
cleanProxyCache(path.Join(config.Config.ExhaustPath, metadata.Id+"*"))
downloadFile(localRawImagePath, url)
}
return metadata
}
func pingURL(url string) string {
// this function will try to return identifiable info, currently include etag, content-length as string
// anything goes wrong, will return ""
var etag, length string
resp, err := http.Head(url)
if err != nil {
log.Errorln("Connection to remote error when pingUrl!")
return ""
}
defer resp.Body.Close()
if resp.StatusCode == fiber.StatusOK {
etag = resp.Header.Get("etag")
length = resp.Header.Get("content-length")
}
if etag == "" {
log.Info("Remote didn't return etag in header when getRemoteImageInfo, please check.")
}
return etag + length
}