mirror of
https://github.com/woodchen-ink/webp_server_go.git
synced 2025-07-18 05:32:02 +08:00
Init
This commit is contained in:
commit
6b5f1e6e92
15
.gitignore
vendored
Normal file
15
.gitignore
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
exhaust/
|
42
README.md
Normal file
42
README.md
Normal file
@ -0,0 +1,42 @@
|
||||
<p align="center">
|
||||
<img src="./pics/webp_server.png"/>
|
||||
</p>
|
||||
|
||||
**THIS PROJECT IS UNDER DEVELOPMENT, DON'T USE IT ON PRODUCTION ENVIRONMENT.**
|
||||
|
||||
After the [n0vad3v/webp_server](https://github.com/n0vad3v/webp_server), I decide to rewrite the whole program with Go, as there will be no more `npm install`s or `docker-compose`s.
|
||||
|
||||
This is a Server based on Go and a precompiled cwebp(libwebp-1.1.0-rc2-linux-x86-64), 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.js`..
|
||||
|
||||
> e.g When you visit `https://a.com/1.jpg`,it will serve as `image/webp` without changing the URL.
|
||||
>
|
||||
> For Safari and Opera users, the original image will be used.
|
||||
|
||||
## Compare to [n0vad3v/webp_server](https://github.com/n0vad3v/webp_server)
|
||||
|
||||
### Size
|
||||
|
||||
* `webp_server` with `node_modules`: 43M
|
||||
* `webp_server_go` single binary: 9.5M
|
||||
|
||||
### Performance
|
||||
|
||||
It's basically between `ExpressJS` and `Fiber`, much faster than the `http` package of course.
|
||||
|
||||
### Convenience
|
||||
|
||||
* `webp_server`: Clone -> `npm install` -> run with `pm2`
|
||||
* `webp_server_go`: Download -> Run
|
||||
|
||||
## Usage
|
||||
|
||||
Regarding the `IMG_PATH` section in `config.json`, if you are serving images at `https://example.com/pics/tsuki.jpg` and your files are at `/var/www/image/pics/tsuki.jpg`, then `IMG_PATH` shall be `/var/www/image`.
|
||||
|
||||
1. Edit the `config.json` to face your need, default convert quality is 80%.
|
||||
2. Run the binary like this: `./webp_server`, use `screen` or `tmux` to hold it currently.
|
||||
3. Let Nginx to `proxy_pass http://localhost:3333/;`
|
||||
|
||||
## TODO
|
||||
|
||||
* This version doesn't support header-based-output, which means Safari users will not see the converted `webp` images, this should be fixed in later releases.
|
||||
* Multi platform support.
|
7
config.json
Normal file
7
config.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"HOST": "127.0.0.1",
|
||||
"PORT": "3333",
|
||||
"QUALITY": "80",
|
||||
"IMG_PATH": "/path/to/pics",
|
||||
"ALLOWED_TYPES": ["jpg","png","jpeg"]
|
||||
}
|
BIN
pics/webp_server.png
Executable file
BIN
pics/webp_server.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 263 KiB |
BIN
webp/cwebp
Executable file
BIN
webp/cwebp
Executable file
Binary file not shown.
149
webp_server.go
Normal file
149
webp_server.go
Normal file
@ -0,0 +1,149 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/gofiber/fiber"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"path"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
HOST string
|
||||
PORT string
|
||||
IMG_PATH string
|
||||
QUALITY string
|
||||
ALLOWED_TYPES []string
|
||||
|
||||
}
|
||||
|
||||
func main() {
|
||||
app := fiber.New()
|
||||
app.Banner = false
|
||||
app.Server = "WebP Server Go"
|
||||
|
||||
// Config Here
|
||||
config := load_config("config.json")
|
||||
|
||||
HOST := config.HOST
|
||||
PORT := config.PORT
|
||||
IMG_PATH := config.IMG_PATH
|
||||
QUALITY := config.QUALITY
|
||||
ALLOWED_TYPES := config.ALLOWED_TYPES
|
||||
|
||||
LISTEN_ADDRESS := HOST + ":" + PORT
|
||||
|
||||
// Server Info
|
||||
SERVER_INFO := "WebP Server is running at " + LISTEN_ADDRESS
|
||||
fmt.Println(SERVER_INFO)
|
||||
|
||||
app.Get("/*", func(c *fiber.Ctx) {
|
||||
|
||||
// /var/www/IMG_PATH/path/to/tsuki.jpg
|
||||
IMG_ABSOLUTE_PATH := IMG_PATH + c.Path()
|
||||
|
||||
// /path/to/tsuki.jpg
|
||||
IMG_PATH := c.Path()
|
||||
|
||||
// jpg
|
||||
IMG_EXT := strings.Split(path.Ext(IMG_PATH),".")[1]
|
||||
|
||||
// tsuki.jpg
|
||||
IMG_NAME := path.Base(IMG_PATH)
|
||||
|
||||
// /path/to
|
||||
DIR_PATH := path.Dir(IMG_PATH)
|
||||
|
||||
// /path/to/tsuki.jpg.webp
|
||||
WEBP_IMG_PATH := DIR_PATH + "/" + IMG_NAME + ".webp"
|
||||
|
||||
// /home/webp_server
|
||||
CURRENT_PATH, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
// /home/webp_server/exhaust/path/to/tsuki.webp
|
||||
WEBP_ABSOLUTE_PATH := CURRENT_PATH + "/exhaust" + WEBP_IMG_PATH
|
||||
|
||||
// /home/webp_server/exhaust/path/to
|
||||
DIR_ABSOLUTE_PATH := CURRENT_PATH + "/exhaust" + DIR_PATH
|
||||
|
||||
// Check file extension
|
||||
_, found := Find(ALLOWED_TYPES, IMG_EXT)
|
||||
if !found {
|
||||
c.Send("File extension not allowed!")
|
||||
c.SendStatus(403)
|
||||
return
|
||||
}
|
||||
|
||||
// Check the original image for existence
|
||||
if !imageExists(IMG_ABSOLUTE_PATH) {
|
||||
// The original image doesn't exist, check the webp image, delete if processed.
|
||||
if imageExists(WEBP_ABSOLUTE_PATH) {
|
||||
os.Remove(WEBP_ABSOLUTE_PATH)
|
||||
}
|
||||
c.Send("File not found!")
|
||||
c.SendStatus(404)
|
||||
return
|
||||
}
|
||||
|
||||
if imageExists(WEBP_ABSOLUTE_PATH) {
|
||||
c.SendFile(WEBP_ABSOLUTE_PATH)
|
||||
} else{
|
||||
// Mkdir
|
||||
os.MkdirAll(DIR_ABSOLUTE_PATH , os.ModePerm)
|
||||
|
||||
// cwebp -q 60 Cute-Baby-Girl.png -o Cute-Baby-Girl.webp
|
||||
OS_CMD := exec.Command("./webp/cwebp","-q",QUALITY,IMG_ABSOLUTE_PATH,"-o",WEBP_ABSOLUTE_PATH)
|
||||
var out bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
OS_CMD.Stdout = &out
|
||||
OS_CMD.Stderr = &stderr
|
||||
err := OS_CMD.Run()
|
||||
if err != nil {
|
||||
fmt.Println(stderr.String())
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
c.SendFile(WEBP_ABSOLUTE_PATH)
|
||||
}
|
||||
})
|
||||
|
||||
app.Listen(LISTEN_ADDRESS)
|
||||
}
|
||||
|
||||
func load_config(path string) Config {
|
||||
var config Config
|
||||
json_object,err := os.Open(path)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
defer json_object.Close()
|
||||
decoder := json.NewDecoder(json_object)
|
||||
decoder.Decode(&config)
|
||||
return config
|
||||
}
|
||||
|
||||
func imageExists(filename string) bool {
|
||||
info, err := os.Stat(filename)
|
||||
if os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
return !info.IsDir()
|
||||
}
|
||||
|
||||
func Find(slice []string, val string) (int, bool) {
|
||||
for i, item := range slice {
|
||||
if item == val {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user