royalcat refactoring
This commit is contained in:
parent
1da835cea6
commit
b245c9f451
81 changed files with 1476 additions and 1580 deletions
127
src/http/api.go
Normal file
127
src/http/api.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"git.kmsign.ru/royalcat/tstor/src/torrent"
|
||||
"github.com/anacrolix/missinggo/v2/filecache"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var apiStatusHandler = func(fc *filecache.Cache, ss *torrent.Stats) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
stat := gin.H{
|
||||
"torrentStats": ss.GlobalStats(),
|
||||
}
|
||||
|
||||
if fc != nil {
|
||||
stat["cacheItems"] = fc.Info().NumItems
|
||||
stat["cacheFilled"] = fc.Info().Filled / 1024 / 1024
|
||||
stat["cacheCapacity"] = fc.Info().Capacity / 1024 / 1024
|
||||
}
|
||||
|
||||
// TODO move to a struct
|
||||
ctx.JSON(http.StatusOK, stat)
|
||||
}
|
||||
}
|
||||
|
||||
var apiServersHandler = func(ss []*torrent.Server) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
var infos []*torrent.ServerInfo
|
||||
for _, s := range ss {
|
||||
infos = append(infos, s.Info())
|
||||
}
|
||||
ctx.JSON(http.StatusOK, infos)
|
||||
}
|
||||
}
|
||||
|
||||
var apiRoutesHandler = func(ss *torrent.Stats) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
s := ss.RoutesStats()
|
||||
sort.Sort(torrent.ByName(s))
|
||||
ctx.JSON(http.StatusOK, s)
|
||||
}
|
||||
}
|
||||
|
||||
var apiAddTorrentHandler = func(s *torrent.Service) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
route := ctx.Param("route")
|
||||
|
||||
var json RouteAdd
|
||||
if err := ctx.ShouldBindJSON(&json); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.AddMagnet(route, json.Magnet); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, nil)
|
||||
}
|
||||
}
|
||||
|
||||
var apiDelTorrentHandler = func(s *torrent.Service) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
route := ctx.Param("route")
|
||||
hash := ctx.Param("torrent_hash")
|
||||
|
||||
if err := s.RemoveFromHash(route, hash); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, nil)
|
||||
}
|
||||
}
|
||||
|
||||
var apiLogHandler = func(path string) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
max := math.Max(float64(-fi.Size()), -1024*8*8)
|
||||
_, err = f.Seek(int64(max), io.SeekEnd)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var b bytes.Buffer
|
||||
ctx.Stream(func(w io.Writer) bool {
|
||||
_, err := b.ReadFrom(f)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return false
|
||||
}
|
||||
|
||||
_, err = b.WriteTo(w)
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if err := f.Close(); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
92
src/http/http.go
Normal file
92
src/http/http.go
Normal file
|
@ -0,0 +1,92 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"git.kmsign.ru/royalcat/tstor"
|
||||
"git.kmsign.ru/royalcat/tstor/src/config"
|
||||
"git.kmsign.ru/royalcat/tstor/src/torrent"
|
||||
"github.com/anacrolix/missinggo/v2/filecache"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/shurcooL/httpfs/html/vfstemplate"
|
||||
)
|
||||
|
||||
func New(fc *filecache.Cache, ss *torrent.Stats, s *torrent.Service, ch *config.Config, tss []*torrent.Server, fs http.FileSystem, logPath string, cfg *config.Config) error {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
r := gin.New()
|
||||
r.Use(gin.Recovery())
|
||||
r.Use(gin.ErrorLogger())
|
||||
r.Use(Logger())
|
||||
|
||||
r.GET("/assets/*filepath", func(c *gin.Context) {
|
||||
c.FileFromFS(c.Request.URL.Path, http.FS(tstor.Assets))
|
||||
})
|
||||
|
||||
if cfg.Mounts.HttpFs.Enabled {
|
||||
log.Info().Str("host", fmt.Sprintf("0.0.0.0:%d/fs", cfg.Mounts.HttpFs.Port)).Msg("starting HTTPFS")
|
||||
r.GET("/fs/*filepath", func(c *gin.Context) {
|
||||
path := c.Param("filepath")
|
||||
c.FileFromFS(path, fs)
|
||||
})
|
||||
}
|
||||
|
||||
t, err := vfstemplate.ParseGlob(http.FS(tstor.Templates), nil, "/templates/*")
|
||||
if err != nil {
|
||||
return fmt.Errorf("error parsing html: %w", err)
|
||||
}
|
||||
|
||||
r.SetHTMLTemplate(t)
|
||||
|
||||
r.GET("/", indexHandler)
|
||||
r.GET("/routes", routesHandler(ss))
|
||||
r.GET("/logs", logsHandler)
|
||||
r.GET("/servers", serversFoldersHandler())
|
||||
|
||||
api := r.Group("/api")
|
||||
{
|
||||
api.GET("/log", apiLogHandler(logPath))
|
||||
api.GET("/status", apiStatusHandler(fc, ss))
|
||||
api.GET("/servers", apiServersHandler(tss))
|
||||
|
||||
api.GET("/routes", apiRoutesHandler(ss))
|
||||
api.POST("/routes/:route/torrent", apiAddTorrentHandler(s))
|
||||
api.DELETE("/routes/:route/torrent/:torrent_hash", apiDelTorrentHandler(s))
|
||||
|
||||
}
|
||||
|
||||
log.Info().Str("host", fmt.Sprintf("%s:%d", cfg.WebUi.IP, cfg.WebUi.Port)).Msg("starting webserver")
|
||||
|
||||
if err := r.Run(fmt.Sprintf("%s:%d", cfg.WebUi.IP, cfg.WebUi.Port)); err != nil {
|
||||
return fmt.Errorf("error initializing server: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Logger() gin.HandlerFunc {
|
||||
l := log.Logger.With().Str("component", "http").Logger()
|
||||
return func(c *gin.Context) {
|
||||
path := c.Request.URL.Path
|
||||
raw := c.Request.URL.RawQuery
|
||||
c.Next()
|
||||
if raw != "" {
|
||||
path = path + "?" + raw
|
||||
}
|
||||
msg := c.Errors.String()
|
||||
if msg == "" {
|
||||
msg = "Request"
|
||||
}
|
||||
|
||||
s := c.Writer.Status()
|
||||
switch {
|
||||
case s >= 400 && s < 500:
|
||||
l.Warn().Str("path", path).Int("status", s).Msg(msg)
|
||||
case s >= 500:
|
||||
l.Error().Str("path", path).Int("status", s).Msg(msg)
|
||||
default:
|
||||
l.Debug().Str("path", path).Int("status", s).Msg(msg)
|
||||
}
|
||||
}
|
||||
}
|
9
src/http/model.go
Normal file
9
src/http/model.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package http
|
||||
|
||||
type RouteAdd struct {
|
||||
Magnet string `json:"magnet" binding:"required"`
|
||||
}
|
||||
|
||||
type Error struct {
|
||||
Error string `json:"error"`
|
||||
}
|
28
src/http/web.go
Normal file
28
src/http/web.go
Normal file
|
@ -0,0 +1,28 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"git.kmsign.ru/royalcat/tstor/src/torrent"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var indexHandler = func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "index.html", nil)
|
||||
}
|
||||
|
||||
var routesHandler = func(ss *torrent.Stats) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "routes.html", ss.RoutesStats())
|
||||
}
|
||||
}
|
||||
|
||||
var logsHandler = func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "logs.html", nil)
|
||||
}
|
||||
|
||||
var serversFoldersHandler = func() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "servers.html", nil)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue