unrip/src/core/control-api.mjs
philipp 41b9ec680b
Some checks failed
deploy / deploy (push) Failing after 1m35s
Implement funded NEAR Intents trade loop
Proof: first non-mocked tradeable loop for one pair using funded NEAR Intents inventory, Kafka, and PostgreSQL.

Assumptions: solver-side execution is performed by signed token_diff quote responses over the Solver Relay; EURe is treated as 1:1 with EUR; k3s runtime uses unrip-dev.near as the named signer account.

Still fake: signer key is not yet registered on intents.near, strategy and executor remain disarmed by default, and no live mainnet quote response has been submitted from this repo yet.
2026-04-02 10:01:15 +02:00

121 lines
2.7 KiB
JavaScript

import http from 'node:http';
export function startControlApi({
host = '0.0.0.0',
port = 8081,
logger = null,
service = 'service',
namespace = 'unrip',
stateProvider = null,
healthProvider = null,
routes = [],
} = {}) {
const routeMap = new Map(routes.map((route) => [`${route.method} ${route.path}`, route]));
const server = http.createServer(async (req, res) => {
try {
if (req.method === 'GET' && req.url === '/healthz') {
return sendJson(res, 200, {
ok: true,
service,
namespace,
...(await healthProvider?.getHealth?.()),
});
}
if (req.method === 'GET' && req.url === '/state') {
return sendJson(res, 200, {
service,
namespace,
...(await stateProvider?.getState?.()),
});
}
const route = routeMap.get(`${req.method} ${req.url}`);
if (!route) {
return sendJson(res, 404, {
error: 'not_found',
});
}
const body = route.readBody === false ? null : await readJsonBody(req);
const result = await route.handler({
req,
res,
body: body || {},
});
if (result == null) return;
if (result.statusCode != null) {
return sendJson(res, result.statusCode, result.payload ?? {});
}
return sendJson(res, 200, result);
} catch (error) {
logger?.error('control_api_request_failed', {
details: {
method: req.method,
path: req.url,
error: error.message,
},
});
return sendJson(res, 500, {
error: error.message,
});
}
});
server.listen(port, host, () => {
logger?.info('control_api_started', {
details: {
host,
port,
},
});
});
return {
close() {
return new Promise((resolve, reject) => {
server.close((error) => {
if (error) reject(error);
else resolve();
});
});
},
};
}
export function sendJson(res, statusCode, payload) {
const body = JSON.stringify(payload, null, 2);
res.statusCode = statusCode;
res.setHeader('content-type', 'application/json; charset=utf-8');
res.end(`${body}\n`);
}
export function readJsonBody(req) {
return new Promise((resolve, reject) => {
let raw = '';
req.on('data', (chunk) => {
raw += chunk;
if (raw.length > 64 * 1024) {
reject(new Error('request body too large'));
}
});
req.on('end', () => {
if (!raw.trim()) {
resolve({});
return;
}
try {
resolve(JSON.parse(raw));
} catch {
reject(new Error('invalid_json'));
}
});
req.on('error', reject);
});
}