From ceef413dc40d0203b44252528c79ce8d70020c00 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Wed, 3 Jun 2026 21:52:37 +0200 Subject: [PATCH] feat(xray): add connIdle and bufferSize policy controls Expose level-0 connection policies in the panel's Basics tab: idle timeout (connIdle) and per-connection buffer size (bufferSize). Empty fields delete the key so Xray falls back to its own defaults. Adds en-US/fa-IR strings and types policy.levels in the Zod schema. --- frontend/src/pages/xray/basics/BasicsTab.tsx | 62 +++++++++++++++++++- frontend/src/schemas/xray.ts | 1 + web/translation/en-US.json | 8 +++ web/translation/fa-IR.json | 8 +++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/xray/basics/BasicsTab.tsx b/frontend/src/pages/xray/basics/BasicsTab.tsx index 67fad5b5..d630abfd 100644 --- a/frontend/src/pages/xray/basics/BasicsTab.tsx +++ b/frontend/src/pages/xray/basics/BasicsTab.tsx @@ -1,8 +1,9 @@ import { useCallback } from 'react'; import { useTranslation } from 'react-i18next'; -import { Alert, Button, Input, Modal, Select, Space, Switch, Tabs } from 'antd'; +import { Alert, Button, Input, InputNumber, Modal, Select, Space, Switch, Tabs } from 'antd'; import { BarChartOutlined, + ClockCircleOutlined, FileTextOutlined, ReloadOutlined, SettingOutlined, @@ -54,6 +55,20 @@ export default function BasicsTab({ [setTemplateSettings], ); + const setLevel0 = useCallback( + (field: string, value: number | null) => mutate((tt) => { + if (!tt.policy) tt.policy = {}; + if (!tt.policy.levels) tt.policy.levels = {}; + if (!tt.policy.levels['0']) tt.policy.levels['0'] = {}; + if (value === null || value === undefined) { + delete tt.policy.levels['0'][field]; + } else { + tt.policy.levels['0'][field] = value; + } + }), + [mutate], + ); + function confirmResetDefault() { modal.confirm({ title: t('pages.settings.resetDefaultConfig'), @@ -72,6 +87,7 @@ export default function BasicsTab({ const routingStrategy = templateSettings?.routing?.domainStrategy ?? 'AsIs'; const log = (templateSettings?.log || {}) as Record; const policy = (templateSettings?.policy?.system || {}) as Record; + const level0 = (templateSettings?.policy?.levels?.['0'] || {}) as Record; const items = [ { @@ -168,6 +184,50 @@ export default function BasicsTab({ ), }, + { + key: 'connection', + label: catTabLabel(, t('pages.xray.connectionLimits'), isMobile), + children: ( + <> + + setLevel0('connIdle', v as number | null)} + /> + } + /> + setLevel0('bufferSize', v as number | null)} + /> + } + /> + + ), + }, { key: '3', label: catTabLabel(, t('pages.xray.logConfigs'), isMobile), diff --git a/frontend/src/schemas/xray.ts b/frontend/src/schemas/xray.ts index ad19e5dd..1eeedb4d 100644 --- a/frontend/src/schemas/xray.ts +++ b/frontend/src/schemas/xray.ts @@ -28,6 +28,7 @@ export const XraySettingsValueSchema = z.object({ log: z.record(z.string(), z.unknown()).optional(), policy: z.object({ system: z.record(z.string(), z.boolean()).optional(), + levels: z.record(z.string(), z.record(z.string(), z.unknown())).optional(), }).loose().optional(), observatory: z.unknown().optional(), burstObservatory: z.unknown().optional(), diff --git a/web/translation/en-US.json b/web/translation/en-US.json index 323d3466..7e0f91be 100644 --- a/web/translation/en-US.json +++ b/web/translation/en-US.json @@ -1201,6 +1201,14 @@ "statsOutboundUplinkDesc": "Enables the statistics collection for upstream traffic of all outbound proxies.", "statsOutboundDownlink": "Outbound Download Statistics", "statsOutboundDownlinkDesc": "Enables the statistics collection for downstream traffic of all outbound proxies.", + "connectionLimits": "Connection Limits", + "connectionLimitsDesc": "Connection-level policies for user level 0. Leave a field empty to use Xray's default.", + "connIdle": "Idle Timeout", + "connIdleDesc": "Closes a connection after it stays idle for this many seconds. Lowering it frees memory and file descriptors faster on busy servers (Xray default: 300).", + "bufferSize": "Buffer Size", + "bufferSizeDesc": "Per-connection internal buffer size in KB. Set to 0 to minimize memory usage on low-RAM servers (Xray default depends on the platform).", + "bufferSizePlaceholder": "auto", + "seconds": "seconds", "rules": { "first": "First", "last": "Last", diff --git a/web/translation/fa-IR.json b/web/translation/fa-IR.json index 9be8418c..bef48625 100644 --- a/web/translation/fa-IR.json +++ b/web/translation/fa-IR.json @@ -1201,6 +1201,14 @@ "statsOutboundUplinkDesc": "جمع‌آوری آمار برای ترافیک بالارو (آپلود) تمام پروکسی‌های خروجی را فعال می‌کند.", "statsOutboundDownlink": "آمار دانلود خروجی", "statsOutboundDownlinkDesc": "جمع‌آوری آمار برای ترافیک پایین‌رو (دانلود) تمام پروکسی‌های خروجی را فعال می‌کند.", + "connectionLimits": "محدودیت اتصال", + "connectionLimitsDesc": "سیاست‌های سطح اتصال برای کاربرانِ سطح ۰. هر فیلد را خالی بگذارید تا مقدار پیش‌فرض Xray استفاده شود.", + "connIdle": "مهلت بی‌کاری", + "connIdleDesc": "اتصال را پس از این تعداد ثانیه بی‌کار ماندن می‌بندد. کم‌کردن آن، روی سرورهای شلوغ حافظه و file descriptor را زودتر آزاد می‌کند (پیش‌فرض Xray: ۳۰۰).", + "bufferSize": "اندازهٔ بافر", + "bufferSizeDesc": "اندازهٔ بافر داخلی هر اتصال بر حسب کیلوبایت. برای کم‌کردن مصرف حافظه روی سرورهای کم‌رم روی ۰ بگذارید (پیش‌فرض Xray به پلتفرم بستگی دارد).", + "bufferSizePlaceholder": "خودکار", + "seconds": "ثانیه", "rules": { "first": "اولین", "last": "آخرین",