diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index 9c1ef04..1219730 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -12,8 +12,6 @@ jobs: ci: name: CI check on every push runs-on: ubuntu-latest - container: - image: centos:centos7 steps: - name: Checkout uses: actions/checkout@v3 @@ -25,9 +23,7 @@ jobs: - name: Setup necessary packages run: | - yum install epel-release -y - yum groupinstall 'Development Tools' -y - yum install libaom-devel -y + sudo apt install libvips-dev -y - name: run test cases run: make test && make @@ -81,17 +77,17 @@ jobs: id: trivy with: run: | - trivy image --no-progress --severity "HIGH,CRITICAL" ghcr.io/${{ github.event.repository.full_name }} + trivy image --no-progress --severity "HIGH,CRITICAL" --ignore-unfixed ghcr.io/${{ github.event.repository.full_name }} - name: Print CVE run: | echo "${{ steps.trivy.outputs.stdout }}" - name: Comment PR - uses: thollander/actions-comment-pull-request@v1 + uses: thollander/actions-comment-pull-request@v2 with: message: | ``` ${{ steps.trivy.outputs.stdout }} ``` - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 87ce3ab..edbca9b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,7 +38,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/release_binary.yaml b/.github/workflows/release_binary.yaml index cbcd48b..35c1e1d 100644 --- a/.github/workflows/release_binary.yaml +++ b/.github/workflows/release_binary.yaml @@ -13,9 +13,6 @@ jobs: build: name: Create Release runs-on: ubuntu-latest - container: - image: centos:centos7 - steps: - name: Checkout code uses: actions/checkout@v2 @@ -27,9 +24,7 @@ jobs: - name: Setup necessary packages run: | - yum install epel-release -y - yum groupinstall 'Development Tools' -y - yum install libaom-devel -y + sudo apt install libvips-dev -y - name: Make WebP Server Go run: | diff --git a/Dockerfile b/Dockerfile index a2d4314..4439fa2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM golang:1.20 as builder ARG IMG_PATH=/opt/pics ARG EXHAUST_PATH=/opt/exhaust -RUN apt update && apt install libaom-dev -y && mkdir /build +RUN apt update && apt install --no-install-recommends libvips-dev -y && mkdir /build COPY go.mod /build RUN cd /build && go mod download @@ -14,11 +14,11 @@ RUN cd /build && sed -i "s|.\/pics|${IMG_PATH}|g" config.json \ FROM debian:bullseye-slim +RUN apt update && apt install --no-install-recommends libvips ca-certificates -y && rm -rf /var/lib/apt/lists/* && rm -rf /var/cache/apt/archives/* + COPY --from=builder /build/webp-server /usr/bin/webp-server COPY --from=builder /build/config.json /etc/config.json -RUN apt update && apt install libaom-dev -y && rm -rf /var/lib/apt/lists/* - WORKDIR /opt VOLUME /opt/exhaust CMD ["/usr/bin/webp-server", "--config", "/etc/config.json"] diff --git a/README.md b/README.md index af116ce..bd89edf 100644 --- a/README.md +++ b/README.md @@ -12,30 +12,40 @@ This is a Server based on Golang, which allows you to serve WebP images on the fly. It will convert `jpg,jpeg,png` files by default, this can be customized by editing the `config.json`.. -* currently supported image format: JPEG, PNG, BMP, GIF(static image for now) - +* currently supported image format: JPEG, PNG, BMP, GIF(static image for now) > e.g When you visit `https://your.website/pics/tsuki.jpg`,it will serve as `image/webp` format without changing the URL. > -> ~~For Safari and Opera users, the original image will be used.~~ -> We've now support Safari/Chrome/Firefox on iOS 14/iPadOS 14 - +> ~~For Safari and Opera users, the original image will be used.~~ +> We've now supported Safari/Chrome/Firefox on iOS 14/iPadOS 14 ## Simple Usage Steps(with Binary) +> Note: There is a potential memory leak problem with this server and remains unsolved, we recommend using Docker to mitigate this problem. +> Related discussion: https://github.com/webp-sh/webp_server_go/issues/75 + ### 1. Prepare the environment -If you'd like to run binary directly on your machine, you need to install `libaom`: +#### If you are using version after 0.6.0 -`libaom` is for AVIF support, you can install it by `apt install libaom-dev` on Ubuntu, `yum install libaom-devel` on CentOS. +> Install `libvips` on your machine, more info [here](https://github.com/davidbyttow/govips) +> +> * Ubuntu `apt install libvips-dev` +> * macOS `brew install vips pkg-config` -Without this library, you may encounter error like this: `libaom.so.3: cannot open shared object file: No such file or directory` +#### If you are using version before 0.6.0 -If you are using Intel Mac, you can install it by `brew install aom` - -If you are using Apple Silicon, you need to `brew install aom && export CPATH=/opt/homebrew/opt/aom/include/;LIBRARY_PATH=/opt/homebrew/opt/aom/lib/`, more references can be found at [在M1 Mac下开发WebP Server Go | 土豆不好吃](https://dmesg.app/m1-aom.html). - -If you don't like to hassle around with your system, so do us, why not have a try using Docker? >> [Docker | WebP Server Documentation](https://docs.webp.sh/usage/docker/) +> If you'd like to run binary directly on your machine, you need to install `libaom`: +> +> `libaom` is for AVIF support, you can install it by `apt install libaom-dev` on Ubuntu, `yum install libaom-devel` on CentOS. +> +> Without this library, you may encounter error like this: `libaom.so.3: cannot open shared object file: No such file or directory` +> +> If you are using Intel Mac, you can install it by `brew install aom` +> +> If you are using Apple Silicon, you need to `brew install aom && export CPATH=/opt/homebrew/opt/aom/include/;LIBRARY_PATH=/opt/homebrew/opt/aom/lib/`, more references can be found at [在M1 Mac下开发WebP Server Go | 土豆不好吃](https://dmesg.app/m1-aom.html). +> +> If you don't like to hassle around with your system, so do us, why not have a try using Docker? >> [Docker | WebP Server Documentation](https://docs.webp.sh/usage/docker/) ### 2. Download the binary @@ -96,7 +106,7 @@ For supervisor, Docker sections or detailed Nginx configuration, please read our ## Support us If you find this project useful, please consider supporting -us [becoming a sponsor](https://github.com/sponsors/webp-sh) or using Stripe +us by [becoming a sponsor](https://github.com/sponsors/webp-sh) or Stripe | USD(Card, Apple Pay and Google Pay) | SEK(Card, Apple Pay and Google Pay) | CNY(Card, Apple Pay, Google Pay and Alipay) | |--------------------------------------------------|--------------------------------------------------|--------------------------------------------------| diff --git a/config.go b/config.go index 02e5145..ae63a3d 100644 --- a/config.go +++ b/config.go @@ -1,14 +1,10 @@ -// webp_server_go - config -// 2020-11-27 13:05 -// Benny - package main type Config struct { Host string `json:"HOST"` Port string `json:"PORT"` ImgPath string `json:"IMG_PATH"` - Quality float32 `json:"QUALITY,string"` + Quality int `json:"QUALITY,string"` AllowedTypes []string `json:"ALLOWED_TYPES"` ExhaustPath string `json:"EXHAUST_PATH"` EnableAVIF bool `json:"ENABLE_AVIF"` @@ -22,8 +18,7 @@ var ( prefetch, proxyMode bool remoteRaw = "remote-raw" config Config - version = "0.5.1" - releaseURL = "https://github.com/webp-sh/webp_server_go/releases/latest/download/" + version = "0.6.0" ) const ( diff --git a/encoder.go b/encoder.go index 19e4a42..ab3a130 100644 --- a/encoder.go +++ b/encoder.go @@ -1,23 +1,15 @@ package main import ( - "bytes" "errors" - "fmt" - "image" - "image/jpeg" - "image/png" "os" "path" "path/filepath" - "runtime" "strings" "sync" - "github.com/Kagami/go-avif" - "github.com/chai2010/webp" + "github.com/davidbyttow/govips/v2/vips" log "github.com/sirupsen/logrus" - "golang.org/x/image/bmp" ) func convertFilter(raw, avifPath, webpPath string, c chan int) { @@ -73,12 +65,11 @@ func convertImage(raw, optimized, itype string) error { } } - //we need to create dir first + // we need to create dir first err = os.MkdirAll(path.Dir(optimized), 0755) if err != nil { log.Error(err.Error()) } - //q, _ := strconv.ParseFloat(config.Quality, 32) switch itype { case "webp": @@ -89,79 +80,75 @@ func convertImage(raw, optimized, itype string) error { return err } -func readRawImage(imgPath string, maxPixel int) (img image.Image, err error) { - data, err := os.ReadFile(imgPath) - if err != nil { - log.Errorln(err) - } - - imgExtension := strings.ToLower(path.Ext(imgPath)) - if strings.Contains(imgExtension, "jpeg") || strings.Contains(imgExtension, "jpg") { - img, err = jpeg.Decode(bytes.NewReader(data)) - } else if strings.Contains(imgExtension, "png") { - img, err = png.Decode(bytes.NewReader(data)) - } else if strings.Contains(imgExtension, "bmp") { - img, err = bmp.Decode(bytes.NewReader(data)) - } - if err != nil || img == nil { - errinfo := fmt.Sprintf("image file %s is corrupted: %v", imgPath, err) - log.Errorln(errinfo) - return nil, errors.New(errinfo) - } - - x, y := img.Bounds().Max.X, img.Bounds().Max.Y - if x > maxPixel || y > maxPixel { - errinfo := fmt.Sprintf("Read image error: %s(%dx%d) is too large", imgPath, x, y) - log.Warnf(errinfo) - return nil, errors.New(errinfo) - } - - return img, nil -} - -func avifEncoder(p1, p2 string, quality float32) error { - var img image.Image - dst, err := os.Create(p2) - if err != nil { - log.Fatalf("Can't create destination file: %v", err) - } - // AVIF has a maximum resolution of 65536 x 65536 pixels. - img, err = readRawImage(p1, avifMax) +func avifEncoder(p1, p2 string, quality int) error { + // if convert fails, return error; success nil + var buf []byte + img, err := vips.NewImageFromFile(p1) if err != nil { return err } - - err = avif.Encode(dst, img, &avif.Options{ - Threads: runtime.NumCPU(), - Speed: avif.MaxSpeed, - Quality: int((100 - quality) / 100 * avif.MaxQuality), - SubsampleRatio: nil, - }) + // AVIF has a maximum resolution of 65536 x 65536 pixels. + if img.Metadata().Width > avifMax || img.Metadata().Height > avifMax { + return errors.New("WebP: image too large") + } + // If quality >= 100, we use lossless mode + if quality >= 100 { + buf, _, err = img.ExportAvif(&vips.AvifExportParams{ + Lossless: true, + StripMetadata: true, + }) + } else { + buf, _, err = img.ExportAvif(&vips.AvifExportParams{ + Quality: quality, + Lossless: false, + StripMetadata: true, + }) + } if err != nil { log.Warnf("Can't encode source image: %v to AVIF", err) } + if err := os.WriteFile(p2, buf, 0600); err != nil { + log.Error(err) + return err + } + convertLog("AVIF", p1, p2, quality) return nil } -func webpEncoder(p1, p2 string, quality float32) error { +func webpEncoder(p1, p2 string, quality int) error { // if convert fails, return error; success nil - var buf bytes.Buffer - var img image.Image - // The maximum pixel dimensions of a WebP image is 16383 x 16383. - img, err := readRawImage(p1, webpMax) + var buf []byte + img, err := vips.NewImageFromFile(p1) if err != nil { return err } - err = webp.Encode(&buf, img, &webp.Options{Lossless: false, Quality: quality}) + // The maximum pixel dimensions of a WebP image is 16383 x 16383. + if img.Metadata().Width > webpMax || img.Metadata().Height > webpMax { + return errors.New("WebP: image too large") + } + // If quality >= 100, we use lossless mode + if quality >= 100 { + buf, _, err = img.ExportWebp(&vips.WebpExportParams{ + Lossless: true, + StripMetadata: true, + }) + } else { + buf, _, err = img.ExportWebp(&vips.WebpExportParams{ + Quality: quality, + Lossless: false, + StripMetadata: true, + }) + } + if err != nil { log.Warnf("Can't encode source image: %v to WebP", err) } - if err := os.WriteFile(p2, buf.Bytes(), 0600); err != nil { + if err := os.WriteFile(p2, buf, 0600); err != nil { log.Error(err) return err } @@ -170,9 +157,9 @@ func webpEncoder(p1, p2 string, quality float32) error { return nil } -func convertLog(itype, p1 string, p2 string, quality float32) { +func convertLog(itype, p1 string, p2 string, quality int) { oldf, _ := os.Stat(p1) newf, _ := os.Stat(p2) - log.Infof("%s@%.2f%%: %s->%s %d->%d %.2f%% deflated", itype, quality, + log.Infof("%s@%d%%: %s->%s %d->%d %.2f%% deflated", itype, quality, p1, p2, oldf.Size(), newf.Size(), float32(newf.Size())/float32(oldf.Size())*100) } diff --git a/encoder_test.go b/encoder_test.go index 93e4981..cca8744 100644 --- a/encoder_test.go +++ b/encoder_test.go @@ -10,6 +10,8 @@ import ( "testing" ) +var dest = "/tmp/test-result" + func walker() []string { var list []string _ = filepath.Walk("./pics", func(p string, info os.FileInfo, err error) error { @@ -23,7 +25,6 @@ func walker() []string { func TestWebPEncoder(t *testing.T) { // Go through every files - var dest = "/tmp/test-result" var target = walker() for _, f := range target { runEncoder(t, f, dest) @@ -33,28 +34,25 @@ func TestWebPEncoder(t *testing.T) { func TestAvifEncoder(t *testing.T) { // Only one file: img_over_16383px.jpg might cause memory issues on CI environment - var dest = "/tmp/test-result" - avifEncoder("./pics/big.jpg", dest, 80) + assert.Nil(t, avifEncoder("./pics/big.jpg", dest, 80)) assertType(t, dest, "image/avif") } func TestNonExistImage(t *testing.T) { - var dest = "/tmp/test-result" - webpEncoder("./pics/empty.jpg", dest, 80) - avifEncoder("./pics/empty.jpg", dest, 80) + assert.NotNil(t, webpEncoder("./pics/empty.jpg", dest, 80)) + assert.NotNil(t, avifEncoder("./pics/empty.jpg", dest, 80)) } -func TestConvertFail(t *testing.T) { - var dest = "/tmp/test-result" - webpEncoder("./pics/webp_server.jpg", dest, -1) - avifEncoder("./pics/webp_server.jpg", dest, -1) +func TestHighResolutionImage(t *testing.T) { + assert.NotNil(t, webpEncoder("./pics/img_over_16383px.jpg", dest, 80)) + assert.Nil(t, avifEncoder("./pics/img_over_16383px.jpg", dest, 80)) } func runEncoder(t *testing.T, file string, dest string) { if file == "pics/empty.jpg" { t.Log("Empty file, that's okay.") } - webpEncoder(file, dest, 80) + _ = webpEncoder(file, dest, 80) assertType(t, dest, "image/webp") } diff --git a/go.mod b/go.mod index 7d5a805..aad052e 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,13 @@ module webp_server_go go 1.20 require ( - github.com/Kagami/go-avif v0.1.0 - github.com/chai2010/webp v1.1.0 + github.com/davidbyttow/govips/v2 v2.13.0 github.com/gofiber/fiber/v2 v2.4.0 github.com/h2non/filetype v1.1.3 github.com/schollz/progressbar/v3 v3.13.1 github.com/sirupsen/logrus v1.9.0 - github.com/staktrace/go-update v0.0.0-20210525161054-fc019945f9a2 github.com/stretchr/testify v1.8.2 github.com/valyala/fasthttp v1.47.0 - golang.org/x/image v0.7.0 ) require ( @@ -25,12 +22,12 @@ require ( github.com/rivo/uniseg v0.4.3 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect - golang.org/x/sys v0.6.0 // indirect - golang.org/x/term v0.6.0 // indirect + golang.org/x/image v0.7.0 // indirect + golang.org/x/net v0.8.0 // indirect + golang.org/x/sys v0.7.0 // indirect + golang.org/x/term v0.7.0 // indirect + golang.org/x/text v0.9.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace ( - github.com/chai2010/webp v1.1.0 => github.com/webp-sh/webp v1.2.0 - github.com/gofiber/fiber/v2 v2.4.0 => github.com/webp-sh/fiber/v2 v2.4.0 -) +replace github.com/gofiber/fiber/v2 v2.4.0 => github.com/webp-sh/fiber/v2 v2.4.0 diff --git a/go.sum b/go.sum index 4e1ad74..1790473 100644 --- a/go.sum +++ b/go.sum @@ -1,22 +1,27 @@ -github.com/Kagami/go-avif v0.1.0 h1:8GHAGLxCdFfhpd4Zg8j1EqO7rtcQNenxIDerC/uu68w= -github.com/Kagami/go-avif v0.1.0/go.mod h1:OPmPqzNdQq3+sXm0HqaUJQ9W/4k+Elbc3RSfJUemDKA= github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidbyttow/govips/v2 v2.13.0 h1:5MK9ZcXZC5GzUR9Ca8fJwOYqMgll/H096ec0PJP59QM= +github.com/davidbyttow/govips/v2 v2.13.0/go.mod h1:LPTrwWtNa5n4yl9UC52YBOEGdZcY5hDTP4Ms2QWasTw= github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -26,12 +31,11 @@ github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iH github.com/schollz/progressbar/v3 v3.13.1/go.mod h1:xvrbki8kfT1fzWzBT/UZd9L6GA+jdL7HAgq2RFnO6fQ= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/staktrace/go-update v0.0.0-20210525161054-fc019945f9a2 h1:kyTDvRL8TyTHOx0aK1PKMPVfkI7rCLDC1nrKF7SYOBc= -github.com/staktrace/go-update v0.0.0-20210525161054-fc019945f9a2/go.mod h1:yzHsbjWRHVF1vVGsluwqCc2TvogFSx9C8TeBh34cMb0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -47,12 +51,11 @@ github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVS github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/webp-sh/fiber/v2 v2.4.0 h1:JtkW0HAqHCExodZMZnG7GrLiJuK2YbNYw8eXo55+tr8= github.com/webp-sh/fiber/v2 v2.4.0/go.mod h1:f8BRRIMjMdRyt2qmJ/0Sea3j3rwwfufPrh9WNBRiVZ0= -github.com/webp-sh/webp v1.2.0 h1:WiAR1M4Cz50Ehv0vP8VaBZwuTqBgLxcGMaBV23zLVDA= -github.com/webp-sh/webp v1.2.0/go.mod h1:DWmBXPtpA/zfTgEgWxAlsER3B7nXFvDtCi1YY+K5N9w= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw= golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -63,6 +66,9 @@ golang.org/x/net v0.0.0-20201016165138-7b1cca2348c0/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -77,25 +83,29 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= +gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/helper.go b/helper.go index ba7ac28..8cb6b4e 100644 --- a/helper.go +++ b/helper.go @@ -21,14 +21,14 @@ import ( ) func avifMatcher(buf []byte) bool { - // 0000001C 66747970 6D696631 00000000 6D696631 61766966 6D696166 000000F4 + // 0000001c 66747970 61766966 00000000 61766966 6d696631 6d696166 return len(buf) > 1 && bytes.Equal(buf[:28], []byte{ 0x0, 0x0, 0x0, 0x1c, 0x66, 0x74, 0x79, 0x70, - 0x6d, 0x69, 0x66, 0x31, - 0x0, 0x0, 0x0, 0x0, - 0x6d, 0x69, 0x66, 0x31, 0x61, 0x76, 0x69, 0x66, + 0x0, 0x0, 0x0, 0x0, + 0x61, 0x76, 0x69, 0x66, + 0x6d, 0x69, 0x66, 0x31, 0x6d, 0x69, 0x61, 0x66, }) } diff --git a/pics/invalid.png b/pics/invalid.png new file mode 100644 index 0000000..c6635d3 Binary files /dev/null and b/pics/invalid.png differ diff --git a/prefetch_test.go b/prefetch_test.go index 7788d4d..ec8ea80 100644 --- a/prefetch_test.go +++ b/prefetch_test.go @@ -1,13 +1,10 @@ -// webp_server_go - prefetch_test.go -// 2020-11-10 09:27 -// Benny - package main import ( - "github.com/stretchr/testify/assert" "os" "testing" + + "github.com/stretchr/testify/assert" ) func TestPrefetchImages(t *testing.T) { diff --git a/router_test.go b/router_test.go index c8829f9..4f70151 100644 --- a/router_test.go +++ b/router_test.go @@ -1,7 +1,3 @@ -// webp_server_go - webp-server_test -// 2020-11-09 11:55 -// Benny - package main import ( @@ -76,7 +72,7 @@ func TestConvert(t *testing.T) { "http://127.0.0.1:3333/webp_server.bmp": "image/webp", "http://127.0.0.1:3333/webp_server.png": "image/webp", "http://127.0.0.1:3333/empty.jpg": "", - "http://127.0.0.1:3333/png.jpg": "image/png", + "http://127.0.0.1:3333/png.jpg": "image/webp", "http://127.0.0.1:3333/12314.jpg": "", "http://127.0.0.1:3333/dir1/inside.jpg": "image/webp", "http://127.0.0.1:3333/%e5%a4%aa%e7%a5%9e%e5%95%a6.png": "image/webp", diff --git a/update.go b/update.go deleted file mode 100644 index 4226a16..0000000 --- a/update.go +++ /dev/null @@ -1,63 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - - log "github.com/sirupsen/logrus" - "github.com/staktrace/go-update" - - "io" - "net/http" - "runtime" -) - -func autoUpdate() { - defer func() { - if err := recover(); err != nil { - log.Errorf("Download error: %s", err) - } - }() - - var api = "https://api.github.com/repos/webp-sh/webp_server_go/releases/latest" - type Result struct { - TagName string `json:"tag_name"` - } - var res Result - log.Debugf("Requesting to %s", api) - resp1, err := http.Get(api) - if err != nil { - log.Errorf("Error requesting to %s", api) - } - defer resp1.Body.Close() - data1, _ := io.ReadAll(resp1.Body) - _ = json.Unmarshal(data1, &res) - var gitVersion = res.TagName - - if gitVersion > version { - log.Infof("Time to update! New version %s found", gitVersion) - } else { - log.Debug("No new version found.") - return - } - - var filename = fmt.Sprintf("webp-server-%s-%s", runtime.GOOS, runtime.GOARCH) - if runtime.GOOS == "windows" { - filename += ".exe" - } - log.Info("Downloading binary to update...") - resp, _ := http.Get(releaseURL + filename) - if resp.StatusCode != 200 { - log.Debugf("%s-%s not found on release.", runtime.GOOS, runtime.GOARCH) - return - } - - err = update.Apply(resp.Body, update.Options{}) - if err != nil { - // error handling - log.Errorf("Update error. %v", err) - } else { - log.Info("Update complete. Please restart to apply changes.") - } - _ = resp.Body.Close() -} diff --git a/update_test.go b/update_test.go deleted file mode 100644 index 2f82eb7..0000000 --- a/update_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// webp_server_go - update_test -// 2020-11-10 09:36 -// Benny - -package main - -import ( - "os" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestNormalAutoUpdate(t *testing.T) { - version = "0.0.1" - dir := "./update" - autoUpdate() - assert.NotEqual(t, 0, fileCount(dir)) - _ = os.RemoveAll(dir) -} - -func Test404AutoUpdate(t *testing.T) { - version = "0.0.1" - dir := "./update" - releaseURL = releaseURL + "a" - autoUpdate() - assert.Equal(t, int64(0), fileCount(dir)) - _ = os.RemoveAll(dir) -} - -func TestNoNeedAutoUpdate(t *testing.T) { - version = "99.99" - dir := "./update" - autoUpdate() - info, _ := os.Stat(dir) - assert.Nil(t, info) -} diff --git a/webp-server.go b/webp-server.go index 5b41809..d42aa51 100644 --- a/webp-server.go +++ b/webp-server.go @@ -8,6 +8,7 @@ import ( "regexp" "runtime" + "github.com/davidbyttow/govips/v2/vips" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/logger" log "github.com/sirupsen/logrus" @@ -94,10 +95,14 @@ Develop by WebP Server team. https://github.com/webp-sh`, version) os.Exit(0) } - // go autoUpdate() config = loadConfig(configPath) switchProxyMode() + vips.Startup(&vips.Config{ + ConcurrencyLevel: runtime.NumCPU(), + }) + defer vips.Shutdown() + if prefetch { go prefetchImages(config.ImgPath, config.ExhaustPath) } diff --git a/webp-server_test.go b/webp-server_test.go index 6fb7bdc..4b4ef27 100644 --- a/webp-server_test.go +++ b/webp-server_test.go @@ -1,17 +1,14 @@ -// webp_server_go - webp-server_test -// 2020-11-10 09:41 -// Benny - package main import ( - log "github.com/sirupsen/logrus" - "github.com/stretchr/testify/assert" "net" "os" "runtime" "testing" "time" + + log "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" ) // due to test limit, we can't test for cli param part. @@ -21,7 +18,7 @@ func TestLoadConfig(t *testing.T) { assert.Equal(t, "./exhaust", c.ExhaustPath) assert.Equal(t, "127.0.0.1", c.Host) assert.Equal(t, "3333", c.Port) - assert.Equal(t, float32(80), c.Quality) + assert.Equal(t, 80, c.Quality) assert.Equal(t, "./pics", c.ImgPath) assert.Equal(t, []string{"jpg", "png", "jpeg", "bmp"}, c.AllowedTypes) }