Preserve VLESS WebSocket variants during subscription refresh
Build and Deploy Gateway / build-and-push (push) Successful in 18s
Build and Deploy Gateway / deploy (push) Successful in 13s

This commit is contained in:
2026-08-09 12:42:05 +03:00
parent 90433d7cd8
commit f40221969b
7 changed files with 198 additions and 21 deletions
+42 -13
View File
@@ -545,12 +545,43 @@ function buildActiveConfig(
const stopSingbox = () => singboxRuntime.stop();
const startSingbox = () => singboxRuntime.apply();
function writeCurrentConfig() {
const state = stateStore.read();
function writeCurrentConfig(onlyIfSelectionChanged = false) {
const state = normalizeStoredState(stateStore.read());
const cached = readSubscriptionCache();
if (!state.selectedServerId || !cached?.config) return false;
writeSingboxConfig(buildActiveConfig(cached.config, state.selectedServerId));
return true;
const cachedServers = cached.servers as StoredState['servers'];
const selectedServerId = selectRefreshedServer(
state.selectedServerId,
state.servers,
cachedServers,
);
if (onlyIfSelectionChanged && selectedServerId === state.selectedServerId) return false;
const activeConfig = selectedServerId
? buildActiveConfig(cached.config, selectedServerId)
: null;
const previousConfig = fs.existsSync(settings.configPath)
? fs.readFileSync(settings.configPath, 'utf8')
: null;
try {
if (activeConfig) writeSingboxConfig(activeConfig);
else removeSingboxConfig();
updateStoredState((current) => ({
...current,
servers: cachedServers,
selectedServerId,
appliedServerId: selectedServerId,
...(!selectedServerId ? { connectionDesired: 'stopped' } : {}),
}));
} catch (error) {
try {
if (previousConfig === null) removeSingboxConfig();
else restoreSingboxConfig(previousConfig);
} catch (rollbackError) {
throw new AggregateError([error, rollbackError], 'Current config rollback failed');
}
throw error;
}
return Boolean(selectedServerId);
}
async function handleApi(req: IncomingMessage, res: ServerResponse) {
@@ -623,15 +654,13 @@ process.on('SIGINT', shutdown);
await gatewayAutoService.refresh({ reconfigure: false })
.catch((error: unknown) => console.warn(`[control] Gateway не определён: ${errorMessage(error)}`));
if (settings.appMode === 'client' || !fs.existsSync(settings.configPath)) {
try {
writeCurrentConfig();
} catch (error) {
const candidate = record(error);
if (!String(candidate.code || '').startsWith('SUBSCRIPTION_')) throw error;
console.warn(`[storage] сохранённая подписка отклонена: ${errorMessage(error)}; возврат к первичной настройке`);
await subscriptionService.resetSavedSubscription({ stopRuntime: false });
}
try {
writeCurrentConfig(settings.appMode !== 'client' && fs.existsSync(settings.configPath));
} catch (error) {
const candidate = record(error);
if (!String(candidate.code || '').startsWith('SUBSCRIPTION_')) throw error;
console.warn(`[storage] сохранённая подписка отклонена: ${errorMessage(error)}; возврат к первичной настройке`);
await subscriptionService.resetSavedSubscription({ stopRuntime: false });
}
await startSingbox()
.then(() => {