From ab7d3794082c971ce1e93c0f3e31fd64ec25fad2 Mon Sep 17 00:00:00 2001 From: Antonio Navarro Perez Date: Mon, 9 Nov 2020 11:33:19 +0100 Subject: [PATCH] Improve info when config is reloaded. (#16) - Using toasts as message outputs (still a lot of room for improvement) Signed-off-by: Antonio Navarro Perez --- assets/js/config.js | 29 ++++++++++++----------- assets/js/toasts.js | 46 +++++++++++++++++++----------------- cmd/distribyted/main.go | 5 ++-- fuse/handler.go | 4 +++- http/api.go | 52 +++++++++++++++++++++++++++-------------- http/http.go | 6 +++-- 6 files changed, 83 insertions(+), 59 deletions(-) diff --git a/assets/js/config.js b/assets/js/config.js index da3ab43..baa6d03 100644 --- a/assets/js/config.js +++ b/assets/js/config.js @@ -57,21 +57,22 @@ function bin2string(array) { function reload() { fetch("/api/reload", { method: "POST", - }).then(function (response) { - if (response.ok) { - return response.text(); - } else { - toastError( - "Error saving configuration file. Response: " + response.status - ); - } }) - .then(function (text) { - toastInfo(text); - }) - .catch(function (error) { - toastError("Error reloading server: " + error.message); - }); + .then(function (response) { + if (response.ok) { + return response.json(); + } else { + toastError( + "Error saving configuration file. Response: " + response.status + ); + } + }) + .then(function (json) { + toastInfo(json.message); + }) + .catch(function (error) { + toastError("Error reloading server: " + error.message); + }); } function save() { diff --git a/assets/js/toasts.js b/assets/js/toasts.js index 71a46b3..ca0635f 100644 --- a/assets/js/toasts.js +++ b/assets/js/toasts.js @@ -1,25 +1,29 @@ +function toast(msg, color, time) { + Toastify({ + text: msg, + duration: time, + newWindow: true, + close: true, + gravity: "top", + position: "right", + backgroundColor: color, + stopOnFocus: true, + }).showToast(); +} + function toastError(msg) { - Toastify({ - text: msg, - duration: 5000, - newWindow: true, - close: true, - gravity: "top", // `top` or `bottom` - position: 'right', // `left`, `center` or `right` - backgroundColor: "red", - stopOnFocus: true, // Prevents dismissing of toast on hover - }).showToast(); + toast(msg, "red", 5000); } function toastInfo(msg) { - Toastify({ - text: msg, - duration: 5000, - newWindow: true, - close: true, - gravity: "top", // `top` or `bottom` - position: 'right', // `left`, `center` or `right` - backgroundColor: "green", - stopOnFocus: true, // Prevents dismissing of toast on hover - }).showToast(); -} \ No newline at end of file + toast(msg, "green", 5000); +} + +function toastMessage(msg) { + toast(msg, "grey", 10000); +} + +var stream = new EventSource("/api/events"); +stream.addEventListener("event", function (e) { + toastMessage(e.data); +}); diff --git a/cmd/distribyted/main.go b/cmd/distribyted/main.go index adab334..cfa1a15 100644 --- a/cmd/distribyted/main.go +++ b/cmd/distribyted/main.go @@ -103,13 +103,12 @@ func load(configPath string, port int) error { for _, mp := range c.MountPoints { ef(fmt.Sprintf("mounting %v with %d torrents...", mp.Path, len(mp.Torrents))) - if err := mountService.Mount(mp); err != nil { + if err := mountService.Mount(mp, ef); err != nil { return fmt.Errorf("error mounting folder %v: %w", mp.Path, err) } + ef(fmt.Sprintf("%v mounted", mp.Path)) } - ef("all OK") - return nil }) diff --git a/fuse/handler.go b/fuse/handler.go index 2bbe771..d5f357d 100644 --- a/fuse/handler.go +++ b/fuse/handler.go @@ -29,7 +29,7 @@ func NewHandler(c *torrent.Client, s *stats.Torrent) *Handler { } } -func (s *Handler) Mount(mpc *config.MountPoint) error { +func (s *Handler) Mount(mpc *config.MountPoint, ef config.EventFunc) error { var torrents []fs.Filesystem for _, mpcTorrent := range mpc.Torrents { var t *torrent.Torrent @@ -51,6 +51,7 @@ func (s *Handler) Mount(mpc *config.MountPoint) error { // only get info if name is not available if t.Name() == "" { + ef(fmt.Sprintf("getting torrent info...: %v", t.InfoHash())) log.WithField("hash", t.InfoHash()).Info("getting torrent info") <-t.GotInfo() } @@ -58,6 +59,7 @@ func (s *Handler) Mount(mpc *config.MountPoint) error { s.s.Add(mpc.Path, t) torrents = append(torrents, fs.NewTorrent(t)) + ef(fmt.Sprintf("torrent %v added to mountpoint", t.Name())) log.WithField("name", t.Name()).WithField("path", mpc.Path).Info("torrent added to mountpoint") } diff --git a/http/api.go b/http/api.go index b039a9e..38cdf83 100644 --- a/http/api.go +++ b/http/api.go @@ -4,6 +4,7 @@ import ( "errors" "io" "io/ioutil" + "net/http" "github.com/ajnavarro/distribyted/config" "github.com/ajnavarro/distribyted/stats" @@ -14,7 +15,7 @@ import ( var apiStatusHandler = func(fc *filecache.Cache, ss *stats.Torrent) gin.HandlerFunc { return func(ctx *gin.Context) { // TODO move to a struct - ctx.JSON(200, gin.H{ + ctx.JSON(http.StatusOK, gin.H{ "cacheItems": fc.Info().NumItems, "cacheFilled": fc.Info().Filled / 1024 / 1024, "cacheCapacity": fc.Info().Capacity / 1024 / 1024, @@ -26,7 +27,7 @@ var apiStatusHandler = func(fc *filecache.Cache, ss *stats.Torrent) gin.HandlerF var apiRoutesHandler = func(ss *stats.Torrent) gin.HandlerFunc { return func(ctx *gin.Context) { stats := ss.RoutesStats() - ctx.JSON(200, stats) + ctx.JSON(http.StatusOK, stats) } } @@ -34,54 +35,69 @@ var apiGetConfigFile = func(ch *config.Handler) gin.HandlerFunc { return func(ctx *gin.Context) { rc, err := ch.GetRaw() if err != nil { - ctx.AbortWithError(500, err) + ctx.AbortWithError(http.StatusInternalServerError, err) return } - ctx.Data(200, "text/x-yaml", rc) + ctx.Data(http.StatusOK, "text/x-yaml", rc) } } var apiSetConfigFile = func(ch *config.Handler) gin.HandlerFunc { return func(ctx *gin.Context) { if ctx.Request.Body == nil { - ctx.AbortWithError(500, errors.New("no config file sent")) + ctx.AbortWithError(http.StatusInternalServerError, errors.New("no config file sent")) return } c, err := ioutil.ReadAll(ctx.Request.Body) if err != nil { - ctx.AbortWithError(500, err) + ctx.AbortWithError(http.StatusInternalServerError, err) return } if len(c) == 0 { - ctx.AbortWithError(500, errors.New("no config file sent")) + ctx.AbortWithError(http.StatusInternalServerError, errors.New("no config file sent")) return } if err := ch.Set(c); err != nil { - ctx.AbortWithError(500, err) + ctx.AbortWithError(http.StatusInternalServerError, err) return } - // TODO return something? - ctx.JSON(200, nil) + ctx.JSON(http.StatusOK, gin.H{ + "message": "config file saved", + }) } } -var apiReloadServer = func(ch *config.Handler) gin.HandlerFunc { +var apiStreamEvents = func(events chan string) gin.HandlerFunc { return func(ctx *gin.Context) { ctx.Stream(func(w io.Writer) bool { - err := ch.Reload( - func(m string) { - ctx.SSEvent("reload", m) - }) - if err != nil { - ctx.AbortWithError(500, err) + if msg, ok := <-events; ok { + ctx.SSEvent("event", msg) + return true } - return false }) } } + +var apiReloadServer = func(ch *config.Handler, events chan string) gin.HandlerFunc { + return func(ctx *gin.Context) { + events <- "starting reload configuration process..." + + err := ch.Reload( + func(m string) { + events <- m + }) + if err != nil { + ctx.AbortWithError(http.StatusInternalServerError, err) + } + + ctx.JSON(http.StatusOK, gin.H{ + "message": "reload process finished with no errors", + }) + } +} diff --git a/http/http.go b/http/http.go index 2793c5b..6314aab 100644 --- a/http/http.go +++ b/http/http.go @@ -32,14 +32,16 @@ func New(fc *filecache.Cache, ss *stats.Torrent, ch *config.Handler, port int) e r.GET("/routes", routesHandler(ss)) r.GET("/config", configHandler) + eventChan := make(chan string) + api := r.Group("/api") { api.GET("/status", apiStatusHandler(fc, ss)) api.GET("/routes", apiRoutesHandler(ss)) api.GET("/config", apiGetConfigFile(ch)) api.POST("/config", apiSetConfigFile(ch)) - api.POST("/reload", apiReloadServer(ch)) - + api.POST("/reload", apiReloadServer(ch, eventChan)) + api.GET("/events", apiStreamEvents(eventChan)) } logrus.WithField("host", fmt.Sprintf("0.0.0.0:%d", port)).Info("starting webserver")