mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-01-13 01:02:46 +00:00
253 lines
7.2 KiB
Go
253 lines
7.2 KiB
Go
// Package controller provides HTTP handlers for host management in multi-node mode.
|
|
package controller
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"io"
|
|
"strconv"
|
|
|
|
"github.com/mhsanaei/3x-ui/v2/database/model"
|
|
"github.com/mhsanaei/3x-ui/v2/logger"
|
|
"github.com/mhsanaei/3x-ui/v2/web/service"
|
|
"github.com/mhsanaei/3x-ui/v2/web/session"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// HostController handles HTTP requests related to host management.
|
|
type HostController struct {
|
|
hostService service.HostService
|
|
}
|
|
|
|
// NewHostController creates a new HostController and sets up its routes.
|
|
func NewHostController(g *gin.RouterGroup) *HostController {
|
|
a := &HostController{
|
|
hostService: service.HostService{},
|
|
}
|
|
a.initRouter(g)
|
|
return a
|
|
}
|
|
|
|
// initRouter initializes the routes for host-related operations.
|
|
func (a *HostController) initRouter(g *gin.RouterGroup) {
|
|
g.GET("/list", a.getHosts)
|
|
g.GET("/get/:id", a.getHost)
|
|
g.POST("/add", a.addHost)
|
|
g.POST("/update/:id", a.updateHost)
|
|
g.POST("/del/:id", a.deleteHost)
|
|
}
|
|
|
|
// getHosts retrieves the list of all hosts for the current user.
|
|
func (a *HostController) getHosts(c *gin.Context) {
|
|
user := session.GetLoginUser(c)
|
|
hosts, err := a.hostService.GetHosts(user.Id)
|
|
if err != nil {
|
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
return
|
|
}
|
|
jsonObj(c, hosts, nil)
|
|
}
|
|
|
|
// getHost retrieves a specific host by its ID.
|
|
func (a *HostController) getHost(c *gin.Context) {
|
|
id, err := strconv.Atoi(c.Param("id"))
|
|
if err != nil {
|
|
jsonMsg(c, "Invalid host ID", err)
|
|
return
|
|
}
|
|
user := session.GetLoginUser(c)
|
|
host, err := a.hostService.GetHost(id)
|
|
if err != nil {
|
|
jsonMsg(c, "Failed to get host", err)
|
|
return
|
|
}
|
|
if host.UserId != user.Id {
|
|
jsonMsg(c, "Host not found or access denied", nil)
|
|
return
|
|
}
|
|
jsonObj(c, host, nil)
|
|
}
|
|
|
|
// addHost creates a new host.
|
|
func (a *HostController) addHost(c *gin.Context) {
|
|
user := session.GetLoginUser(c)
|
|
|
|
// Extract inboundIds from JSON or form data
|
|
var inboundIdsFromJSON []int
|
|
var hasInboundIdsInJSON bool
|
|
|
|
if c.ContentType() == "application/json" {
|
|
// Read raw body to extract inboundIds
|
|
bodyBytes, err := c.GetRawData()
|
|
if err == nil && len(bodyBytes) > 0 {
|
|
// Parse JSON to extract inboundIds
|
|
var jsonData map[string]interface{}
|
|
if err := json.Unmarshal(bodyBytes, &jsonData); err == nil {
|
|
// Check for inboundIds array
|
|
if inboundIdsVal, ok := jsonData["inboundIds"]; ok {
|
|
hasInboundIdsInJSON = true
|
|
if inboundIdsArray, ok := inboundIdsVal.([]interface{}); ok {
|
|
for _, val := range inboundIdsArray {
|
|
if num, ok := val.(float64); ok {
|
|
inboundIdsFromJSON = append(inboundIdsFromJSON, int(num))
|
|
} else if num, ok := val.(int); ok {
|
|
inboundIdsFromJSON = append(inboundIdsFromJSON, num)
|
|
}
|
|
}
|
|
} else if num, ok := inboundIdsVal.(float64); ok {
|
|
// Single number instead of array
|
|
inboundIdsFromJSON = append(inboundIdsFromJSON, int(num))
|
|
} else if num, ok := inboundIdsVal.(int); ok {
|
|
inboundIdsFromJSON = append(inboundIdsFromJSON, num)
|
|
}
|
|
}
|
|
}
|
|
// Restore body for ShouldBind
|
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
|
}
|
|
}
|
|
|
|
host := &model.Host{}
|
|
err := c.ShouldBind(host)
|
|
if err != nil {
|
|
jsonMsg(c, "Invalid host data", err)
|
|
return
|
|
}
|
|
|
|
// Set inboundIds from JSON if available
|
|
if hasInboundIdsInJSON {
|
|
host.InboundIds = inboundIdsFromJSON
|
|
logger.Debugf("AddHost: extracted inboundIds from JSON: %v", inboundIdsFromJSON)
|
|
} else {
|
|
// Try to get from form data
|
|
inboundIdsStr := c.PostFormArray("inboundIds")
|
|
if len(inboundIdsStr) > 0 {
|
|
var inboundIds []int
|
|
for _, idStr := range inboundIdsStr {
|
|
if idStr != "" {
|
|
if id, err := strconv.Atoi(idStr); err == nil && id > 0 {
|
|
inboundIds = append(inboundIds, id)
|
|
}
|
|
}
|
|
}
|
|
host.InboundIds = inboundIds
|
|
logger.Debugf("AddHost: extracted inboundIds from form: %v", inboundIds)
|
|
}
|
|
}
|
|
|
|
logger.Debugf("AddHost: host.InboundIds before service call: %v", host.InboundIds)
|
|
err = a.hostService.AddHost(user.Id, host)
|
|
if err != nil {
|
|
logger.Errorf("Failed to add host: %v", err)
|
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
return
|
|
}
|
|
|
|
jsonMsgObj(c, I18nWeb(c, "pages.hosts.toasts.hostCreateSuccess"), host, nil)
|
|
}
|
|
|
|
// updateHost updates an existing host.
|
|
func (a *HostController) updateHost(c *gin.Context) {
|
|
id, err := strconv.Atoi(c.Param("id"))
|
|
if err != nil {
|
|
jsonMsg(c, "Invalid host ID", err)
|
|
return
|
|
}
|
|
|
|
user := session.GetLoginUser(c)
|
|
|
|
// Extract inboundIds from JSON or form data
|
|
var inboundIdsFromJSON []int
|
|
var hasInboundIdsInJSON bool
|
|
|
|
if c.ContentType() == "application/json" {
|
|
// Read raw body to extract inboundIds
|
|
bodyBytes, err := c.GetRawData()
|
|
if err == nil && len(bodyBytes) > 0 {
|
|
// Parse JSON to extract inboundIds
|
|
var jsonData map[string]interface{}
|
|
if err := json.Unmarshal(bodyBytes, &jsonData); err == nil {
|
|
// Check for inboundIds array
|
|
if inboundIdsVal, ok := jsonData["inboundIds"]; ok {
|
|
hasInboundIdsInJSON = true
|
|
if inboundIdsArray, ok := inboundIdsVal.([]interface{}); ok {
|
|
for _, val := range inboundIdsArray {
|
|
if num, ok := val.(float64); ok {
|
|
inboundIdsFromJSON = append(inboundIdsFromJSON, int(num))
|
|
} else if num, ok := val.(int); ok {
|
|
inboundIdsFromJSON = append(inboundIdsFromJSON, num)
|
|
}
|
|
}
|
|
} else if num, ok := inboundIdsVal.(float64); ok {
|
|
// Single number instead of array
|
|
inboundIdsFromJSON = append(inboundIdsFromJSON, int(num))
|
|
} else if num, ok := inboundIdsVal.(int); ok {
|
|
inboundIdsFromJSON = append(inboundIdsFromJSON, num)
|
|
}
|
|
}
|
|
}
|
|
// Restore body for ShouldBind
|
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(bodyBytes))
|
|
}
|
|
}
|
|
|
|
host := &model.Host{}
|
|
err = c.ShouldBind(host)
|
|
if err != nil {
|
|
jsonMsg(c, "Invalid host data", err)
|
|
return
|
|
}
|
|
|
|
// Set inboundIds from JSON if available
|
|
if hasInboundIdsInJSON {
|
|
host.InboundIds = inboundIdsFromJSON
|
|
logger.Debugf("UpdateHost: extracted inboundIds from JSON: %v", inboundIdsFromJSON)
|
|
} else {
|
|
// Try to get from form data
|
|
inboundIdsStr := c.PostFormArray("inboundIds")
|
|
if len(inboundIdsStr) > 0 {
|
|
var inboundIds []int
|
|
for _, idStr := range inboundIdsStr {
|
|
if idStr != "" {
|
|
if id, err := strconv.Atoi(idStr); err == nil && id > 0 {
|
|
inboundIds = append(inboundIds, id)
|
|
}
|
|
}
|
|
}
|
|
host.InboundIds = inboundIds
|
|
logger.Debugf("UpdateHost: extracted inboundIds from form: %v", inboundIds)
|
|
} else {
|
|
logger.Debugf("UpdateHost: inboundIds not provided, keeping existing assignments")
|
|
}
|
|
}
|
|
|
|
host.Id = id
|
|
err = a.hostService.UpdateHost(user.Id, host)
|
|
if err != nil {
|
|
logger.Errorf("Failed to update host: %v", err)
|
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
return
|
|
}
|
|
|
|
jsonMsgObj(c, I18nWeb(c, "pages.hosts.toasts.hostUpdateSuccess"), host, nil)
|
|
}
|
|
|
|
// deleteHost deletes a host by ID.
|
|
func (a *HostController) deleteHost(c *gin.Context) {
|
|
id, err := strconv.Atoi(c.Param("id"))
|
|
if err != nil {
|
|
jsonMsg(c, "Invalid host ID", err)
|
|
return
|
|
}
|
|
|
|
user := session.GetLoginUser(c)
|
|
err = a.hostService.DeleteHost(user.Id, id)
|
|
if err != nil {
|
|
logger.Errorf("Failed to delete host: %v", err)
|
|
jsonMsg(c, I18nWeb(c, "somethingWentWrong"), err)
|
|
return
|
|
}
|
|
|
|
jsonMsg(c, I18nWeb(c, "pages.hosts.toasts.hostDeleteSuccess"), nil)
|
|
}
|