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 <antnavper@gmail.com>
This commit is contained in:
parent
0e2288565d
commit
ab7d379408
6 changed files with 83 additions and 59 deletions
|
@ -57,21 +57,22 @@ function bin2string(array) {
|
||||||
function reload() {
|
function reload() {
|
||||||
fetch("/api/reload", {
|
fetch("/api/reload", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
}).then(function (response) {
|
|
||||||
if (response.ok) {
|
|
||||||
return response.text();
|
|
||||||
} else {
|
|
||||||
toastError(
|
|
||||||
"Error saving configuration file. Response: " + response.status
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.then(function (text) {
|
.then(function (response) {
|
||||||
toastInfo(text);
|
if (response.ok) {
|
||||||
})
|
return response.json();
|
||||||
.catch(function (error) {
|
} else {
|
||||||
toastError("Error reloading server: " + error.message);
|
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() {
|
function save() {
|
||||||
|
|
|
@ -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) {
|
function toastError(msg) {
|
||||||
Toastify({
|
toast(msg, "red", 5000);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toastInfo(msg) {
|
function toastInfo(msg) {
|
||||||
Toastify({
|
toast(msg, "green", 5000);
|
||||||
text: msg,
|
}
|
||||||
duration: 5000,
|
|
||||||
newWindow: true,
|
function toastMessage(msg) {
|
||||||
close: true,
|
toast(msg, "grey", 10000);
|
||||||
gravity: "top", // `top` or `bottom`
|
}
|
||||||
position: 'right', // `left`, `center` or `right`
|
|
||||||
backgroundColor: "green",
|
var stream = new EventSource("/api/events");
|
||||||
stopOnFocus: true, // Prevents dismissing of toast on hover
|
stream.addEventListener("event", function (e) {
|
||||||
}).showToast();
|
toastMessage(e.data);
|
||||||
}
|
});
|
||||||
|
|
|
@ -103,13 +103,12 @@ func load(configPath string, port int) error {
|
||||||
|
|
||||||
for _, mp := range c.MountPoints {
|
for _, mp := range c.MountPoints {
|
||||||
ef(fmt.Sprintf("mounting %v with %d torrents...", mp.Path, len(mp.Torrents)))
|
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)
|
return fmt.Errorf("error mounting folder %v: %w", mp.Path, err)
|
||||||
}
|
}
|
||||||
|
ef(fmt.Sprintf("%v mounted", mp.Path))
|
||||||
}
|
}
|
||||||
|
|
||||||
ef("all OK")
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -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
|
var torrents []fs.Filesystem
|
||||||
for _, mpcTorrent := range mpc.Torrents {
|
for _, mpcTorrent := range mpc.Torrents {
|
||||||
var t *torrent.Torrent
|
var t *torrent.Torrent
|
||||||
|
@ -51,6 +51,7 @@ func (s *Handler) Mount(mpc *config.MountPoint) error {
|
||||||
|
|
||||||
// only get info if name is not available
|
// only get info if name is not available
|
||||||
if t.Name() == "" {
|
if t.Name() == "" {
|
||||||
|
ef(fmt.Sprintf("getting torrent info...: %v", t.InfoHash()))
|
||||||
log.WithField("hash", t.InfoHash()).Info("getting torrent info")
|
log.WithField("hash", t.InfoHash()).Info("getting torrent info")
|
||||||
<-t.GotInfo()
|
<-t.GotInfo()
|
||||||
}
|
}
|
||||||
|
@ -58,6 +59,7 @@ func (s *Handler) Mount(mpc *config.MountPoint) error {
|
||||||
s.s.Add(mpc.Path, t)
|
s.s.Add(mpc.Path, t)
|
||||||
torrents = append(torrents, fs.NewTorrent(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")
|
log.WithField("name", t.Name()).WithField("path", mpc.Path).Info("torrent added to mountpoint")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
52
http/api.go
52
http/api.go
|
@ -4,6 +4,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
"github.com/ajnavarro/distribyted/config"
|
"github.com/ajnavarro/distribyted/config"
|
||||||
"github.com/ajnavarro/distribyted/stats"
|
"github.com/ajnavarro/distribyted/stats"
|
||||||
|
@ -14,7 +15,7 @@ import (
|
||||||
var apiStatusHandler = func(fc *filecache.Cache, ss *stats.Torrent) gin.HandlerFunc {
|
var apiStatusHandler = func(fc *filecache.Cache, ss *stats.Torrent) gin.HandlerFunc {
|
||||||
return func(ctx *gin.Context) {
|
return func(ctx *gin.Context) {
|
||||||
// TODO move to a struct
|
// TODO move to a struct
|
||||||
ctx.JSON(200, gin.H{
|
ctx.JSON(http.StatusOK, gin.H{
|
||||||
"cacheItems": fc.Info().NumItems,
|
"cacheItems": fc.Info().NumItems,
|
||||||
"cacheFilled": fc.Info().Filled / 1024 / 1024,
|
"cacheFilled": fc.Info().Filled / 1024 / 1024,
|
||||||
"cacheCapacity": fc.Info().Capacity / 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 {
|
var apiRoutesHandler = func(ss *stats.Torrent) gin.HandlerFunc {
|
||||||
return func(ctx *gin.Context) {
|
return func(ctx *gin.Context) {
|
||||||
stats := ss.RoutesStats()
|
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) {
|
return func(ctx *gin.Context) {
|
||||||
rc, err := ch.GetRaw()
|
rc, err := ch.GetRaw()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithError(500, err)
|
ctx.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Data(200, "text/x-yaml", rc)
|
ctx.Data(http.StatusOK, "text/x-yaml", rc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiSetConfigFile = func(ch *config.Handler) gin.HandlerFunc {
|
var apiSetConfigFile = func(ch *config.Handler) gin.HandlerFunc {
|
||||||
return func(ctx *gin.Context) {
|
return func(ctx *gin.Context) {
|
||||||
if ctx.Request.Body == nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := ioutil.ReadAll(ctx.Request.Body)
|
c, err := ioutil.ReadAll(ctx.Request.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.AbortWithError(500, err)
|
ctx.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(c) == 0 {
|
if len(c) == 0 {
|
||||||
ctx.AbortWithError(500, errors.New("no config file sent"))
|
ctx.AbortWithError(http.StatusInternalServerError, errors.New("no config file sent"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := ch.Set(c); err != nil {
|
if err := ch.Set(c); err != nil {
|
||||||
ctx.AbortWithError(500, err)
|
ctx.AbortWithError(http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO return something?
|
ctx.JSON(http.StatusOK, gin.H{
|
||||||
ctx.JSON(200, nil)
|
"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) {
|
return func(ctx *gin.Context) {
|
||||||
ctx.Stream(func(w io.Writer) bool {
|
ctx.Stream(func(w io.Writer) bool {
|
||||||
err := ch.Reload(
|
if msg, ok := <-events; ok {
|
||||||
func(m string) {
|
ctx.SSEvent("event", msg)
|
||||||
ctx.SSEvent("reload", m)
|
return true
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
ctx.AbortWithError(500, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
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",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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("/routes", routesHandler(ss))
|
||||||
r.GET("/config", configHandler)
|
r.GET("/config", configHandler)
|
||||||
|
|
||||||
|
eventChan := make(chan string)
|
||||||
|
|
||||||
api := r.Group("/api")
|
api := r.Group("/api")
|
||||||
{
|
{
|
||||||
api.GET("/status", apiStatusHandler(fc, ss))
|
api.GET("/status", apiStatusHandler(fc, ss))
|
||||||
api.GET("/routes", apiRoutesHandler(ss))
|
api.GET("/routes", apiRoutesHandler(ss))
|
||||||
api.GET("/config", apiGetConfigFile(ch))
|
api.GET("/config", apiGetConfigFile(ch))
|
||||||
api.POST("/config", apiSetConfigFile(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")
|
logrus.WithField("host", fmt.Sprintf("0.0.0.0:%d", port)).Info("starting webserver")
|
||||||
|
|
Loading…
Reference in a new issue