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.
This commit is contained in:
MHSanaei
2026-05-04 23:19:25 +02:00
parent e9806832ec
commit 6099a07ff0
24 changed files with 154 additions and 34 deletions

View File

@@ -55,7 +55,7 @@ func (s *SubClashService) GetClash(subId string, host string) (string, string, e
} }
} }
for _, client := range clients { for _, client := range clients {
if client.Enable && client.SubID == subId { if client.SubID == subId {
clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email)) clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email))
proxies = append(proxies, s.getProxies(inbound, client, host)...) proxies = append(proxies, s.getProxies(inbound, client, host)...)
} }

View File

@@ -116,7 +116,7 @@ func (s *SubJsonService) GetJson(subId string, host string) (string, string, err
} }
for _, client := range clients { for _, client := range clients {
if client.Enable && client.SubID == subId { if client.SubID == subId {
clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email)) clientTraffics = append(clientTraffics, s.SubService.getClientTraffics(inbound.ClientStats, client.Email))
newConfigs := s.getConfig(inbound, client, host) newConfigs := s.getConfig(inbound, client, host)
configArray = append(configArray, newConfigs...) configArray = append(configArray, newConfigs...)

View File

@@ -77,7 +77,7 @@ func (s *SubService) GetSubs(subId string, host string) ([]string, int64, xray.C
} }
} }
for _, client := range clients { for _, client := range clients {
if client.Enable && client.SubID == subId { if client.SubID == subId {
link := s.getLink(inbound, client.Email) link := s.getLink(inbound, client.Email)
result = append(result, link) result = append(result, link)
ct := s.getClientTraffics(inbound.ClientStats, client.Email) ct := s.getClientTraffics(inbound.ClientStats, client.Email)

View File

@@ -43,6 +43,7 @@ class AllSetting {
this.subDomain = ""; this.subDomain = "";
this.externalTrafficInformEnable = false; this.externalTrafficInformEnable = false;
this.externalTrafficInformURI = ""; this.externalTrafficInformURI = "";
this.restartXrayOnClientDisable = true;
this.subCertFile = ""; this.subCertFile = "";
this.subKeyFile = ""; this.subKeyFile = "";
this.subUpdates = 12; this.subUpdates = 12;

View File

@@ -71,6 +71,7 @@ type AllSetting struct {
SubUpdates int `json:"subUpdates" form:"subUpdates"` // Subscription update interval in minutes SubUpdates int `json:"subUpdates" form:"subUpdates"` // Subscription update interval in minutes
ExternalTrafficInformEnable bool `json:"externalTrafficInformEnable" form:"externalTrafficInformEnable"` // Enable external traffic reporting ExternalTrafficInformEnable bool `json:"externalTrafficInformEnable" form:"externalTrafficInformEnable"` // Enable external traffic reporting
ExternalTrafficInformURI string `json:"externalTrafficInformURI" form:"externalTrafficInformURI"` // URI for 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 SubEncrypt bool `json:"subEncrypt" form:"subEncrypt"` // Encrypt subscription responses
SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"` // Show client information in subscriptions SubShowInfo bool `json:"subShowInfo" form:"subShowInfo"` // Show client information in subscriptions
SubURI string `json:"subURI" form:"subURI"` // Subscription server URI SubURI string `json:"subURI" form:"subURI"` // Subscription server URI

View File

@@ -124,6 +124,13 @@
v-model="allSetting.externalTrafficInformURI"></a-input> v-model="allSetting.externalTrafficInformURI"></a-input>
</template> </template>
</a-setting-list-item> </a-setting-list-item>
<a-setting-list-item paddings="small">
<template #title>{{ i18n "pages.settings.restartXrayOnClientDisable"}}</template>
<template #description>{{ i18n "pages.settings.restartXrayOnClientDisableDesc"}}</template>
<template #control>
<a-switch v-model="allSetting.restartXrayOnClientDisable"></a-switch>
</template>
</a-setting-list-item>
</a-collapse-panel> </a-collapse-panel>
<a-collapse-panel key="5" header='{{ i18n "pages.settings.dateAndTime" }}'> <a-collapse-panel key="5" header='{{ i18n "pages.settings.dateAndTime" }}'>
<a-setting-list-item paddings="small"> <a-setting-list-item paddings="small">

View File

@@ -199,6 +199,9 @@ func (j *CheckClientIpJob) processLogFile() bool {
inboundClientIps[email][ip] = timestamp inboundClientIps[email][ip] = timestamp
} }
} }
if err := scanner.Err(); err != nil {
j.checkError(err)
}
shouldCleanLog := false shouldCleanLog := false
for email, ipTimestamps := range inboundClientIps { for email, ipTimestamps := range inboundClientIps {

View File

@@ -33,7 +33,7 @@ func (j *XrayTrafficJob) Run() {
if err != nil { if err != nil {
return return
} }
err, needRestart0 := j.inboundService.AddTraffic(traffics, clientTraffics) err, needRestart0, clientsDisabled := j.inboundService.AddTraffic(traffics, clientTraffics)
if err != nil { if err != nil {
logger.Warning("add inbound traffic failed:", err) logger.Warning("add inbound traffic failed:", err)
} }
@@ -41,6 +41,18 @@ func (j *XrayTrafficJob) Run() {
if err != nil { if err != nil {
logger.Warning("add outbound traffic failed:", err) 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 { if ExternalTrafficInformEnable, err := j.settingService.GetExternalTrafficInformEnable(); ExternalTrafficInformEnable {
j.informTrafficToExternalAPI(traffics, clientTraffics) j.informTrafficToExternalAPI(traffics, clientTraffics)
} else if err != nil { } else if err != nil {

View File

@@ -1228,7 +1228,7 @@ func (s *InboundService) UpdateInboundClient(data *model.Inbound, clientId strin
return needRestart, tx.Save(oldInbound).Error 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 var err error
db := database.GetDB() db := database.GetDB()
tx := db.Begin() tx := db.Begin()
@@ -1242,11 +1242,11 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff
}() }()
err = s.addInboundTraffic(tx, inboundTraffics) err = s.addInboundTraffic(tx, inboundTraffics)
if err != nil { if err != nil {
return err, false return err, false, false
} }
err = s.addClientTraffic(tx, clientTraffics) err = s.addClientTraffic(tx, clientTraffics)
if err != nil { if err != nil {
return err, false return err, false, false
} }
needRestart0, count, err := s.autoRenewClients(tx) needRestart0, count, err := s.autoRenewClients(tx)
@@ -1256,11 +1256,13 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff
logger.Debugf("%v clients renewed", count) logger.Debugf("%v clients renewed", count)
} }
disabledClientsCount := int64(0)
needRestart1, count, err := s.disableInvalidClients(tx) needRestart1, count, err := s.disableInvalidClients(tx)
if err != nil { if err != nil {
logger.Warning("Error in disabling invalid clients:", err) logger.Warning("Error in disabling invalid clients:", err)
} else if count > 0 { } else if count > 0 {
logger.Debugf("%v clients disabled", count) logger.Debugf("%v clients disabled", count)
disabledClientsCount = count
} }
needRestart2, count, err := s.disableInvalidInbounds(tx) needRestart2, count, err := s.disableInvalidInbounds(tx)
@@ -1269,7 +1271,7 @@ func (s *InboundService) AddTraffic(inboundTraffics []*xray.Traffic, clientTraff
} else if count > 0 { } else if count > 0 {
logger.Debugf("%v inbounds disabled", count) 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 { 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 now := time.Now().Unix() * 1000
needRestart := false needRestart := false
if p != nil { var clientsToDisable []struct {
var results []struct { InboundId int
Tag string Tag string
Email string Email string
} }
err := tx.Table("inbounds"). err := tx.Table("inbounds").
Select("inbounds.tag, client_traffics.email"). Select("inbounds.id as inbound_id, inbounds.tag, client_traffics.email").
Joins("JOIN client_traffics ON inbounds.id = client_traffics.inbound_id"). 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). 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 Scan(&clientsToDisable).Error
if err != nil { if err != nil {
return false, 0, err return false, 0, err
} }
if p != nil {
s.xrayApi.Init(p.GetAPIPort()) s.xrayApi.Init(p.GetAPIPort())
for _, result := range results { for _, client := range clientsToDisable {
err1 := s.xrayApi.RemoveUser(result.Tag, result.Email) err1 := s.xrayApi.RemoveUser(client.Tag, client.Email)
if err1 == nil { if err1 == nil {
logger.Debug("Client disabled by api:", result.Email) logger.Debug("Client disabled by api:", client.Email)
} else { } 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...") logger.Debug("User is already disabled. Nothing to do more...")
} else { } else {
if strings.Contains(err1.Error(), fmt.Sprintf("User %s not found.", result.Email)) { logger.Debug("Error in disabling client by api:", err1)
logger.Debug("User is already disabled. Nothing to do more...") needRestart = true
} else {
logger.Debug("Error in disabling client by api:", err1)
needRestart = true
}
} }
} }
} }
s.xrayApi.Close() s.xrayApi.Close()
} }
result := tx.Model(xray.ClientTraffic{}). result := tx.Model(xray.ClientTraffic{}).
Where("((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?", now, true). Where("((total > 0 and up + down >= total) or (expiry_time > 0 and expiry_time <= ?)) and enable = ?", now, true).
Update("enable", false) Update("enable", false)
err := result.Error err = result.Error
count := result.RowsAffected 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) { func (s *InboundService) GetInboundTags() (string, error) {

View File

@@ -83,6 +83,7 @@ var defaultValueMap = map[string]string{
"nord": "", "nord": "",
"externalTrafficInformEnable": "false", "externalTrafficInformEnable": "false",
"externalTrafficInformURI": "", "externalTrafficInformURI": "",
"restartXrayOnClientDisable": "true",
"xrayOutboundTestUrl": "https://www.google.com/generate_204", "xrayOutboundTestUrl": "https://www.google.com/generate_204",
// LDAP defaults // LDAP defaults
@@ -628,6 +629,14 @@ func (s *SettingService) SetExternalTrafficInformURI(InformURI string) error {
return s.setString("externalTrafficInformURI", InformURI) 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) { func (s *SettingService) GetIpLimitEnable() (bool, error) {
accessLogPath, err := xray.GetAccessLogPath() accessLogPath, err := xray.GetAccessLogPath()
if err != nil { if err != nil {

View File

@@ -103,7 +103,7 @@ func (s *XrayService) GetXrayConfig() (*xray.Config, error) {
return nil, err return nil, err
} }
s.inboundService.AddTraffic(nil, nil) _, _, _ = s.inboundService.AddTraffic(nil, nil)
inbounds, err := s.inboundService.GetAllInbounds() inbounds, err := s.inboundService.GetAllInbounds()
if err != nil { if err != nil {

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "يبعت تنبيه لـ API خارجي مع كل تحديث للترافيك." "externalTrafficInformEnableDesc" = "يبعت تنبيه لـ API خارجي مع كل تحديث للترافيك."
"externalTrafficInformURI" = "مسار تنبيه الترافيك الخارجي" "externalTrafficInformURI" = "مسار تنبيه الترافيك الخارجي"
"externalTrafficInformURIDesc" = "تحديثات الترافيك هتتبعت للمسار ده." "externalTrafficInformURIDesc" = "تحديثات الترافيك هتتبعت للمسار ده."
"restartXrayOnClientDisable" = "إعادة تشغيل Xray بعد التعطيل التلقائي"
"restartXrayOnClientDisableDesc" = "عند تعطيل العميل تلقائيا بسبب انتهاء الصلاحية أو حد حركة المرور، أعد تشغيل Xray."
"fragment" = "تجزئة" "fragment" = "تجزئة"
"fragmentDesc" = "يفعل تجزئة لحزمة TLS hello." "fragmentDesc" = "يفعل تجزئة لحزمة TLS hello."
"fragmentSett" = "إعدادات التجزئة" "fragmentSett" = "إعدادات التجزئة"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "Inform external API on every traffic update." "externalTrafficInformEnableDesc" = "Inform external API on every traffic update."
"externalTrafficInformURI" = "External Traffic Inform URI" "externalTrafficInformURI" = "External Traffic Inform URI"
"externalTrafficInformURIDesc" = "Traffic updates are sent to this 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" "fragment" = "Fragmentation"
"fragmentDesc" = "Enable fragmentation for TLS hello packet." "fragmentDesc" = "Enable fragmentation for TLS hello packet."
"fragmentSett" = "Fragmentation Settings" "fragmentSett" = "Fragmentation Settings"

View File

@@ -476,6 +476,8 @@
"externalTrafficInformEnableDesc" = "Informar a la API externa sobre cada actualización de tráfico." "externalTrafficInformEnableDesc" = "Informar a la API externa sobre cada actualización de tráfico."
"externalTrafficInformURI" = "URI de información de tráfico externo" "externalTrafficInformURI" = "URI de información de tráfico externo"
"externalTrafficInformURIDesc" = "Las actualizaciones de tráfico se envían a este URI." "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" "subURIDesc" = "Cambiar el URI base de la URL de suscripción para usar detrás de los servidores proxy"
"fragment" = "Fragmentación" "fragment" = "Fragmentación"
"fragmentDesc" = "Habilitar la fragmentación para el paquete de saludo de TLS" "fragmentDesc" = "Habilitar la fragmentación para el paquete de saludo de TLS"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "مصرف ترافیک به سرویس خارجی ارسال می شود" "externalTrafficInformEnableDesc" = "مصرف ترافیک به سرویس خارجی ارسال می شود"
"externalTrafficInformURI" = "لینک اطلاع رسانی خارجی مصرف ترافیک" "externalTrafficInformURI" = "لینک اطلاع رسانی خارجی مصرف ترافیک"
"externalTrafficInformURIDesc" = "ترافیک های مصرفی به این لینک هم ارسال می شود" "externalTrafficInformURIDesc" = "ترافیک های مصرفی به این لینک هم ارسال می شود"
"restartXrayOnClientDisable" = "ری‌استارت Xray بعد از غیرفعال‌سازی خودکار"
"restartXrayOnClientDisableDesc" = "وقتی کاربر به‌صورت خودکار به‌دلیل اتمام زمان یا ترافیک غیرفعال می‌شود، Xray ری‌استارت شود."
"fragment" = "فرگمنت" "fragment" = "فرگمنت"
"fragmentDesc" = "فعال کردن فرگمنت برای بسته‌ی نخست تی‌ال‌اس" "fragmentDesc" = "فعال کردن فرگمنت برای بسته‌ی نخست تی‌ال‌اس"
"fragmentSett" = "تنظیمات فرگمنت" "fragmentSett" = "تنظیمات فرگمنت"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "Inform external API on every traffic update." "externalTrafficInformEnableDesc" = "Inform external API on every traffic update."
"externalTrafficInformURI" = "Lalu Lintas Eksternal Menginformasikan URI" "externalTrafficInformURI" = "Lalu Lintas Eksternal Menginformasikan URI"
"externalTrafficInformURIDesc" = "Pembaruan lalu lintas dikirim ke URI ini." "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" "fragment" = "Fragmentasi"
"fragmentDesc" = "Aktifkan fragmentasi untuk paket hello TLS" "fragmentDesc" = "Aktifkan fragmentasi untuk paket hello TLS"
"fragmentSett" = "Pengaturan Fragmentasi" "fragmentSett" = "Pengaturan Fragmentasi"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "トラフィックの更新ごとに外部 API に通知します。" "externalTrafficInformEnableDesc" = "トラフィックの更新ごとに外部 API に通知します。"
"externalTrafficInformURI" = "外部トラフィック通知 URI" "externalTrafficInformURI" = "外部トラフィック通知 URI"
"externalTrafficInformURIDesc" = "トラフィックの更新ごとに外部 API に通知します。" "externalTrafficInformURIDesc" = "トラフィックの更新ごとに外部 API に通知します。"
"restartXrayOnClientDisable" = "自動無効化後に Xray を再起動"
"restartXrayOnClientDisableDesc" = "有効期限切れまたはトラフィック上限でクライアントが自動的に無効化されたとき、Xray を再起動します。"
"fragment" = "フラグメント" "fragment" = "フラグメント"
"fragmentDesc" = "TLS helloパケットのフラグメントを有効にする" "fragmentDesc" = "TLS helloパケットのフラグメントを有効にする"
"fragmentSett" = "設定" "fragmentSett" = "設定"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "Informar a API externa sobre cada atualização de tráfego." "externalTrafficInformEnableDesc" = "Informar a API externa sobre cada atualização de tráfego."
"externalTrafficInformURI" = "URI de informação de tráfego externo" "externalTrafficInformURI" = "URI de informação de tráfego externo"
"externalTrafficInformURIDesc" = "As atualizações de tráfego são enviadas para este URI." "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" "fragment" = "Fragmentação"
"fragmentDesc" = "Ativa a fragmentação para o pacote TLS hello." "fragmentDesc" = "Ativa a fragmentação para o pacote TLS hello."
"fragmentSett" = "Configurações de Fragmentação" "fragmentSett" = "Configurações de Fragmentação"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "Информировать внешний API о каждом обновлении трафика" "externalTrafficInformEnableDesc" = "Информировать внешний API о каждом обновлении трафика"
"externalTrafficInformURI" = "URI информации о внешнем трафике" "externalTrafficInformURI" = "URI информации о внешнем трафике"
"externalTrafficInformURIDesc" = "Обновления трафика отправляются на этот URI" "externalTrafficInformURIDesc" = "Обновления трафика отправляются на этот URI"
"restartXrayOnClientDisable" = "Перезапускать Xray после автоотключения"
"restartXrayOnClientDisableDesc" = "Когда клиент автоматически отключается из-за окончания срока действия или лимита трафика, перезапускать Xray."
"fragment" = "Фрагментация" "fragment" = "Фрагментация"
"fragmentDesc" = "Включить фрагментацию TLS-хэндшейка" "fragmentDesc" = "Включить фрагментацию TLS-хэндшейка"
"fragmentSett" = "Настройки фрагментации" "fragmentSett" = "Настройки фрагментации"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "Her trafik güncellemesinde harici API'yi bilgilendirin." "externalTrafficInformEnableDesc" = "Her trafik güncellemesinde harici API'yi bilgilendirin."
"externalTrafficInformURI" = "Harici Trafik Bilgisi URI'si" "externalTrafficInformURI" = "Harici Trafik Bilgisi URI'si"
"externalTrafficInformURIDesc" = "Trafik güncellemeleri bu URI'ye gönderildi." "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" "fragment" = "Parçalama"
"fragmentDesc" = "TLS merhaba paketinin parçalanmasını etkinleştir." "fragmentDesc" = "TLS merhaba paketinin parçalanmasını etkinleştir."
"fragmentSett" = "Parçalama Ayarları" "fragmentSett" = "Parçalama Ayarları"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "Інформувати зовнішній API про кожне оновлення трафіку." "externalTrafficInformEnableDesc" = "Інформувати зовнішній API про кожне оновлення трафіку."
"externalTrafficInformURI" = "Інформаційний URI зовнішнього трафіку" "externalTrafficInformURI" = "Інформаційний URI зовнішнього трафіку"
"externalTrafficInformURIDesc" = "Оновлення трафіку надсилаються на цей URI." "externalTrafficInformURIDesc" = "Оновлення трафіку надсилаються на цей URI."
"restartXrayOnClientDisable" = "Перезапускати Xray після авто-вимкнення"
"restartXrayOnClientDisableDesc" = "Коли клієнт автоматично вимикається через закінчення терміну дії або ліміт трафіку, перезапускати Xray."
"fragment" = "Фрагментація" "fragment" = "Фрагментація"
"fragmentDesc" = "Увімкнути фрагментацію для пакету привітання TLS" "fragmentDesc" = "Увімкнути фрагментацію для пакету привітання TLS"
"fragmentSett" = "Параметри фрагментації" "fragmentSett" = "Параметри фрагментації"

View File

@@ -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." "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" "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." "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" "fragment" = "Sự phân mảnh"
"fragmentDesc" = "Kích hoạt phân mảnh cho gói TLS hello" "fragmentDesc" = "Kích hoạt phân mảnh cho gói TLS hello"
"fragmentSett" = "Cài đặt phân mảnh" "fragmentSett" = "Cài đặt phân mảnh"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "每次流量更新时通知外部 API" "externalTrafficInformEnableDesc" = "每次流量更新时通知外部 API"
"externalTrafficInformURI" = "外部流量通知 URI" "externalTrafficInformURI" = "外部流量通知 URI"
"externalTrafficInformURIDesc" = "流量更新将发送到此 URI" "externalTrafficInformURIDesc" = "流量更新将发送到此 URI"
"restartXrayOnClientDisable" = "客户端自动禁用后重启 Xray"
"restartXrayOnClientDisableDesc" = "当客户端因到期或流量超限被自动禁用时,重启 Xray。"
"fragment" = "分片" "fragment" = "分片"
"fragmentDesc" = "启用 TLS hello 数据包分片" "fragmentDesc" = "启用 TLS hello 数据包分片"
"fragmentSett" = "设置" "fragmentSett" = "设置"

View File

@@ -477,6 +477,8 @@
"externalTrafficInformEnableDesc" = "每次流量更新時通知外部 API" "externalTrafficInformEnableDesc" = "每次流量更新時通知外部 API"
"externalTrafficInformURI" = "外部流量通知 URI" "externalTrafficInformURI" = "外部流量通知 URI"
"externalTrafficInformURIDesc" = "流量更新將會傳送到此 URI" "externalTrafficInformURIDesc" = "流量更新將會傳送到此 URI"
"restartXrayOnClientDisable" = "用戶自動停用後重新啟動 Xray"
"restartXrayOnClientDisableDesc" = "當用戶因到期或流量上限而被自動停用時,重新啟動 Xray。"
"fragment" = "分片" "fragment" = "分片"
"fragmentDesc" = "啟用 TLS hello 資料包分片" "fragmentDesc" = "啟用 TLS hello 資料包分片"
"fragmentSett" = "設定" "fragmentSett" = "設定"