feat: add unified API proxy layer, debug endpoint, and systemd service for node-guardian
This commit is contained in:
16
apps/web/src/app/api/_debug/api-config/route.ts
Normal file
16
apps/web/src/app/api/_debug/api-config/route.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import { NextResponse } from 'next/server';
|
||||||
|
import { getApiConfig } from '@/lib/apiProxy';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Debug endpoint to check API configuration
|
||||||
|
* GET /api/_debug/api-config
|
||||||
|
*/
|
||||||
|
export async function GET() {
|
||||||
|
const config = getApiConfig();
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
...config,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
111
apps/web/src/lib/apiProxy.ts
Normal file
111
apps/web/src/lib/apiProxy.ts
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
/**
|
||||||
|
* Unified API Proxy Layer for DAARION.city
|
||||||
|
*
|
||||||
|
* Provides consistent access to backend services:
|
||||||
|
* - city-service (main API)
|
||||||
|
* - dagi-router (AI routing)
|
||||||
|
* - swapper-service (model management)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Environment configuration
|
||||||
|
const CITY_API_BASE_URL = process.env.INTERNAL_API_URL || process.env.CITY_SERVICE_URL || 'http://daarion-city-service:7001';
|
||||||
|
const DAGI_ROUTER_API_URL = process.env.DAGI_ROUTER_API_URL || 'http://dagi-router:9102';
|
||||||
|
const SWAPPER_API_BASE_URL = process.env.SWAPPER_API_BASE_URL || 'http://swapper-service:8890';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get API configuration (for debugging)
|
||||||
|
*/
|
||||||
|
export function getApiConfig() {
|
||||||
|
return {
|
||||||
|
CITY_API_BASE_URL,
|
||||||
|
DAGI_ROUTER_API_URL,
|
||||||
|
SWAPPER_API_BASE_URL,
|
||||||
|
NODE_ENV: process.env.NODE_ENV,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy request to city-service
|
||||||
|
*/
|
||||||
|
export async function proxyCity(
|
||||||
|
path: string,
|
||||||
|
init: RequestInit = {}
|
||||||
|
): Promise<Response> {
|
||||||
|
const url = `${CITY_API_BASE_URL}${path.startsWith('/') ? path : `/${path}`}`;
|
||||||
|
|
||||||
|
console.log(`[proxyCity] ${init.method || 'GET'} ${url}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
...init,
|
||||||
|
headers: {
|
||||||
|
...init.headers,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`[proxyCity] Response: ${response.status}`);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[proxyCity] Error:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy request to dagi-router
|
||||||
|
*/
|
||||||
|
export async function proxyRouter(
|
||||||
|
path: string,
|
||||||
|
init: RequestInit = {}
|
||||||
|
): Promise<Response> {
|
||||||
|
const url = `${DAGI_ROUTER_API_URL}${path.startsWith('/') ? path : `/${path}`}`;
|
||||||
|
|
||||||
|
console.log(`[proxyRouter] ${init.method || 'GET'} ${url}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, init);
|
||||||
|
console.log(`[proxyRouter] Response: ${response.status}`);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[proxyRouter] Error:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Proxy request to swapper-service
|
||||||
|
*/
|
||||||
|
export async function proxySwapper(
|
||||||
|
path: string,
|
||||||
|
init: RequestInit = {}
|
||||||
|
): Promise<Response> {
|
||||||
|
const url = `${SWAPPER_API_BASE_URL}${path.startsWith('/') ? path : `/${path}`}`;
|
||||||
|
|
||||||
|
console.log(`[proxySwapper] ${init.method || 'GET'} ${url}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, init);
|
||||||
|
console.log(`[proxySwapper] Response: ${response.status}`);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[proxySwapper] Error:`, error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to safely parse JSON response
|
||||||
|
*/
|
||||||
|
export async function safeJsonParse<T>(response: Response, fallback: T): Promise<T> {
|
||||||
|
try {
|
||||||
|
if (!response.ok) {
|
||||||
|
console.warn(`[safeJsonParse] Non-OK response: ${response.status}`);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
return await response.json();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[safeJsonParse] Error parsing JSON:`, error);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
23
scripts/node-guardian.service
Normal file
23
scripts/node-guardian.service
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=DAARION Node Guardian Loop
|
||||||
|
After=network.target docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=/opt/microdao-daarion
|
||||||
|
ExecStart=/usr/bin/python3 /opt/microdao-daarion/scripts/node-guardian-loop.py --node-id=node-1-hetzner-gex44
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
Environment=CITY_API_URL=http://localhost:7001
|
||||||
|
Environment=SWAPPER_URL=http://localhost:8890
|
||||||
|
Environment=PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
SyslogIdentifier=node-guardian
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
|
||||||
Reference in New Issue
Block a user