@@ -27,7 +27,6 @@ import (
2727 "strings"
2828 "sync/atomic"
2929
30- "github.com/fsnotify/fsnotify"
3130 "github.com/gorilla/mux"
3231 "go.uber.org/zap"
3332
@@ -61,10 +60,10 @@ func RegisterStaticHandler(r *mux.Router, logger *zap.Logger, qOpts *QueryOption
6160
6261// StaticAssetsHandler handles static assets
6362type StaticAssetsHandler struct {
64- options StaticAssetsHandlerOptions
65- indexHTML atomic.Value // stores []byte
66- assetsFS http.FileSystem
67- newWatcher func () ( fswatcher.Watcher , error )
63+ options StaticAssetsHandlerOptions
64+ indexHTML atomic.Value // stores []byte
65+ assetsFS http.FileSystem
66+ watcher * fswatcher.FSWatcher
6867}
6968
7069// StaticAssetsHandlerOptions defines options for NewStaticAssetsHandler
@@ -73,7 +72,6 @@ type StaticAssetsHandlerOptions struct {
7372 UIConfigPath string
7473 LogAccess bool
7574 Logger * zap.Logger
76- NewWatcher func () (fswatcher.Watcher , error )
7775}
7876
7977type loadedConfig struct {
@@ -92,23 +90,23 @@ func NewStaticAssetsHandler(staticAssetsRoot string, options StaticAssetsHandler
9290 options .Logger = zap .NewNop ()
9391 }
9492
95- if options .NewWatcher == nil {
96- options .NewWatcher = fswatcher .NewWatcher
97- }
98-
9993 indexHTML , err := loadAndEnrichIndexHTML (assetsFS .Open , options )
10094 if err != nil {
10195 return nil , err
10296 }
10397
10498 h := & StaticAssetsHandler {
105- options : options ,
106- assetsFS : assetsFS ,
107- newWatcher : options .NewWatcher ,
99+ options : options ,
100+ assetsFS : assetsFS ,
108101 }
109102
103+ watcher , err := fswatcher .New ([]string {options .UIConfigPath }, h .reloadUIConfig , h .options .Logger )
104+ if err != nil {
105+ return nil , err
106+ }
107+ h .watcher = watcher
108+
110109 h .indexHTML .Store (indexHTML )
111- h .watch ()
112110
113111 return h , nil
114112}
@@ -142,67 +140,14 @@ func loadAndEnrichIndexHTML(open func(string) (http.File, error), options Static
142140 return indexBytes , nil
143141}
144142
145- func (sH * StaticAssetsHandler ) configListener (watcher fswatcher.Watcher ) {
146- for {
147- select {
148- case event := <- watcher .Events ():
149- // ignore if the event filename is not the UI configuration
150- if filepath .Base (event .Name ) != filepath .Base (sH .options .UIConfigPath ) {
151- continue
152- }
153- // ignore if the event is a chmod event (permission or owner changes)
154- if event .Op & fsnotify .Chmod == fsnotify .Chmod {
155- continue
156- }
157- if event .Op & fsnotify .Remove == fsnotify .Remove {
158- sH .options .Logger .Warn ("the UI config file has been removed, using the last known version" )
159- continue
160- }
161- // this will catch events for all files inside the same directory, which is OK if we don't have many changes
162- sH .options .Logger .Info ("reloading UI config" , zap .String ("filename" , sH .options .UIConfigPath ))
163- content , err := loadAndEnrichIndexHTML (sH .assetsFS .Open , sH .options )
164- if err != nil {
165- sH .options .Logger .Error ("error while reloading the UI config" , zap .Error (err ))
166- }
167- sH .indexHTML .Store (content )
168- sH .options .Logger .Info ("reloaded UI config" , zap .String ("filename" , sH .options .UIConfigPath ))
169- case err , ok := <- watcher .Errors ():
170- if ! ok {
171- return
172- }
173- sH .options .Logger .Error ("event" , zap .Error (err ))
174- }
175- }
176- }
177-
178- func (sH * StaticAssetsHandler ) watch () {
179- if sH .options .UIConfigPath == "" {
180- sH .options .Logger .Info ("UI config path not provided, config file will not be watched" )
181- return
182- }
183-
184- watcher , err := sH .newWatcher ()
143+ func (sH * StaticAssetsHandler ) reloadUIConfig () {
144+ sH .options .Logger .Info ("reloading UI config" , zap .String ("filename" , sH .options .UIConfigPath ))
145+ content , err := loadAndEnrichIndexHTML (sH .assetsFS .Open , sH .options )
185146 if err != nil {
186- sH .options .Logger .Error ("failed to create a new watcher for the UI config" , zap .Error (err ))
187- return
188- }
189-
190- go func () {
191- sH .configListener (watcher )
192- }()
193-
194- if err := watcher .Add (sH .options .UIConfigPath ); err != nil {
195- sH .options .Logger .Error ("error adding watcher to file" , zap .String ("file" , sH .options .UIConfigPath ), zap .Error (err ))
196- } else {
197- sH .options .Logger .Info ("watching" , zap .String ("file" , sH .options .UIConfigPath ))
198- }
199-
200- dir := filepath .Dir (sH .options .UIConfigPath )
201- if err := watcher .Add (dir ); err != nil {
202- sH .options .Logger .Error ("error adding watcher to dir" , zap .String ("dir" , dir ), zap .Error (err ))
203- } else {
204- sH .options .Logger .Info ("watching" , zap .String ("dir" , dir ))
147+ sH .options .Logger .Error ("error while reloading the UI config" , zap .Error (err ))
205148 }
149+ sH .indexHTML .Store (content )
150+ sH .options .Logger .Info ("reloaded UI config" , zap .String ("filename" , sH .options .UIConfigPath ))
206151}
207152
208153func loadIndexHTML (open func (string ) (http.File , error )) ([]byte , error ) {
0 commit comments