feat: variant badges, live RSS RAM tracking, sysctl network tuning, telegram updates (1.3.18)
This commit is contained in:
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "fe-app-tachyon",
|
||||
"version": "1.3.17",
|
||||
"version": "1.3.18",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "fe-app-tachyon",
|
||||
"version": "1.3.17",
|
||||
"version": "1.3.18",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@esbuild/win32-x64": "^0.28.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "fe-app-tachyon",
|
||||
"version": "1.3.17",
|
||||
"version": "1.3.18",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
||||
@@ -59,6 +59,9 @@ export async function fetchServicesInfo() {
|
||||
failed: !tachyon.success || !singbox.success,
|
||||
data: {
|
||||
singbox: singbox.success ? singbox.data.running : previousData.singbox,
|
||||
singboxMemoryMb: singbox.success
|
||||
? singbox.data.memory_rss_mb
|
||||
: previousData.singboxMemoryMb,
|
||||
tachyonRunning: tachyon.success
|
||||
? tachyon.data.running
|
||||
: previousData.tachyonRunning,
|
||||
@@ -71,6 +74,8 @@ export async function fetchServicesInfo() {
|
||||
watchdogRunning: watchdog.success
|
||||
? Number((watchdog.data as { running: boolean }).running)
|
||||
: previousData.watchdogRunning,
|
||||
zapret2Running: previousData.zapret2Running,
|
||||
zapret2MemoryMb: previousData.zapret2MemoryMb,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@@ -56,6 +56,8 @@ export function formatSingBoxVersion(value: SingBoxVariantFields) {
|
||||
variant = _('compressed');
|
||||
} else if (normalizedValue.sing_box_extended && normalizedValue.sing_box_lx) {
|
||||
variant = _('lx');
|
||||
} else if (normalizedValue.sing_box_extended) {
|
||||
variant = _('extended');
|
||||
} else if (normalizedValue.sing_box_tiny) {
|
||||
variant = _('tiny');
|
||||
}
|
||||
@@ -66,15 +68,69 @@ export function formatSingBoxVersion(value: SingBoxVariantFields) {
|
||||
export function normalizeSingBoxVariantFields<T extends SingBoxVariantFields>(
|
||||
value: T,
|
||||
): T {
|
||||
const versionExtended = isExtendedSingBoxVersion(value.sing_box_version);
|
||||
const version = String(value.sing_box_version || '');
|
||||
const versionExtended = isExtendedSingBoxVersion(version);
|
||||
const versionLx = version.includes('-lx');
|
||||
const singBoxExtended = Boolean(value.sing_box_extended) || versionExtended;
|
||||
const singBoxLx =
|
||||
singBoxExtended && (Boolean(value.sing_box_lx) || versionLx);
|
||||
|
||||
return {
|
||||
...value,
|
||||
sing_box_extended: singBoxExtended ? 1 : 0,
|
||||
sing_box_tiny: singBoxExtended ? 0 : value.sing_box_tiny ? 1 : 0,
|
||||
sing_box_compressed: singBoxExtended && value.sing_box_compressed ? 1 : 0,
|
||||
sing_box_lx: singBoxExtended && value.sing_box_lx ? 1 : 0,
|
||||
sing_box_lx: singBoxLx ? 1 : 0,
|
||||
sing_box_tailscale: singBoxExtended || value.sing_box_tailscale ? 1 : 0,
|
||||
} as T;
|
||||
}
|
||||
|
||||
export function renderSingBoxVariantBadge(
|
||||
value: SingBoxVariantFields,
|
||||
): HTMLSpanElement | null {
|
||||
const version = String(value.sing_box_version || '');
|
||||
if (!version || isVersionPlaceholder(version)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const normalized = normalizeSingBoxVariantFields(value);
|
||||
const badge = document.createElement('span');
|
||||
badge.className = 'tachyon-badge';
|
||||
badge.style.display = 'inline-block';
|
||||
badge.style.marginLeft = '8px';
|
||||
badge.style.padding = '2px 8px';
|
||||
badge.style.borderRadius = '9999px';
|
||||
badge.style.fontSize = '11px';
|
||||
badge.style.fontWeight = '600';
|
||||
badge.style.lineHeight = '16px';
|
||||
badge.style.verticalAlign = 'middle';
|
||||
|
||||
if (normalized.sing_box_lx) {
|
||||
badge.textContent = 'Leadaxe (lx)';
|
||||
badge.style.backgroundColor = 'rgba(16, 185, 129, 0.15)';
|
||||
badge.style.color = '#10b981';
|
||||
badge.style.border = '1px solid rgba(16, 185, 129, 0.35)';
|
||||
} else if (normalized.sing_box_compressed) {
|
||||
badge.textContent = 'Extended (compressed)';
|
||||
badge.style.backgroundColor = 'rgba(59, 130, 246, 0.15)';
|
||||
badge.style.color = '#3b82f6';
|
||||
badge.style.border = '1px solid rgba(59, 130, 246, 0.35)';
|
||||
} else if (normalized.sing_box_extended) {
|
||||
badge.textContent = 'Extended (shtorm-7)';
|
||||
badge.style.backgroundColor = 'rgba(59, 130, 246, 0.15)';
|
||||
badge.style.color = '#3b82f6';
|
||||
badge.style.border = '1px solid rgba(59, 130, 246, 0.35)';
|
||||
} else if (normalized.sing_box_tiny) {
|
||||
badge.textContent = 'Tiny';
|
||||
badge.style.backgroundColor = 'rgba(245, 158, 11, 0.15)';
|
||||
badge.style.color = '#f59e0b';
|
||||
badge.style.border = '1px solid rgba(245, 158, 11, 0.35)';
|
||||
} else {
|
||||
badge.textContent = 'Official';
|
||||
badge.style.backgroundColor = 'rgba(107, 114, 128, 0.15)';
|
||||
badge.style.color = '#6b7280';
|
||||
badge.style.border = '1px solid rgba(107, 114, 128, 0.35)';
|
||||
}
|
||||
|
||||
return badge;
|
||||
}
|
||||
|
||||
@@ -167,6 +167,9 @@ export interface StoreType {
|
||||
tachyonEnabled: number;
|
||||
tachyonStatus: string;
|
||||
watchdogRunning: number;
|
||||
singboxMemoryMb?: number;
|
||||
zapret2Running?: number;
|
||||
zapret2MemoryMb?: number;
|
||||
};
|
||||
};
|
||||
tailscaleWidget: {
|
||||
|
||||
@@ -100,10 +100,17 @@ function applyServiceState(uiState: Tachyon.UiState) {
|
||||
failed: false,
|
||||
data: {
|
||||
singbox: uiState.service.sing_box.running,
|
||||
singboxMemoryMb: uiState.service.sing_box.memory_rss_mb,
|
||||
tachyonRunning: uiState.service.tachyon.running,
|
||||
tachyonEnabled: uiState.service.tachyon.enabled,
|
||||
tachyonStatus: uiState.service.tachyon.status,
|
||||
watchdogRunning: store.get().servicesInfoWidget.data.watchdogRunning,
|
||||
zapret2Running: uiState.service.zapret2
|
||||
? uiState.service.zapret2.running
|
||||
: undefined,
|
||||
zapret2MemoryMb: uiState.service.zapret2
|
||||
? uiState.service.zapret2.memory_rss_mb
|
||||
: undefined,
|
||||
},
|
||||
},
|
||||
diagnosticsSystemInfo: normalizeSingBoxVariantFields(nextSystemInfo),
|
||||
|
||||
@@ -1885,26 +1885,47 @@ async function renderServicesInfoWidget() {
|
||||
'dashboard-widget-service-info',
|
||||
'servicesInfoWidget',
|
||||
_('Services info'),
|
||||
(data) => [
|
||||
{
|
||||
key: 'Tachyon',
|
||||
value: data.tachyonRunning ? _('✔ Running') : _('✘ Stopped'),
|
||||
attributes: {
|
||||
class: data.tachyonRunning
|
||||
? 'tachyon_dashboard-page__widgets-section__item__row--success'
|
||||
: 'tachyon_dashboard-page__widgets-section__item__row--error',
|
||||
(data) => {
|
||||
const items = [
|
||||
{
|
||||
key: 'Tachyon',
|
||||
value: data.tachyonRunning ? _('✔ Running') : _('✘ Stopped'),
|
||||
attributes: {
|
||||
class: data.tachyonRunning
|
||||
? 'tachyon_dashboard-page__widgets-section__item__row--success'
|
||||
: 'tachyon_dashboard-page__widgets-section__item__row--error',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'Sing-box',
|
||||
value: data.singbox ? _('✔ Running') : _('✘ Stopped'),
|
||||
attributes: {
|
||||
class: data.singbox
|
||||
? 'tachyon_dashboard-page__widgets-section__item__row--success'
|
||||
: 'tachyon_dashboard-page__widgets-section__item__row--error',
|
||||
{
|
||||
key: 'Sing-box',
|
||||
value: data.singbox
|
||||
? data.singboxMemoryMb
|
||||
? `${_('✔ Running')} (${data.singboxMemoryMb} MB)`
|
||||
: _('✔ Running')
|
||||
: _('✘ Stopped'),
|
||||
attributes: {
|
||||
class: data.singbox
|
||||
? 'tachyon_dashboard-page__widgets-section__item__row--success'
|
||||
: 'tachyon_dashboard-page__widgets-section__item__row--error',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
];
|
||||
|
||||
if (data.zapret2Running) {
|
||||
items.push({
|
||||
key: 'Zapret2',
|
||||
value: data.zapret2MemoryMb
|
||||
? `${_('✔ Running')} (${data.zapret2MemoryMb} MB)`
|
||||
: _('✔ Running'),
|
||||
attributes: {
|
||||
class:
|
||||
'tachyon_dashboard-page__widgets-section__item__row--success',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return items;
|
||||
},
|
||||
'renderServicesInfoWidget',
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { shouldShowLoadingForRestoredAction } from '../../helpers/restoredAction
|
||||
import {
|
||||
formatSingBoxVersion,
|
||||
normalizeSingBoxVariantFields,
|
||||
renderSingBoxVariantBadge,
|
||||
} from '../../helpers/singBoxVariant';
|
||||
import { shouldApplyCompletedComponentActionResult } from './componentActionCompletion';
|
||||
import {
|
||||
@@ -115,6 +116,7 @@ interface ComponentCard {
|
||||
releaseUrl?: string;
|
||||
repoUrl?: string;
|
||||
actions: ComponentActionButton[];
|
||||
badgeNode?: Node | null;
|
||||
}
|
||||
|
||||
let updatesLifecycleRegistered = false;
|
||||
@@ -1271,6 +1273,9 @@ function getComponentCards(): ComponentCard[] {
|
||||
version: systemInfoLoading
|
||||
? _('Loading...')
|
||||
: formatSingBoxVersion(systemInfo),
|
||||
badgeNode: systemInfoLoading
|
||||
? null
|
||||
: renderSingBoxVariantBadge(systemInfo),
|
||||
latestVersion: getLatestVersion('sing_box'),
|
||||
releaseUrl: getGitHubReleaseUrl('sing_box'),
|
||||
repoUrl:
|
||||
@@ -1350,12 +1355,17 @@ function renderComponentCard(card: ComponentCard) {
|
||||
|
||||
const headerChildren: Node[] = [
|
||||
E('b', { class: 'tachyon_updates-page__component__title' }, card.title),
|
||||
];
|
||||
if (card.badgeNode) {
|
||||
headerChildren.push(card.badgeNode);
|
||||
}
|
||||
headerChildren.push(
|
||||
E(
|
||||
'span',
|
||||
{ class: 'tachyon_updates-page__component__header-version' },
|
||||
card.version,
|
||||
),
|
||||
];
|
||||
);
|
||||
if (card.repoUrl) {
|
||||
headerChildren.push(
|
||||
E(
|
||||
|
||||
@@ -571,6 +571,7 @@ export namespace Tachyon {
|
||||
running: number;
|
||||
enabled: number;
|
||||
status: string;
|
||||
memory_rss_mb?: number;
|
||||
}
|
||||
|
||||
export interface GetSystemInfo {
|
||||
@@ -654,6 +655,10 @@ export namespace Tachyon {
|
||||
service: {
|
||||
tachyon: GetStatus;
|
||||
sing_box: GetSingBoxStatus;
|
||||
zapret2?: {
|
||||
running: number;
|
||||
memory_rss_mb?: number;
|
||||
};
|
||||
};
|
||||
capabilities: GetUiCapabilities;
|
||||
actions: {
|
||||
|
||||
@@ -6261,23 +6261,72 @@ function formatSingBoxVersion(value) {
|
||||
variant = _("compressed");
|
||||
} else if (normalizedValue.sing_box_extended && normalizedValue.sing_box_lx) {
|
||||
variant = _("lx");
|
||||
} else if (normalizedValue.sing_box_extended) {
|
||||
variant = _("extended");
|
||||
} else if (normalizedValue.sing_box_tiny) {
|
||||
variant = _("tiny");
|
||||
}
|
||||
return variant ? `${version} (${variant})` : version;
|
||||
}
|
||||
function normalizeSingBoxVariantFields(value) {
|
||||
const versionExtended = isExtendedSingBoxVersion(value.sing_box_version);
|
||||
const version = String(value.sing_box_version || "");
|
||||
const versionExtended = isExtendedSingBoxVersion(version);
|
||||
const versionLx = version.includes("-lx");
|
||||
const singBoxExtended = Boolean(value.sing_box_extended) || versionExtended;
|
||||
const singBoxLx = singBoxExtended && (Boolean(value.sing_box_lx) || versionLx);
|
||||
return {
|
||||
...value,
|
||||
sing_box_extended: singBoxExtended ? 1 : 0,
|
||||
sing_box_tiny: singBoxExtended ? 0 : value.sing_box_tiny ? 1 : 0,
|
||||
sing_box_compressed: singBoxExtended && value.sing_box_compressed ? 1 : 0,
|
||||
sing_box_lx: singBoxExtended && value.sing_box_lx ? 1 : 0,
|
||||
sing_box_lx: singBoxLx ? 1 : 0,
|
||||
sing_box_tailscale: singBoxExtended || value.sing_box_tailscale ? 1 : 0
|
||||
};
|
||||
}
|
||||
function renderSingBoxVariantBadge(value) {
|
||||
const version = String(value.sing_box_version || "");
|
||||
if (!version || isVersionPlaceholder(version)) {
|
||||
return null;
|
||||
}
|
||||
const normalized = normalizeSingBoxVariantFields(value);
|
||||
const badge = document.createElement("span");
|
||||
badge.className = "tachyon-badge";
|
||||
badge.style.display = "inline-block";
|
||||
badge.style.marginLeft = "8px";
|
||||
badge.style.padding = "2px 8px";
|
||||
badge.style.borderRadius = "9999px";
|
||||
badge.style.fontSize = "11px";
|
||||
badge.style.fontWeight = "600";
|
||||
badge.style.lineHeight = "16px";
|
||||
badge.style.verticalAlign = "middle";
|
||||
if (normalized.sing_box_lx) {
|
||||
badge.textContent = "Leadaxe (lx)";
|
||||
badge.style.backgroundColor = "rgba(16, 185, 129, 0.15)";
|
||||
badge.style.color = "#10b981";
|
||||
badge.style.border = "1px solid rgba(16, 185, 129, 0.35)";
|
||||
} else if (normalized.sing_box_compressed) {
|
||||
badge.textContent = "Extended (compressed)";
|
||||
badge.style.backgroundColor = "rgba(59, 130, 246, 0.15)";
|
||||
badge.style.color = "#3b82f6";
|
||||
badge.style.border = "1px solid rgba(59, 130, 246, 0.35)";
|
||||
} else if (normalized.sing_box_extended) {
|
||||
badge.textContent = "Extended (shtorm-7)";
|
||||
badge.style.backgroundColor = "rgba(59, 130, 246, 0.15)";
|
||||
badge.style.color = "#3b82f6";
|
||||
badge.style.border = "1px solid rgba(59, 130, 246, 0.35)";
|
||||
} else if (normalized.sing_box_tiny) {
|
||||
badge.textContent = "Tiny";
|
||||
badge.style.backgroundColor = "rgba(245, 158, 11, 0.15)";
|
||||
badge.style.color = "#f59e0b";
|
||||
badge.style.border = "1px solid rgba(245, 158, 11, 0.35)";
|
||||
} else {
|
||||
badge.textContent = "Official";
|
||||
badge.style.backgroundColor = "rgba(107, 114, 128, 0.15)";
|
||||
badge.style.color = "#6b7280";
|
||||
badge.style.border = "1px solid rgba(107, 114, 128, 0.35)";
|
||||
}
|
||||
return badge;
|
||||
}
|
||||
|
||||
// src/tachyon/services/localActionOverlay.service.ts
|
||||
var componentActions = /* @__PURE__ */ new Set();
|
||||
@@ -6398,10 +6447,13 @@ function applyServiceState(uiState) {
|
||||
failed: false,
|
||||
data: {
|
||||
singbox: uiState.service.sing_box.running,
|
||||
singboxMemoryMb: uiState.service.sing_box.memory_rss_mb,
|
||||
tachyonRunning: uiState.service.tachyon.running,
|
||||
tachyonEnabled: uiState.service.tachyon.enabled,
|
||||
tachyonStatus: uiState.service.tachyon.status,
|
||||
watchdogRunning: store.get().servicesInfoWidget.data.watchdogRunning
|
||||
watchdogRunning: store.get().servicesInfoWidget.data.watchdogRunning,
|
||||
zapret2Running: uiState.service.zapret2 ? uiState.service.zapret2.running : void 0,
|
||||
zapret2MemoryMb: uiState.service.zapret2 ? uiState.service.zapret2.memory_rss_mb : void 0
|
||||
}
|
||||
},
|
||||
diagnosticsSystemInfo: normalizeSingBoxVariantFields(nextSystemInfo)
|
||||
@@ -7024,10 +7076,13 @@ async function fetchServicesInfo() {
|
||||
failed: !tachyon.success || !singbox.success,
|
||||
data: {
|
||||
singbox: singbox.success ? singbox.data.running : previousData.singbox,
|
||||
singboxMemoryMb: singbox.success ? singbox.data.memory_rss_mb : previousData.singboxMemoryMb,
|
||||
tachyonRunning: tachyon.success ? tachyon.data.running : previousData.tachyonRunning,
|
||||
tachyonEnabled: tachyon.success ? tachyon.data.enabled : previousData.tachyonEnabled,
|
||||
tachyonStatus: tachyon.success ? tachyon.data.status : previousData.tachyonStatus,
|
||||
watchdogRunning: watchdog.success ? Number(watchdog.data.running) : previousData.watchdogRunning
|
||||
watchdogRunning: watchdog.success ? Number(watchdog.data.running) : previousData.watchdogRunning,
|
||||
zapret2Running: previousData.zapret2Running,
|
||||
zapret2MemoryMb: previousData.zapret2MemoryMb
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -8537,22 +8592,34 @@ async function renderServicesInfoWidget() {
|
||||
"dashboard-widget-service-info",
|
||||
"servicesInfoWidget",
|
||||
_("Services info"),
|
||||
(data) => [
|
||||
{
|
||||
key: "Tachyon",
|
||||
value: data.tachyonRunning ? _("\u2714 Running") : _("\u2718 Stopped"),
|
||||
attributes: {
|
||||
class: data.tachyonRunning ? "tachyon_dashboard-page__widgets-section__item__row--success" : "tachyon_dashboard-page__widgets-section__item__row--error"
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "Sing-box",
|
||||
value: data.singbox ? _("\u2714 Running") : _("\u2718 Stopped"),
|
||||
attributes: {
|
||||
class: data.singbox ? "tachyon_dashboard-page__widgets-section__item__row--success" : "tachyon_dashboard-page__widgets-section__item__row--error"
|
||||
(data) => {
|
||||
const items = [
|
||||
{
|
||||
key: "Tachyon",
|
||||
value: data.tachyonRunning ? _("\u2714 Running") : _("\u2718 Stopped"),
|
||||
attributes: {
|
||||
class: data.tachyonRunning ? "tachyon_dashboard-page__widgets-section__item__row--success" : "tachyon_dashboard-page__widgets-section__item__row--error"
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "Sing-box",
|
||||
value: data.singbox ? data.singboxMemoryMb ? `${_("\u2714 Running")} (${data.singboxMemoryMb} MB)` : _("\u2714 Running") : _("\u2718 Stopped"),
|
||||
attributes: {
|
||||
class: data.singbox ? "tachyon_dashboard-page__widgets-section__item__row--success" : "tachyon_dashboard-page__widgets-section__item__row--error"
|
||||
}
|
||||
}
|
||||
];
|
||||
if (data.zapret2Running) {
|
||||
items.push({
|
||||
key: "Zapret2",
|
||||
value: data.zapret2MemoryMb ? `${_("\u2714 Running")} (${data.zapret2MemoryMb} MB)` : _("\u2714 Running"),
|
||||
attributes: {
|
||||
class: "tachyon_dashboard-page__widgets-section__item__row--success"
|
||||
}
|
||||
});
|
||||
}
|
||||
],
|
||||
return items;
|
||||
},
|
||||
"renderServicesInfoWidget"
|
||||
);
|
||||
}
|
||||
@@ -20142,6 +20209,7 @@ function getComponentCards() {
|
||||
column: 0,
|
||||
title: "Sing-box",
|
||||
version: systemInfoLoading ? _("Loading...") : formatSingBoxVersion(systemInfo),
|
||||
badgeNode: systemInfoLoading ? null : renderSingBoxVariantBadge(systemInfo),
|
||||
latestVersion: getLatestVersion("sing_box"),
|
||||
releaseUrl: getGitHubReleaseUrl("sing_box"),
|
||||
repoUrl: systemInfo.sing_box_repo_url || (singBoxLx ? "https://github.com/Leadaxe/sing-box-lx" : singBoxExtended || singBoxExtendedCompressed ? "https://github.com/shtorm-7/sing-box-extended" : COMPONENT_REPO_URLS.sing_box),
|
||||
@@ -20195,13 +20263,18 @@ function renderComponentCard(card) {
|
||||
const systemInfoLoading = isSystemInfoLoading();
|
||||
const checkResult = getVisibleCheckResult(card.component);
|
||||
const headerChildren = [
|
||||
E("b", { class: "tachyon_updates-page__component__title" }, card.title),
|
||||
E("b", { class: "tachyon_updates-page__component__title" }, card.title)
|
||||
];
|
||||
if (card.badgeNode) {
|
||||
headerChildren.push(card.badgeNode);
|
||||
}
|
||||
headerChildren.push(
|
||||
E(
|
||||
"span",
|
||||
{ class: "tachyon_updates-page__component__header-version" },
|
||||
card.version
|
||||
)
|
||||
];
|
||||
);
|
||||
if (card.repoUrl) {
|
||||
headerChildren.push(
|
||||
E(
|
||||
|
||||
@@ -839,7 +839,8 @@ function clear_version_caches() {
|
||||
}
|
||||
|
||||
function managed_sing_box_service_installed() {
|
||||
return file_exists("/etc/init.d/sing-box") && index(read_file("/etc/init.d/sing-box"), SB_MANAGED_SERVICE_MARKER) >= 0;
|
||||
let data = fs.readfile("/etc/init.d/sing-box");
|
||||
return data != null && index(as_string(data), SB_MANAGED_SERVICE_MARKER) >= 0 && index(as_string(data), "GOGC") >= 0;
|
||||
}
|
||||
|
||||
function managed_sing_box_service_text() {
|
||||
@@ -851,7 +852,7 @@ function managed_sing_box_service_text() {
|
||||
"start_service() {\n" +
|
||||
" config_load \"sing-box\"\n" +
|
||||
" local enabled config_file working_directory\n" +
|
||||
" local log_stderr\n\n" +
|
||||
" local log_stderr mem_total_kb mem_limit_mb gogc scale scale_pct\n\n" +
|
||||
" config_get_bool enabled \"main\" \"enabled\" \"0\"\n" +
|
||||
" [ \"$enabled\" -eq \"1\" ] || return 0\n\n" +
|
||||
" config_get config_file \"main\" \"conffile\" \"/etc/sing-box/config.json\"\n" +
|
||||
@@ -863,6 +864,34 @@ function managed_sing_box_service_text() {
|
||||
" procd_set_param stderr \"$log_stderr\"\n" +
|
||||
" procd_set_param limits core=\"unlimited\"\n" +
|
||||
" procd_set_param limits nofile=\"1000000 1000000\"\n" +
|
||||
" mem_total_kb=\"$(awk '/MemTotal/ {print $2}' /proc/meminfo 2>/dev/null || echo 0)\"\n" +
|
||||
" if [ \"$mem_total_kb\" -gt 0 ]; then\n" +
|
||||
" if [ \"$mem_total_kb\" -lt 131072 ]; then\n" +
|
||||
" mem_limit_mb=$(( mem_total_kb / 1024 * 30 / 100 ))\n" +
|
||||
" [ \"$mem_limit_mb\" -lt 16 ] && mem_limit_mb=16\n" +
|
||||
" gogc=20\n" +
|
||||
" elif [ \"$mem_total_kb\" -lt 262144 ]; then\n" +
|
||||
" mem_limit_mb=$(( mem_total_kb / 1024 * 35 / 100 ))\n" +
|
||||
" [ \"$mem_limit_mb\" -lt 24 ] && mem_limit_mb=24\n" +
|
||||
" gogc=25\n" +
|
||||
" elif [ \"$mem_total_kb\" -lt 524288 ]; then\n" +
|
||||
" mem_limit_mb=$(( mem_total_kb / 1024 * 40 / 100 ))\n" +
|
||||
" gogc=30\n" +
|
||||
" else\n" +
|
||||
" mem_limit_mb=$(( mem_total_kb / 1024 * 30 / 100 ))\n" +
|
||||
" [ \"$mem_limit_mb\" -gt 256 ] && mem_limit_mb=256\n" +
|
||||
" gogc=40\n" +
|
||||
" fi\n" +
|
||||
" if [ -r \"/etc/tachyon/mem_scale\" ]; then\n" +
|
||||
" scale=\"$(cat /etc/tachyon/mem_scale 2>/dev/null)\"\n" +
|
||||
" scale_pct=\"$(awk -v s=\"$scale\" 'BEGIN { pct=int(s*100); if (pct < 20) pct=20; if (pct > 100) pct=100; print pct }')\"\n" +
|
||||
" if [ -n \"$scale_pct\" ] && [ \"$scale_pct\" -lt 100 ]; then\n" +
|
||||
" mem_limit_mb=$(( mem_limit_mb * scale_pct / 100 ))\n" +
|
||||
" [ \"$mem_limit_mb\" -lt 12 ] && mem_limit_mb=12\n" +
|
||||
" fi\n" +
|
||||
" fi\n" +
|
||||
" procd_set_param env GOMEMLIMIT=\"${mem_limit_mb}MiB\" GOGC=\"$gogc\"\n" +
|
||||
" fi\n" +
|
||||
" procd_set_param term_timeout 15\n" +
|
||||
" procd_set_param respawn\n" +
|
||||
" procd_close_instance\n" +
|
||||
|
||||
@@ -2082,7 +2082,7 @@ function managed_sing_box_service_script(marker) {
|
||||
"start_service() {\n" +
|
||||
" config_load \"sing-box\"\n" +
|
||||
" local enabled config_file working_directory\n" +
|
||||
" local log_stderr\n" +
|
||||
" local log_stderr mem_total_kb mem_limit_mb gogc scale scale_pct\n" +
|
||||
"\n" +
|
||||
" config_get_bool enabled \"main\" \"enabled\" \"0\"\n" +
|
||||
" [ \"$enabled\" -eq \"1\" ] || return 0\n" +
|
||||
@@ -2097,6 +2097,34 @@ function managed_sing_box_service_script(marker) {
|
||||
" procd_set_param stderr \"$log_stderr\"\n" +
|
||||
" procd_set_param limits core=\"unlimited\"\n" +
|
||||
" procd_set_param limits nofile=\"1000000 1000000\"\n" +
|
||||
" mem_total_kb=\"$(awk '/MemTotal/ {print $2}' /proc/meminfo 2>/dev/null || echo 0)\"\n" +
|
||||
" if [ \"$mem_total_kb\" -gt 0 ]; then\n" +
|
||||
" if [ \"$mem_total_kb\" -lt 131072 ]; then\n" +
|
||||
" mem_limit_mb=$(( mem_total_kb / 1024 * 30 / 100 ))\n" +
|
||||
" [ \"$mem_limit_mb\" -lt 16 ] && mem_limit_mb=16\n" +
|
||||
" gogc=20\n" +
|
||||
" elif [ \"$mem_total_kb\" -lt 262144 ]; then\n" +
|
||||
" mem_limit_mb=$(( mem_total_kb / 1024 * 35 / 100 ))\n" +
|
||||
" [ \"$mem_limit_mb\" -lt 24 ] && mem_limit_mb=24\n" +
|
||||
" gogc=25\n" +
|
||||
" elif [ \"$mem_total_kb\" -lt 524288 ]; then\n" +
|
||||
" mem_limit_mb=$(( mem_total_kb / 1024 * 40 / 100 ))\n" +
|
||||
" gogc=30\n" +
|
||||
" else\n" +
|
||||
" mem_limit_mb=$(( mem_total_kb / 1024 * 30 / 100 ))\n" +
|
||||
" [ \"$mem_limit_mb\" -gt 256 ] && mem_limit_mb=256\n" +
|
||||
" gogc=40\n" +
|
||||
" fi\n" +
|
||||
" if [ -r \"/etc/tachyon/mem_scale\" ]; then\n" +
|
||||
" scale=\"$(cat /etc/tachyon/mem_scale 2>/dev/null)\"\n" +
|
||||
" scale_pct=\"$(awk -v s=\"$scale\" 'BEGIN { pct=int(s*100); if (pct < 20) pct=20; if (pct > 100) pct=100; print pct }')\"\n" +
|
||||
" if [ -n \"$scale_pct\" ] && [ \"$scale_pct\" -lt 100 ]; then\n" +
|
||||
" mem_limit_mb=$(( mem_limit_mb * scale_pct / 100 ))\n" +
|
||||
" [ \"$mem_limit_mb\" -lt 12 ] && mem_limit_mb=12\n" +
|
||||
" fi\n" +
|
||||
" fi\n" +
|
||||
" procd_set_param env GOMEMLIMIT=\"${mem_limit_mb}MiB\" GOGC=\"$gogc\"\n" +
|
||||
" fi\n" +
|
||||
" procd_set_param term_timeout 15\n" +
|
||||
" procd_set_param respawn\n" +
|
||||
" procd_close_instance\n" +
|
||||
|
||||
@@ -1959,11 +1959,13 @@ function ensure_bridge_netfilter_disabled() {
|
||||
|
||||
// TCP keepalive: detect dead connections in ~90s instead of kernel default (hours).
|
||||
// Conntrack: expire stale TCP entries in 10 min instead of 5 days.
|
||||
// Buffers & TCP fastopen: accelerate QUIC/Hysteria2 and reduce TLS handshake RTT.
|
||||
function apply_connection_tuning() {
|
||||
let sysctls = [
|
||||
[ "net.ipv4.tcp_keepalive_time", "60" ],
|
||||
[ "net.ipv4.tcp_keepalive_intvl", "10" ],
|
||||
[ "net.ipv4.tcp_keepalive_probes", "3" ],
|
||||
[ "net.ipv4.tcp_fastopen", "3" ],
|
||||
[ "net.netfilter.nf_conntrack_tcp_timeout_established", "600" ],
|
||||
[ "net.netfilter.nf_conntrack_tcp_timeout_time_wait", "30" ]
|
||||
];
|
||||
@@ -1974,8 +1976,21 @@ function apply_connection_tuning() {
|
||||
if (!run_args_quiet([ "sysctl", "-w", pair[0] + "=" + pair[1] ]))
|
||||
ok = false;
|
||||
}
|
||||
|
||||
let ct_max = int(trim(command_output_from_args([ "sysctl", "-n", "net.netfilter.nf_conntrack_max" ]) || "0"));
|
||||
if (ct_max > 0 && ct_max < 65536)
|
||||
run_args_quiet([ "sysctl", "-w", "net.netfilter.nf_conntrack_max=65536" ]);
|
||||
|
||||
let rmem_max = int(trim(command_output_from_args([ "sysctl", "-n", "net.core.rmem_max" ]) || "0"));
|
||||
if (rmem_max > 0 && rmem_max < 2621440)
|
||||
run_args_quiet([ "sysctl", "-w", "net.core.rmem_max=2621440" ]);
|
||||
|
||||
let wmem_max = int(trim(command_output_from_args([ "sysctl", "-n", "net.core.wmem_max" ]) || "0"));
|
||||
if (wmem_max > 0 && wmem_max < 2621440)
|
||||
run_args_quiet([ "sysctl", "-w", "net.core.wmem_max=2621440" ]);
|
||||
|
||||
if (ok)
|
||||
log_debug("Connection tuning applied: tcp_keepalive=60/10/3, conntrack_established=600");
|
||||
log_debug("Connection tuning applied: tcp_keepalive=60/10/3, tcp_fastopen=3, conntrack_established=600");
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,19 @@ function get_system_status() {
|
||||
let sb_running = command_success_from_args(["pidof", "sing-box"]);
|
||||
status_obj.singbox_running = sb_running;
|
||||
status_obj.singbox = sb_running ? "🟢 running" : "🔴 stopped";
|
||||
let sb_variant = trim(as_string(fs.readfile("/etc/tachyon/sing-box-variant") || ""));
|
||||
if (sb_variant != "")
|
||||
status_obj.singbox_variant = sb_variant;
|
||||
|
||||
// zapret2 status
|
||||
let z2_installed = fs.stat("/opt/zapret2/nfq2/nfqws2") != null;
|
||||
status_obj.zapret2_installed = z2_installed;
|
||||
if (z2_installed) {
|
||||
let z2_running = command_success_from_args(["pidof", "nfqws2"]);
|
||||
status_obj.zapret2_running = z2_running;
|
||||
status_obj.zapret2 = z2_running ? "🟢 running" : "🔴 stopped";
|
||||
}
|
||||
|
||||
status_obj.tachyon_running = command_success_from_args(["/etc/init.d/tachyon", "status"]);
|
||||
|
||||
// Active servers for all Selector groups
|
||||
|
||||
@@ -864,7 +864,8 @@ function view_status(token, chat_id, msg_id) {
|
||||
t("status_uptime") + ": <code>" + sys.uptime + "</code>\n" +
|
||||
t("status_cpu") + ": <code>" + sys.cpu + "</code>\n" +
|
||||
"RAM: <code>" + sys.ram_avail + "MB / " + sys.ram_total + "MB</code>\n\n" +
|
||||
"sing-box: <code>" + sys.singbox + "</code>\n" +
|
||||
"sing-box: <code>" + sys.singbox + (sys.singbox_variant ? " [" + sys.singbox_variant + "]" : "") + "</code>\n" +
|
||||
(sys.zapret2_installed ? "zapret2: <code>" + sys.zapret2 + "</code>\n" : "") +
|
||||
"Watchdog: <code>" + (sys.watchdog_running ? "🟢 running" : "🔴 stopped") + "</code>\n\n" +
|
||||
"WAN: <code>" + (sys.wan_ip || "?") + "</code> " +
|
||||
(conn && conn.direct ? "✅" : "❌") + "\n" +
|
||||
@@ -1754,9 +1755,12 @@ function view_system_info(token, chat_id, msg_id) {
|
||||
text += "🔧 Tachyon: <code>" + as_string(info.tachyon_version || "N/A") + "</code>\n";
|
||||
text += "📱 LuCI App: <code>" + as_string(info.luci_app_version || "N/A") + "</code>\n\n";
|
||||
text += "📦 sing-box: <code>" + as_string(info.sing_box_version || "N/A") + "</code>\n";
|
||||
if (info.sing_box_extended) text += " Extended: ✅\n";
|
||||
if (info.sing_box_tiny) text += " Tiny: ✅\n";
|
||||
if (info.sing_box_tailscale) text += " Tailscale: ✅\n";
|
||||
if (info.sing_box_lx == 1) text += " Fork: Leadaxe (lx) 🟢\n";
|
||||
else if (info.sing_box_compressed == 1) text += " Fork: Extended (compressed) 🔵\n";
|
||||
else if (info.sing_box_extended == 1) text += " Fork: Extended (shtorm-7) 🔵\n";
|
||||
else if (info.sing_box_tiny == 1) text += " Variant: Tiny 🟡\n";
|
||||
else text += " Variant: Official / Stock ⚪\n";
|
||||
if (info.sing_box_tailscale == 1) text += " Tailscale: ✅\n";
|
||||
text += "\n";
|
||||
if (info.zapret_installed == "1") text += "🛡 Zapret: <code>" + as_string(info.zapret_version || "?") + "</code>\n";
|
||||
if (info.zapret2_installed == "1") text += "🛡 Zapret2: <code>" + as_string(info.zapret2_version || "?") + "</code>\n";
|
||||
|
||||
@@ -1044,6 +1044,24 @@ function ui_capabilities_json() {
|
||||
write_json(capability_flags());
|
||||
}
|
||||
|
||||
function process_memory_rss_mb(process_name) {
|
||||
let output = common.command_output_from_args([ "pidof", process_name ]);
|
||||
let pids = split(trim(as_string(output)), /[ \t\r\n]+/);
|
||||
let total_kb = 0;
|
||||
for (let p in pids) {
|
||||
let pid = trim(as_string(p));
|
||||
if (!pid || match(pid, /^[0-9]+$/) == null)
|
||||
continue;
|
||||
let status = fs.readfile("/proc/" + pid + "/status");
|
||||
if (!status)
|
||||
continue;
|
||||
let m = match(status, /VmRSS:[ \t]+([0-9]+)/);
|
||||
if (m)
|
||||
total_kb += int(m[1]);
|
||||
}
|
||||
return total_kb > 0 ? int(total_kb / 1024) : 0;
|
||||
}
|
||||
|
||||
function current_ui_state_json() {
|
||||
refresh_action_dirs();
|
||||
|
||||
@@ -1065,6 +1083,9 @@ function current_ui_state_json() {
|
||||
else if (active_action == "reload")
|
||||
tachyon_status = "reloading";
|
||||
|
||||
let sing_box_rss = sing_box_is_running ? process_memory_rss_mb("sing-box") : 0;
|
||||
let zapret2_rss = file_executable(ZAPRET2_PROVIDER_NFQWS2_BIN) ? process_memory_rss_mb("nfqws2") : 0;
|
||||
|
||||
write_json({
|
||||
service: {
|
||||
tachyon: {
|
||||
@@ -1076,7 +1097,12 @@ function current_ui_state_json() {
|
||||
sing_box: {
|
||||
running: sing_box_is_running,
|
||||
enabled: sing_box_is_enabled,
|
||||
status: sing_box_status
|
||||
status: sing_box_status,
|
||||
memory_rss_mb: sing_box_rss
|
||||
},
|
||||
zapret2: {
|
||||
running: zapret2_rss > 0 ? 1 : 0,
|
||||
memory_rss_mb: zapret2_rss
|
||||
}
|
||||
},
|
||||
capabilities,
|
||||
|
||||
Reference in New Issue
Block a user