API - Update Client to inbounds

This commit is contained in:
Javad Tinatpak 2024-08-06 16:37:12 +03:30
parent e299365c62
commit b3e1052c61
4 changed files with 199 additions and 3 deletions

View file

@ -459,7 +459,7 @@ Enter the user ID in input field number 4. The Telegram accounts with this id wi
| `GET` | `"/list"` | Get all inbounds | | `GET` | `"/list"` | Get all inbounds |
| `GET` | `"/get/:id"` | Get inbound with inbound.id | | `GET` | `"/get/:id"` | Get inbound with inbound.id |
| `GET` | `"/getClientTraffics/:email"` | Get Client Traffics with email | | `GET` | `"/getClientTraffics/:email"` | Get Client Traffics with email |
| `GET` | `"/getClientTrafficsById/:id"` | Get client's traffic By ID | | `GET` | `"/getClientTrafficsById/:id"` | Get client's traffic By ID |
| `GET` | `"/createbackup"` | Telegram bot sends backup to admins | | `GET` | `"/createbackup"` | Telegram bot sends backup to admins |
| `POST` | `"/add"` | Add inbound | | `POST` | `"/add"` | Add inbound |
| `POST` | `"/del/:id"` | Delete Inbound | | `POST` | `"/del/:id"` | Delete Inbound |
@ -470,6 +470,7 @@ Enter the user ID in input field number 4. The Telegram accounts with this id wi
| `POST` | `"/addClientInbounds"` | Add Client to inbounds | | `POST` | `"/addClientInbounds"` | Add Client to inbounds |
| `POST` | `"/:id/delClient/:clientId"` | Delete Client by clientId\* | | `POST` | `"/:id/delClient/:clientId"` | Delete Client by clientId\* |
| `POST` | `"/updateClient/:clientId"` | Update Client by clientId\* | | `POST` | `"/updateClient/:clientId"` | Update Client by clientId\* |
| `POST` | `"/updateClientInbounds/:subId"` | Update Client by subId\* |
| `POST` | `"/:id/resetClientTraffic/:email"` | Reset Client's Traffic | | `POST` | `"/:id/resetClientTraffic/:email"` | Reset Client's Traffic |
| `POST` | `"/resetAllTraffics"` | Reset traffics of all inbounds | | `POST` | `"/resetAllTraffics"` | Reset traffics of all inbounds |
| `POST` | `"/resetAllClientTraffics/:id"` | Reset traffics of all clients in an inbound | | `POST` | `"/resetAllClientTraffics/:id"` | Reset traffics of all clients in an inbound |

View file

@ -43,6 +43,7 @@ func (a *APIController) initRouter(g *gin.RouterGroup) {
{"POST", "/addClientInbounds", a.inboundController.addClientToMultipleInbounds}, {"POST", "/addClientInbounds", a.inboundController.addClientToMultipleInbounds},
{"POST", "/:id/delClient/:clientId", a.inboundController.delInboundClient}, {"POST", "/:id/delClient/:clientId", a.inboundController.delInboundClient},
{"POST", "/updateClient/:clientId", a.inboundController.updateInboundClient}, {"POST", "/updateClient/:clientId", a.inboundController.updateInboundClient},
{"POST", "/updateClientInbounds/:subId", a.inboundController.updateClientInMultipleInbounds},
{"POST", "/:id/resetClientTraffic/:email", a.inboundController.resetClientTraffic}, {"POST", "/:id/resetClientTraffic/:email", a.inboundController.resetClientTraffic},
{"POST", "/resetAllTraffics", a.inboundController.resetAllTraffics}, {"POST", "/resetAllTraffics", a.inboundController.resetAllTraffics},
{"POST", "/resetAllClientTraffics/:id", a.inboundController.resetAllClientTraffics}, {"POST", "/resetAllClientTraffics/:id", a.inboundController.resetAllClientTraffics},

View file

@ -18,7 +18,6 @@ type InboundController struct {
} }
type AddClientPayload struct { type AddClientPayload struct {
Id int `json:"id"`
Settings string `json:"settings"` Settings string `json:"settings"`
InboundIds []int `json:"inboundIds"` InboundIds []int `json:"inboundIds"`
} }
@ -42,6 +41,7 @@ func (a *InboundController) initRouter(g *gin.RouterGroup) {
g.POST("/addClientInbounds", a.addClientToMultipleInbounds) g.POST("/addClientInbounds", a.addClientToMultipleInbounds)
g.POST("/:id/delClient/:clientId", a.delInboundClient) g.POST("/:id/delClient/:clientId", a.delInboundClient)
g.POST("/updateClient/:clientId", a.updateInboundClient) g.POST("/updateClient/:clientId", a.updateInboundClient)
g.POST("/updateClientInbounds/:subId", a.updateClientInMultipleInbounds)
g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic) g.POST("/:id/resetClientTraffic/:email", a.resetClientTraffic)
g.POST("/resetAllTraffics", a.resetAllTraffics) g.POST("/resetAllTraffics", a.resetAllTraffics)
g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics) g.POST("/resetAllClientTraffics/:id", a.resetAllClientTraffics)
@ -206,7 +206,6 @@ func (a *InboundController) addClientToMultipleInbounds(c *gin.Context) {
} }
data := &model.Inbound{ data := &model.Inbound{
Id: payload.Id,
Settings: payload.Settings, Settings: payload.Settings,
} }
@ -236,6 +235,45 @@ func (a *InboundController) addClientToMultipleInbounds(c *gin.Context) {
} }
func (a *InboundController) updateClientInMultipleInbounds(c *gin.Context) {
var payload AddClientPayload
subId := c.Param("subId")
if err := c.ShouldBindJSON(&payload); err != nil {
jsonMsg(c, "Invalid request payload", err)
return
}
data := &model.Inbound{
Settings: payload.Settings,
}
// If no specific inbound IDs are provided, add to all inbounds
if len(payload.InboundIds) == 0 {
allInbounds, err := a.inboundService.GetAllInbounds()
if err != nil {
jsonMsg(c, "Could not retrieve inbounds", err)
return
}
for _, inbound := range allInbounds {
payload.InboundIds = append(payload.InboundIds, inbound.Id)
}
}
needRestart := true
needRestart, err = a.inboundService.UpdateClientInMultipleInbounds(data, subId, payload.InboundIds)
if err != nil {
jsonMsg(c, "Something went wrong!", err)
return
}
jsonMsg(c, "Client updated in multiple inbounds", nil)
if needRestart {
a.xrayService.SetToNeedRestart()
}
}
func (a *InboundController) delInboundClient(c *gin.Context) { func (a *InboundController) delInboundClient(c *gin.Context) {

View file

@ -838,6 +838,162 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
return needRestart, tx.Save(oldInbound).Error return needRestart, tx.Save(oldInbound).Error
} }
func (s *InboundService) UpdateClientInMultipleInbounds(data *model.Inbound, subId string, inboundIds []int) (bool, error) {
var needRestart bool
for _, inboundId := range inboundIds {
inbound, err := s.GetInbound(inboundId)
if err != nil {
return false, err
}
clients, err := s.GetClients(data)
if err != nil {
return false, err
}
var settings map[string]interface{}
err = json.Unmarshal([]byte(inbound.Settings), &settings)
if err != nil {
return false, err
}
interfaceClients := settings["clients"].([]interface{})
oldClients, err := s.GetClients(inbound)
if err != nil {
return false, err
}
oldEmail := ""
newClientsubId := ""
clientIndex := -1
for index, oldClient := range oldClients {
oldClientsubId := ""
if inbound.Protocol == "trojan" {
oldClientsubId = oldClient.SubID
newClientsubId = clients[0].SubID
} else if inbound.Protocol == "shadowsocks" {
oldClientsubId = oldClient.SubID
newClientsubId = clients[0].SubID
} else {
oldClientsubId = oldClient.SubID
newClientsubId = clients[0].SubID
}
if subId == oldClientsubId {
oldEmail = oldClient.Email
clientIndex = index
break
}
}
if newClientsubId == "" || clientIndex == -1 {
return false, common.NewError("empty client SubID")
}
if len(clients[0].Email) > 0 && clients[0].Email != oldEmail {
existEmail, err := s.checkEmailsExistForClients(clients)
if err != nil {
return false, err
}
if existEmail != "" {
return false, common.NewError("Duplicate email:", existEmail)
}
}
var oldSettings map[string]interface{}
err = json.Unmarshal([]byte(inbound.Settings), &oldSettings)
if err != nil {
return false, err
}
settingsClients := oldSettings["clients"].([]interface{})
settingsClients[clientIndex] = interfaceClients[0]
oldSettings["clients"] = settingsClients
newSettings, err := json.MarshalIndent(oldSettings, "", " ")
if err != nil {
return false, err
}
inbound.Settings = string(newSettings)
db := database.GetDB()
tx := db.Begin()
defer func() {
if err != nil {
tx.Rollback()
} else {
tx.Commit()
}
}()
if len(clients[0].Email) > 0 {
if len(oldEmail) > 0 {
err = s.UpdateClientStat(tx, oldEmail, &clients[0])
if err != nil {
return false, err
}
err = s.UpdateClientIPs(tx, oldEmail, clients[0].Email)
if err != nil {
return false, err
}
} else {
s.AddClientStat(tx, inbound.Id, &clients[0])
}
} else {
err = s.DelClientStat(tx, oldEmail)
if err != nil {
return false, err
}
err = s.DelClientIPs(tx, oldEmail)
if err != nil {
return false, err
}
}
if len(oldEmail) > 0 {
s.xrayApi.Init(p.GetAPIPort())
err1 := s.xrayApi.RemoveUser(inbound.Tag, oldEmail)
if err1 == nil {
logger.Debug("Old client deleted by api:", clients[0].Email)
} else {
logger.Debug("Error in deleting client by api:", err1)
needRestart = true
}
if clients[0].Enable {
cipher := ""
if inbound.Protocol == "shadowsocks" {
cipher = oldSettings["method"].(string)
}
err1 := s.xrayApi.AddUser(string(inbound.Protocol), inbound.Tag, map[string]interface{}{
"email": clients[0].Email,
"id": clients[0].ID,
"flow": clients[0].Flow,
"password": clients[0].Password,
"cipher": cipher,
})
if err1 == nil {
logger.Debug("Client edited by api:", clients[0].Email)
} else {
logger.Debug("Error in adding client by api:", err1)
needRestart = true
}
}
s.xrayApi.Close()
} else {
logger.Debug("Client old email not found")
needRestart = true
}
if err := tx.Save(inbound).Error; err != nil {
return false, err
}
}
return needRestart, nil
}
func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) { func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) {
var err error var err error
db := database.GetDB() db := database.GetDB()