diff --git a/web/controller/multi_server_controller.go b/web/controller/multi_server_controller.go index 1b5c171d..4164febb 100644 --- a/web/controller/multi_server_controller.go +++ b/web/controller/multi_server_controller.go @@ -25,6 +25,7 @@ func (c *MultiServerController) initRouter(g *gin.RouterGroup) { g.POST("/add", c.addServer) g.POST("/del/:id", c.delServer) g.POST("/update/:id", c.updateServer) + g.GET("/onlines", c.getOnlineClients) } func (c *MultiServerController) getServers(ctx *gin.Context) { @@ -36,6 +37,15 @@ func (c *MultiServerController) getServers(ctx *gin.Context) { jsonObj(ctx, servers, nil) } +func (c *MultiServerController) getOnlineClients(ctx *gin.Context) { + clients, err := c.multiServerService.GetOnlineClients() + if err != nil { + jsonMsg(ctx, "Failed to get online clients", err) + return + } + jsonObj(ctx, clients, nil) +} + func (c *MultiServerController) addServer(ctx *gin.Context) { server := &model.Server{} err := ctx.ShouldBind(server) diff --git a/web/html/servers.html b/web/html/servers.html index 7a14456d..01051f18 100644 --- a/web/html/servers.html +++ b/web/html/servers.html @@ -29,6 +29,37 @@
| [[ server.name ]] | [[ server.address ]] | [[ server.port ]] | +
+
+ [[ clientEmail ]]
+
+
+ |
YesNo @@ -154,6 +210,10 @@ el: "#app", data: { themeSwitcher, + onlineClients: [], + isRefreshEnabled: localStorage.getItem("isRefreshEnabled") === "true" ? true : false, + refreshing: false, + refreshInterval: Number(localStorage.getItem("refreshInterval")) || 5000, loadingStates: { fetched: false, spinning: false, @@ -173,18 +233,42 @@ }, methods: { loadServers() { - axios.get('/panel/api/servers/list') .then(response => { this.servers = response.data.obj; + this.servers = servers.map(s => { + s.status = 'Checking...'; + return s; + }); if (this.servers.length == 0) { } + this.checkStatuses(); }) .catch(error => { alert(error); }); }, + async manualRefresh() { + await this.getOnlineUsers(); + }, + + async getOnlineUsers() { + const msg = await HttpUtil.post('/panel/api/servers/onlines'); + if (!msg.success) { + return; + } + this.onlineClients = msg.obj != null ? msg.obj : []; + }, + toggleRefresh() { + localStorage.setItem("isRefreshEnabled", this.isRefreshEnabled); + if (this.isRefreshEnabled) { + this.startDataRefreshLoop(); + } + }, + changeRefreshInterval() { + localStorage.setItem("refreshInterval", this.refreshInterval); + }, showAddModal() { this.modal.title = "Add Server"; this.modal.server = { @@ -208,6 +292,16 @@ const modal = new bootstrap.Modal(modalEl); modal.show(); }, + async startDataRefreshLoop() { + while (this.isRefreshEnabled) { + try { + await this.getOnlineUsers(); + } catch (e) { + console.error(e); + } + await PromiseUtil.sleep(this.refreshInterval); + } + }, saveServer() { let url = "/panel/api/servers/add"; if (this.modal.server.id) { @@ -286,6 +380,12 @@ mounted() { this.loadServers(); + if (this.isRefreshEnabled) { + this.startDataRefreshLoop(); + } + else { + this.getDBInbounds(); + } }, }); diff --git a/web/service/multi_server_service.go b/web/service/multi_server_service.go index 2491d088..bef52255 100644 --- a/web/service/multi_server_service.go +++ b/web/service/multi_server_service.go @@ -1,6 +1,10 @@ package service import ( + "encoding/json" + "fmt" + "net/http" + "github.com/mhsanaei/3x-ui/v2/database" "github.com/mhsanaei/3x-ui/v2/database/model" ) @@ -21,6 +25,39 @@ func (s *MultiServerService) GetServer(id int) (*model.Server, error) { return &server, err } +// GetOnlineClients +func (s *MultiServerService) GetOnlineClients() (map[int][]string, error) { + db := database.GetDB() + var servers []*model.Server + err := db.Find(&servers).Error + if err != nil { + return nil, err + } + + var clients map[int][]string + for _, server := range servers { + var onlineResp struct { + Success bool `json:"success"` + Msg string `json:"msg"` + Obj []string `json:"obj"` + } + url := fmt.Sprintf("http://%s:%d%spanel/api/inbounds/onlines", server.Address, server.Port, server.SecretWebPath) + resp, err := http.Post(url, "application/json", nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if err := json.NewDecoder(resp.Body).Decode(&onlineResp); err != nil { + return nil, fmt.Errorf("decode online: %w", err) + } + if !onlineResp.Success { + return nil, fmt.Errorf("failed to get online list at %s", server.Address) + } + clients[server.Id] = onlineResp.Obj + } + return clients, nil +} + func (s *MultiServerService) AddServer(server *model.Server) error { db := database.GetDB() return db.Create(server).Error |