mirror of
https://github.com/woodchen-ink/webp_server_go.git
synced 2025-07-18 13:42:02 +08:00
Feature: Add Compression rate on header (#59)
* Add X-Compression-Rate on response header * add test case for compression rate, change logging and other improvements * move config to config.go, add header for safari and proxyMode, logging improvement * update gitignore for remote-raw and coverage.txt * Refine log level
This commit is contained in:
parent
1881ae83cc
commit
9eda9ee799
2
.gitignore
vendored
2
.gitignore
vendored
@ -19,3 +19,5 @@ exhaust/
|
|||||||
/.idea/modules.xml
|
/.idea/modules.xml
|
||||||
/.idea/vcs.xml
|
/.idea/vcs.xml
|
||||||
/.idea/webp_server_go.iml
|
/.idea/webp_server_go.iml
|
||||||
|
remote-raw/
|
||||||
|
coverage.txt
|
59
config.go
Normal file
59
config.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// webp_server_go - config
|
||||||
|
// 2020-11-27 13:05
|
||||||
|
// Benny <benny.think@gmail.com>
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Host string `json:"HOST"`
|
||||||
|
Port string `json:"PORT"`
|
||||||
|
ImgPath string `json:"IMG_PATH"`
|
||||||
|
Quality string `json:"QUALITY"`
|
||||||
|
AllowedTypes []string `json:"ALLOWED_TYPES"`
|
||||||
|
ExhaustPath string `json:"EXHAUST_PATH"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
configPath string
|
||||||
|
jobs int
|
||||||
|
dumpConfig, dumpSystemd bool
|
||||||
|
verboseMode, showVersion bool
|
||||||
|
prefetch, proxyMode bool
|
||||||
|
|
||||||
|
config Config
|
||||||
|
version = "0.2.2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NotCompressed = "not_compressed"
|
||||||
|
WebpBigger = "webp_bigger"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
sampleConfig = `
|
||||||
|
{
|
||||||
|
"HOST": "127.0.0.1",
|
||||||
|
"PORT": "3333",
|
||||||
|
"QUALITY": "80",
|
||||||
|
"IMG_PATH": "./pics",
|
||||||
|
"EXHAUST_PATH": "./exhaust",
|
||||||
|
"ALLOWED_TYPES": ["jpg","png","jpeg","bmp"]
|
||||||
|
}`
|
||||||
|
|
||||||
|
sampleSystemd = `
|
||||||
|
[Unit]
|
||||||
|
Description=WebP Server Go
|
||||||
|
Documentation=https://github.com/webp-sh/webp_server_go
|
||||||
|
After=nginx.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
StandardError=journal
|
||||||
|
WorkingDirectory=/opt/webps
|
||||||
|
ExecStart=/opt/webps/webp-server --config /opt/webps/config.json
|
||||||
|
Restart=always
|
||||||
|
RestartSec=3s
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target`
|
||||||
|
)
|
20
helper.go
20
helper.go
@ -91,7 +91,7 @@ func cleanProxyCache(cacheImagePath string) {
|
|||||||
// Delete /node.png*
|
// Delete /node.png*
|
||||||
files, err := filepath.Glob(cacheImagePath + "*")
|
files, err := filepath.Glob(cacheImagePath + "*")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
log.Infoln(err)
|
||||||
}
|
}
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
if err := os.Remove(f); err != nil {
|
if err := os.Remove(f); err != nil {
|
||||||
@ -108,7 +108,7 @@ func genWebpAbs(RawImagePath string, ExhaustPath string, ImgFilename string, req
|
|||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
ModifiedTime := STAT.ModTime().Unix()
|
ModifiedTime := STAT.ModTime().Unix()
|
||||||
// webpFilename: abc.jpg.png -> abc.jpg.png1582558990.webp
|
// webpFilename: abc.jpg.png -> abc.jpg.png.1582558990.webp
|
||||||
WebpFilename := fmt.Sprintf("%s.%d.webp", ImgFilename, ModifiedTime)
|
WebpFilename := fmt.Sprintf("%s.%d.webp", ImgFilename, ModifiedTime)
|
||||||
cwd, _ := os.Getwd()
|
cwd, _ := os.Getwd()
|
||||||
|
|
||||||
@ -127,6 +127,22 @@ func genEtag(ImgAbsPath string) string {
|
|||||||
return fmt.Sprintf(`W/"%d-%08X"`, len(data), crc)
|
return fmt.Sprintf(`W/"%d-%08X"`, len(data), crc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCompressionRate(RawImagePath string, webpAbsPath string) string {
|
||||||
|
originFileInfo, err := os.Stat(RawImagePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("fail to get raw image %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
webpFileInfo, err := os.Stat(webpAbsPath)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("fail to get webp image %v", err)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
compressionRate := float64(webpFileInfo.Size()) / float64(originFileInfo.Size())
|
||||||
|
log.Debugf("The compress rate is %d/%d=%.2f", originFileInfo.Size(), webpFileInfo.Size(), compressionRate)
|
||||||
|
return fmt.Sprintf(`%.2f`, compressionRate)
|
||||||
|
}
|
||||||
|
|
||||||
func goOrigin(UA string) bool {
|
func goOrigin(UA string) bool {
|
||||||
// for more information, please check test case
|
// for more information, please check test case
|
||||||
if strings.Contains(UA, "Firefox") || strings.Contains(UA, "Chrome") {
|
if strings.Contains(UA, "Firefox") || strings.Contains(UA, "Chrome") {
|
||||||
|
@ -157,3 +157,18 @@ func TestCleanProxyCache(t *testing.T) {
|
|||||||
// test bad dir
|
// test bad dir
|
||||||
cleanProxyCache("/aasdyg/dhj2/dagh")
|
cleanProxyCache("/aasdyg/dhj2/dagh")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetCompressionRate(t *testing.T) {
|
||||||
|
pic1 := "pics/webp_server.bmp"
|
||||||
|
pic2 := "pics/webp_server.jpg"
|
||||||
|
var ratio string
|
||||||
|
|
||||||
|
ratio = getCompressionRate(pic1, pic2)
|
||||||
|
assert.Equal(t, "0.16", ratio)
|
||||||
|
|
||||||
|
ratio = getCompressionRate(pic1, "pic2")
|
||||||
|
assert.Equal(t, "", ratio)
|
||||||
|
|
||||||
|
ratio = getCompressionRate("pic1", pic2)
|
||||||
|
assert.Equal(t, "", ratio)
|
||||||
|
}
|
||||||
|
17
router.go
17
router.go
@ -20,16 +20,17 @@ func convert(c *fiber.Ctx) error {
|
|||||||
var imgFilename = path.Base(reqURI) // pure filename, 123.jpg
|
var imgFilename = path.Base(reqURI) // pure filename, 123.jpg
|
||||||
var finalFile string // We'll only need one c.sendFile()
|
var finalFile string // We'll only need one c.sendFile()
|
||||||
var UA = c.Get("User-Agent")
|
var UA = c.Get("User-Agent")
|
||||||
done := goOrigin(UA)
|
log.Debugf("Incoming connection from %s@%s with %s", UA, c.IP(), imgFilename)
|
||||||
if done {
|
|
||||||
|
needOrigin := goOrigin(UA)
|
||||||
|
if needOrigin {
|
||||||
log.Infof("A Safari/IE/whatever user has arrived...%s", UA)
|
log.Infof("A Safari/IE/whatever user has arrived...%s", UA)
|
||||||
// Check for Safari users. If they're Safari, just simply ignore everything.
|
// Check for Safari users. If they're Safari, just simply ignore everything.
|
||||||
|
|
||||||
etag := genEtag(rawImageAbs)
|
etag := genEtag(rawImageAbs)
|
||||||
c.Set("ETag", etag)
|
c.Set("ETag", etag)
|
||||||
|
c.Set("X-Compression-Rate", NotCompressed)
|
||||||
return c.SendFile(rawImageAbs)
|
return c.SendFile(rawImageAbs)
|
||||||
}
|
}
|
||||||
log.Debugf("Incoming connection from %s@%s with %s", UA, c.IP(), imgFilename)
|
|
||||||
|
|
||||||
// check ext
|
// check ext
|
||||||
var allowed = false
|
var allowed = false
|
||||||
@ -43,6 +44,7 @@ func convert(c *fiber.Ctx) error {
|
|||||||
allowed = false
|
allowed = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !allowed {
|
if !allowed {
|
||||||
msg := "File extension not allowed! " + imgFilename
|
msg := "File extension not allowed! " + imgFilename
|
||||||
log.Warn(msg)
|
log.Warn(msg)
|
||||||
@ -60,7 +62,7 @@ func convert(c *fiber.Ctx) error {
|
|||||||
// https://test.webp.sh/node.png
|
// https://test.webp.sh/node.png
|
||||||
realRemoteAddr := config.ImgPath + reqURI
|
realRemoteAddr := config.ImgPath + reqURI
|
||||||
// Ping Remote for status code and etag info
|
// Ping Remote for status code and etag info
|
||||||
fmt.Println("Remote Addr is " + realRemoteAddr + ", fetching..")
|
log.Infof("Remote Addr is %s fetching", realRemoteAddr)
|
||||||
statusCode, etagValue := getRemoteImageInfo(realRemoteAddr)
|
statusCode, etagValue := getRemoteImageInfo(realRemoteAddr)
|
||||||
if statusCode == 200 {
|
if statusCode == 200 {
|
||||||
// Check local path: /node.png-etag-<etagValue>
|
// Check local path: /node.png-etag-<etagValue>
|
||||||
@ -77,7 +79,7 @@ func convert(c *fiber.Ctx) error {
|
|||||||
_ = os.MkdirAll(path.Dir(localEtagImagePath), 0755)
|
_ = os.MkdirAll(path.Dir(localEtagImagePath), 0755)
|
||||||
err := webpEncoder(localRemoteTmpPath, localEtagImagePath, float32(q), true, nil)
|
err := webpEncoder(localRemoteTmpPath, localEtagImagePath, float32(q), true, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
log.Warning(err)
|
||||||
}
|
}
|
||||||
return c.SendFile(localEtagImagePath)
|
return c.SendFile(localEtagImagePath)
|
||||||
}
|
}
|
||||||
@ -130,13 +132,14 @@ func convert(c *fiber.Ctx) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
_ = c.SendStatus(400)
|
_ = c.SendStatus(400)
|
||||||
_ = c.Send([]byte("Bad file!"))
|
_ = c.Send([]byte("Bad file. " + err.Error()))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
finalFile = webpAbsPath
|
finalFile = webpAbsPath
|
||||||
}
|
}
|
||||||
etag := genEtag(finalFile)
|
etag := genEtag(finalFile)
|
||||||
c.Set("ETag", etag)
|
c.Set("ETag", etag)
|
||||||
|
c.Set("X-Compression-Rate", getCompressionRate(rawImageAbs, webpAbsPath))
|
||||||
return c.SendFile(finalFile)
|
return c.SendFile(finalFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,44 @@ var (
|
|||||||
SafariUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15"
|
SafariUA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_4) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.1 Safari/605.1.15"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func setupParam() {
|
||||||
|
// setup parameters here...
|
||||||
|
config.ImgPath = "./pics"
|
||||||
|
config.ExhaustPath = "./exhaust"
|
||||||
|
config.AllowedTypes = []string{"jpg", "png", "jpeg", "bmp"}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestToServer(url string, app *fiber.App, ua string) (*http.Response, []byte) {
|
||||||
|
req := httptest.NewRequest("GET", url, nil)
|
||||||
|
req.Header.Set("User-Agent", ua)
|
||||||
|
resp, _ := app.Test(req, 60000)
|
||||||
|
data, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
return resp, data
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerHeaders(t *testing.T) {
|
||||||
|
setupParam()
|
||||||
|
var app = fiber.New()
|
||||||
|
app.Get("/*", convert)
|
||||||
|
url := "http://127.0.0.1:3333/webp_server.bmp"
|
||||||
|
|
||||||
|
// test for chrome
|
||||||
|
response, _ := requestToServer(url, app, chromeUA)
|
||||||
|
ratio := response.Header.Get("X-Compression-Rate")
|
||||||
|
etag := response.Header.Get("Etag")
|
||||||
|
|
||||||
|
assert.NotEqual(t, "", ratio)
|
||||||
|
assert.NotEqual(t, "", etag)
|
||||||
|
|
||||||
|
// test for safari
|
||||||
|
response, _ = requestToServer(url, app, SafariUA)
|
||||||
|
ratio = response.Header.Get("X-Compression-Rate")
|
||||||
|
etag = response.Header.Get("Etag")
|
||||||
|
|
||||||
|
assert.Equal(t, NotCompressed, ratio)
|
||||||
|
assert.NotEqual(t, "", etag)
|
||||||
|
}
|
||||||
|
|
||||||
func TestConvert(t *testing.T) {
|
func TestConvert(t *testing.T) {
|
||||||
setupParam()
|
setupParam()
|
||||||
var testChromeLink = map[string]string{
|
var testChromeLink = map[string]string{
|
||||||
@ -108,20 +146,4 @@ func TestConvertProxyModeWork(t *testing.T) {
|
|||||||
resp, data := requestToServer(url, app, chromeUA)
|
resp, data := requestToServer(url, app, chromeUA)
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
assert.Equal(t, "image/webp", getFileContentType(data))
|
assert.Equal(t, "image/webp", getFileContentType(data))
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupParam() {
|
|
||||||
// setup parameters here...
|
|
||||||
config.ImgPath = "./pics"
|
|
||||||
config.ExhaustPath = "./exhaust"
|
|
||||||
config.AllowedTypes = []string{"jpg", "png", "jpeg", "bmp"}
|
|
||||||
}
|
|
||||||
|
|
||||||
func requestToServer(url string, app *fiber.App, ua string) (*http.Response, []byte) {
|
|
||||||
req := httptest.NewRequest("GET", url, nil)
|
|
||||||
req.Header.Set("User-Agent", ua)
|
|
||||||
resp, _ := app.Test(req, 60000)
|
|
||||||
data, _ := ioutil.ReadAll(resp.Body)
|
|
||||||
return resp, data
|
|
||||||
}
|
}
|
||||||
|
@ -12,54 +12,6 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
Host string `json:"HOST"`
|
|
||||||
Port string `json:"PORT"`
|
|
||||||
ImgPath string `json:"IMG_PATH"`
|
|
||||||
Quality string `json:"QUALITY"`
|
|
||||||
AllowedTypes []string `json:"ALLOWED_TYPES"`
|
|
||||||
ExhaustPath string `json:"EXHAUST_PATH"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
configPath string
|
|
||||||
jobs int
|
|
||||||
dumpConfig, dumpSystemd, verboseMode, prefetch, showVersion bool
|
|
||||||
|
|
||||||
proxyMode bool
|
|
||||||
config Config
|
|
||||||
version = "0.2.2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
sampleConfig = `
|
|
||||||
{
|
|
||||||
"HOST": "127.0.0.1",
|
|
||||||
"PORT": "3333",
|
|
||||||
"QUALITY": "80",
|
|
||||||
"IMG_PATH": "./pics",
|
|
||||||
"EXHAUST_PATH": "./exhaust",
|
|
||||||
"ALLOWED_TYPES": ["jpg","png","jpeg","bmp"]
|
|
||||||
}`
|
|
||||||
|
|
||||||
sampleSystemd = `
|
|
||||||
[Unit]
|
|
||||||
Description=WebP Server Go
|
|
||||||
Documentation=https://github.com/webp-sh/webp_server_go
|
|
||||||
After=nginx.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
StandardError=journal
|
|
||||||
WorkingDirectory=/opt/webps
|
|
||||||
ExecStart=/opt/webps/webp-server --config /opt/webps/config.json
|
|
||||||
Restart=always
|
|
||||||
RestartSec=3s
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target`
|
|
||||||
)
|
|
||||||
|
|
||||||
func loadConfig(path string) Config {
|
func loadConfig(path string) Config {
|
||||||
jsonObject, err := os.Open(path)
|
jsonObject, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user