Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlolka1333 <xtrafcyz@gmail.com>2026-01-18 17:38:57 +0300
committerGitHub <noreply@github.com>2026-01-18 17:38:57 +0300
commit77fa976ee9d6ad529adc96e8826dc56eaedf061d (patch)
treea565d25e69c756acb752ddad710f01707228633a
parent8098d2b1b1c028e4f3d220cc27f43c7a70115a0e (diff)
Enhance WebSocket client connection logic and improve event listener management (#3636)
- Updated WebSocketClient to allow connection during CONNECTING state. - Introduced a flag for reconnection attempts. - Improved event listener registration to prevent duplicate callbacks. - Refactored online clients update logic in inbounds.html for better performance and clarity. - Added CSS styles for subscription link boxes in subpage.html to enhance UI consistency and interactivity. Co-authored-by: lolka1333 <test123@gmail.com>
-rw-r--r--web/assets/js/websocket.js9
-rw-r--r--web/html/inbounds.html32
-rw-r--r--web/html/settings/panel/subscription/subpage.html56
3 files changed, 70 insertions, 27 deletions
diff --git a/web/assets/js/websocket.js b/web/assets/js/websocket.js
index 5b8a3948..ccafef87 100644
--- a/web/assets/js/websocket.js
+++ b/web/assets/js/websocket.js
@@ -14,10 +14,12 @@ class WebSocketClient {
}
connect() {
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
+ if (this.ws && (this.ws.readyState === WebSocket.OPEN || this.ws.readyState === WebSocket.CONNECTING)) {
return;
}
+ this.shouldReconnect = true;
+
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
// Ensure basePath ends with '/' for proper URL construction
let basePath = this.basePath || '';
@@ -97,7 +99,10 @@ class WebSocketClient {
if (!this.listeners.has(event)) {
this.listeners.set(event, []);
}
- this.listeners.get(event).push(callback);
+ const callbacks = this.listeners.get(event);
+ if (!callbacks.includes(callback)) {
+ callbacks.push(callback);
+ }
}
off(event, callback) {
diff --git a/web/html/inbounds.html b/web/html/inbounds.html
index eeffd98d..b945da90 100644
--- a/web/html/inbounds.html
+++ b/web/html/inbounds.html
@@ -1602,7 +1602,6 @@
if (payload && Array.isArray(payload)) {
// Use setInbounds to properly convert to DBInbound objects with methods
this.setInbounds(payload);
- this.searchInbounds(this.searchKey);
}
});
@@ -1614,14 +1613,31 @@
// Update online clients list in real-time
if (payload && Array.isArray(payload.onlineClients)) {
- this.onlineClients = payload.onlineClients;
- // Recalculate client counts to update online status
- this.dbInbounds.forEach(dbInbound => {
- const inbound = this.inbounds.find(ib => ib.id === dbInbound.id);
- if (inbound && this.clientCount[dbInbound.id]) {
- this.clientCount[dbInbound.id] = this.getClientCounts(dbInbound, inbound);
+ const nextOnlineClients = payload.onlineClients;
+ let onlineChanged = this.onlineClients.length !== nextOnlineClients.length;
+ if (!onlineChanged) {
+ const prevSet = new Set(this.onlineClients);
+ for (const email of nextOnlineClients) {
+ if (!prevSet.has(email)) {
+ onlineChanged = true;
+ break;
+ }
}
- });
+ }
+ this.onlineClients = nextOnlineClients;
+ if (onlineChanged) {
+ // Recalculate client counts to update online status
+ this.dbInbounds.forEach(dbInbound => {
+ const inbound = this.inbounds.find(ib => ib.id === dbInbound.id);
+ if (inbound && this.clientCount[dbInbound.id]) {
+ this.clientCount[dbInbound.id] = this.getClientCounts(dbInbound, inbound);
+ }
+ });
+
+ if (this.enableFilter) {
+ this.filterInbounds();
+ }
+ }
}
// Update last online map in real-time
diff --git a/web/html/settings/panel/subscription/subpage.html b/web/html/settings/panel/subscription/subpage.html
index 222352ff..c59f68ee 100644
--- a/web/html/settings/panel/subscription/subpage.html
+++ b/web/html/settings/panel/subscription/subpage.html
@@ -5,6 +5,43 @@
<script src="{{ .base_path }}assets/ant-design-vue/antd.min.js"></script>
<script src="{{ .base_path }}assets/js/util/index.js?{{ .cur_ver }}"></script>
<script src="{{ .base_path }}assets/qrcode/qrious2.min.js?{{ .cur_ver }}"></script>
+<style>
+ .subscription-page .subscription-link-box {
+ cursor: pointer;
+ border-radius: 12px;
+ padding: 25px 20px 15px 20px;
+ margin-top: -12px;
+ word-break: break-all;
+ font-size: 13px;
+ line-height: 1.5;
+ text-align: left;
+ font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
+ transition: all 0.3s;
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
+ }
+
+ .dark.subscription-page .subscription-link-box {
+ background: rgba(0, 0, 0, 0.2);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ color: #fff;
+ }
+
+ .dark.subscription-page .subscription-link-box:hover {
+ background: rgba(0, 0, 0, 0.3);
+ border-color: rgba(255, 255, 255, 0.2);
+ }
+
+ .light.subscription-page .subscription-link-box {
+ background: rgba(0, 0, 0, 0.03);
+ border: 1px solid rgba(0, 0, 0, 0.08);
+ color: rgba(0, 0, 0, 0.85);
+ }
+
+ .light.subscription-page .subscription-link-box:hover {
+ background: rgba(0, 0, 0, 0.05);
+ border-color: rgba(0, 0, 0, 0.14);
+ }
+</style>
{{ template "page/head_end" .}}
{{ template "page/body_start" .}}
@@ -138,27 +175,12 @@
style="margin-bottom: -10px; position: relative; z-index: 2; box-shadow: 0 2px 4px rgba(0,0,0,0.2);">
<span>[[ linkName(link, idx) ]]</span>
</a-tag>
- <div @click="copy(link)" style="
- cursor: pointer;
- background: rgba(0, 0, 0, 0.2);
- border: 1px solid rgba(255, 255, 255, 0.1);
- border-radius: 12px;
- padding: 25px 20px 15px 20px;
- margin-top: -12px;
- word-break: break-all;
- color: #fff;
- font-size: 13px;
- line-height: 1.5;
- text-align: left;
- font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
- transition: all 0.3s;
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
- " onmouseover="this.style.background='rgba(0, 0, 0, 0.3)'; this.style.borderColor='rgba(255, 255, 255, 0.2)'"
- onmouseout="this.style.background='rgba(0, 0, 0, 0.2)'; this.style.borderColor='rgba(255, 255, 255, 0.1)'">
+ <div @click="copy(link)" class="subscription-link-box">
[[ link ]]
</div>
</div>
</div>
+
</div>
<br />