From 6099a07ff0a3f619ace3c7645ee76dce943a97e0 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Mon, 4 May 2026 23:19:25 +0200 Subject: [PATCH] feat: add configurable auto-restart on client auto-disable Add a configurable option to restart Xray when clients are auto-disabled and persist disable actions. Changes include: - New setting restartXrayOnClientDisable (default true), getters/setters in SettingService, UI toggle in general settings, and translations for multiple locales. - AddTraffic signature updated to return a third bool (clientsDisabled). disableInvalidClients now calls Xray API to remove users, marks client_traffics.enable=false, updates inbound.Settings JSON so clients appear disabled in stored settings, and returns appropriate counts/errors. - XrayTrafficJob now checks the clientsDisabled flag and restarts Xray when the setting is enabled (with fallback to mark Xray as needing restart on failure). - XrayService.GetXrayConfig call adjusted to ignore AddTraffic returns. - Subscription generation (subService/subJson/subClash) no longer filters clients by their enable flag when matching subId. - Minor fixes: check_client_ip_job now checks scanner.Err and improved API error handling/logging. These changes ensure auto-disabled clients are propagated to Xray and the stored inbound settings, and provide an option to restart Xray automatically after auto-disable events. --- sub/subClashService.go | 2 +- sub/subJsonService.go | 2 +- sub/subService.go | 2 +- web/assets/js/model/setting.js | 1 + web/entity/entity.go | 1 + web/html/settings/panel/general.html | 7 ++ web/job/check_client_ip_job.go | 3 + web/job/xray_traffic_job.go | 14 +++- web/service/inbound.go | 119 ++++++++++++++++++++------- web/service/setting.go | 9 ++ web/service/xray.go | 2 +- web/translation/translate.ar_EG.toml | 2 + web/translation/translate.en_US.toml | 2 + web/translation/translate.es_ES.toml | 2 + web/translation/translate.fa_IR.toml | 2 + web/translation/translate.id_ID.toml | 2 + web/translation/translate.ja_JP.toml | 2 + web/translation/translate.pt_BR.toml | 2 + web/translation/translate.ru_RU.toml | 2 + web/translation/translate.tr_TR.toml | 2 + web/translation/translate.uk_UA.toml | 2 + web/translation/translate.vi_VN.toml | 2 + web/translation/translate.zh_CN.toml | 2 + web/translation/translate.zh_TW.toml | 2 + 24 files changed, 154 insertions(+), 34 deletions(-) diff --git a/sub/subClashService.go b/sub/subClashService.go index 7b6b8214..e2f61bec 100644 --- a/sub/subClashService.go +++ b/sub/subClashService.go @@ -55,7 +55,7 @@ func (s *SubClashService) GetClash(subId string, host string) (string, string, e } } for _, client := range clients { - if client.Enable && client.SubID == subId { + if client.SubID == subId { clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email)) proxies = append(proxies, s.getProxies(inbound, client, host)...) } diff --git a/sub/subJsonService.go b/sub/subJsonService.go index a51f10bb..38f1ddc8 100644 --- a/sub/subJsonService.go +++ b/sub/subJsonService.go @@ -116,7 +116,7 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err } for _, client := range clients { - if client.Enable && client.SubID == subId { + if client.SubID == subId { clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email)) newConfigs := s.getConfig(inbound, client, host) configArray = append(configArray, newConfigs...) diff --git a/sub/subService.go b/sub/subService.go index 19ca21d9..d9fe0a6b 100644 --- a/sub/subService.go +++ b/sub/subService.go @@ -77,7 +77,7 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, int64, xray.C } } for _, client := range clients { - if client.Enable && client.SubID == subId { + if client.SubID == subId { link := s.getLink(inbound, client.Email) result = append(result, link) ct := s.getClientTraffics(inbound.ClientStats, client.Email) diff --git a/web/assets/js/model/setting.js b/web/assets/js/model/setting.js index d61d4b8e..d5b7d523 100644 --- a/web/assets/js/model/setting.js +++ b/web/assets/js/model/setting.js @@ -43,6 +43,7 @@ class AllSetting { this.subDomain = ""; this.externalTrafficInformEnable = false; this.externalTrafficInformURI = ""; + this.restartXrayOnClientDisable = true; this.subCertFile = ""; this.subKeyFile = ""; this.subUpdates = 12; diff --git a/web/entity/entity.go b/web/entity/entity.go index 7f37f564..8b340279 100644 --- a/web/entity/entity.go +++ b/web/entity/entity.go @@ -71,6 +71,7 @@ type AllSetting struct { SubUpdates int `json:"subUpdates" form:"subUpdates"` // Subscription update interval in minutes ExternalTrafficInformEnable bool `json:"externalTrafficInformEnable" form:"externalTrafficInformEnable"` // Enable external traffic reporting ExternalTrafficInformURI string `json:"externalTrafficInformURI" form:"externalTrafficInformURI"` // URI for external traffic reporting + RestartXrayOnClientDisable bool `json:"restartXrayOnClientDisable" form:"restartXrayOnClientDisable"` // Restart Xray when clients are auto-disabled by expiry/traffic limit SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"` // Encrypt subscription responses SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"` // Show client information in subscriptions SubURI string `json:"subURI" form:"subURI"` // Subscription server URI diff --git a/web/html/settings/panel/general.html b/web/html/settings/panel/general.html index ffc2cda1..718c431c 100644 --- a/web/html/settings/panel/general.html +++ b/web/html/settings/panel/general.html @@ -124,6 +124,13 @@ v-model="allSetting.externalTrafficInformURI"> + + + + + diff --git a/web/job/check_client_ip_job.go b/web/job/check_client_ip_job.go index 29aa9775..7f0ac2cf 100644 --- a/web/job/check_client_ip_job.go +++ b/web/job/check_client_ip_job.go @@ -199,6 +199,9 @@ func (j *CheckClientIpJob) processLogFile() bool { inboundClientIps[email][ip] = timestamp } } + if err := scanner.Err(); err != nil { + j.checkError(err) + } shouldCleanLog := false for email, ipTimestamps := range inboundClientIps { diff --git a/web/job/xray_traffic_job.go b/web/job/xray_traffic_job.go index f443aa77..71e90caa 100644 --- a/web/job/xray_traffic_job.go +++ b/web/job/xray_traffic_job.go @@ -33,7 +33,7 @@ func (j *XrayTrafficJob) Run() { if err != nil { return } - err, needRestart0 := j.inboundService.AddTraffic(traffics, clientTraffics) + err, needRestart0, clientsDisabled := j.inboundService.AddTraffic(traffics, clientTraffics) if err != nil { logger.Warning("add inbound traffic failed:", err) } @@ -41,6 +41,18 @@ func (j *XrayTrafficJob) Run() { if err != nil { logger.Warning("add outbound traffic failed:", err) } + if clientsDisabled { + restartOnDisable, settingErr := j.settingService.GetRestartXrayOnClientDisable() + if settingErr != nil { + logger.Warning("get RestartXrayOnClientDisable failed:", settingErr) + } + if restartOnDisable { + if err := j.xrayService.RestartXray(true); err != nil { + logger.Warning("restart xray after disabling clients failed:", err) + j.xrayService.SetToNeedRestart() + } + } + } if ExternalTrafficInformEnable, err := j.settingService.GetExternalTrafficInformEnable(); ExternalTrafficInformEnable { j.informTrafficToExternalAPI(traffics, clientTraffics) } else if err != nil { diff --git a/web/service/inbound.go b/web/service/inbound.go index 74b44b99..f536efb9 100644 --- a/web/service/inbound.go +++ b/web/service/inbound.go @@ -1228,7 +1228,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin return needRestart, tx.Save(oldInbound).Error } -func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool) { +func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraffics []*xray.ClientTraffic) (error, bool, bool) { var err error db := database.GetDB() tx := db.Begin() @@ -1242,11 +1242,11 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff }() err = s.addInboundTraffic(tx, inboundTraffics) if err != nil { - return err, false + return err, false, false } err = s.addClientTraffic(tx, clientTraffics) if err != nil { - return err, false + return err, false, false } needRestart0, count, err := s.autoRenewClients(tx) @@ -1256,11 +1256,13 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff logger.Debugf("%v clients renewed", count) } + disabledClientsCount := int64(0) needRestart1, count, err := s.disableInvalidClients(tx) if err != nil { logger.Warning("Error in disabling invalid clients:", err) } else if count > 0 { logger.Debugf("%v clients disabled", count) + disabledClientsCount = count } needRestart2, count, err := s.disableInvalidInbounds(tx) @@ -1269,7 +1271,7 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff } else if count > 0 { logger.Debugf("%v inbounds disabled", count) } - return nil, (needRestart0 || needRestart1 || needRestart2) + return nil, (needRestart0 || needRestart1 || needRestart2), disabledClientsCount > 0 } func (s *InboundService) addInboundTraffic(tx *gorm.DB, traffics []*xray.Traffic) error { @@ -1546,46 +1548,105 @@ func (s *InboundService) disableInvalidClients(tx *gorm.DB) (bool, int64, error) now := time.Now().Unix() * 1000 needRestart := false - if p != nil { - var results []struct { - Tag string - Email string - } + var clientsToDisable []struct { + InboundId int + Tag string + Email string + } - err := tx.Table("inbounds"). - Select("inbounds.tag, client_traffics.email"). - Joins("JOIN client_traffics ON inbounds.id = client_traffics.inbound_id"). - Where("((client_traffics.total > 0 AND client_traffics.up + client_traffics.down >= client_traffics.total) OR (client_traffics.expiry_time > 0 AND client_traffics.expiry_time <= ?)) AND client_traffics.enable = ?", now, true). - Scan(&results).Error - if err != nil { - return false, 0, err - } + err := tx.Table("inbounds"). + Select("inbounds.id as inbound_id, inbounds.tag, client_traffics.email"). + Joins("JOIN client_traffics ON inbounds.id = client_traffics.inbound_id"). + Where("((client_traffics.total > 0 AND client_traffics.up + client_traffics.down >= client_traffics.total) OR (client_traffics.expiry_time > 0 AND client_traffics.expiry_time <= ?)) AND client_traffics.enable = ?", now, true). + Scan(&clientsToDisable).Error + if err != nil { + return false, 0, err + } + + if p != nil { s.xrayApi.Init(p.GetAPIPort()) - for _, result := range results { - err1 := s.xrayApi.RemoveUser(result.Tag, result.Email) + for _, client := range clientsToDisable { + err1 := s.xrayApi.RemoveUser(client.Tag, client.Email) if err1 == nil { - logger.Debug("Client disabled by api:", result.Email) + logger.Debug("Client disabled by api:", client.Email) } else { - if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", result.Email)) { + if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", client.Email)) { logger.Debug("User is already disabled. Nothing to do more...") } else { - if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", result.Email)) { - logger.Debug("User is already disabled. Nothing to do more...") - } else { - logger.Debug("Error in disabling client by api:", err1) - needRestart = true - } + logger.Debug("Error in disabling client by api:", err1) + needRestart = true } } } s.xrayApi.Close() } + result := tx.Model(xray.ClientTraffic{}). Where("((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?", now, true). Update("enable", false) - err := result.Error + err = result.Error count := result.RowsAffected - return needRestart, count, err + if err != nil { + return needRestart, count, err + } + + // Also set enable=false in inbounds.settings JSON so clients are visibly disabled + if len(clientsToDisable) > 0 { + inboundEmailMap := make(map[int]map[string]struct{}) + for _, c := range clientsToDisable { + if inboundEmailMap[c.InboundId] == nil { + inboundEmailMap[c.InboundId] = make(map[string]struct{}) + } + inboundEmailMap[c.InboundId][c.Email] = struct{}{} + } + inboundIds := make([]int, 0, len(inboundEmailMap)) + for id := range inboundEmailMap { + inboundIds = append(inboundIds, id) + } + var inbounds []*model.Inbound + if err = tx.Model(model.Inbound{}).Where("id IN ?", inboundIds).Find(&inbounds).Error; err != nil { + logger.Warning("disableInvalidClients fetch inbounds:", err) + return needRestart, count, nil + } + for _, inbound := range inbounds { + settings := map[string]any{} + if jsonErr := json.Unmarshal([]byte(inbound.Settings), &settings); jsonErr != nil { + continue + } + clients, ok := settings["clients"].([]any) + if !ok { + continue + } + emailSet := inboundEmailMap[inbound.Id] + changed := false + for i := range clients { + c, ok := clients[i].(map[string]any) + if !ok { + continue + } + email, _ := c["email"].(string) + if _, shouldDisable := emailSet[email]; shouldDisable { + c["enable"] = false + c["updated_at"] = time.Now().Unix() * 1000 + clients[i] = c + changed = true + } + } + if changed { + settings["clients"] = clients + modifiedSettings, jsonErr := json.MarshalIndent(settings, "", " ") + if jsonErr != nil { + continue + } + inbound.Settings = string(modifiedSettings) + } + } + if err = tx.Save(inbounds).Error; err != nil { + logger.Warning("disableInvalidClients update inbound settings:", err) + } + } + + return needRestart, count, nil } func (s *InboundService) GetInboundTags() (string, error) { diff --git a/web/service/setting.go b/web/service/setting.go index 560dce3a..aca5f9a4 100644 --- a/web/service/setting.go +++ b/web/service/setting.go @@ -83,6 +83,7 @@ var defaultValueMap = map[string]string{ "nord": "", "externalTrafficInformEnable": "false", "externalTrafficInformURI": "", + "restartXrayOnClientDisable": "true", "xrayOutboundTestUrl": "https://www.google.com/generate_204", // LDAP defaults @@ -628,6 +629,14 @@ func (s *SettingService) SetExternalTrafficInformURI(InformURI string) error { return s.setString("externalTrafficInformURI", InformURI) } +func (s *SettingService) GetRestartXrayOnClientDisable() (bool, error) { + return s.getBool("restartXrayOnClientDisable") +} + +func (s *SettingService) SetRestartXrayOnClientDisable(value bool) error { + return s.setBool("restartXrayOnClientDisable", value) +} + func (s *SettingService) GetIpLimitEnable() (bool, error) { accessLogPath, err := xray.GetAccessLogPath() if err != nil { diff --git a/web/service/xray.go b/web/service/xray.go index 958d36d2..385936d5 100644 --- a/web/service/xray.go +++ b/web/service/xray.go @@ -103,7 +103,7 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) { return nil, err } - s.inboundService.AddTraffic(nil, nil) + _, _, _ = s.inboundService.AddTraffic(nil, nil) inbounds, err := s.inboundService.GetAllInbounds() if err != nil { diff --git a/web/translation/translate.ar_EG.toml b/web/translation/translate.ar_EG.toml index 2e76cf94..a509c7aa 100644 --- a/web/translation/translate.ar_EG.toml +++ b/web/translation/translate.ar_EG.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "يبعت تنبيه لـ API خارجي مع كل تحديث للترافيك." "externalTrafficInformURI" = "مسار تنبيه الترافيك الخارجي" "externalTrafficInformURIDesc" = "تحديثات الترافيك هتتبعت للمسار ده." +"restartXrayOnClientDisable" = "إعادة تشغيل Xray بعد التعطيل التلقائي" +"restartXrayOnClientDisableDesc" = "عند تعطيل العميل تلقائيا بسبب انتهاء الصلاحية أو حد حركة المرور، أعد تشغيل Xray." "fragment" = "تجزئة" "fragmentDesc" = "يفعل تجزئة لحزمة TLS hello." "fragmentSett" = "إعدادات التجزئة" diff --git a/web/translation/translate.en_US.toml b/web/translation/translate.en_US.toml index 49c9f952..afa29080 100644 --- a/web/translation/translate.en_US.toml +++ b/web/translation/translate.en_US.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "Inform external API on every traffic update." "externalTrafficInformURI" = "External Traffic Inform URI" "externalTrafficInformURIDesc" = "Traffic updates are sent to this URI." +"restartXrayOnClientDisable" = "Restart Xray After Auto Disable" +"restartXrayOnClientDisableDesc" = "When a client is automatically disabled due to expiration or traffic limit, restart Xray." "fragment" = "Fragmentation" "fragmentDesc" = "Enable fragmentation for TLS hello packet." "fragmentSett" = "Fragmentation Settings" diff --git a/web/translation/translate.es_ES.toml b/web/translation/translate.es_ES.toml index cce4018f..6802d1aa 100644 --- a/web/translation/translate.es_ES.toml +++ b/web/translation/translate.es_ES.toml @@ -476,6 +476,8 @@ "externalTrafficInformEnableDesc" = "Informar a la API externa sobre cada actualización de tráfico." "externalTrafficInformURI" = "URI de información de tráfico externo" "externalTrafficInformURIDesc" = "Las actualizaciones de tráfico se envían a este URI." +"restartXrayOnClientDisable" = "Reiniciar Xray tras desactivación automática" +"restartXrayOnClientDisableDesc" = "Cuando un cliente se desactive automáticamente por vencimiento o límite de tráfico, reiniciar Xray." "subURIDesc" = "Cambiar el URI base de la URL de suscripción para usar detrás de los servidores proxy" "fragment" = "Fragmentación" "fragmentDesc" = "Habilitar la fragmentación para el paquete de saludo de TLS" diff --git a/web/translation/translate.fa_IR.toml b/web/translation/translate.fa_IR.toml index e1f49b80..4f2792d7 100644 --- a/web/translation/translate.fa_IR.toml +++ b/web/translation/translate.fa_IR.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "مصرف ترافیک به سرویس خارجی ارسال می شود" "externalTrafficInformURI" = "لینک اطلاع رسانی خارجی مصرف ترافیک" "externalTrafficInformURIDesc" = "ترافیک های مصرفی به این لینک هم ارسال می شود" +"restartXrayOnClientDisable" = "ری‌استارت Xray بعد از غیرفعال‌سازی خودکار" +"restartXrayOnClientDisableDesc" = "وقتی کاربر به‌صورت خودکار به‌دلیل اتمام زمان یا ترافیک غیرفعال می‌شود، Xray ری‌استارت شود." "fragment" = "فرگمنت" "fragmentDesc" = "فعال کردن فرگمنت برای بسته‌ی نخست تی‌ال‌اس" "fragmentSett" = "تنظیمات فرگمنت" diff --git a/web/translation/translate.id_ID.toml b/web/translation/translate.id_ID.toml index f2ac71fc..57615d89 100644 --- a/web/translation/translate.id_ID.toml +++ b/web/translation/translate.id_ID.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "Inform external API on every traffic update." "externalTrafficInformURI" = "Lalu Lintas Eksternal Menginformasikan URI" "externalTrafficInformURIDesc" = "Pembaruan lalu lintas dikirim ke URI ini." +"restartXrayOnClientDisable" = "Nyalakan Ulang Xray Setelah Nonaktif Otomatis" +"restartXrayOnClientDisableDesc" = "Saat klien otomatis dinonaktifkan karena kedaluwarsa atau batas trafik, mulai ulang Xray." "fragment" = "Fragmentasi" "fragmentDesc" = "Aktifkan fragmentasi untuk paket hello TLS" "fragmentSett" = "Pengaturan Fragmentasi" diff --git a/web/translation/translate.ja_JP.toml b/web/translation/translate.ja_JP.toml index da67e758..62d9f789 100644 --- a/web/translation/translate.ja_JP.toml +++ b/web/translation/translate.ja_JP.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "トラフィックの更新ごとに外部 API に通知します。" "externalTrafficInformURI" = "外部トラフィック通知 URI" "externalTrafficInformURIDesc" = "トラフィックの更新ごとに外部 API に通知します。" +"restartXrayOnClientDisable" = "自動無効化後に Xray を再起動" +"restartXrayOnClientDisableDesc" = "有効期限切れまたはトラフィック上限でクライアントが自動的に無効化されたとき、Xray を再起動します。" "fragment" = "フラグメント" "fragmentDesc" = "TLS helloパケットのフラグメントを有効にする" "fragmentSett" = "設定" diff --git a/web/translation/translate.pt_BR.toml b/web/translation/translate.pt_BR.toml index 10a2b156..0c51772e 100644 --- a/web/translation/translate.pt_BR.toml +++ b/web/translation/translate.pt_BR.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "Informar a API externa sobre cada atualização de tráfego." "externalTrafficInformURI" = "URI de informação de tráfego externo" "externalTrafficInformURIDesc" = "As atualizações de tráfego são enviadas para este URI." +"restartXrayOnClientDisable" = "Reiniciar Xray Após Desativação Automática" +"restartXrayOnClientDisableDesc" = "Quando um cliente for desativado automaticamente por expiração ou limite de tráfego, reinicie o Xray." "fragment" = "Fragmentação" "fragmentDesc" = "Ativa a fragmentação para o pacote TLS hello." "fragmentSett" = "Configurações de Fragmentação" diff --git a/web/translation/translate.ru_RU.toml b/web/translation/translate.ru_RU.toml index b3ec617d..abb3cf9e 100644 --- a/web/translation/translate.ru_RU.toml +++ b/web/translation/translate.ru_RU.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "Информировать внешний API о каждом обновлении трафика" "externalTrafficInformURI" = "URI информации о внешнем трафике" "externalTrafficInformURIDesc" = "Обновления трафика отправляются на этот URI" +"restartXrayOnClientDisable" = "Перезапускать Xray после автоотключения" +"restartXrayOnClientDisableDesc" = "Когда клиент автоматически отключается из-за окончания срока действия или лимита трафика, перезапускать Xray." "fragment" = "Фрагментация" "fragmentDesc" = "Включить фрагментацию TLS-хэндшейка" "fragmentSett" = "Настройки фрагментации" diff --git a/web/translation/translate.tr_TR.toml b/web/translation/translate.tr_TR.toml index 5aaa1b03..13a61c64 100644 --- a/web/translation/translate.tr_TR.toml +++ b/web/translation/translate.tr_TR.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "Her trafik güncellemesinde harici API'yi bilgilendirin." "externalTrafficInformURI" = "Harici Trafik Bilgisi URI'si" "externalTrafficInformURIDesc" = "Trafik güncellemeleri bu URI'ye gönderildi." +"restartXrayOnClientDisable" = "Otomatik Devre Dışı Sonrası Xray'i Yeniden Başlat" +"restartXrayOnClientDisableDesc" = "Bir istemci süre dolumu veya trafik limiti nedeniyle otomatik devre dışı bırakıldığında Xray'i yeniden başlat." "fragment" = "Parçalama" "fragmentDesc" = "TLS merhaba paketinin parçalanmasını etkinleştir." "fragmentSett" = "Parçalama Ayarları" diff --git a/web/translation/translate.uk_UA.toml b/web/translation/translate.uk_UA.toml index b83122c9..d99bf955 100644 --- a/web/translation/translate.uk_UA.toml +++ b/web/translation/translate.uk_UA.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "Інформувати зовнішній API про кожне оновлення трафіку." "externalTrafficInformURI" = "Інформаційний URI зовнішнього трафіку" "externalTrafficInformURIDesc" = "Оновлення трафіку надсилаються на цей URI." +"restartXrayOnClientDisable" = "Перезапускати Xray після авто-вимкнення" +"restartXrayOnClientDisableDesc" = "Коли клієнт автоматично вимикається через закінчення терміну дії або ліміт трафіку, перезапускати Xray." "fragment" = "Фрагментація" "fragmentDesc" = "Увімкнути фрагментацію для пакету привітання TLS" "fragmentSett" = "Параметри фрагментації" diff --git a/web/translation/translate.vi_VN.toml b/web/translation/translate.vi_VN.toml index 3d836b33..db8c424a 100644 --- a/web/translation/translate.vi_VN.toml +++ b/web/translation/translate.vi_VN.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "Thông báo cho API bên ngoài về mọi cập nhật lưu lượng truy cập." "externalTrafficInformURI" = "URI thông báo lưu lượng truy cập bên ngoài" "externalTrafficInformURIDesc" = "Cập nhật lưu lượng truy cập được gửi tới URI này." +"restartXrayOnClientDisable" = "Khởi Động Lại Xray Sau Khi Tự Động Vô Hiệu Hóa" +"restartXrayOnClientDisableDesc" = "Khi người dùng bị vô hiệu hóa tự động do hết hạn hoặc chạm giới hạn lưu lượng, hãy khởi động lại Xray." "fragment" = "Sự phân mảnh" "fragmentDesc" = "Kích hoạt phân mảnh cho gói TLS hello" "fragmentSett" = "Cài đặt phân mảnh" diff --git a/web/translation/translate.zh_CN.toml b/web/translation/translate.zh_CN.toml index 57c23eac..428ea92a 100644 --- a/web/translation/translate.zh_CN.toml +++ b/web/translation/translate.zh_CN.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "每次流量更新时通知外部 API" "externalTrafficInformURI" = "外部流量通知 URI" "externalTrafficInformURIDesc" = "流量更新将发送到此 URI" +"restartXrayOnClientDisable" = "客户端自动禁用后重启 Xray" +"restartXrayOnClientDisableDesc" = "当客户端因到期或流量超限被自动禁用时,重启 Xray。" "fragment" = "分片" "fragmentDesc" = "启用 TLS hello 数据包分片" "fragmentSett" = "设置" diff --git a/web/translation/translate.zh_TW.toml b/web/translation/translate.zh_TW.toml index 69e5164c..6216c885 100644 --- a/web/translation/translate.zh_TW.toml +++ b/web/translation/translate.zh_TW.toml @@ -477,6 +477,8 @@ "externalTrafficInformEnableDesc" = "每次流量更新時通知外部 API" "externalTrafficInformURI" = "外部流量通知 URI" "externalTrafficInformURIDesc" = "流量更新將會傳送到此 URI" +"restartXrayOnClientDisable" = "用戶自動停用後重新啟動 Xray" +"restartXrayOnClientDisableDesc" = "當用戶因到期或流量上限而被自動停用時,重新啟動 Xray。" "fragment" = "分片" "fragmentDesc" = "啟用 TLS hello 資料包分片" "fragmentSett" = "設定"