diff options
Diffstat (limited to 'server.go')
| -rw-r--r-- | server.go | 67 |
1 files changed, 56 insertions, 11 deletions
@@ -10,6 +10,7 @@ import ( "html/template" "log" "net/http" + "sync" "time" ) @@ -24,11 +25,18 @@ type Server struct { httpd *http.Server worker *worker + // updateq channel to receive notification when the new report coming + // from worker. + updateq chan struct{} + Options ServerOptions - Reports Reports pageIndexTmpl *template.Template pageIndexBody bytes.Buffer + + // pageIndexMutex guard the pageIndexBody between changes from worker + // Reports (write) and when rendered to client (read). + pageIndexMutex sync.Mutex } // NewServer create new server to serve the content of _www and HTTP APIs. @@ -37,9 +45,7 @@ func NewServer(opts ServerOptions) (srv *Server, err error) { srv = &Server{ Options: opts, - Reports: Reports{ - Services: map[string]ServiceReport{}, - }, + updateq: make(chan struct{}, 1), } err = srv.Options.init() @@ -52,17 +58,11 @@ func NewServer(opts ServerOptions) (srv *Server, err error) { return nil, fmt.Errorf(`%s: %w`, logp, err) } - for name := range srv.worker.Services { - srv.Reports.Services[name] = ServiceReport{ - Name: name, - } - } - srv.pageIndexTmpl, err = template.ParseFS(wwwFS, `_www/index.tmpl`) if err != nil { return nil, err } - err = srv.pageIndexTmpl.Execute(&srv.pageIndexBody, &srv.Reports) + err = srv.pageIndexTmpl.Execute(&srv.pageIndexBody, &srv.worker.Reports) if err != nil { return nil, err } @@ -81,6 +81,9 @@ func NewServer(opts ServerOptions) (srv *Server, err error) { // ListenAndServe start handling request on incoming connections. func (srv *Server) ListenAndServe() (err error) { + go srv.update() + go srv.worker.start(srv.updateq) + log.Printf(`lilin: starting HTTP server at %s`, srv.Options.Address) err = srv.httpd.ListenAndServe() @@ -97,6 +100,8 @@ func (srv *Server) Shutdown(ctx context.Context) (err error) { if err != nil { return fmt.Errorf(`Shutdown: %w`, err) } + srv.worker.stop() + close(srv.updateq) return nil } @@ -105,7 +110,9 @@ func (srv *Server) ServeHTTP(resw http.ResponseWriter, req *http.Request) { switch req.URL.Path { case `/`, `/index.html`: + srv.pageIndexMutex.Lock() _, err = resw.Write(srv.pageIndexBody.Bytes()) + srv.pageIndexMutex.Unlock() if err != nil { srv.internalError(resw, err) } @@ -122,3 +129,41 @@ func (srv *Server) internalError(resw http.ResponseWriter, err error) { log.Println(`internalError:`, err.Error()) } } + +// update the index page body periodically only when there is changes from +// upstream worker. +// Since services may have different scanned interval (and may longer than +// default interval), it will takes times to update the index page body every +// times we receive updates from worker. +// Hence why we need to update only when changes happened. +func (srv *Server) update() { + var ticker = time.NewTicker(defInterval) + var c int + var err error + for { + select { + case _, ok := <-srv.updateq: + if !ok { + return + } + c++ + case <-ticker.C: + if c == 0 { + continue + } + c = 0 + + srv.pageIndexMutex.Lock() + srv.worker.reportsMutex.Lock() + + srv.pageIndexBody.Reset() + err = srv.pageIndexTmpl.Execute(&srv.pageIndexBody, &srv.worker.Reports) + if err != nil { + log.Printf(`update: pageIndexTmpl: %s`, err) + } + + srv.worker.reportsMutex.Unlock() + srv.pageIndexMutex.Unlock() + } + } +} |
