Files
3x-ui-agent/internal/web/controller/sub_balancer.go
T
Sanaei f727d04f65
Release 3X-UI for Docker / build (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
v3.7.0
2026-08-24 15:07:15 +02:00

127 lines
3.4 KiB
Go

package controller
import (
"fmt"
"strconv"
"github.com/gin-gonic/gin"
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
)
// SubBalancerController manages client-side JSON-subscription balancers.
type SubBalancerController struct {
SubBalancerService service.SubBalancerService
}
func NewSubBalancerController(g *gin.RouterGroup) *SubBalancerController {
a := &SubBalancerController{}
g = g.Group("/sub-balancers")
g.GET("", a.list)
g.POST("", a.create)
g.POST("/:id", a.update)
g.DELETE("/:id", a.del)
g.POST("/:id/del", a.del)
return a
}
// parseSubBalancerForm reads the urlencoded form (HttpUtil default): scalars
// via ShouldBind, inboundIds as repeated keys. enabled is returned as *bool so
// Update can keep the stored value when the key is absent; a bad value is a 400.
func parseSubBalancerForm(c *gin.Context) (*model.SubBalancer, *bool, error) {
form := struct {
Remark string `form:"remark"`
Strategy string `form:"strategy"`
SortOrder int `form:"sortOrder"`
}{}
if err := c.ShouldBind(&form); err != nil {
return nil, nil, err
}
var enabled *bool
if raw, ok := c.GetPostForm("enabled"); ok {
v, err := strconv.ParseBool(raw)
if err != nil {
return nil, nil, fmt.Errorf("invalid enabled %q: %w", raw, err)
}
enabled = &v
}
balancer := &model.SubBalancer{
Remark: form.Remark,
Strategy: form.Strategy,
SortOrder: form.SortOrder,
}
for _, raw := range c.PostFormArray("inboundIds") {
id, err := strconv.Atoi(raw)
if err != nil {
return nil, nil, fmt.Errorf("invalid inbound id %q: %w", raw, err)
}
balancer.InboundIds = append(balancer.InboundIds, id)
}
return balancer, enabled, nil
}
func (a *SubBalancerController) parseID(c *gin.Context) (int, error) {
id, err := strconv.Atoi(c.Param("id"))
if err != nil || id < 1 {
return 0, fmt.Errorf("invalid id %q", c.Param("id"))
}
return id, nil
}
func (a *SubBalancerController) list(c *gin.Context) {
balancers, err := a.SubBalancerService.List()
if err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.subBalancers.toasts.list"), err)
return
}
jsonObj(c, balancers, nil)
}
func (a *SubBalancerController) create(c *gin.Context) {
balancer, enabled, err := parseSubBalancerForm(c)
if err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.subBalancers.toasts.create"), err)
return
}
balancer.Enabled = enabled == nil || *enabled
created, err := a.SubBalancerService.Create(balancer)
if err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.subBalancers.toasts.create"), err)
return
}
jsonObj(c, created, nil)
}
func (a *SubBalancerController) update(c *gin.Context) {
id, err := a.parseID(c)
if err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.subBalancers.toasts.invalidId"), err)
return
}
balancer, enabled, err := parseSubBalancerForm(c)
if err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.subBalancers.toasts.update"), err)
return
}
updated, err := a.SubBalancerService.Update(id, balancer, enabled)
if err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.subBalancers.toasts.update"), err)
return
}
jsonObj(c, updated, nil)
}
func (a *SubBalancerController) del(c *gin.Context) {
id, err := a.parseID(c)
if err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.subBalancers.toasts.invalidId"), err)
return
}
if err := a.SubBalancerService.Delete(id); err != nil {
jsonMsg(c, I18nWeb(c, "pages.settings.subBalancers.toasts.delete"), err)
return
}
jsonObj(c, "", nil)
}