Files
harbor-net/src/server/dataplaneClient.js
T
dokril 560c243047
Build and Deploy Gateway / build-and-push (push) Successful in 10s
Build and Deploy Gateway / deploy (push) Successful in 16s
Add per-device VPN and direct routing policies
2026-08-07 16:18:31 +03:00

65 lines
2.2 KiB
JavaScript

import http from 'node:http';
import { HarborError } from '../shared/errors.js';
function request(socketPath, pathname, method = 'GET', body = null) {
return new Promise((resolve, reject) => {
const encoded = body == null ? null : JSON.stringify(body);
const req = http.request({
socketPath,
path: pathname,
method,
headers: encoded ? {
'content-type': 'application/json',
'content-length': Buffer.byteLength(encoded),
} : {},
}, (res) => {
const chunks = [];
res.on('data', (chunk) => chunks.push(chunk));
res.on('end', () => {
let body = {};
try {
body = JSON.parse(Buffer.concat(chunks).toString('utf8') || '{}');
} catch {
return reject(new Error('Dataplane вернул невалидный JSON'));
}
if ((res.statusCode || 500) >= 400) {
return reject(new Error(body.error || `Dataplane HTTP ${res.statusCode}`));
}
resolve(body);
});
});
req.on('error', reject);
req.setTimeout(6000, () => req.destroy(new Error('Dataplane не ответил за 6 секунд')));
req.end(encoded);
});
}
export function createDataplaneClient(socketPath, send = request) {
let current = { running: false, startedAt: null };
const update = async (pathname, method) => {
try {
current = await send(socketPath, pathname, method);
return current;
} catch (cause) {
if (pathname === '/apply' || pathname === '/restart') {
throw new HarborError('PROCESS_START_FAILED', { cause });
}
throw cause;
}
};
return {
get running() { return Boolean(current.running); },
get startedAt() { return current.startedAt || null; },
refresh: () => update('/status', 'GET'),
observeDevices: () => send(socketPath, '/devices', 'GET'),
observeTraffic: () => send(socketPath, '/device-traffic', 'GET'),
observeDevicePolicy: () => send(socketPath, '/device-policy', 'GET'),
applyDevicePolicies: (devices) => send(socketPath, '/device-policy', 'PUT', { devices }),
apply: () => update('/apply', 'POST'),
restart: () => update('/restart', 'POST'),
stop: () => update('/stop', 'POST'),
shutdown: async () => current,
};
}