From 1016f3b4f9ac6df05a2b3479c485cdba1b0a4705 Mon Sep 17 00:00:00 2001 From: mhsanaei Date: Mon, 22 Sep 2025 00:20:05 +0200 Subject: [PATCH 01/12] fix: outbound address for vless --- web/html/xray.html | 11 +++++++---- web/service/tgbot.go | 34 +++++++++++++++++----------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/web/html/xray.html b/web/html/xray.html index 266f9eef..4dacd021 100644 --- a/web/html/xray.html +++ b/web/html/xray.html @@ -12,13 +12,14 @@ - + - + @@ -37,7 +38,8 @@ {{ i18n "pages.index.xrayErrorPopoverTitle" }} @@ -537,6 +539,7 @@ serverObj = o.settings.vnext; break; case Protocols.VLESS: + return [o.settings?.address + ':' + o.settings?.port]; case Protocols.HTTP: case Protocols.Socks: case Protocols.Shadowsocks: diff --git a/web/service/tgbot.go b/web/service/tgbot.go index 762ffd25..0c9d820c 100644 --- a/web/service/tgbot.go +++ b/web/service/tgbot.go @@ -46,22 +46,22 @@ var ( hashStorage *global.HashStorage // Performance improvements - messageWorkerPool chan struct{} // Semaphore for limiting concurrent message processing - optimizedHTTPClient *http.Client // HTTP client with connection pooling and timeouts - + messageWorkerPool chan struct{} // Semaphore for limiting concurrent message processing + optimizedHTTPClient *http.Client // HTTP client with connection pooling and timeouts + // Simple cache for frequently accessed data statusCache struct { data *Status timestamp time.Time mutex sync.RWMutex } - + serverStatsCache struct { data string timestamp time.Time mutex sync.RWMutex } - + // clients data to adding new client receiver_inbound_ID int client_Id string @@ -122,7 +122,7 @@ func (t *Tgbot) GetHashStorage() *global.HashStorage { func (t *Tgbot) getCachedStatus() (*Status, bool) { statusCache.mutex.RLock() defer statusCache.mutex.RUnlock() - + if statusCache.data != nil && time.Since(statusCache.timestamp) < 5*time.Second { return statusCache.data, true } @@ -133,7 +133,7 @@ func (t *Tgbot) getCachedStatus() (*Status, bool) { func (t *Tgbot) setCachedStatus(status *Status) { statusCache.mutex.Lock() defer statusCache.mutex.Unlock() - + statusCache.data = status statusCache.timestamp = time.Now() } @@ -142,7 +142,7 @@ func (t *Tgbot) setCachedStatus(status *Status) { func (t *Tgbot) getCachedServerStats() (string, bool) { serverStatsCache.mutex.RLock() defer serverStatsCache.mutex.RUnlock() - + if serverStatsCache.data != "" && time.Since(serverStatsCache.timestamp) < 10*time.Second { return serverStatsCache.data, true } @@ -153,7 +153,7 @@ func (t *Tgbot) getCachedServerStats() (string, bool) { func (t *Tgbot) setCachedServerStats(stats string) { serverStatsCache.mutex.Lock() defer serverStatsCache.mutex.Unlock() - + serverStatsCache.data = stats serverStatsCache.timestamp = time.Now() } @@ -171,7 +171,7 @@ func (t *Tgbot) Start(i18nFS embed.FS) error { // Initialize worker pool for concurrent message processing (max 10 concurrent handlers) messageWorkerPool = make(chan struct{}, 10) - + // Initialize optimized HTTP client with connection pooling optimizedHTTPClient = &http.Client{ Timeout: 15 * time.Second, @@ -359,9 +359,9 @@ func (t *Tgbot) OnReceive() { botHandler.HandleMessage(func(ctx *th.Context, message telego.Message) error { // Use goroutine with worker pool for concurrent command processing go func() { - messageWorkerPool <- struct{}{} // Acquire worker + messageWorkerPool <- struct{}{} // Acquire worker defer func() { <-messageWorkerPool }() // Release worker - + delete(userStates, message.Chat.ID) t.answerCommand(&message, message.Chat.ID, checkAdmin(message.From.ID)) }() @@ -371,9 +371,9 @@ func (t *Tgbot) OnReceive() { botHandler.HandleCallbackQuery(func(ctx *th.Context, query telego.CallbackQuery) error { // Use goroutine with worker pool for concurrent callback processing go func() { - messageWorkerPool <- struct{}{} // Acquire worker + messageWorkerPool <- struct{}{} // Acquire worker defer func() { <-messageWorkerPool }() // Release worker - + delete(userStates, query.Message.GetChat().ID) t.answerCallback(&query, checkAdmin(query.From.ID)) }() @@ -2537,7 +2537,7 @@ func (t *Tgbot) prepareServerUsageInfo() string { if cachedStats, found := t.getCachedServerStats(); found { return cachedStats } - + info, ipv4, ipv6 := "", "", "" // get latest status of server with caching @@ -2588,10 +2588,10 @@ func (t *Tgbot) prepareServerUsageInfo() string { info += t.I18nBot("tgbot.messages.udpCount", "Count=="+strconv.Itoa(t.lastStatus.UdpCount)) info += t.I18nBot("tgbot.messages.traffic", "Total=="+common.FormatTraffic(int64(t.lastStatus.NetTraffic.Sent+t.lastStatus.NetTraffic.Recv)), "Upload=="+common.FormatTraffic(int64(t.lastStatus.NetTraffic.Sent)), "Download=="+common.FormatTraffic(int64(t.lastStatus.NetTraffic.Recv))) info += t.I18nBot("tgbot.messages.xrayStatus", "State=="+fmt.Sprint(t.lastStatus.Xray.State)) - + // Cache the complete server stats t.setCachedServerStats(info) - + return info } From b3e96230c4556656df92c85e6a68f741a0e1470f Mon Sep 17 00:00:00 2001 From: Evgeny Volferts Date: Mon, 22 Sep 2025 19:56:43 +0000 Subject: [PATCH 02/12] Add Alpine Linux support (#3534) * Add Alpine linux support * Fix for reading logs --- install.sh | 25 ++++-- x-ui.rc | 13 +++ x-ui.sh | 251 ++++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 223 insertions(+), 66 deletions(-) create mode 100644 x-ui.rc diff --git a/install.sh b/install.sh index 4c959a2a..2c1a6822 100644 --- a/install.sh +++ b/install.sh @@ -56,6 +56,9 @@ install_base() { opensuse-tumbleweed) zypper refresh && zypper -q install -y wget curl tar timezone ;; + alpine) + apk update && apk add wget curl tar tzdata + ;; *) apt-get update && apt-get install -y -q wget curl tar tzdata ;; @@ -177,7 +180,11 @@ install_x-ui() { # Stop x-ui service and remove old resources if [[ -e /usr/local/x-ui/ ]]; then - systemctl stop x-ui + if [[ $release == "alpine" ]]; then + rc-service x-ui stop + else + systemctl stop x-ui + fi rm /usr/local/x-ui/ -rf fi @@ -201,10 +208,18 @@ install_x-ui() { chmod +x /usr/bin/x-ui config_after_install - cp -f x-ui.service /etc/systemd/system/ - systemctl daemon-reload - systemctl enable x-ui - systemctl start x-ui + if [[ $release == "alpine" ]]; then + wget -O /etc/init.d/x-ui https://raw.githubusercontent.com/MHSanaei/3x-ui/main/x-ui.rc + chmod +x /etc/init.d/x-ui + rc-update add x-ui + rc-service x-ui start + else + cp -f x-ui.service /etc/systemd/system/ + systemctl daemon-reload + systemctl enable x-ui + systemctl start x-ui + fi + echo -e "${green}x-ui ${tag_version}${plain} installation finished, it is running now..." echo -e "" echo -e "┌───────────────────────────────────────────────────────┐ diff --git a/x-ui.rc b/x-ui.rc new file mode 100644 index 00000000..1323d76a --- /dev/null +++ b/x-ui.rc @@ -0,0 +1,13 @@ +#!/sbin/openrc-run + +command="/usr/local/x-ui/x-ui" +command_background=true +pidfile="/run/x-ui.pid" +description="x-ui Service" +procname="x-ui" +depend() { + need net +} +start_pre(){ + cd /usr/local/x-ui +} \ No newline at end of file diff --git a/x-ui.sh b/x-ui.sh index cec86ba0..6038db7d 100644 --- a/x-ui.sh +++ b/x-ui.sh @@ -153,11 +153,19 @@ uninstall() { fi return 0 fi - systemctl stop x-ui - systemctl disable x-ui - rm /etc/systemd/system/x-ui.service -f - systemctl daemon-reload - systemctl reset-failed + + if [[ $release == "alpine" ]]; then + rc-service x-ui stop + rc-update del x-ui + rm /etc/init.d/x-ui -f + else + systemctl stop x-ui + systemctl disable x-ui + rm /etc/systemd/system/x-ui.service -f + systemctl daemon-reload + systemctl reset-failed + fi + rm /etc/x-ui/ -rf rm /usr/local/x-ui/ -rf @@ -286,7 +294,11 @@ start() { echo "" LOGI "Panel is running, No need to start again, If you need to restart, please select restart" else - systemctl start x-ui + if [[ $release == "alpine" ]]; then + rc-service x-ui start + else + systemctl start x-ui + fi sleep 2 check_status if [[ $? == 0 ]]; then @@ -307,7 +319,11 @@ stop() { echo "" LOGI "Panel stopped, No need to stop again!" else - systemctl stop x-ui + if [[ $release == "alpine" ]]; then + rc-service x-ui stop + else + systemctl stop x-ui + fi sleep 2 check_status if [[ $? == 1 ]]; then @@ -323,7 +339,11 @@ stop() { } restart() { - systemctl restart x-ui + if [[ $release == "alpine" ]]; then + rc-service x-ui restart + else + systemctl restart x-ui + fi sleep 2 check_status if [[ $? == 0 ]]; then @@ -337,14 +357,22 @@ restart() { } status() { - systemctl status x-ui -l + if [[ $release == "alpine" ]]; then + rc-service x-ui status + else + systemctl status x-ui -l + fi if [[ $# == 0 ]]; then before_show_menu fi } enable() { - systemctl enable x-ui + if [[ $release == "alpine" ]]; then + rc-update add x-ui + else + systemctl enable x-ui + fi if [[ $? == 0 ]]; then LOGI "x-ui Set to boot automatically on startup successfully" else @@ -357,7 +385,11 @@ enable() { } disable() { - systemctl disable x-ui + if [[ $release == "alpine" ]]; then + rc-update del x-ui + else + systemctl disable x-ui + fi if [[ $? == 0 ]]; then LOGI "x-ui Autostart Cancelled successfully" else @@ -370,32 +402,54 @@ disable() { } show_log() { - echo -e "${green}\t1.${plain} Debug Log" - echo -e "${green}\t2.${plain} Clear All logs" - echo -e "${green}\t0.${plain} Back to Main Menu" - read -rp "Choose an option: " choice + if [[ $release == "alpine" ]]; then + echo -e "${green}\t1.${plain} Debug Log" + echo -e "${green}\t0.${plain} Back to Main Menu" + read -rp "Choose an option: " choice - case "$choice" in - 0) - show_menu - ;; - 1) - journalctl -u x-ui -e --no-pager -f -p debug - if [[ $# == 0 ]]; then - before_show_menu - fi - ;; - 2) - sudo journalctl --rotate - sudo journalctl --vacuum-time=1s - echo "All Logs cleared." - restart - ;; - *) - echo -e "${red}Invalid option. Please select a valid number.${plain}\n" - show_log - ;; - esac + case "$choice" in + 0) + show_menu + ;; + 1) + grep -F 'x-ui[' /var/log/messages + if [[ $# == 0 ]]; then + before_show_menu + fi + ;; + *) + echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + show_log + ;; + esac + else + echo -e "${green}\t1.${plain} Debug Log" + echo -e "${green}\t2.${plain} Clear All logs" + echo -e "${green}\t0.${plain} Back to Main Menu" + read -rp "Choose an option: " choice + + case "$choice" in + 0) + show_menu + ;; + 1) + journalctl -u x-ui -e --no-pager -f -p debug + if [[ $# == 0 ]]; then + before_show_menu + fi + ;; + 2) + sudo journalctl --rotate + sudo journalctl --vacuum-time=1s + echo "All Logs cleared." + restart + ;; + *) + echo -e "${red}Invalid option. Please select a valid number.${plain}\n" + show_log + ;; + esac + fi } bbr_menu() { @@ -464,6 +518,9 @@ enable_bbr() { arch | manjaro | parch) pacman -Sy --noconfirm ca-certificates ;; + alpine) + apk add ca-certificates + ;; *) echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" exit 1 @@ -500,23 +557,42 @@ update_shell() { # 0: running, 1: not running, 2: not installed check_status() { - if [[ ! -f /etc/systemd/system/x-ui.service ]]; then - return 2 - fi - temp=$(systemctl status x-ui | grep Active | awk '{print $3}' | cut -d "(" -f2 | cut -d ")" -f1) - if [[ "${temp}" == "running" ]]; then - return 0 + if [[ $release == "alpine" ]]; then + if [[ ! -f /etc/init.d/x-ui ]]; then + return 2 + fi + if [[ $(rc-service x-ui status | grep -F 'status: started' -c) == 1 ]]; then + return 0 + else + return 1 + fi else - return 1 + if [[ ! -f /etc/systemd/system/x-ui.service ]]; then + return 2 + fi + temp=$(systemctl status x-ui | grep Active | awk '{print $3}' | cut -d "(" -f2 | cut -d ")" -f1) + if [[ "${temp}" == "running" ]]; then + return 0 + else + return 1 + fi fi } check_enabled() { - temp=$(systemctl is-enabled x-ui) - if [[ "${temp}" == "enabled" ]]; then - return 0 + if [[ $release == "alpine" ]]; then + if [[ $(rc-update show | grep -F 'x-ui' | grep default -c) == 1 ]]; then + return 0 + else + return 1 + fi else - return 1 + temp=$(systemctl is-enabled x-ui) + if [[ "${temp}" == "enabled" ]]; then + return 0 + else + return 1 + fi fi } @@ -798,7 +874,11 @@ update_geo() { show_menu ;; 1) - systemctl stop x-ui + if [[ $release == "alpine" ]]; then + rc-service x-ui stop + else + systemctl stop x-ui + fi rm -f geoip.dat geosite.dat wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat wget -N https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat @@ -806,7 +886,11 @@ update_geo() { restart ;; 2) - systemctl stop x-ui + if [[ $release == "alpine" ]]; then + rc-service x-ui stop + else + systemctl stop x-ui + fi rm -f geoip_IR.dat geosite_IR.dat wget -O geoip_IR.dat -N https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat wget -O geosite_IR.dat -N https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat @@ -814,7 +898,11 @@ update_geo() { restart ;; 3) - systemctl stop x-ui + if [[ $release == "alpine" ]]; then + rc-service x-ui stop + else + systemctl stop x-ui + fi rm -f geoip_RU.dat geosite_RU.dat wget -O geoip_RU.dat -N https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat wget -O geosite_RU.dat -N https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat @@ -985,6 +1073,9 @@ ssl_cert_issue() { arch | manjaro | parch) pacman -Sy --noconfirm socat ;; + alpine) + apk add socat + ;; *) echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" exit 1 @@ -1335,7 +1426,11 @@ iplimit_main() { read -rp "Please enter new Ban Duration in Minutes [default 30]: " NUM if [[ $NUM =~ ^[0-9]+$ ]]; then create_iplimit_jails ${NUM} - systemctl restart fail2ban + if [[ $release == "alpine" ]]; then + rc-service fail2ban restart + else + systemctl restart fail2ban + fi else echo -e "${red}${NUM} is not a number! Please, try again.${plain}" fi @@ -1388,7 +1483,11 @@ iplimit_main() { iplimit_main ;; 9) - systemctl restart fail2ban + if [[ $release == "alpine" ]]; then + rc-service fail2ban restart + else + systemctl restart fail2ban + fi iplimit_main ;; 10) @@ -1436,6 +1535,9 @@ install_iplimit() { arch | manjaro | parch) pacman -Syu --noconfirm fail2ban ;; + alpine) + apk add fail2ban + ;; *) echo -e "${red}Unsupported operating system. Please check the script and install the necessary packages manually.${plain}\n" exit 1 @@ -1472,12 +1574,21 @@ install_iplimit() { create_iplimit_jails # Launching fail2ban - if ! systemctl is-active --quiet fail2ban; then - systemctl start fail2ban + if [[ $release == "alpine" ]]; then + if [[ $(rc-service fail2ban status | grep -F 'status: started' -c) == 0 ]]; then + rc-service fail2ban start + else + rc-service fail2ban restart + fi + rc-update add fail2ban else - systemctl restart fail2ban + if ! systemctl is-active --quiet fail2ban; then + systemctl start fail2ban + else + systemctl restart fail2ban + fi + systemctl enable fail2ban fi - systemctl enable fail2ban echo -e "${green}IP Limit installed and configured successfully!${plain}\n" before_show_menu @@ -1493,13 +1604,21 @@ remove_iplimit() { rm -f /etc/fail2ban/filter.d/3x-ipl.conf rm -f /etc/fail2ban/action.d/3x-ipl.conf rm -f /etc/fail2ban/jail.d/3x-ipl.conf - systemctl restart fail2ban + if [[ $release == "alpine" ]]; then + rc-service fail2ban restart + else + systemctl restart fail2ban + fi echo -e "${green}IP Limit removed successfully!${plain}\n" before_show_menu ;; 2) rm -rf /etc/fail2ban - systemctl stop fail2ban + if [[ $release == "alpine" ]]; then + rc-service fail2ban stop + else + systemctl stop fail2ban + fi case "${release}" in ubuntu | debian | armbian) apt-get remove -y fail2ban @@ -1517,6 +1636,9 @@ remove_iplimit() { arch | manjaro | parch) pacman -Rns --noconfirm fail2ban ;; + alpine) + apk del fail2ban + ;; *) echo -e "${red}Unsupported operating system. Please uninstall Fail2ban manually.${plain}\n" exit 1 @@ -1540,9 +1662,16 @@ show_banlog() { echo -e "${green}Checking ban logs...${plain}\n" - if ! systemctl is-active --quiet fail2ban; then - echo -e "${red}Fail2ban service is not running!${plain}\n" - return 1 + if [[ $release == "alpine" ]]; then + if [[ $(rc-service fail2ban status | grep -F 'status: started' -c) == 0 ]]; then + echo -e "${red}Fail2ban service is not running!${plain}\n" + return 1 + fi + else + if ! systemctl is-active --quiet fail2ban; then + echo -e "${red}Fail2ban service is not running!${plain}\n" + return 1 + fi fi if [[ -f "$system_log" ]]; then From 26c6438ec2b32529ffb85454b60f7b996fec7692 Mon Sep 17 00:00:00 2001 From: mhsanaei Date: Tue, 23 Sep 2025 11:52:40 +0200 Subject: [PATCH 03/12] fix api : subid, uuid from inbound settings --- web/service/inbound.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/web/service/inbound.go b/web/service/inbound.go index 49916b52..448e6832 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -35,6 +35,25 @@ func (s *InboundService) GetInbounds(userId int) ([]*model.Inbound, error) { if err != nil && err != gorm.ErrRecordNotFound { return nil, err } + // Enrich client stats with UUID/SubId from inbound settings + for _, inbound := range inbounds { + clients, _ := s.GetClients(inbound) + if len(clients) == 0 || len(inbound.ClientStats) == 0 { + continue + } + // Build a map email -> client + cMap := make(map[string]model.Client, len(clients)) + for _, c := range clients { + cMap[strings.ToLower(c.Email)] = c + } + for i := range inbound.ClientStats { + email := strings.ToLower(inbound.ClientStats[i].Email) + if c, ok := cMap[email]; ok { + inbound.ClientStats[i].UUID = c.ID + inbound.ClientStats[i].SubId = c.SubID + } + } + } return inbounds, nil } @@ -47,6 +66,24 @@ func (s *InboundService) GetAllInbounds() ([]*model.Inbound, error) { if err != nil && err != gorm.ErrRecordNotFound { return nil, err } + // Enrich client stats with UUID/SubId from inbound settings + for _, inbound := range inbounds { + clients, _ := s.GetClients(inbound) + if len(clients) == 0 || len(inbound.ClientStats) == 0 { + continue + } + cMap := make(map[string]model.Client, len(clients)) + for _, c := range clients { + cMap[strings.ToLower(c.Email)] = c + } + for i := range inbound.ClientStats { + email := strings.ToLower(inbound.ClientStats[i].Email) + if c, ok := cMap[email]; ok { + inbound.ClientStats[i].UUID = c.ID + inbound.ClientStats[i].SubId = c.SubID + } + } + } return inbounds, nil } From 8ff4e1ff316cc60d1fb408c074f6294393758f43 Mon Sep 17 00:00:00 2001 From: Happ-dev Date: Tue, 23 Sep 2025 17:46:45 +0300 Subject: [PATCH 04/12] Add Happ client export open link (#3542) Co-authored-by: y.sivushkin --- web/assets/js/subscription.js | 5 ++++- web/html/settings/panel/subscription/subpage.html | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/web/assets/js/subscription.js b/web/assets/js/subscription.js index 0af95890..c7627837 100644 --- a/web/assets/js/subscription.js +++ b/web/assets/js/subscription.js @@ -142,7 +142,10 @@ }, npvtunUrl() { return this.app.subUrl; - } + }, + happUrl() { + return `happ://add/${encodeURIComponent(this.app.subUrl)}`; + } }, methods: { renderLink, diff --git a/web/html/settings/panel/subscription/subpage.html b/web/html/settings/panel/subscription/subpage.html index 6d56496b..670cc37b 100644 --- a/web/html/settings/panel/subscription/subpage.html +++ b/web/html/settings/panel/subscription/subpage.html @@ -218,6 +218,8 @@ NPV Tunnel + Happ @@ -244,6 +246,8 @@ @click="copy(npvtunUrl)">NPV Tunnel + Happ From 02bff4db6c99bac0aefb5c4c65c986d8d5b802a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=9E=D0=BB?= =?UTF-8?q?=D0=B5=D0=B3=D0=BE=D0=B2=D0=B8=D1=87=20=D0=A1=D0=B0=D0=B5=D0=BD?= =?UTF-8?q?=D0=BA=D0=BE?= Date: Tue, 23 Sep 2025 20:43:56 +0300 Subject: [PATCH 05/12] max port to 65535 (#3536) * add EXPOSE port in Dockerfile * fix: max port 65 531 -> 65 535 * fix --------- Co-authored-by: mhsanaei --- web/html/form/inbound.html | 9 +++++---- web/html/form/stream/external_proxy.html | 10 ++++++---- web/html/modals/xray_dns_modal.html | 9 +++++---- web/html/settings/panel/general.html | 5 +++-- web/html/settings/panel/subscription/general.html | 11 ++++------- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/web/html/form/inbound.html b/web/html/form/inbound.html index ca4dc66a..00f97f6e 100644 --- a/web/html/form/inbound.html +++ b/web/html/form/inbound.html @@ -28,7 +28,7 @@ - + @@ -51,8 +51,9 @@ {{ i18n "pages.inbounds.periodicTrafficResetDesc" }}
- {{ i18n "pages.inbounds.lastReset" }}: - [[ moment(dbInbound.lastTrafficResetTime).format('YYYY-MM-DD HH:mm:ss') ]] + {{ i18n "pages.inbounds.lastReset" }}: + [[ + moment(dbInbound.lastTrafficResetTime).format('YYYY-MM-DD HH:mm:ss') ]] [[ DateUtil.convertToJalalian(moment(dbInbound.lastTrafficResetTime)) ]] @@ -145,4 +146,4 @@ -{{end}} +{{end}} \ No newline at end of file diff --git a/web/html/form/stream/external_proxy.html b/web/html/form/stream/external_proxy.html index 187090d8..5c13df1b 100644 --- a/web/html/form/stream/external_proxy.html +++ b/web/html/form/stream/external_proxy.html @@ -3,12 +3,14 @@ - + - +