import http from 'node:http'; import { HarborError } from '../shared/errors.js'; function request(socketPath, pathname, method = 'GET') { return new Promise((resolve, reject) => { const req = http.request({ socketPath, path: pathname, method }, (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(); }); } 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'), apply: () => update('/apply', 'POST'), restart: () => update('/restart', 'POST'), stop: () => update('/stop', 'POST'), shutdown: async () => current, }; }