static.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package xweb
  2. import (
  3. "crypto/md5"
  4. "fmt"
  5. "io"
  6. "os"
  7. "path/filepath"
  8. "sync"
  9. "github.com/howeyc/fsnotify"
  10. )
  11. type StaticVerMgr struct {
  12. Caches map[string]string
  13. mutex *sync.Mutex
  14. Path string
  15. Ignores map[string]bool
  16. app *App
  17. }
  18. func (self *StaticVerMgr) Moniter(staticPath string) error {
  19. watcher, err := fsnotify.NewWatcher()
  20. if err != nil {
  21. return err
  22. }
  23. done := make(chan bool)
  24. go func() {
  25. for {
  26. select {
  27. case ev := <-watcher.Event:
  28. if ev == nil {
  29. break
  30. }
  31. if _, ok := self.Ignores[filepath.Base(ev.Name)]; ok {
  32. break
  33. }
  34. d, err := os.Stat(ev.Name)
  35. if err != nil {
  36. break
  37. }
  38. if ev.IsCreate() {
  39. if d.IsDir() {
  40. watcher.Watch(ev.Name)
  41. } else {
  42. url := ev.Name[len(self.Path)+1:]
  43. self.CacheItem(url)
  44. }
  45. } else if ev.IsDelete() {
  46. if d.IsDir() {
  47. watcher.RemoveWatch(ev.Name)
  48. } else {
  49. pa := ev.Name[len(self.Path)+1:]
  50. self.CacheDelete(pa)
  51. }
  52. } else if ev.IsModify() {
  53. if d.IsDir() {
  54. } else {
  55. url := ev.Name[len(staticPath)+1:]
  56. self.CacheItem(url)
  57. }
  58. } else if ev.IsRename() {
  59. if d.IsDir() {
  60. watcher.RemoveWatch(ev.Name)
  61. } else {
  62. url := ev.Name[len(staticPath)+1:]
  63. self.CacheDelete(url)
  64. }
  65. }
  66. case err := <-watcher.Error:
  67. self.app.Errorf("error: %v", err)
  68. }
  69. }
  70. }()
  71. err = filepath.Walk(staticPath, func(f string, info os.FileInfo, err error) error {
  72. if info.IsDir() {
  73. return watcher.Watch(f)
  74. }
  75. return nil
  76. })
  77. if err != nil {
  78. fmt.Println(err)
  79. return err
  80. }
  81. <-done
  82. watcher.Close()
  83. return nil
  84. }
  85. func (self *StaticVerMgr) Init(app *App, staticPath string) error {
  86. self.Path = staticPath
  87. self.Caches = make(map[string]string)
  88. self.mutex = &sync.Mutex{}
  89. self.Ignores = map[string]bool{".DS_Store": true}
  90. self.app = app
  91. if dirExists(staticPath) {
  92. self.CacheAll(staticPath)
  93. go self.Moniter(staticPath)
  94. }
  95. return nil
  96. }
  97. func (self *StaticVerMgr) getFileVer(url string) string {
  98. //content, err := ioutil.ReadFile(path.Join(self.Path, url))
  99. fPath := filepath.Join(self.Path, url)
  100. self.app.Debug("loaded static ", fPath)
  101. f, err := os.Open(fPath)
  102. if err != nil {
  103. return ""
  104. }
  105. defer f.Close()
  106. fInfo, err := f.Stat()
  107. if err != nil {
  108. return ""
  109. }
  110. content := make([]byte, int(fInfo.Size()))
  111. _, err = f.Read(content)
  112. if err == nil {
  113. h := md5.New()
  114. io.WriteString(h, string(content))
  115. return fmt.Sprintf("%x", h.Sum(nil))[0:4]
  116. }
  117. return ""
  118. }
  119. func (self *StaticVerMgr) CacheAll(staticPath string) error {
  120. self.mutex.Lock()
  121. defer self.mutex.Unlock()
  122. //fmt.Print("Getting static file version number, please wait... ")
  123. err := filepath.Walk(staticPath, func(f string, info os.FileInfo, err error) error {
  124. if info.IsDir() {
  125. return nil
  126. }
  127. rp := f[len(staticPath)+1:]
  128. if _, ok := self.Ignores[filepath.Base(rp)]; !ok {
  129. self.Caches[rp] = self.getFileVer(rp)
  130. }
  131. return nil
  132. })
  133. //fmt.Println("Complete.")
  134. return err
  135. }
  136. func (self *StaticVerMgr) GetVersion(url string) string {
  137. self.mutex.Lock()
  138. defer self.mutex.Unlock()
  139. if ver, ok := self.Caches[url]; ok {
  140. return ver
  141. }
  142. ver := self.getFileVer(url)
  143. if ver != "" {
  144. self.Caches[url] = ver
  145. }
  146. return ver
  147. }
  148. func (self *StaticVerMgr) CacheDelete(url string) {
  149. self.mutex.Lock()
  150. defer self.mutex.Unlock()
  151. delete(self.Caches, url)
  152. self.app.Infof("static file %s is deleted.\n", url)
  153. }
  154. func (self *StaticVerMgr) CacheItem(url string) {
  155. fmt.Println(url)
  156. ver := self.getFileVer(url)
  157. if ver != "" {
  158. self.mutex.Lock()
  159. defer self.mutex.Unlock()
  160. self.Caches[url] = ver
  161. self.app.Infof("static file %s is created.", url)
  162. }
  163. }