Refactor VPN proxy client implementation
Build and Deploy Gateway / build-and-push (push) Failing after 2s
Build and Deploy Gateway / deploy (push) Has been skipped

This commit is contained in:
2026-08-09 00:41:52 +03:00
parent 32be4380a3
commit 34d8b681ad
190 changed files with 20064 additions and 9761 deletions
@@ -0,0 +1,119 @@
import { isDeepStrictEqual } from 'node:util';
import type { RouteRule, StoredState } from '../../../shared/contracts/state.js';
import { HarborError } from '../../../shared/errors.js';
import { normalizeRouteRules } from '../../../shared/routingRules.js';
import type { RuntimeCommandResult } from '../connection/index.js';
import { finishRollback } from '../../services/rollback.js';
interface RouteRulesDependencies {
state: {
read(): StoredState;
update(mutator: (state: StoredState) => Record<string, unknown>): StoredState;
};
subscription: { readConfig(): unknown | null };
config: {
build(subscriptionConfig: unknown, selectedServerId: string, routeRules: RouteRule[]): unknown;
read(): string | null;
write(value: unknown): void;
restore(value: string): void;
remove(): void;
};
runtime: {
isRunning(): Promise<boolean>;
applyCommand(): Promise<RuntimeCommandResult>;
restoreRunning(): Promise<unknown>;
};
serialize<T>(operation: () => Promise<T>): Promise<T>;
runOperation<T>(operation: () => Promise<T>): Promise<T>;
}
export function createRouteRulesService(dependencies: RouteRulesDependencies) {
const applyRules = async (previousState: StoredState, routeRules: RouteRule[]) => {
const subscriptionConfig = dependencies.subscription.readConfig();
if (!previousState.selectedServerId || !subscriptionConfig) {
let stateCommitStarted = false;
try {
stateCommitStarted = true;
dependencies.state.update((state) => ({
...state,
routeRules,
routeRulesRevision: state.routeRulesRevision + 1,
}));
} catch (error) {
await finishRollback(error, [
...(stateCommitStarted ? [{ run: () => dependencies.state.update(() => previousState) }] : []),
], 'Route rules rollback failed');
}
return;
}
const candidateConfig = dependencies.config.build(
subscriptionConfig,
previousState.selectedServerId,
routeRules,
);
const previousConfig = dependencies.config.read();
const wasRunning = await dependencies.runtime.isRunning();
let configMutationStarted = false;
let runtimeMutationStarted = false;
let stateCommitStarted = false;
try {
configMutationStarted = true;
dependencies.config.write(candidateConfig);
if (wasRunning) {
const command = await dependencies.runtime.applyCommand();
runtimeMutationStarted = command.mutationStarted;
if (!command.ok) throw command.error;
}
stateCommitStarted = true;
dependencies.state.update((state) => ({
...state,
routeRules,
...(wasRunning ? { appliedRouteRules: routeRules } : {}),
routeRulesRevision: state.routeRulesRevision + 1,
}));
} catch (error) {
await finishRollback(error, [
...(configMutationStarted ? [{
run: () => previousConfig === null
? dependencies.config.remove()
: dependencies.config.restore(previousConfig),
}] : []),
...(wasRunning && runtimeMutationStarted ? [{
run: () => dependencies.runtime.restoreRunning(),
runtime: true,
}] : []),
...(stateCommitStarted ? [{ run: () => dependencies.state.update(() => previousState) }] : []),
], 'Route rules rollback failed');
}
};
const update = (rules: unknown, expectedRulesRevision: unknown, expectedRevision: unknown) => {
let routeRules: RouteRule[];
try {
routeRules = normalizeRouteRules(rules, { strict: true }) as RouteRule[];
} catch (cause) {
throw new HarborError('REQUEST_INVALID', { cause });
}
const rulesRevision = expectedRulesRevision ?? expectedRevision;
if (!Number.isSafeInteger(rulesRevision) || Number(rulesRevision) < 0) {
throw new HarborError('REQUEST_INVALID');
}
return dependencies.serialize(async () => {
const current = dependencies.state.read();
const currentRevision = expectedRulesRevision == null
? current.revision
: current.routeRulesRevision;
if (currentRevision !== rulesRevision) throw new HarborError('STATE_CONFLICT');
if (isDeepStrictEqual(current.routeRules, routeRules)) return;
await dependencies.runOperation(() => applyRules(current, routeRules));
});
};
return { update };
}
export type RouteRulesService = ReturnType<typeof createRouteRulesService>;