118 lines
3.6 KiB
TypeScript
118 lines
3.6 KiB
TypeScript
import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
|
|
|
|
interface RibPrefixQuery {
|
|
prefix?: string;
|
|
router?: string;
|
|
}
|
|
|
|
interface RibDumpQuery {
|
|
router?: string;
|
|
asn?: string;
|
|
limit?: string;
|
|
}
|
|
|
|
// risClient is injected from outside; lazy import avoids circular deps at startup
|
|
let risClient: any = null;
|
|
|
|
export function setRisClient(client: any): void {
|
|
risClient = client;
|
|
}
|
|
|
|
export async function ribRoutes(fastify: FastifyInstance): Promise<void> {
|
|
// GET /api/rib/prefix
|
|
fastify.get<{ Querystring: RibPrefixQuery }>(
|
|
'/rib/prefix',
|
|
async (request: FastifyRequest<{ Querystring: RibPrefixQuery }>, reply: FastifyReply) => {
|
|
reply.header('Access-Control-Allow-Origin', '*');
|
|
reply.header('Cache-Control', 'no-store');
|
|
|
|
if (!risClient) {
|
|
return reply.status(503).send({ error: 'bio-rd RIS not configured' });
|
|
}
|
|
|
|
const prefix = request.query.prefix || '';
|
|
const routerParam = request.query.router || 'default';
|
|
|
|
if (!prefix) {
|
|
return reply.status(400).send({ error: 'prefix required' });
|
|
}
|
|
|
|
try {
|
|
const t0 = Date.now();
|
|
const routers = await risClient.getRouters();
|
|
const routerName = (routerParam === 'default' && routers.length > 0) ? routers[0] : routerParam;
|
|
const [routes, longer] = await Promise.all([
|
|
risClient.lpm(routerName, prefix),
|
|
risClient.getLonger(routerName, prefix),
|
|
]);
|
|
return reply.status(200).send({
|
|
prefix,
|
|
router: routerName,
|
|
routes: routes || [],
|
|
moreSpecifics: (longer || []).slice(0, 20),
|
|
source: 'bio-rd-local',
|
|
latencyMs: Date.now() - t0,
|
|
});
|
|
} catch (e: any) {
|
|
return reply.status(500).send({ error: e.message });
|
|
}
|
|
}
|
|
);
|
|
|
|
// GET /api/rib/routers
|
|
fastify.get(
|
|
'/rib/routers',
|
|
async (_request: FastifyRequest, reply: FastifyReply) => {
|
|
reply.header('Access-Control-Allow-Origin', '*');
|
|
reply.header('Cache-Control', 'no-store');
|
|
|
|
if (!risClient) {
|
|
return reply.status(503).send({ error: 'bio-rd RIS not configured' });
|
|
}
|
|
|
|
try {
|
|
const routers = await risClient.getRouters();
|
|
return reply.status(200).send({ routers: routers || [], source: 'bio-rd-local' });
|
|
} catch (e: any) {
|
|
return reply.status(500).send({ error: e.message });
|
|
}
|
|
}
|
|
);
|
|
|
|
// GET /api/rib/dump
|
|
fastify.get<{ Querystring: RibDumpQuery }>(
|
|
'/rib/dump',
|
|
async (request: FastifyRequest<{ Querystring: RibDumpQuery }>, reply: FastifyReply) => {
|
|
reply.header('Access-Control-Allow-Origin', '*');
|
|
reply.header('Cache-Control', 'no-store');
|
|
|
|
if (!risClient) {
|
|
return reply.status(503).send({ error: 'bio-rd RIS not configured' });
|
|
}
|
|
|
|
const router = request.query.router || '';
|
|
const asnFilter = request.query.asn ? parseInt(request.query.asn, 10) : undefined;
|
|
const limit = Math.min(parseInt(request.query.limit || '100', 10), 1000);
|
|
|
|
if (!router) {
|
|
return reply.status(400).send({ error: 'router required' });
|
|
}
|
|
|
|
try {
|
|
const t0 = Date.now();
|
|
const allRoutes = await risClient.dumpRib(router, 'default', asnFilter);
|
|
const routes = (allRoutes || []).slice(0, limit);
|
|
return reply.status(200).send({
|
|
router,
|
|
routes,
|
|
total: (allRoutes || []).length,
|
|
source: 'bio-rd-local',
|
|
latencyMs: Date.now() - t0,
|
|
});
|
|
} catch (e: any) {
|
|
return reply.status(500).send({ error: e.message });
|
|
}
|
|
}
|
|
);
|
|
}
|