first version

This commit is contained in:
Jay 2019-05-15 18:09:36 +08:00
commit 1275619fa0
10 changed files with 365 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
config.yml

6
Makefile Normal file
View File

@ -0,0 +1,6 @@
.PHONY: clean build
build:
GOOS=linux go build -o convert-webp -ldflags "-s -w" .
clean:
rm -rf convert-webp && go clean

2
config.default.yml Normal file
View File

@ -0,0 +1,2 @@
src:
dist:

15
go.mod Normal file
View File

@ -0,0 +1,15 @@
module git.trj.tw/golang/go-watch-webp
go 1.12
require (
git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f // indirect
golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec
golang.org/x/net v0.0.0-20190514140710-3ec191127204 // indirect
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f // indirect
golang.org/x/text v0.3.2 // indirect
golang.org/x/tools v0.0.0-20190515035509-2196cb7019cc // indirect
gopkg.in/fsnotify.v1 v1.4.7
gopkg.in/yaml.v2 v2.2.2
)

23
go.sum Normal file
View File

@ -0,0 +1,23 @@
git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349 h1:V6ifeiJ3ExnjaUylTOz37n6z5uLwm6fjKjnztbTCaQI=
git.trj.tw/golang/utils v0.0.0-20190225142552-b019626f0349/go.mod h1:yE+qbsUsijCTdwsaQRkPT1CXYk7ftMzXsCaaYx/0QI0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec h1:arXJwtMuk5vqI1NHX0UTnNw977rYk5Sl4jQqHj+hun4=
golang.org/x/image v0.0.0-20190507092727-e4e5bf290fec/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190514140710-3ec191127204/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f h1:Xab8gg26GrI/x3RNdVhVkHHM1XLyGeRBEvz4Q5x4YW8=
golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190515035509-2196cb7019cc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

159
main.go Normal file
View File

@ -0,0 +1,159 @@
package main
import (
"errors"
"flag"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"time"
"git.trj.tw/golang/go-watch-webp/module/config"
"git.trj.tw/golang/go-watch-webp/module/image"
"git.trj.tw/golang/go-watch-webp/module/option"
"git.trj.tw/golang/utils"
"gopkg.in/fsnotify.v1"
)
func init() {
option.RegOptions()
}
func main() {
fmt.Println("watch dir webp image")
var err error
lock := make(chan os.Signal, 1)
signal.Notify(lock, os.Interrupt)
opts := option.GetOptions()
if opts.Help {
flag.Usage()
return
}
err = config.LoadConfig(opts.Config)
if err != nil {
log.Fatal(err)
}
conf := config.GetConfig()
if exists := checkDirectory(conf.Src); !exists {
log.Fatal(errors.New("source folder not exists"))
}
if exists := checkDirectory(conf.Dist); !exists {
log.Fatal(errors.New("target folder not exists"))
}
watcher, err := fsnotify.NewWatcher()
if err != nil {
log.Fatal(err)
}
// watch fs notify
go func() {
for {
select {
case event, ok := <-watcher.Events:
if !ok {
return
}
log.Println("fs event :: ", event)
if event.Op&fsnotify.Create == fsnotify.Create {
log.Println("create file :: ", event.Name)
go procFile(event.Name)
}
case err, ok := <-watcher.Errors:
if !ok {
return
}
log.Println("error: ", err)
}
}
}()
err = watcher.Add(conf.Src)
if err != nil {
log.Fatal(err)
}
<-lock
}
func procFile(loc string) {
// only proc webp file
if ext := filepath.Ext(loc); ext != ".webp" {
return
}
go func(loc string) {
fin := waitFile(loc)
if fin {
log.Println("file write ok")
file, err := os.Open(loc)
if err != nil {
log.Println("err :: ", err)
}
defer file.Close()
err = image.ConvertToPng(file)
if err != nil {
log.Println("err :: ", err)
}
}
}(loc)
}
func waitFile(loc string) bool {
if len(loc) == 0 {
return false
}
for {
// check file modify time
t1, err := getFileModTime(loc)
if err != nil {
return false
}
time.Sleep(100 * time.Millisecond)
t2, err := getFileModTime(loc)
if err != nil {
return false
}
if t1 == t2 {
break
}
}
return true
}
func getFileModTime(loc string) (int64, error) {
file, err := os.Open(loc)
if err != nil {
return -1, err
}
defer file.Close()
info, err := file.Stat()
if err != nil {
return -1, err
}
return info.ModTime().UnixNano(), nil
}
func checkDirectory(dir string) bool {
if len(dir) == 0 {
return false
}
dir = utils.ParsePath(dir)
if exists := utils.CheckExists(dir, true); !exists {
return false
}
if isDir := utils.IsDir(dir); !isDir {
return false
}
return true
}

56
module/config/config.go Normal file
View File

@ -0,0 +1,56 @@
package config
import (
"errors"
"io/ioutil"
"os"
"path"
"git.trj.tw/golang/utils"
"gopkg.in/yaml.v2"
)
// Config -
type Config struct {
Src string `yaml:"src"`
Dist string `yaml:"dist"`
}
var conf *Config
// LoadConfig -
func LoadConfig(p ...string) error {
var fp string
if len(p) > 0 && len(p[0]) > 0 {
fp = p[0]
} else {
wd, err := os.Getwd()
if err != nil {
return err
}
fp = path.Join(wd, "config.yml")
}
fp = utils.ParsePath(fp)
if exists := utils.CheckExists(fp, false); !exists {
return errors.New("config not found")
}
dataByte, err := ioutil.ReadFile(fp)
if err != nil {
return err
}
conf = &Config{}
err = yaml.Unmarshal(dataByte, conf)
if err != nil {
return err
}
return nil
}
// GetConfig -
func GetConfig() *Config { return conf }

40
module/image/image.go Normal file
View File

@ -0,0 +1,40 @@
package image
import (
"fmt"
"io"
"log"
"os"
"path"
"time"
"image/png"
"git.trj.tw/golang/go-watch-webp/module/config"
"golang.org/x/image/webp"
)
// ConvertToPng -
func ConvertToPng(file io.Reader) error {
log.Println("convert func ")
conf := config.GetConfig()
webpImg, err := webp.Decode(file)
if err != nil {
return err
}
filename := fmt.Sprintf("%d.png", time.Now().UnixNano())
fp := path.Join(conf.Dist, filename)
target, err := os.Create(fp)
if err != nil {
return err
}
if err := png.Encode(target, webpImg); err != nil {
return err
}
return nil
}

23
module/option/option.go Normal file
View File

@ -0,0 +1,23 @@
package option
import "flag"
// Options -
type Options struct {
Help bool
Config string
}
var opts *Options
// RegOptions -
func RegOptions() {
opts = &Options{}
flag.StringVar(&opts.Config, "config", "", "config file path - default: `pwd/config.yml`")
flag.StringVar(&opts.Config, "f", "", "config file path - default: `pwd/config.yml`")
flag.BoolVar(&opts.Help, "help", false, "show help")
flag.Parse()
}
// GetOptions -
func GetOptions() *Options { return opts }

40
module/pool/pool.go Normal file
View File

@ -0,0 +1,40 @@
package pool
import "sync"
// Pool -
type Pool struct {
q chan bool
wg *sync.WaitGroup
}
// NewPool -
func NewPool(size int) *Pool {
if size < 1 {
size = 1
}
p := &Pool{
q: make(chan bool, size),
wg: &sync.WaitGroup{},
}
return p
}
// Add new queue work
func (p *Pool) Add() {
p.q <- true
p.wg.Add(1)
}
// Done finish work
func (p *Pool) Done() {
<-p.q
p.wg.Done()
}
// Wait -
func (p *Pool) Wait() {
p.wg.Wait()
}