mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2025-11-29 02:42:51 +00:00
feat sync btn
This commit is contained in:
parent
72109c040e
commit
b2efeec70f
3 changed files with 165 additions and 5 deletions
|
|
@ -26,6 +26,7 @@ func (c *MultiServerController) initRouter(g *gin.RouterGroup) {
|
|||
g.POST("/del/:id", c.delServer)
|
||||
g.POST("/update/:id", c.updateServer)
|
||||
g.GET("/onlines", c.getOnlineClients)
|
||||
g.POST("/sync/:id", c.syncServer)
|
||||
}
|
||||
|
||||
func (c *MultiServerController) getServers(ctx *gin.Context) {
|
||||
|
|
@ -96,3 +97,17 @@ func (c *MultiServerController) updateServer(ctx *gin.Context) {
|
|||
}
|
||||
jsonMsg(ctx, "Server updated successfully", nil)
|
||||
}
|
||||
|
||||
func (c *MultiServerController) syncServer(ctx *gin.Context) {
|
||||
id, err := strconv.Atoi(ctx.Param("id"))
|
||||
if err != nil {
|
||||
jsonMsg(ctx, "Invalid ID", err)
|
||||
return
|
||||
}
|
||||
err = c.multiServerService.SyncServer(id)
|
||||
if err != nil {
|
||||
jsonMsg(ctx, "Failed to sync server", err)
|
||||
return
|
||||
}
|
||||
jsonMsg(ctx, "Server synced successfully", nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
<link rel="stylesheet" href="{{ .base_path }}assets/bootstrap/bootstrap.min.css">
|
||||
{{ template "page/head_end" .}} {{ template
|
||||
"page/body_start" .}}
|
||||
|
||||
<a-layout id="app" v-cloak :class="themeSwitcher.currentTheme + ' settings-page'">
|
||||
<a-sidebar></a-sidebar>
|
||||
<a-layout id="content-layout">
|
||||
|
|
@ -111,9 +110,11 @@
|
|||
class="badge bg-danger">No</span>
|
||||
</td>
|
||||
<td><button class="btn btn-info btn-sm"
|
||||
@click="showEditModal(server)">Edit</button><button
|
||||
class="btn btn-danger btn-sm"
|
||||
@click="deleteServer(server.id)">Delete</button></td>
|
||||
@click="showEditModal(server)">Edit</button>
|
||||
<button class="btn btn-danger btn-sm"
|
||||
@click="deleteServer(server.id)">Delete</button>
|
||||
<button class="btn btn-sm btn-secondary"
|
||||
@click="syncServer(server)">Sync</button></td>
|
||||
</tr>
|
||||
</template>
|
||||
<tr v-else>
|
||||
|
|
@ -331,6 +332,19 @@
|
|||
alert(error.response.data.msg);
|
||||
});
|
||||
},
|
||||
syncServer(server) {
|
||||
if (!confirm("Are you sure you want to sync inbounds with server \"" + server.name + "\" server?")) {
|
||||
return;
|
||||
}
|
||||
axios
|
||||
.post(`/panel/api/servers/sync/${server.id}`)
|
||||
.then((response) => {
|
||||
alert(response.data.msg);
|
||||
})
|
||||
.catch((error) => {
|
||||
alert(error.response.data.msg);
|
||||
});
|
||||
},
|
||||
deleteServer(id) {
|
||||
if (!confirm("Are you sure you want to delete this server?")) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v2/database"
|
||||
"github.com/mhsanaei/3x-ui/v2/database/model"
|
||||
"github.com/mhsanaei/3x-ui/v2/logger"
|
||||
)
|
||||
|
||||
type MultiServerService struct{}
|
||||
|
|
@ -72,3 +74,132 @@ func (s *MultiServerService) DeleteServer(id int) error {
|
|||
db := database.GetDB()
|
||||
return db.Delete(&model.Server{}, id).Error
|
||||
}
|
||||
|
||||
// SyncServer synchronizes the inbounds list between the given server and the local inbounds list.
|
||||
// It gets the inbounds list from the server, and then syncs it with the local inbounds list.
|
||||
// If an inbound exists on the server but not locally, it adds the inbound.
|
||||
// If an inbound exists locally but not on the server, it removes the inbound.
|
||||
// If an inbound exists on both the server and locally, it updates the inbound if they are different.
|
||||
func (s *MultiServerService) SyncServer(id int) error {
|
||||
inboundService := &InboundService{}
|
||||
inboundsSource, err := inboundService.GetAllInbounds()
|
||||
if err != nil {
|
||||
logger.Error("failed to get all inbounds", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
db := database.GetDB()
|
||||
var server model.Server
|
||||
if err = db.First(&server, id).Error; err != nil {
|
||||
logger.Error("failed to get server", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
//get inbounds from server throw api
|
||||
listURL := fmt.Sprintf("http://%s:%d%spanel/api/inbounds/list", server.Address, server.Port, server.SecretWebPath)
|
||||
req, _ := http.NewRequest("GET", listURL, nil)
|
||||
req.Header.Set("X-API-KEY", server.APIKey)
|
||||
httpResp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
logger.Error("failed to get inbounds from server", "err", err)
|
||||
return err
|
||||
}
|
||||
defer httpResp.Body.Close()
|
||||
|
||||
var resp struct {
|
||||
Success bool `json:"success"`
|
||||
Msg string `json:"msg"`
|
||||
Obj []model.Inbound `json:"obj"`
|
||||
}
|
||||
if err := json.NewDecoder(httpResp.Body).Decode(&resp); err != nil {
|
||||
logger.Error("failed to decode inbounds response", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
type InboundPayload struct {
|
||||
Up int64 `json:"up"`
|
||||
Down int64 `json:"down"`
|
||||
Total int64 `json:"total"`
|
||||
Remark string `json:"remark"`
|
||||
Enable bool `json:"enable"`
|
||||
ExpiryTime int64 `json:"expiryTime"`
|
||||
Listen string `json:"listen"`
|
||||
Port int `json:"port"`
|
||||
Protocol model.Protocol `json:"protocol"`
|
||||
Settings string `json:"settings"`
|
||||
StreamSettings string `json:"streamSettings"`
|
||||
Sniffing string `json:"sniffing"`
|
||||
}
|
||||
|
||||
//sync inbounds
|
||||
for _, src := range inboundsSource {
|
||||
logger.Debugf("syncing inbound %d", src.Id)
|
||||
found := false
|
||||
for _, remote := range resp.Obj {
|
||||
if remote.Tag == src.Tag {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
payload := InboundPayload{
|
||||
Up: src.Up, Down: src.Down, Total: src.Total,
|
||||
Remark: src.Remark, Enable: src.Enable,
|
||||
ExpiryTime: src.ExpiryTime, Listen: src.Listen,
|
||||
Port: src.Port, Protocol: src.Protocol,
|
||||
Settings: src.Settings, StreamSettings: src.StreamSettings, Sniffing: src.Sniffing,
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(payload)
|
||||
|
||||
if found {
|
||||
//update inbound trow api
|
||||
updateURL := fmt.Sprintf("http://%s:%d%spanel/api/inbounds/update/%d", server.Address, server.Port, server.SecretWebPath, src.Id)
|
||||
req, _ := http.NewRequest("POST", updateURL, bytes.NewBuffer(data))
|
||||
req.Header.Set("X-API-KEY", server.APIKey)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
logger.Error("failed to update inbounds at server", "err", err)
|
||||
return err
|
||||
}
|
||||
var updateResp struct {
|
||||
Success bool `json:"success"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
if err := json.NewDecoder(httpResp.Body).Decode(&updateResp); err != nil {
|
||||
logger.Error("failed to decode update inbounds response", "err", err)
|
||||
return fmt.Errorf("decode update inbounds: %w", err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
if !updateResp.Success {
|
||||
return fmt.Errorf("failed to update inbounds at %s %s", server.Name, server.Address)
|
||||
}
|
||||
} else {
|
||||
// add inbound trow api
|
||||
addURL := fmt.Sprintf("http://%s:%d%spanel/api/inbounds/add", server.Address, server.Port, server.SecretWebPath)
|
||||
req, _ := http.NewRequest("POST", addURL, bytes.NewBuffer(data))
|
||||
req.Header.Set("X-API-KEY", server.APIKey)
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
logger.Error("failed to add inbounds at server", "err", err)
|
||||
return err
|
||||
}
|
||||
|
||||
var addResp struct {
|
||||
Success bool `json:"success"`
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
if err := json.NewDecoder(httpResp.Body).Decode(&addResp); err != nil {
|
||||
logger.Error("failed to decode add inbounds response", "err", err)
|
||||
return fmt.Errorf("decode add inbounds: %w", err)
|
||||
}
|
||||
resp.Body.Close()
|
||||
if !addResp.Success {
|
||||
return fmt.Errorf("failed to add inbounds at %s %s", server.Name, server.Address)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue