Compare commits

...

6 commits

Author SHA1 Message Date
Ilya Kryuchkov
3f59c68efc
Merge 65a6401251 into 4c797dc154 2025-12-24 01:16:53 +03:00
zd
4c797dc154
fix: display of outbound traffic (#3604)
Some checks failed
Release 3X-UI / build (386) (push) Has been cancelled
Release 3X-UI / build (amd64) (push) Has been cancelled
Release 3X-UI / build (arm64) (push) Has been cancelled
Release 3X-UI / build (armv5) (push) Has been cancelled
Release 3X-UI / build (armv6) (push) Has been cancelled
Release 3X-UI / build (armv7) (push) Has been cancelled
Release 3X-UI / build (s390x) (push) Has been cancelled
Release 3X-UI / Build for Windows (push) Has been cancelled
shows the direction of traffic
2025-12-23 15:43:25 +01:00
kr-ilya
65a6401251 Cr fixes 2025-12-11 01:09:11 +03:00
kr-ilya
5df9b4f5c2 remove duplicate code 2025-12-03 23:12:03 +03:00
kr-ilya
5d84ed255d Fix panel redirect logic 2025-12-01 00:01:05 +03:00
kr-ilya
1e5e1ff0b9 Fix panel redirect logic 2025-11-30 23:46:07 +03:00
4 changed files with 78 additions and 11 deletions

4
.env.example Normal file
View file

@ -0,0 +1,4 @@
XUI_DEBUG=true
XUI_DB_FOLDER=x-ui
XUI_LOG_FOLDER=x-ui
XUI_BIN_FOLDER=x-ui

5
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,5 @@
## Local Development Setup
- Create a directory named `x-ui` in the project root
- Rename `.env.example` to `.env `
- Run `main.go`

View file

@ -120,6 +120,10 @@
oldAllSetting: new AllSetting(),
allSetting: new AllSetting(),
saveBtnDisable: true,
entryHost: null,
entryPort: null,
entryProtocol: null,
entryIsIP: false,
user: {},
lang: LanguageManager.getLanguage(),
inboundOptions: [],
@ -233,6 +237,31 @@
loading(spinning = true) {
this.loadingStates.spinning = spinning;
},
_isIp(h) {
if (typeof h !== "string") return false;
// IPv4: four dot-separated octets 0-255
const v4 = h.split(".");
if (
v4.length === 4 &&
v4.every(p => /^\d{1,3}$/.test(p) && Number(p) <= 255)
) return true;
// IPv6: hex groups, optional single :: compression
if (!h.includes(":") || h.includes(":::")) return false;
const parts = h.split("::");
if (parts.length > 2) return false;
const splitGroups = s => (s ? s.split(":").filter(Boolean) : []);
const head = splitGroups(parts[0]);
const tail = splitGroups(parts[1]);
const validGroup = seg => /^[0-9a-fA-F]{1,4}$/.test(seg);
if (![...head, ...tail].every(validGroup)) return false;
const groups = head.length + tail.length;
return parts.length === 2 ? groups < 8 : groups === 8;
},
async getAllSetting() {
const msg = await HttpUtil.post("/panel/setting/all");
@ -307,16 +336,41 @@
this.loading(true);
const msg = await HttpUtil.post("/panel/setting/restartPanel");
this.loading(false);
if (msg.success) {
this.loading(true);
await PromiseUtil.sleep(5000);
var { webCertFile, webKeyFile, webDomain: host, webPort: port, webBasePath: base } = this.allSetting;
if (host == this.oldAllSetting.webDomain) host = null;
if (port == this.oldAllSetting.webPort) port = null;
const isTLS = webCertFile !== "" || webKeyFile !== "";
const url = URLBuilder.buildURL({ host, port, isTLS, base, path: "panel/settings" });
window.location.replace(url);
if (!msg.success) return;
this.loading(true);
await PromiseUtil.sleep(5000);
const { webDomain, webPort, webBasePath, webCertFile, webKeyFile } = this.allSetting;
const newProtocol = (webCertFile || webKeyFile) ? "https:" : "http:";
let base = webBasePath ? webBasePath.replace(/^\//, "") : "";
if (base && !base.endsWith("/")) base += "/";
if (!this.entryIsIP) {
const url = new URL(window.location.href);
url.pathname = `/${base}panel/settings`;
url.protocol = newProtocol;
window.location.replace(url.toString());
return;
}
let finalHost = this.entryHost;
let finalPort = this.entryPort || "";
if (webDomain && this._isIp(webDomain)) {
finalHost = webDomain;
}
if (webPort && Number(webPort) !== Number(this.entryPort)) {
finalPort = String(webPort);
}
const url = new URL(`${newProtocol}//${finalHost}`);
if (finalPort) url.port = finalPort;
url.pathname = `/${base}panel/settings`;
window.location.replace(url.toString());
},
toggleTwoFactor(newValue) {
if (newValue) {
@ -568,6 +622,10 @@
}
},
async mounted() {
this.entryHost = window.location.hostname;
this.entryPort = window.location.port;
this.entryProtocol = window.location.protocol;
this.entryIsIP = this._isIp(this.entryHost);
await this.getAllSetting();
await this.loadInboundTags();
while (true) {

View file

@ -527,10 +527,10 @@
findOutboundTraffic(o) {
for (const otraffic of this.outboundsTraffic) {
if (otraffic.tag == o.tag) {
return SizeFormatter.sizeFormat(otraffic.up) + ' / ' + SizeFormatter.sizeFormat(otraffic.down);
return `↑ ${SizeFormatter.sizeFormat(otraffic.up)} / ${SizeFormatter.sizeFormat(otraffic.down)} ↓`
}
}
return SizeFormatter.sizeFormat(0) + ' / ' + SizeFormatter.sizeFormat(0);
return `${SizeFormatter.sizeFormat(0)} / ${SizeFormatter.sizeFormat(0)}`
},
findOutboundAddress(o) {
serverObj = null;