Update Harbor client and gateway integration workflows
Build and Deploy Gateway / build-and-push (push) Failing after 14s
Build and Deploy Gateway / deploy (push) Has been skipped

This commit is contained in:
2026-08-19 18:16:10 +03:00
parent 416b2b294a
commit daec12e013
63 changed files with 5016 additions and 108 deletions
@@ -0,0 +1,66 @@
import http from 'node:http';
import {
FAILOVER_PRIMARY_TAG,
FAILOVER_RESERVE_TAG,
FAILOVER_SELECTOR_TAG,
} from '../singbox.js';
type Role = 'primary' | 'reserve';
function request(port: number, method: string, body?: unknown): Promise<unknown> {
return new Promise((resolve, reject) => {
const encoded = body === undefined ? null : JSON.stringify(body);
const req = http.request({
host: '127.0.0.1',
port,
path: `/proxies/${encodeURIComponent(FAILOVER_SELECTOR_TAG)}`,
method,
headers: encoded ? {
'content-type': 'application/json',
'content-length': Buffer.byteLength(encoded),
} : {},
}, (res) => {
const chunks: Buffer[] = [];
res.on('data', (chunk: Buffer) => chunks.push(chunk));
res.on('end', () => {
if ((res.statusCode || 500) >= 400) return reject(new Error(`Sing-box selector HTTP ${res.statusCode}`));
if (!chunks.length) return resolve({});
try {
resolve(JSON.parse(Buffer.concat(chunks).toString('utf8')));
} catch (cause) {
reject(new Error('Sing-box selector вернул невалидный JSON', { cause }));
}
});
});
req.setTimeout(2_000, () => req.destroy(new Error('Sing-box selector timeout')));
req.on('error', reject);
req.end(encoded);
});
}
const tagFor = (role: Role) => role === 'primary' ? FAILOVER_PRIMARY_TAG : FAILOVER_RESERVE_TAG;
const roleFor = (tag: unknown): Role | null => (
tag === FAILOVER_PRIMARY_TAG ? 'primary' : tag === FAILOVER_RESERVE_TAG ? 'reserve' : null
);
export function createSingboxSelectorService({
port,
send = (method: string, body?: unknown) => request(port, method, body),
}: {
port: number;
send?: (method: string, body?: unknown) => Promise<unknown>;
}) {
async function read() {
const value = await send('GET') as Record<string, unknown>;
const role = roleFor(value.now);
if (!role) throw new Error('Sing-box selector вернул неизвестный outbound');
return { role };
}
async function select(role: Role) {
await send('PUT', { name: tagFor(role) });
const selected = await read();
if (selected.role !== role) throw new Error('Sing-box selector не подтвердил переключение');
return selected;
}
return { read, select };
}