From a4a9afc4b0140123c8ef79766c7ad5187265aa05 Mon Sep 17 00:00:00 2001 From: damiva <96115589+damiva@users.noreply.github.com> Date: Tue, 28 May 2024 15:29:59 +0300 Subject: [PATCH] Update msx.go (#411) --- server/web/msx/msx.go | 267 ++++++++++++++++++------------------------ 1 file changed, 116 insertions(+), 151 deletions(-) diff --git a/server/web/msx/msx.go b/server/web/msx/msx.go index b797209..ffe50f3 100644 --- a/server/web/msx/msx.go +++ b/server/web/msx/msx.go @@ -2,93 +2,125 @@ package msx import ( "encoding/json" - "errors" "net/http" "os" - "path" - "strconv" - "strings" - "time" - + "path/filepath" "server/settings" "server/torr" "server/utils" "server/version" "server/web/auth" + "strconv" + "strings" "github.com/gin-gonic/gin" ) -const ( - files = `files` - base = `https://damiva.github.io/msx/` - htmlB = ` - - - TorrServer MSX Plugin - - - - - -` -) +const base, files = "tsmsx.yourok.ru", "media" -var start = struct { - N string `json:"name"` - V string `json:"version"` - P string `json:"parameter"` -}{"TorrServer", version.Version, "menu:request:interaction:init@{PREFIX}{SERVER}/msx/ts"} +var param = "menu:request:interaction:{SERVER}@{PREFIX}" + base + "/start.html" + +func trn(h string) (st, sc string) { + if h := torr.GetTorrent(h); h != nil { + if h := h.Status(); h != nil && h.Stat < 5 { + switch h.Stat { + case 4: + sc = "msx-red" + case 3: + sc = "msx-green" + default: + sc = "msx-yellow" + } + st = "{ico:north} " + strconv.Itoa(h.ActivePeers) + " / " + strconv.Itoa(h.TotalPeers) + " {ico:south} " + strconv.Itoa(h.ConnectedSeeders) + } + } + return +} +func rsp(c *gin.Context, r *http.Response, e error) { + if e != nil { + c.AbortWithError(http.StatusInternalServerError, e) + } else { + defer r.Body.Close() + c.DataFromReader(r.StatusCode, r.ContentLength, r.Header.Get("Content-Type"), r.Body, nil) + } +} func SetupRoute(r gin.IRouter) { authorized := r.Group("/", auth.CheckAuth()) - // MSX: - authorized.Any("/msx/*pth", func(c *gin.Context) { - switch p := strings.TrimPrefix(c.Param("pth"), "/"); p { - case "start.json": - if c.Request.Method != "POST" { - c.JSON(200, &start) - } else if e := json.NewDecoder(c.Request.Body).Decode(&start); e != nil { - c.AbortWithError(http.StatusBadRequest, e) - } - case "proxy": - proxy(c, c.Query("url"), c.QueryArray("header")...) - case "torrent": - torrent(c) - default: - if p != "" && !strings.HasSuffix(p, "/") && path.Ext(p) == "" { - p = base + p + `.js?t=` + strconv.FormatInt(time.Now().Unix(), 16) - c.Data(200, "text/html;charset=UTF-8", append(append([]byte(htmlB), p...), htmlE...)) - } else { - proxy(c, base+p) - } - } + //MSX: + authorized.GET("/msx/", func(c *gin.Context) { + r, e := http.Get("http://" + base) + rsp(c, r, e) }) - // files: - authorized.GET("/files", func(c *gin.Context) { - if l, e := os.Readlink(files); e == nil || os.IsNotExist(e) { - c.JSON(200, l) - } else { - c.AbortWithError(http.StatusInternalServerError, e) - } + authorized.GET("/msx/start.json", func(c *gin.Context) { + c.JSON(200, map[string]string{"name": "TorrServer", "version": version.Version, "parameter": param}) }) - authorized.POST("/files", func(c *gin.Context) { - var l string - if e := c.Bind(&l); e != nil { + authorized.POST("/msx/start.json", func(c *gin.Context) { + if e := json.NewDecoder(c.Request.Body).Decode(¶m); e != nil { c.AbortWithError(http.StatusBadRequest, e) - } else if e = os.Remove(files); e != nil && !os.IsNotExist(e) { - c.AbortWithError(http.StatusInternalServerError, e) - } else if l != "" { - if e = os.Symlink(l, files); e != nil { - c.AbortWithError(http.StatusInternalServerError, e) - } } }) - authorized.StaticFS("/files/", gin.Dir(files, true)) - // IMDB: - authorized.GET("/imdb/:id", func(c *gin.Context) { + authorized.GET("/msx/trn", func(c *gin.Context) { + r := false + if h := c.Query("hash"); h != "" { + for _, t := range settings.ListTorrent() { + if r = (t != nil && t.InfoHash.HexString() == h); r { + break + } + } + } + c.JSON(200, r) + }) + authorized.POST("/msx/trn", func(c *gin.Context) { + var r struct { + R struct { + S int `json:"status"` + T string `json:"text"` + M string `json:"message,omitempty"` + D map[string]any `json:"data,omitempty"` + } `json:"response"` + } + if j := struct{ Data string }{Data: c.Query("hash")}; j.Data != "" { + st, sc := trn(j.Data) + if sc != "" { + sc = "{col:" + sc + "}" + } + r.R.S, r.R.D = http.StatusOK, map[string]any{"action": "player:label:position:{LABEL}{tb}{tb}" + sc + st} + } else if e := json.NewDecoder(c.Request.Body).Decode(&j); e != nil { + r.R.S, r.R.M = http.StatusBadRequest, e.Error() + } else if j.Data == "" { + r.R.S, r.R.M = http.StatusBadRequest, "data is not set" + } else { + st, sc := trn(j.Data[strings.LastIndexByte(j.Data, ':')+1:]) + r.R.D = map[string]any{"stamp": st, "stampColor": sc} + if sc != "" { + r.R.D["live"] = map[string]any{ + "type": "airtime", "duration": 1000, "over": map[string]any{ + "action": "execute:" + utils.GetScheme(c) + "://" + c.Request.Host + c.Request.URL.Path, "data": j.Data, + }, + } + } + r.R.S, r.R.D = http.StatusOK, map[string]any{"action": j.Data, "data": r.R.D} + } + r.R.T = http.StatusText(r.R.S) + c.JSON(200, &r) + }) + authorized.Any("/msx/proxy", func(c *gin.Context) { + if u := c.Query("url"); u == "" { + c.AbortWithStatus(http.StatusBadRequest) + } else if q, e := http.NewRequest(c.Request.Method, u, c.Request.Body); e != nil { + c.AbortWithError(http.StatusInternalServerError, e) + } else { + for _, v := range c.QueryArray("header") { + if v := strings.SplitN(v, ":", 2); len(v) == 2 { + q.Header.Add(v[0], v[1]) + } + } + r, e := http.DefaultClient.Do(q) + rsp(c, r, e) + } + }) + authorized.GET("/msx/imdb/:id", func(c *gin.Context) { i, l, j := strings.TrimPrefix(c.Param("id"), "/"), "", false if j = strings.HasSuffix(i, ".json"); !j { i += ".json" @@ -112,92 +144,25 @@ func SetupRoute(r gin.IRouter) { c.Redirect(http.StatusMovedPermanently, l) } }) -} - -func proxy(c *gin.Context, u string, h ...string) { - if u == "" { - c.AbortWithStatus(http.StatusBadRequest) - } else if q, e := http.NewRequest(c.Request.Method, u, c.Request.Body); e != nil { - c.AbortWithError(http.StatusInternalServerError, e) - } else { - for _, v := range h { - if v := strings.SplitN(v, ":", 2); len(v) == 2 { - q.Header.Add(v[0], v[1]) - } - } - if r, e := http.DefaultClient.Do(q); e != nil { - c.AbortWithError(http.StatusInternalServerError, e) + //Files: + authorized.StaticFS("/files/", gin.Dir(filepath.Join(settings.Path, files), true)) + authorized.GET("/files", func(c *gin.Context) { + if l, e := os.Readlink(filepath.Join(settings.Path, files)); e == nil || os.IsNotExist(e) { + c.JSON(200, l) } else { - c.DataFromReader(r.StatusCode, r.ContentLength, r.Header.Get("Content-Type"), r.Body, nil) - r.Body.Close() + c.AbortWithError(http.StatusInternalServerError, e) } - } -} - -func trnGet(h string) (st, sc string) { - if h := torr.GetTorrent(h); h != nil { - if h := h.Status(); h != nil && h.Stat < 5 { - switch h.Stat { - case 4: - sc = "msx-red" - case 3: - sc = "msx-green" - default: - sc = "msx-yellow" - } - st = "{ico:north} " + strconv.Itoa(h.ActivePeers) + " / " + strconv.Itoa(h.TotalPeers) + " {ico:south} " + strconv.Itoa(h.ConnectedSeeders) - } - } - return -} - -func response(c *gin.Context, a any) { - var r struct { - R struct { - S int `json:"status"` - T string `json:"text"` - M string `json:"message,omitempty"` - D any `json:"data,omitempty"` - } `json:"response"` - } - if e, o := a.(error); o { - r.R.S, r.R.M = http.StatusBadRequest, e.Error() - } else { - r.R.S, r.R.D = http.StatusOK, a - } - r.R.T = http.StatusText(r.R.S) - c.JSON(200, &r) -} - -func torrent(c *gin.Context) { - if c.Request.Method != "POST" { - r := false - if h := c.Query("hash"); h != "" { - for _, t := range settings.ListTorrent() { - if r = (t != nil && t.InfoHash.HexString() == h); r { - break - } + }) + authorized.POST("/files", func(c *gin.Context) { + var l string + if e := c.Bind(&l); e != nil { + c.AbortWithError(http.StatusBadRequest, e) + } else if e = os.Remove(filepath.Join(settings.Path, files)); e != nil && !os.IsNotExist(e) { + c.AbortWithError(http.StatusInternalServerError, e) + } else if l != "" { + if e = os.Symlink(l, filepath.Join(settings.Path, files)); e != nil { + c.AbortWithError(http.StatusInternalServerError, e) } } - c.JSON(200, r) - } else if j := struct{ Data string }{Data: c.Query("hash")}; j.Data != "" { - st, sc := trnGet(j.Data) - if sc != "" { - sc = "{col:" + sc + "}" - } - response(c, map[string]string{"action": "player:label:position:{VALUE}{tb}{tb}" + sc + st}) - } else if e := json.NewDecoder(c.Request.Body).Decode(&j); e != nil { - response(c, e) - } else if j.Data == "" { - response(c, errors.New("data is not set")) - } else { - st, sc := trnGet(j.Data[strings.LastIndexByte(j.Data, ':')+1:]) - response(c, map[string]any{"action": j.Data, "data": map[string]any{ - "stamp": st, "stampColor": sc, "live": map[string]any{ - "type": "airtime", "duration": 1000, "over": map[string]any{ - "action": "execute:" + utils.GetScheme(c) + "://" + c.Request.Host + c.Request.URL.Path, "data": j.Data, - }, - }, - }}) - } + }) }