207 lines
5.6 KiB
Go
207 lines
5.6 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
var DashboardDir string
|
|
|
|
func declarePublicRoutes(router *gin.RouterGroup) {
|
|
router.GET("/public/", listPublic)
|
|
router.GET("/public/:sid", getPublic)
|
|
router.DELETE("/public/:sid", deletePublic)
|
|
router.PUT("/public/:sid", savePublic)
|
|
}
|
|
|
|
type FICPublicScene struct {
|
|
Type string `json:"type"`
|
|
Params map[string]interface{} `json:"params"`
|
|
}
|
|
|
|
type FICPublicDisplay struct {
|
|
Scenes []FICPublicScene `json:"scenes"`
|
|
Side []FICPublicScene `json:"side"`
|
|
CustomCountdown map[string]interface{} `json:"customCountdown"`
|
|
HideEvents bool `json:"hideEvents"`
|
|
HideCountdown bool `json:"hideCountdown"`
|
|
HideCarousel bool `json:"hideCarousel"`
|
|
PropagationTime *time.Time `json:"propagationTime,omitempty"`
|
|
}
|
|
|
|
func InitDashboardPresets(dir string) error {
|
|
return nil
|
|
}
|
|
|
|
func readPublic(path string) (FICPublicDisplay, error) {
|
|
var s FICPublicDisplay
|
|
if fd, err := os.Open(path); err != nil {
|
|
return s, err
|
|
} else {
|
|
defer fd.Close()
|
|
jdec := json.NewDecoder(fd)
|
|
|
|
if err := jdec.Decode(&s); err != nil {
|
|
return s, err
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
}
|
|
|
|
func savePublicTo(path string, s FICPublicDisplay) error {
|
|
if fd, err := os.Create(path); err != nil {
|
|
return err
|
|
} else {
|
|
defer fd.Close()
|
|
jenc := json.NewEncoder(fd)
|
|
|
|
if err := jenc.Encode(s); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
type DashboardFiles struct {
|
|
Presets []string `json:"presets"`
|
|
Nexts []*NextDashboardFile `json:"nexts"`
|
|
}
|
|
|
|
type NextDashboardFile struct {
|
|
Name string `json:"name"`
|
|
Screen int `json:"screen"`
|
|
Date time.Time `json:"date"`
|
|
}
|
|
|
|
func listPublic(c *gin.Context) {
|
|
files, err := os.ReadDir(DashboardDir)
|
|
if err != nil {
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": err.Error()})
|
|
return
|
|
}
|
|
|
|
var ret DashboardFiles
|
|
for _, file := range files {
|
|
if strings.HasPrefix(file.Name(), "preset-") {
|
|
ret.Presets = append(ret.Presets, strings.TrimSuffix(strings.TrimPrefix(file.Name(), "preset-"), ".json"))
|
|
continue
|
|
}
|
|
|
|
if !strings.HasPrefix(file.Name(), "public") || len(file.Name()) < 18 {
|
|
continue
|
|
}
|
|
|
|
ts, err := strconv.ParseInt(file.Name()[8:18], 10, 64)
|
|
if err == nil {
|
|
s, _ := strconv.Atoi(file.Name()[6:7])
|
|
ret.Nexts = append(ret.Nexts, &NextDashboardFile{
|
|
Name: file.Name()[6:18],
|
|
Screen: s,
|
|
Date: time.Unix(ts, 0),
|
|
})
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, ret)
|
|
}
|
|
|
|
func getPublic(c *gin.Context) {
|
|
if strings.Contains(c.Params.ByName("sid"), "/") {
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "sid cannot contains /"})
|
|
return
|
|
}
|
|
|
|
filename := fmt.Sprintf("public%s.json", c.Params.ByName("sid"))
|
|
if strings.HasPrefix(c.Params.ByName("sid"), "preset-") {
|
|
filename = fmt.Sprintf("%s.json", c.Params.ByName("sid"))
|
|
}
|
|
|
|
if _, err := os.Stat(path.Join(DashboardDir, filename)); !os.IsNotExist(err) {
|
|
p, err := readPublic(path.Join(DashboardDir, filename))
|
|
if err != nil {
|
|
log.Println("Unable to readPublic in getPublic:", err.Error())
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during scene retrieval."})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, p)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, FICPublicDisplay{Scenes: []FICPublicScene{}, Side: []FICPublicScene{}})
|
|
}
|
|
|
|
func deletePublic(c *gin.Context) {
|
|
if strings.Contains(c.Params.ByName("sid"), "/") {
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "sid cannot contains /"})
|
|
return
|
|
}
|
|
|
|
filename := fmt.Sprintf("public%s.json", c.Params.ByName("sid"))
|
|
if strings.HasPrefix(c.Params.ByName("sid"), "preset-") {
|
|
filename = fmt.Sprintf("%s.json", c.Params.ByName("sid"))
|
|
}
|
|
|
|
if len(filename) == 12 {
|
|
if err := savePublicTo(path.Join(DashboardDir, filename), FICPublicDisplay{}); err != nil {
|
|
log.Println("Unable to deletePublic:", err.Error())
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during scene deletion."})
|
|
return
|
|
}
|
|
} else {
|
|
if err := os.Remove(path.Join(DashboardDir, filename)); err != nil {
|
|
log.Println("Unable to deletePublic:", err.Error())
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during scene deletion."})
|
|
return
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, FICPublicDisplay{Scenes: []FICPublicScene{}, Side: []FICPublicScene{}})
|
|
}
|
|
|
|
func savePublic(c *gin.Context) {
|
|
if strings.Contains(c.Params.ByName("sid"), "/") {
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": "sid cannot contains /"})
|
|
return
|
|
}
|
|
|
|
var scenes FICPublicDisplay
|
|
err := c.ShouldBindJSON(&scenes)
|
|
if err != nil {
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
|
|
return
|
|
}
|
|
|
|
filename := fmt.Sprintf("public%s.json", c.Params.ByName("sid"))
|
|
if c.Request.URL.Query().Has("t") {
|
|
t, err := time.Parse(time.RFC3339, c.Request.URL.Query().Get("t"))
|
|
if err != nil {
|
|
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"errmsg": err.Error()})
|
|
return
|
|
}
|
|
|
|
filename = fmt.Sprintf("public%s-%d.json", c.Params.ByName("sid"), t.Unix())
|
|
} else if c.Request.URL.Query().Has("p") {
|
|
filename = fmt.Sprintf("preset-%s.json", c.Request.URL.Query().Get("p"))
|
|
}
|
|
|
|
if err := savePublicTo(path.Join(DashboardDir, filename), scenes); err != nil {
|
|
log.Println("Unable to savePublicTo:", err.Error())
|
|
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"errmsg": "An error occurs during scene saving."})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, scenes)
|
|
}
|