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",
|
"name": "fe-app-tachyon",
|
||||||
"version": "1.3.17",
|
"version": "1.3.18",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "fe-app-tachyon",
|
"name": "fe-app-tachyon",
|
||||||
"version": "1.3.17",
|
"version": "1.3.18",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@esbuild/win32-x64": "^0.28.2",
|
"@esbuild/win32-x64": "^0.28.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "fe-app-tachyon",
|
"name": "fe-app-tachyon",
|
||||||
"version": "1.3.17",
|
"version": "1.3.18",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ export async function fetchServicesInfo() {
|
|||||||
failed: !tachyon.success || !singbox.success,
|
failed: !tachyon.success || !singbox.success,
|
||||||
data: {
|
data: {
|
||||||
singbox: singbox.success ? singbox.data.running : previousData.singbox,
|
singbox: singbox.success ? singbox.data.running : previousData.singbox,
|
||||||
|
singboxMemoryMb: singbox.success
|
||||||
|
? singbox.data.memory_rss_mb
|
||||||
|
: previousData.singboxMemoryMb,
|
||||||
tachyonRunning: tachyon.success
|
tachyonRunning: tachyon.success
|
||||||
? tachyon.data.running
|
? tachyon.data.running
|
||||||
: previousData.tachyonRunning,
|
: previousData.tachyonRunning,
|
||||||
@@ -71,6 +74,8 @@ export async function fetchServicesInfo() {
|
|||||||
watchdogRunning: watchdog.success
|
watchdogRunning: watchdog.success
|
||||||
? Number((watchdog.data as { running: boolean }).running)
|
? Number((watchdog.data as { running: boolean }).running)
|
||||||
: previousData.watchdogRunning,
|
: previousData.watchdogRunning,
|
||||||
|
zapret2Running: previousData.zapret2Running,
|
||||||
|
zapret2MemoryMb: previousData.zapret2MemoryMb,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -56,6 +56,8 @@ export function formatSingBoxVersion(value: SingBoxVariantFields) {
|
|||||||
variant = _('compressed');
|
variant = _('compressed');
|
||||||
} else if (normalizedValue.sing_box_extended && normalizedValue.sing_box_lx) {
|
} else if (normalizedValue.sing_box_extended && normalizedValue.sing_box_lx) {
|
||||||
variant = _('lx');
|
variant = _('lx');
|
||||||
|
} else if (normalizedValue.sing_box_extended) {
|
||||||
|
variant = _('extended');
|
||||||
} else if (normalizedValue.sing_box_tiny) {
|
} else if (normalizedValue.sing_box_tiny) {
|
||||||
variant = _('tiny');
|
variant = _('tiny');
|
||||||
}
|
}
|
||||||
@@ -66,15 +68,69 @@ export function formatSingBoxVersion(value: SingBoxVariantFields) {
|
|||||||
export function normalizeSingBoxVariantFields<T extends SingBoxVariantFields>(
|
export function normalizeSingBoxVariantFields<T extends SingBoxVariantFields>(
|
||||||
value: T,
|
value: T,
|
||||||
): 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 singBoxExtended = Boolean(value.sing_box_extended) || versionExtended;
|
||||||
|
const singBoxLx =
|
||||||
|
singBoxExtended && (Boolean(value.sing_box_lx) || versionLx);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...value,
|
...value,
|
||||||
sing_box_extended: singBoxExtended ? 1 : 0,
|
sing_box_extended: singBoxExtended ? 1 : 0,
|
||||||
sing_box_tiny: singBoxExtended ? 0 : value.sing_box_tiny ? 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_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,
|
sing_box_tailscale: singBoxExtended || value.sing_box_tailscale ? 1 : 0,
|
||||||
} as T;
|
} 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;
|
tachyonEnabled: number;
|
||||||
tachyonStatus: string;
|
tachyonStatus: string;
|
||||||
watchdogRunning: number;
|
watchdogRunning: number;
|
||||||
|
singboxMemoryMb?: number;
|
||||||
|
zapret2Running?: number;
|
||||||
|
zapret2MemoryMb?: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
tailscaleWidget: {
|
tailscaleWidget: {
|
||||||
|
|||||||
@@ -100,10 +100,17 @@ function applyServiceState(uiState: Tachyon.UiState) {
|
|||||||
failed: false,
|
failed: false,
|
||||||
data: {
|
data: {
|
||||||
singbox: uiState.service.sing_box.running,
|
singbox: uiState.service.sing_box.running,
|
||||||
|
singboxMemoryMb: uiState.service.sing_box.memory_rss_mb,
|
||||||
tachyonRunning: uiState.service.tachyon.running,
|
tachyonRunning: uiState.service.tachyon.running,
|
||||||
tachyonEnabled: uiState.service.tachyon.enabled,
|
tachyonEnabled: uiState.service.tachyon.enabled,
|
||||||
tachyonStatus: uiState.service.tachyon.status,
|
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
|
||||||
|
: undefined,
|
||||||
|
zapret2MemoryMb: uiState.service.zapret2
|
||||||
|
? uiState.service.zapret2.memory_rss_mb
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
diagnosticsSystemInfo: normalizeSingBoxVariantFields(nextSystemInfo),
|
diagnosticsSystemInfo: normalizeSingBoxVariantFields(nextSystemInfo),
|
||||||
|
|||||||
@@ -1885,26 +1885,47 @@ async function renderServicesInfoWidget() {
|
|||||||
'dashboard-widget-service-info',
|
'dashboard-widget-service-info',
|
||||||
'servicesInfoWidget',
|
'servicesInfoWidget',
|
||||||
_('Services info'),
|
_('Services info'),
|
||||||
(data) => [
|
(data) => {
|
||||||
{
|
const items = [
|
||||||
key: 'Tachyon',
|
{
|
||||||
value: data.tachyonRunning ? _('✔ Running') : _('✘ Stopped'),
|
key: 'Tachyon',
|
||||||
attributes: {
|
value: data.tachyonRunning ? _('✔ Running') : _('✘ Stopped'),
|
||||||
class: data.tachyonRunning
|
attributes: {
|
||||||
? 'tachyon_dashboard-page__widgets-section__item__row--success'
|
class: data.tachyonRunning
|
||||||
: 'tachyon_dashboard-page__widgets-section__item__row--error',
|
? 'tachyon_dashboard-page__widgets-section__item__row--success'
|
||||||
|
: 'tachyon_dashboard-page__widgets-section__item__row--error',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
{
|
||||||
{
|
key: 'Sing-box',
|
||||||
key: 'Sing-box',
|
value: data.singbox
|
||||||
value: data.singbox ? _('✔ Running') : _('✘ Stopped'),
|
? data.singboxMemoryMb
|
||||||
attributes: {
|
? `${_('✔ Running')} (${data.singboxMemoryMb} MB)`
|
||||||
class: data.singbox
|
: _('✔ Running')
|
||||||
? 'tachyon_dashboard-page__widgets-section__item__row--success'
|
: _('✘ Stopped'),
|
||||||
: 'tachyon_dashboard-page__widgets-section__item__row--error',
|
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',
|
'renderServicesInfoWidget',
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import { shouldShowLoadingForRestoredAction } from '../../helpers/restoredAction
|
|||||||
import {
|
import {
|
||||||
formatSingBoxVersion,
|
formatSingBoxVersion,
|
||||||
normalizeSingBoxVariantFields,
|
normalizeSingBoxVariantFields,
|
||||||
|
renderSingBoxVariantBadge,
|
||||||
} from '../../helpers/singBoxVariant';
|
} from '../../helpers/singBoxVariant';
|
||||||
import { shouldApplyCompletedComponentActionResult } from './componentActionCompletion';
|
import { shouldApplyCompletedComponentActionResult } from './componentActionCompletion';
|
||||||
import {
|
import {
|
||||||
@@ -115,6 +116,7 @@ interface ComponentCard {
|
|||||||
releaseUrl?: string;
|
releaseUrl?: string;
|
||||||
repoUrl?: string;
|
repoUrl?: string;
|
||||||
actions: ComponentActionButton[];
|
actions: ComponentActionButton[];
|
||||||
|
badgeNode?: Node | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let updatesLifecycleRegistered = false;
|
let updatesLifecycleRegistered = false;
|
||||||
@@ -1271,6 +1273,9 @@ function getComponentCards(): ComponentCard[] {
|
|||||||
version: systemInfoLoading
|
version: systemInfoLoading
|
||||||
? _('Loading...')
|
? _('Loading...')
|
||||||
: formatSingBoxVersion(systemInfo),
|
: formatSingBoxVersion(systemInfo),
|
||||||
|
badgeNode: systemInfoLoading
|
||||||
|
? null
|
||||||
|
: renderSingBoxVariantBadge(systemInfo),
|
||||||
latestVersion: getLatestVersion('sing_box'),
|
latestVersion: getLatestVersion('sing_box'),
|
||||||
releaseUrl: getGitHubReleaseUrl('sing_box'),
|
releaseUrl: getGitHubReleaseUrl('sing_box'),
|
||||||
repoUrl:
|
repoUrl:
|
||||||
@@ -1350,12 +1355,17 @@ function renderComponentCard(card: ComponentCard) {
|
|||||||
|
|
||||||
const headerChildren: Node[] = [
|
const headerChildren: Node[] = [
|
||||||
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(
|
E(
|
||||||
'span',
|
'span',
|
||||||
{ class: 'tachyon_updates-page__component__header-version' },
|
{ class: 'tachyon_updates-page__component__header-version' },
|
||||||
card.version,
|
card.version,
|
||||||
),
|
),
|
||||||
];
|
);
|
||||||
if (card.repoUrl) {
|
if (card.repoUrl) {
|
||||||
headerChildren.push(
|
headerChildren.push(
|
||||||
E(
|
E(
|
||||||
|
|||||||
@@ -571,6 +571,7 @@ export namespace Tachyon {
|
|||||||
running: number;
|
running: number;
|
||||||
enabled: number;
|
enabled: number;
|
||||||
status: string;
|
status: string;
|
||||||
|
memory_rss_mb?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GetSystemInfo {
|
export interface GetSystemInfo {
|
||||||
@@ -654,6 +655,10 @@ export namespace Tachyon {
|
|||||||
service: {
|
service: {
|
||||||
tachyon: GetStatus;
|
tachyon: GetStatus;
|
||||||
sing_box: GetSingBoxStatus;
|
sing_box: GetSingBoxStatus;
|
||||||
|
zapret2?: {
|
||||||
|
running: number;
|
||||||
|
memory_rss_mb?: number;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
capabilities: GetUiCapabilities;
|
capabilities: GetUiCapabilities;
|
||||||
actions: {
|
actions: {
|
||||||
|
|||||||
@@ -6261,23 +6261,72 @@ function formatSingBoxVersion(value) {
|
|||||||
variant = _("compressed");
|
variant = _("compressed");
|
||||||
} else if (normalizedValue.sing_box_extended && normalizedValue.sing_box_lx) {
|
} else if (normalizedValue.sing_box_extended && normalizedValue.sing_box_lx) {
|
||||||
variant = _("lx");
|
variant = _("lx");
|
||||||
|
} else if (normalizedValue.sing_box_extended) {
|
||||||
|
variant = _("extended");
|
||||||
} else if (normalizedValue.sing_box_tiny) {
|
} else if (normalizedValue.sing_box_tiny) {
|
||||||
variant = _("tiny");
|
variant = _("tiny");
|
||||||
}
|
}
|
||||||
return variant ? `${version} (${variant})` : version;
|
return variant ? `${version} (${variant})` : version;
|
||||||
}
|
}
|
||||||
function normalizeSingBoxVariantFields(value) {
|
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 singBoxExtended = Boolean(value.sing_box_extended) || versionExtended;
|
||||||
|
const singBoxLx = singBoxExtended && (Boolean(value.sing_box_lx) || versionLx);
|
||||||
return {
|
return {
|
||||||
...value,
|
...value,
|
||||||
sing_box_extended: singBoxExtended ? 1 : 0,
|
sing_box_extended: singBoxExtended ? 1 : 0,
|
||||||
sing_box_tiny: singBoxExtended ? 0 : value.sing_box_tiny ? 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_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
|
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
|
// src/tachyon/services/localActionOverlay.service.ts
|
||||||
var componentActions = /* @__PURE__ */ new Set();
|
var componentActions = /* @__PURE__ */ new Set();
|
||||||
@@ -6398,10 +6447,13 @@ function applyServiceState(uiState) {
|
|||||||
failed: false,
|
failed: false,
|
||||||
data: {
|
data: {
|
||||||
singbox: uiState.service.sing_box.running,
|
singbox: uiState.service.sing_box.running,
|
||||||
|
singboxMemoryMb: uiState.service.sing_box.memory_rss_mb,
|
||||||
tachyonRunning: uiState.service.tachyon.running,
|
tachyonRunning: uiState.service.tachyon.running,
|
||||||
tachyonEnabled: uiState.service.tachyon.enabled,
|
tachyonEnabled: uiState.service.tachyon.enabled,
|
||||||
tachyonStatus: uiState.service.tachyon.status,
|
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)
|
diagnosticsSystemInfo: normalizeSingBoxVariantFields(nextSystemInfo)
|
||||||
@@ -7024,10 +7076,13 @@ async function fetchServicesInfo() {
|
|||||||
failed: !tachyon.success || !singbox.success,
|
failed: !tachyon.success || !singbox.success,
|
||||||
data: {
|
data: {
|
||||||
singbox: singbox.success ? singbox.data.running : previousData.singbox,
|
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,
|
tachyonRunning: tachyon.success ? tachyon.data.running : previousData.tachyonRunning,
|
||||||
tachyonEnabled: tachyon.success ? tachyon.data.enabled : previousData.tachyonEnabled,
|
tachyonEnabled: tachyon.success ? tachyon.data.enabled : previousData.tachyonEnabled,
|
||||||
tachyonStatus: tachyon.success ? tachyon.data.status : previousData.tachyonStatus,
|
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",
|
"dashboard-widget-service-info",
|
||||||
"servicesInfoWidget",
|
"servicesInfoWidget",
|
||||||
_("Services info"),
|
_("Services info"),
|
||||||
(data) => [
|
(data) => {
|
||||||
{
|
const items = [
|
||||||
key: "Tachyon",
|
{
|
||||||
value: data.tachyonRunning ? _("\u2714 Running") : _("\u2718 Stopped"),
|
key: "Tachyon",
|
||||||
attributes: {
|
value: data.tachyonRunning ? _("\u2714 Running") : _("\u2718 Stopped"),
|
||||||
class: data.tachyonRunning ? "tachyon_dashboard-page__widgets-section__item__row--success" : "tachyon_dashboard-page__widgets-section__item__row--error"
|
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"),
|
key: "Sing-box",
|
||||||
attributes: {
|
value: data.singbox ? data.singboxMemoryMb ? `${_("\u2714 Running")} (${data.singboxMemoryMb} MB)` : _("\u2714 Running") : _("\u2718 Stopped"),
|
||||||
class: data.singbox ? "tachyon_dashboard-page__widgets-section__item__row--success" : "tachyon_dashboard-page__widgets-section__item__row--error"
|
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"
|
"renderServicesInfoWidget"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -20142,6 +20209,7 @@ function getComponentCards() {
|
|||||||
column: 0,
|
column: 0,
|
||||||
title: "Sing-box",
|
title: "Sing-box",
|
||||||
version: systemInfoLoading ? _("Loading...") : formatSingBoxVersion(systemInfo),
|
version: systemInfoLoading ? _("Loading...") : formatSingBoxVersion(systemInfo),
|
||||||
|
badgeNode: systemInfoLoading ? null : renderSingBoxVariantBadge(systemInfo),
|
||||||
latestVersion: getLatestVersion("sing_box"),
|
latestVersion: getLatestVersion("sing_box"),
|
||||||
releaseUrl: getGitHubReleaseUrl("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),
|
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 systemInfoLoading = isSystemInfoLoading();
|
||||||
const checkResult = getVisibleCheckResult(card.component);
|
const checkResult = getVisibleCheckResult(card.component);
|
||||||
const headerChildren = [
|
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(
|
E(
|
||||||
"span",
|
"span",
|
||||||
{ class: "tachyon_updates-page__component__header-version" },
|
{ class: "tachyon_updates-page__component__header-version" },
|
||||||
card.version
|
card.version
|
||||||
)
|
)
|
||||||
];
|
);
|
||||||
if (card.repoUrl) {
|
if (card.repoUrl) {
|
||||||
headerChildren.push(
|
headerChildren.push(
|
||||||
E(
|
E(
|
||||||
|
|||||||
@@ -839,7 +839,8 @@ function clear_version_caches() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function managed_sing_box_service_installed() {
|
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() {
|
function managed_sing_box_service_text() {
|
||||||
@@ -851,7 +852,7 @@ function managed_sing_box_service_text() {
|
|||||||
"start_service() {\n" +
|
"start_service() {\n" +
|
||||||
" config_load \"sing-box\"\n" +
|
" config_load \"sing-box\"\n" +
|
||||||
" local enabled config_file working_directory\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" +
|
" config_get_bool enabled \"main\" \"enabled\" \"0\"\n" +
|
||||||
" [ \"$enabled\" -eq \"1\" ] || return 0\n\n" +
|
" [ \"$enabled\" -eq \"1\" ] || return 0\n\n" +
|
||||||
" config_get config_file \"main\" \"conffile\" \"/etc/sing-box/config.json\"\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 stderr \"$log_stderr\"\n" +
|
||||||
" procd_set_param limits core=\"unlimited\"\n" +
|
" procd_set_param limits core=\"unlimited\"\n" +
|
||||||
" procd_set_param limits nofile=\"1000000 1000000\"\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 term_timeout 15\n" +
|
||||||
" procd_set_param respawn\n" +
|
" procd_set_param respawn\n" +
|
||||||
" procd_close_instance\n" +
|
" procd_close_instance\n" +
|
||||||
|
|||||||
@@ -2082,7 +2082,7 @@ function managed_sing_box_service_script(marker) {
|
|||||||
"start_service() {\n" +
|
"start_service() {\n" +
|
||||||
" config_load \"sing-box\"\n" +
|
" config_load \"sing-box\"\n" +
|
||||||
" local enabled config_file working_directory\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" +
|
"\n" +
|
||||||
" config_get_bool enabled \"main\" \"enabled\" \"0\"\n" +
|
" config_get_bool enabled \"main\" \"enabled\" \"0\"\n" +
|
||||||
" [ \"$enabled\" -eq \"1\" ] || return 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 stderr \"$log_stderr\"\n" +
|
||||||
" procd_set_param limits core=\"unlimited\"\n" +
|
" procd_set_param limits core=\"unlimited\"\n" +
|
||||||
" procd_set_param limits nofile=\"1000000 1000000\"\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 term_timeout 15\n" +
|
||||||
" procd_set_param respawn\n" +
|
" procd_set_param respawn\n" +
|
||||||
" procd_close_instance\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).
|
// TCP keepalive: detect dead connections in ~90s instead of kernel default (hours).
|
||||||
// Conntrack: expire stale TCP entries in 10 min instead of 5 days.
|
// 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() {
|
function apply_connection_tuning() {
|
||||||
let sysctls = [
|
let sysctls = [
|
||||||
[ "net.ipv4.tcp_keepalive_time", "60" ],
|
[ "net.ipv4.tcp_keepalive_time", "60" ],
|
||||||
[ "net.ipv4.tcp_keepalive_intvl", "10" ],
|
[ "net.ipv4.tcp_keepalive_intvl", "10" ],
|
||||||
[ "net.ipv4.tcp_keepalive_probes", "3" ],
|
[ "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_established", "600" ],
|
||||||
[ "net.netfilter.nf_conntrack_tcp_timeout_time_wait", "30" ]
|
[ "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] ]))
|
if (!run_args_quiet([ "sysctl", "-w", pair[0] + "=" + pair[1] ]))
|
||||||
ok = false;
|
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)
|
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;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,19 @@ function get_system_status() {
|
|||||||
let sb_running = command_success_from_args(["pidof", "sing-box"]);
|
let sb_running = command_success_from_args(["pidof", "sing-box"]);
|
||||||
status_obj.singbox_running = sb_running;
|
status_obj.singbox_running = sb_running;
|
||||||
status_obj.singbox = sb_running ? "🟢 running" : "🔴 stopped";
|
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"]);
|
status_obj.tachyon_running = command_success_from_args(["/etc/init.d/tachyon", "status"]);
|
||||||
|
|
||||||
// Active servers for all Selector groups
|
// 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_uptime") + ": <code>" + sys.uptime + "</code>\n" +
|
||||||
t("status_cpu") + ": <code>" + sys.cpu + "</code>\n" +
|
t("status_cpu") + ": <code>" + sys.cpu + "</code>\n" +
|
||||||
"RAM: <code>" + sys.ram_avail + "MB / " + sys.ram_total + "MB</code>\n\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" +
|
"Watchdog: <code>" + (sys.watchdog_running ? "🟢 running" : "🔴 stopped") + "</code>\n\n" +
|
||||||
"WAN: <code>" + (sys.wan_ip || "?") + "</code> " +
|
"WAN: <code>" + (sys.wan_ip || "?") + "</code> " +
|
||||||
(conn && conn.direct ? "✅" : "❌") + "\n" +
|
(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 += "🔧 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 += "📱 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";
|
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_lx == 1) text += " Fork: Leadaxe (lx) 🟢\n";
|
||||||
if (info.sing_box_tiny) text += " Tiny: ✅\n";
|
else if (info.sing_box_compressed == 1) text += " Fork: Extended (compressed) 🔵\n";
|
||||||
if (info.sing_box_tailscale) text += " Tailscale: ✅\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";
|
text += "\n";
|
||||||
if (info.zapret_installed == "1") text += "🛡 Zapret: <code>" + as_string(info.zapret_version || "?") + "</code>\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";
|
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());
|
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() {
|
function current_ui_state_json() {
|
||||||
refresh_action_dirs();
|
refresh_action_dirs();
|
||||||
|
|
||||||
@@ -1065,6 +1083,9 @@ function current_ui_state_json() {
|
|||||||
else if (active_action == "reload")
|
else if (active_action == "reload")
|
||||||
tachyon_status = "reloading";
|
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({
|
write_json({
|
||||||
service: {
|
service: {
|
||||||
tachyon: {
|
tachyon: {
|
||||||
@@ -1076,7 +1097,12 @@ function current_ui_state_json() {
|
|||||||
sing_box: {
|
sing_box: {
|
||||||
running: sing_box_is_running,
|
running: sing_box_is_running,
|
||||||
enabled: sing_box_is_enabled,
|
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,
|
capabilities,
|
||||||
|
|||||||
Reference in New Issue
Block a user