Track applied route rules separately from pending edits
This commit is contained in:
@@ -380,16 +380,14 @@ async function applySelectedServer(selectedTag, { persist = true } = {}) {
|
||||
else restoreSingboxConfig(previousConfig);
|
||||
throw error;
|
||||
}
|
||||
if (persist || stateStore.read().routeRulesPendingRestart) {
|
||||
updateStoredState((state) => ({
|
||||
...state,
|
||||
...(persist ? {
|
||||
appliedTag: selectedTag,
|
||||
appliedAt: new Date().toISOString(),
|
||||
} : {}),
|
||||
routeRulesPendingRestart: false,
|
||||
}));
|
||||
}
|
||||
updateStoredState((state) => ({
|
||||
...state,
|
||||
...(persist ? {
|
||||
appliedTag: selectedTag,
|
||||
appliedAt: new Date().toISOString(),
|
||||
} : {}),
|
||||
appliedRouteRules: state.routeRules,
|
||||
}));
|
||||
}
|
||||
|
||||
async function applyRouteRules(routeRules) {
|
||||
@@ -399,7 +397,7 @@ async function applyRouteRules(routeRules) {
|
||||
updateStoredState((current) => ({
|
||||
...current,
|
||||
routeRules,
|
||||
routeRulesPendingRestart: true,
|
||||
routeRulesRevision: current.routeRulesRevision + 1,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
@@ -414,7 +412,8 @@ async function applyRouteRules(routeRules) {
|
||||
updateStoredState((current) => ({
|
||||
...current,
|
||||
routeRules,
|
||||
routeRulesPendingRestart: !wasRunning,
|
||||
...(wasRunning ? { appliedRouteRules: routeRules } : {}),
|
||||
routeRulesRevision: current.routeRulesRevision + 1,
|
||||
}));
|
||||
} catch (error) {
|
||||
if (previousConfig === null) removeSingboxConfig();
|
||||
@@ -611,19 +610,23 @@ async function handleApi(req, res) {
|
||||
}
|
||||
|
||||
if (req.method === 'PUT' && req.url === '/api/route-rules') {
|
||||
const { rules, expectedRevision } = await readBody(req);
|
||||
const { rules, expectedRulesRevision, expectedRevision } = await readBody(req);
|
||||
let routeRules;
|
||||
try {
|
||||
routeRules = normalizeRouteRules(rules, { strict: true });
|
||||
} catch (cause) {
|
||||
throw new HarborError('REQUEST_INVALID', { cause });
|
||||
}
|
||||
if (!Number.isSafeInteger(expectedRevision) || expectedRevision < 0) {
|
||||
const rulesRevision = expectedRulesRevision ?? expectedRevision;
|
||||
if (!Number.isSafeInteger(rulesRevision) || rulesRevision < 0) {
|
||||
throw new HarborError('REQUEST_INVALID');
|
||||
}
|
||||
await serializeControl(async () => {
|
||||
const current = normalizeStoredState(stateStore.read());
|
||||
if (current.revision !== expectedRevision) throw new HarborError('STATE_CONFLICT');
|
||||
const currentRevision = expectedRulesRevision == null
|
||||
? current.revision
|
||||
: current.routeRulesRevision;
|
||||
if (currentRevision !== rulesRevision) throw new HarborError('STATE_CONFLICT');
|
||||
if (isDeepStrictEqual(current.routeRules, routeRules)) return;
|
||||
await withOperation('route-rules', () => applyRouteRules(routeRules));
|
||||
});
|
||||
@@ -667,7 +670,7 @@ async function handleApi(req, res) {
|
||||
...state,
|
||||
appliedTag: state.selectedTag,
|
||||
connectionDesired: 'running',
|
||||
routeRulesPendingRestart: false,
|
||||
appliedRouteRules: state.routeRules,
|
||||
}));
|
||||
}));
|
||||
return sendState(res, { singboxRunning: true });
|
||||
@@ -727,8 +730,8 @@ if (settings.appMode === 'client' || !fs.existsSync(settings.configPath)) {
|
||||
}
|
||||
await startSingbox()
|
||||
.then(() => {
|
||||
if (fs.existsSync(settings.configPath) && stateStore.read().routeRulesPendingRestart) {
|
||||
updateStoredState((state) => ({ ...state, routeRulesPendingRestart: false }));
|
||||
if (fs.existsSync(settings.configPath)) {
|
||||
updateStoredState((state) => ({ ...state, appliedRouteRules: state.routeRules }));
|
||||
}
|
||||
})
|
||||
.catch((error) => console.warn(`[control] sing-box не запущен: ${error.message}`));
|
||||
|
||||
Reference in New Issue
Block a user