Merge pull request #24 from webp-sh/add-log-level

Add custom log level, unsupported file returns
This commit is contained in:
Nova Kwok 2020-03-07 13:57:11 +08:00 committed by GitHub
commit e8e12ee10c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 82 additions and 40 deletions

View File

@ -6,7 +6,6 @@ go:
arch: arch:
- amd64 - amd64
- arm64 - arm64
- ppc64le
os: os:
- windows - windows

View File

@ -3,21 +3,24 @@ package main
import ( import (
"bytes" "bytes"
"errors" "errors"
"fmt"
"github.com/chai2010/webp"
"golang.org/x/image/bmp"
"image" "image"
"image/gif" "image/gif"
"image/jpeg" "image/jpeg"
"image/png" "image/png"
"io/ioutil" "io/ioutil"
"log"
"path" "path"
"strings" "strings"
log "github.com/sirupsen/logrus"
"github.com/chai2010/webp"
"golang.org/x/image/bmp"
) )
func WebpEncoder(p1, p2 string, quality float32, Log bool, c chan int) (err error) { func WebpEncoder(p1, p2 string, quality float32, Log bool, c chan int) (err error) {
// if convert fails, return error; success nil // if convert fails, return error; success nil
log.Debugf("target: %s with quality of %f", path.Base(p1), quality)
var buf bytes.Buffer var buf bytes.Buffer
var img image.Image var img image.Image
@ -36,30 +39,31 @@ func WebpEncoder(p1, p2 string, quality float32, Log bool, c chan int) (err erro
img, _ = bmp.Decode(bytes.NewReader(data)) img, _ = bmp.Decode(bytes.NewReader(data))
} else if strings.Contains(contentType, "gif") { } else if strings.Contains(contentType, "gif") {
// TODO: need to support animated webp // TODO: need to support animated webp
log.Warn("Gif support is not perfect!")
img, _ = gif.Decode(bytes.NewReader(data)) img, _ = gif.Decode(bytes.NewReader(data))
} }
if img == nil { if img == nil {
msg := "image file " + path.Base(p1) + " is corrupted or not supported" msg := "image file " + path.Base(p1) + " is corrupted or not supported"
log.Println(msg) log.Debug(msg)
err = errors.New(msg) err = errors.New(msg)
ChanErr(c) ChanErr(c)
return return
} }
if err = webp.Encode(&buf, img, &webp.Options{Lossless: false, Quality: quality}); err != nil { if err = webp.Encode(&buf, img, &webp.Options{Lossless: false, Quality: quality}); err != nil {
log.Println(err) log.Error(err)
ChanErr(c) ChanErr(c)
return return
} }
if err = ioutil.WriteFile(p2, buf.Bytes(), 0755); err != nil { if err = ioutil.WriteFile(p2, buf.Bytes(), 0755); err != nil {
log.Println(err) log.Error(err)
ChanErr(c) ChanErr(c)
return return
} }
if Log { if Log {
fmt.Printf("Save to %s ok\n", p2) log.Info("Save to " + p2 + " ok!\n")
} }
ChanErr(c) ChanErr(c)

1
go.mod
View File

@ -5,5 +5,6 @@ go 1.13
require ( require (
github.com/chai2010/webp v1.1.0 github.com/chai2010/webp v1.1.0
github.com/gofiber/fiber v1.4.0 github.com/gofiber/fiber v1.4.0
github.com/sirupsen/logrus v1.4.2
golang.org/x/image v0.0.0-20200119044424-58c23975cae1 golang.org/x/image v0.0.0-20200119044424-58c23975cae1
) )

View File

@ -2,6 +2,7 @@ package main
import ( import (
"fmt" "fmt"
log "github.com/sirupsen/logrus"
"net/http" "net/http"
"os" "os"
"path" "path"
@ -38,6 +39,7 @@ func ImageExists(filename string) bool {
if os.IsNotExist(err) { if os.IsNotExist(err) {
return false return false
} }
log.Debugf("file %s exists!", filename)
return !info.IsDir() return !info.IsDir()
} }
@ -45,7 +47,7 @@ func GenWebpAbs(RawImagePath string, ExhaustPath string, ImgFilename string, req
// get file mod time // get file mod time
STAT, err := os.Stat(RawImagePath) STAT, err := os.Stat(RawImagePath)
if err != nil { if err != nil {
fmt.Println(err.Error()) log.Error(err.Error())
} }
ModifiedTime := STAT.ModTime().Unix() ModifiedTime := STAT.ModTime().Unix()
// webpFilename: abc.jpg.png -> abc.jpg.png1582558990.webp // webpFilename: abc.jpg.png -> abc.jpg.png1582558990.webp

View File

@ -3,20 +3,23 @@ package main
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"log"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
log "github.com/sirupsen/logrus"
) )
func PrefetchImages(confImgPath string, ExhaustPath string, QUALITY string) { func PrefetchImages(confImgPath string, ExhaustPath string, QUALITY string) {
fmt.Println(`Prefetch will convert all your images to webp, it may take some time and consume a lot of CPU resource. Do you want to proceed(Y/n)`) fmt.Println(`Prefetch will convert all your images to webp,
it may take some time and consume a lot of CPU resource. Do you want to proceed(Y/n)`)
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
char, _, _ := reader.ReadRune() //y Y enter char, _, _ := reader.ReadRune() //y Y enter
// maximum ongoing prefetch is depending on your core of CPU // maximum ongoing prefetch is depending on your core of CPU
log.Printf("Prefetching using %d cores", jobs) log.Infof("Prefetching using %d cores", jobs)
var finishChan = make(chan int, jobs) var finishChan = make(chan int, jobs)
for i := 0; i < jobs; i++ { for i := 0; i < jobs; i++ {
finishChan <- 0 finishChan <- 0
@ -42,7 +45,7 @@ func PrefetchImages(confImgPath string, ExhaustPath string, QUALITY string) {
return nil return nil
}) })
if err != nil { if err != nil {
log.Println(err) log.Debug(err)
} }
} }

View File

@ -1,13 +1,14 @@
package main package main
import ( import (
"fmt" log "github.com/sirupsen/logrus"
"github.com/gofiber/fiber"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"github.com/gofiber/fiber"
) )
func Convert(ImgPath string, ExhaustPath string, AllowedTypes []string, QUALITY string) func(c *fiber.Ctx) { func Convert(ImgPath string, ExhaustPath string, AllowedTypes []string, QUALITY string) func(c *fiber.Ctx) {
@ -21,9 +22,11 @@ func Convert(ImgPath string, ExhaustPath string, AllowedTypes []string, QUALITY
UA := c.Get("User-Agent") UA := c.Get("User-Agent")
if strings.Contains(UA, "Safari") && !strings.Contains(UA, "Chrome") && if strings.Contains(UA, "Safari") && !strings.Contains(UA, "Chrome") &&
!strings.Contains(UA, "Firefox") { !strings.Contains(UA, "Firefox") {
log.Info("A Safari use has arrived...")
c.SendFile(RawImageAbs) c.SendFile(RawImageAbs)
return return
} }
log.Debugf("Incoming connection from %s@%s with %s", UA, c.IP(), ImgFilename)
// check ext // check ext
// TODO: may remove this function. Check in Nginx. // TODO: may remove this function. Check in Nginx.
@ -39,19 +42,25 @@ func Convert(ImgPath string, ExhaustPath string, AllowedTypes []string, QUALITY
} }
} }
if !allowed { if !allowed {
c.Send("File extension not allowed!") msg := "File extension not allowed! " + ImgFilename
c.SendStatus(403) log.Warn(msg)
c.Send(msg)
if ImageExists(RawImageAbs) {
c.SendFile(RawImageAbs)
}
return return
} }
// Check the original image for existence, // Check the original image for existence,
if !ImageExists(RawImageAbs) { if !ImageExists(RawImageAbs) {
c.Send("Image not found!") msg := "Image not found!"
c.Send(msg)
log.Warn(msg)
c.SendStatus(404) c.SendStatus(404)
return return
} }
cwd, WebpAbsPath := GenWebpAbs(RawImageAbs, ExhaustPath, ImgFilename, reqURI) _, WebpAbsPath := GenWebpAbs(RawImageAbs, ExhaustPath, ImgFilename, reqURI)
if ImageExists(WebpAbsPath) { if ImageExists(WebpAbsPath) {
finalFile = WebpAbsPath finalFile = WebpAbsPath
@ -59,10 +68,10 @@ func Convert(ImgPath string, ExhaustPath string, AllowedTypes []string, QUALITY
// we don't have abc.jpg.png1582558990.webp // we don't have abc.jpg.png1582558990.webp
// delete the old pic and convert a new one. // delete the old pic and convert a new one.
// /home/webp_server/exhaust/path/to/tsuki.jpg.1582558990.webp // /home/webp_server/exhaust/path/to/tsuki.jpg.1582558990.webp
destHalfFile := path.Clean(path.Join(cwd, "exhaust", path.Dir(reqURI), ImgFilename)) destHalfFile := path.Clean(path.Join(WebpAbsPath, path.Dir(reqURI), ImgFilename))
matches, err := filepath.Glob(destHalfFile + "*") matches, err := filepath.Glob(destHalfFile + "*")
if err != nil { if err != nil {
fmt.Println(err.Error()) log.Error(err.Error())
} else { } else {
// /home/webp_server/exhaust/path/to/tsuki.jpg.1582558100.webp <- older ones will be removed // /home/webp_server/exhaust/path/to/tsuki.jpg.1582558100.webp <- older ones will be removed
// /home/webp_server/exhaust/path/to/tsuki.jpg.1582558990.webp <- keep the latest one // /home/webp_server/exhaust/path/to/tsuki.jpg.1582558990.webp <- keep the latest one
@ -79,7 +88,7 @@ func Convert(ImgPath string, ExhaustPath string, AllowedTypes []string, QUALITY
err = WebpEncoder(RawImageAbs, WebpAbsPath, float32(q), true, nil) err = WebpEncoder(RawImageAbs, WebpAbsPath, float32(q), true, nil)
if err != nil { if err != nil {
fmt.Println(err) log.Error(err)
c.SendStatus(400) c.SendStatus(400)
c.Send("Bad file!") c.Send("Bad file!")
return return

View File

@ -1,5 +1,5 @@
Name: webp-server Name: webp-server
Version: 0.0.4 Version: 0.1.1
Release: 1%{?dist} Release: 1%{?dist}
Summary: Go version of WebP Server. A tool that will serve your JPG/PNGs as WebP format with compression, on-the-fly. Summary: Go version of WebP Server. A tool that will serve your JPG/PNGs as WebP format with compression, on-the-fly.

View File

@ -4,17 +4,18 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"os" "os"
"path" "path"
"runtime" "runtime"
log "github.com/sirupsen/logrus"
) )
func autoUpdate() { func autoUpdate() {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
log.Println("Download error.", err) log.Error("Download error.", err)
} }
}() }()
@ -23,16 +24,16 @@ func autoUpdate() {
TagName string `json:"tag_name"` TagName string `json:"tag_name"`
} }
var res Result var res Result
log.Debugf("Requesting to %s", api)
resp1, _ := http.Get(api) resp1, _ := http.Get(api)
data1, _ := ioutil.ReadAll(resp1.Body) data1, _ := ioutil.ReadAll(resp1.Body)
_ = json.Unmarshal(data1, &res) _ = json.Unmarshal(data1, &res)
var gitVersion = res.TagName var gitVersion = res.TagName
if gitVersion > version { if gitVersion > version {
log.Printf("Time to update! New version %s found!", gitVersion) log.Infof("Time to update! New version %s found", gitVersion)
} else { } else {
log.Println("No new version found.") log.Debug("No new version found.")
return return
} }
@ -41,11 +42,10 @@ func autoUpdate() {
filename += ".exe" filename += ".exe"
} }
var releaseUrl = "https://github.com/webp-sh/webp_server_go/releases/latest/download/" + filename var releaseUrl = "https://github.com/webp-sh/webp_server_go/releases/latest/download/" + filename
log.Println("Downloading binary...") log.Info("Downloading binary to update...")
resp, _ := http.Get(releaseUrl) resp, _ := http.Get(releaseUrl)
if resp.StatusCode != 200 { if resp.StatusCode != 200 {
log.Printf("%s-%s not found on release. "+ log.Debug("%s-%s not found on release.", runtime.GOOS, runtime.GOARCH)
"Contact developers to supply your version", runtime.GOOS, runtime.GOARCH)
return return
} }
data, _ := ioutil.ReadAll(resp.Body) data, _ := ioutil.ReadAll(resp.Body)
@ -54,7 +54,7 @@ func autoUpdate() {
err := ioutil.WriteFile(path.Join("update", filename), data, 0755) err := ioutil.WriteFile(path.Join("update", filename), data, 0755)
if err == nil { if err == nil {
log.Println("Update complete. Please find your binary from update directory.") log.Info("Update complete. Please find your binary from update directory.")
} }
_ = resp.Body.Close() _ = resp.Body.Close()
} }

View File

@ -4,12 +4,12 @@ import (
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"log"
"os" "os"
"path" "path"
"runtime" "runtime"
"github.com/gofiber/fiber" "github.com/gofiber/fiber"
log "github.com/sirupsen/logrus"
) )
type Config struct { type Config struct {
@ -21,13 +21,14 @@ type Config struct {
ExhaustPath string `json:"EXHAUST_PATH"` ExhaustPath string `json:"EXHAUST_PATH"`
} }
const version = "0.1.0" const version = "0.1.1"
var configPath string var configPath string
var prefetch bool var prefetch bool
var jobs int var jobs int
var dumpConfig bool var dumpConfig bool
var dumpSystemd bool var dumpSystemd bool
var verboseMode bool
const sampleConfig = ` const sampleConfig = `
{ {
@ -36,7 +37,7 @@ const sampleConfig = `
"QUALITY": "80", "QUALITY": "80",
"IMG_PATH": "/path/to/pics", "IMG_PATH": "/path/to/pics",
"EXHAUST_PATH": "", "EXHAUST_PATH": "",
"ALLOWED_TYPES": ["jpg","png","jpeg","bmp","gif"] "ALLOWED_TYPES": ["jpg","png","jpeg","bmp"]
}` }`
const sampleSystemd = ` const sampleSystemd = `
[Unit] [Unit]
@ -54,7 +55,6 @@ ExecReload=/bin/kill -HUP $MAINPID
Restart=always Restart=always
RestartSec=3s RestartSec=3s
[Install] [Install]
WantedBy=multi-user.target` WantedBy=multi-user.target`
@ -67,6 +67,11 @@ func loadConfig(path string) Config {
defer jsonObject.Close() defer jsonObject.Close()
decoder := json.NewDecoder(jsonObject) decoder := json.NewDecoder(jsonObject)
_ = decoder.Decode(&config) _ = decoder.Decode(&config)
_, err = os.Stat(config.ImgPath)
if err != nil {
log.Fatalf("Your image path %s is incorrect.Please check and confirm.", config.ImgPath)
}
return config return config
} }
@ -76,7 +81,27 @@ func init() {
flag.IntVar(&jobs, "jobs", runtime.NumCPU(), "Prefetch thread, default is all.") flag.IntVar(&jobs, "jobs", runtime.NumCPU(), "Prefetch thread, default is all.")
flag.BoolVar(&dumpConfig, "dump-config", false, "Print sample config.json") flag.BoolVar(&dumpConfig, "dump-config", false, "Print sample config.json")
flag.BoolVar(&dumpSystemd, "dump-systemd", false, "Print sample systemd service file.") flag.BoolVar(&dumpSystemd, "dump-systemd", false, "Print sample systemd service file.")
flag.BoolVar(&verboseMode, "v", false, "Verbose, print out debug info.")
flag.Parse() flag.Parse()
// Logrus
log.SetOutput(os.Stdout)
log.SetReportCaller(true)
Formatter := &log.TextFormatter{
EnvironmentOverrideColors: true,
FullTimestamp: true,
TimestampFormat: "2006-01-02 15:04:05",
CallerPrettyfier: func(f *runtime.Frame) (string, string) {
return fmt.Sprintf("[%s()]", f.Function), ""
},
}
log.SetFormatter(Formatter)
if verboseMode {
log.SetLevel(log.DebugLevel)
log.Debug("Debug mode is enable!")
} else {
log.SetLevel(log.InfoLevel)
}
} }
func main() { func main() {
@ -116,8 +141,7 @@ func main() {
ListenAddress := HOST + ":" + PORT ListenAddress := HOST + ":" + PORT
// Server Info // Server Info
ServerInfo := "WebP Server " + version + " is running at " + ListenAddress log.Infof("WebP Server %s %s", version, ListenAddress)
fmt.Println(ServerInfo)
app.Get("/*", Convert(confImgPath, ExhaustPath, AllowedTypes, QUALITY)) app.Get("/*", Convert(confImgPath, ExhaustPath, AllowedTypes, QUALITY))
app.Listen(ListenAddress) app.Listen(ListenAddress)