186 lines
3.6 KiB
Go
186 lines
3.6 KiB
Go
package xweb
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
"github.com/howeyc/fsnotify"
|
|
)
|
|
|
|
type StaticVerMgr struct {
|
|
Caches map[string]string
|
|
mutex *sync.Mutex
|
|
Path string
|
|
Ignores map[string]bool
|
|
app *App
|
|
}
|
|
|
|
func (self *StaticVerMgr) Moniter(staticPath string) error {
|
|
watcher, err := fsnotify.NewWatcher()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
done := make(chan bool)
|
|
go func() {
|
|
for {
|
|
select {
|
|
case ev := <-watcher.Event:
|
|
if ev == nil {
|
|
break
|
|
}
|
|
if _, ok := self.Ignores[filepath.Base(ev.Name)]; ok {
|
|
break
|
|
}
|
|
d, err := os.Stat(ev.Name)
|
|
if err != nil {
|
|
break
|
|
}
|
|
|
|
if ev.IsCreate() {
|
|
if d.IsDir() {
|
|
watcher.Watch(ev.Name)
|
|
} else {
|
|
url := ev.Name[len(self.Path)+1:]
|
|
self.CacheItem(url)
|
|
}
|
|
} else if ev.IsDelete() {
|
|
if d.IsDir() {
|
|
watcher.RemoveWatch(ev.Name)
|
|
} else {
|
|
pa := ev.Name[len(self.Path)+1:]
|
|
self.CacheDelete(pa)
|
|
}
|
|
} else if ev.IsModify() {
|
|
if d.IsDir() {
|
|
} else {
|
|
url := ev.Name[len(staticPath)+1:]
|
|
self.CacheItem(url)
|
|
}
|
|
} else if ev.IsRename() {
|
|
if d.IsDir() {
|
|
watcher.RemoveWatch(ev.Name)
|
|
} else {
|
|
url := ev.Name[len(staticPath)+1:]
|
|
self.CacheDelete(url)
|
|
}
|
|
}
|
|
case err := <-watcher.Error:
|
|
self.app.Errorf("error: %v", err)
|
|
}
|
|
}
|
|
}()
|
|
|
|
err = filepath.Walk(staticPath, func(f string, info os.FileInfo, err error) error {
|
|
if info.IsDir() {
|
|
return watcher.Watch(f)
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
fmt.Println(err)
|
|
return err
|
|
}
|
|
|
|
<-done
|
|
|
|
watcher.Close()
|
|
return nil
|
|
}
|
|
|
|
func (self *StaticVerMgr) Init(app *App, staticPath string) error {
|
|
self.Path = staticPath
|
|
self.Caches = make(map[string]string)
|
|
self.mutex = &sync.Mutex{}
|
|
self.Ignores = map[string]bool{".DS_Store": true}
|
|
self.app = app
|
|
|
|
if dirExists(staticPath) {
|
|
self.CacheAll(staticPath)
|
|
|
|
go self.Moniter(staticPath)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (self *StaticVerMgr) getFileVer(url string) string {
|
|
//content, err := ioutil.ReadFile(path.Join(self.Path, url))
|
|
fPath := filepath.Join(self.Path, url)
|
|
self.app.Debug("loaded static ", fPath)
|
|
f, err := os.Open(fPath)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
defer f.Close()
|
|
|
|
fInfo, err := f.Stat()
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
|
|
content := make([]byte, int(fInfo.Size()))
|
|
_, err = f.Read(content)
|
|
if err == nil {
|
|
h := md5.New()
|
|
io.WriteString(h, string(content))
|
|
return fmt.Sprintf("%x", h.Sum(nil))[0:4]
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (self *StaticVerMgr) CacheAll(staticPath string) error {
|
|
self.mutex.Lock()
|
|
defer self.mutex.Unlock()
|
|
//fmt.Print("Getting static file version number, please wait... ")
|
|
err := filepath.Walk(staticPath, func(f string, info os.FileInfo, err error) error {
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
rp := f[len(staticPath)+1:]
|
|
if _, ok := self.Ignores[filepath.Base(rp)]; !ok {
|
|
self.Caches[rp] = self.getFileVer(rp)
|
|
}
|
|
return nil
|
|
})
|
|
//fmt.Println("Complete.")
|
|
return err
|
|
}
|
|
|
|
func (self *StaticVerMgr) GetVersion(url string) string {
|
|
self.mutex.Lock()
|
|
defer self.mutex.Unlock()
|
|
if ver, ok := self.Caches[url]; ok {
|
|
return ver
|
|
}
|
|
|
|
ver := self.getFileVer(url)
|
|
if ver != "" {
|
|
self.Caches[url] = ver
|
|
}
|
|
return ver
|
|
}
|
|
|
|
func (self *StaticVerMgr) CacheDelete(url string) {
|
|
self.mutex.Lock()
|
|
defer self.mutex.Unlock()
|
|
delete(self.Caches, url)
|
|
self.app.Infof("static file %s is deleted.\n", url)
|
|
}
|
|
|
|
func (self *StaticVerMgr) CacheItem(url string) {
|
|
fmt.Println(url)
|
|
ver := self.getFileVer(url)
|
|
if ver != "" {
|
|
self.mutex.Lock()
|
|
defer self.mutex.Unlock()
|
|
self.Caches[url] = ver
|
|
self.app.Infof("static file %s is created.", url)
|
|
}
|
|
}
|