package api import ( "bytes" "fmt" "net/http" "time" "github.com/gin-gonic/gin" "git.nemunai.re/nemunaire/reveil/config" "git.nemunai.re/nemunaire/reveil/model" "git.nemunai.re/nemunaire/reveil/player" ) func declareFederationRoutes(cfg *config.Config, router *gin.RouterGroup) { router.POST("/federation/wakeup", func(c *gin.Context) { var s map[string]interface{} c.ShouldBind(s) if player.CommonPlayer == nil { var seed int64 if tmp, ok := s["seed"].(int64); ok { seed = tmp } else { seed := time.Now().Unix() seed -= seed % 172800 } err := player.WakeUpFromFederation(cfg, seed, nil) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) return } } else { c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "Player already running"}) return } c.JSON(http.StatusOK, true) }) router.POST("/federation/wakeok", func(c *gin.Context) { if player.CommonPlayer != nil { err := player.CommonPlayer.Stop() if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) return } } c.JSON(http.StatusOK, true) }) router.GET("/federation", func(c *gin.Context) { settings, err := reveil.ReadSettings(cfg.SettingsFile) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) return } c.JSON(http.StatusOK, settings.Federation) }) federationsRoutes := router.Group("/federation/:fid") federationsRoutes.Use(func(c *gin.Context) { settings, err := reveil.ReadSettings(cfg.SettingsFile) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) return } f, ok := settings.Federation[string(c.Param("fid"))] if !ok { c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"errmsg": "Action not found"}) return } c.Set("federation", &f) c.Next() }) federationsRoutes.GET("", func(c *gin.Context) { c.JSON(http.StatusOK, c.MustGet("federation")) }) federationsRoutes.POST("sync", func(c *gin.Context) { srv := c.MustGet("federation").(*reveil.FederationServer) // Retrieve music list on remote remoteMusics, err := srv.GetMusics() if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to retrieve remote tracks lists: %s", err.Error())}) return } // Retrieve local music list localMusics, err := reveil.LoadTracks(cfg) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("Unable to retrieve local tracks: %s", err.Error())}) return } // Compute diff var newMusics []reveil.Track var oldMusics []reveil.Track var musicsToEnable []reveil.Track for _, rTrack := range remoteMusics { found := false for _, lTrack := range localMusics { if bytes.Compare(lTrack.Id, rTrack.Id) == 0 || lTrack.Name == rTrack.Name { if lTrack.Enabled != rTrack.Enabled { if lTrack.Enabled { musicsToEnable = append(musicsToEnable, rTrack) } else { oldMusics = append(oldMusics, *lTrack) } } found = true break } } if !found && rTrack.Enabled { oldMusics = append(oldMusics, rTrack) } } for _, lTrack := range localMusics { found := false for _, rTrack := range remoteMusics { if bytes.Compare(lTrack.Id, rTrack.Id) == 0 || lTrack.Name == rTrack.Name { found = true break } } if !found && lTrack.Enabled { newMusics = append(newMusics, *lTrack) } } // Disable unexistant musics on local for _, t := range oldMusics { t.Enabled = false err = srv.UpdateTrack(&t) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": fmt.Sprintf("An error occurs when disabling remote tracks (unexistant on local): %s: %s", t.Id.ToString(), err.Error())}) return } } // Enable existant musics on remote for _, t := range musicsToEnable { t.Enabled = true err = srv.UpdateTrack(&t) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) return } } // Send new musics for _, t := range newMusics { err = srv.SendTrack(&t) if err != nil { c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()}) return } } c.JSON(http.StatusOK, true) }) }