Files
the-nexus/server.ts

204 lines
6.4 KiB
TypeScript
Raw Normal View History

2026-03-30 16:07:31 +00:00
import express from 'express';
import { createServer as createViteServer } from 'vite';
import path from 'path';
import { fileURLToPath } from 'url';
import 'dotenv/config';
import { WebSocketServer, WebSocket } from 'ws';
import { createServer } from 'http';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Primary (Local) Gitea
const GITEA_URL = process.env.GITEA_URL || 'http://localhost:3000/api/v1';
const GITEA_TOKEN = process.env.GITEA_TOKEN || '';
// Backup (Remote) Gitea
const REMOTE_GITEA_URL = process.env.REMOTE_GITEA_URL || 'http://143.198.27.163:3000/api/v1';
const REMOTE_GITEA_TOKEN = process.env.REMOTE_GITEA_TOKEN || '';
async function startServer() {
const app = express();
const httpServer = createServer(app);
const PORT = 3000;
// WebSocket Server for Hermes/Evennia Bridge
const wss = new WebSocketServer({ noServer: true });
const clients = new Set<WebSocket>();
wss.on('connection', (ws) => {
clients.add(ws);
console.log(`Client connected to Nexus Bridge. Total: ${clients.size}`);
ws.on('close', () => {
clients.delete(ws);
console.log(`Client disconnected. Total: ${clients.size}`);
});
});
// Simulate Evennia Heartbeat (Source of Truth)
setInterval(() => {
const heartbeat = {
type: 'heartbeat',
frequency: 0.5 + Math.random() * 0.2, // 0.5Hz to 0.7Hz
intensity: 0.8 + Math.random() * 0.4,
timestamp: Date.now(),
source: 'evonia-layer'
};
const message = JSON.stringify(heartbeat);
clients.forEach(client => {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
});
}, 2000);
app.use(express.json({ limit: '50mb' }));
// Diagnostic Endpoint for Agent Inspection
app.get('/api/diagnostic/inspect', async (req, res) => {
console.log('Diagnostic request received');
try {
const REPO_OWNER = 'google';
const REPO_NAME = 'timmy-tower';
const [stateRes, issuesRes] = await Promise.all([
fetch(`${GITEA_URL}/repos/${REPO_OWNER}/${REPO_NAME}/contents/world_state.json`, {
headers: { 'Authorization': `token ${GITEA_TOKEN}` }
}),
fetch(`${GITEA_URL}/repos/${REPO_OWNER}/${REPO_NAME}/issues?state=all`, {
headers: { 'Authorization': `token ${GITEA_TOKEN}` }
})
]);
let worldState = null;
if (stateRes.ok) {
const content = await stateRes.json();
worldState = JSON.parse(Buffer.from(content.content, 'base64').toString());
} else if (stateRes.status !== 404) {
console.error(`Failed to fetch world state: ${stateRes.status} ${stateRes.statusText}`);
}
let issues = [];
if (issuesRes.ok) {
issues = await issuesRes.json();
} else {
console.error(`Failed to fetch issues: ${issuesRes.status} ${issuesRes.statusText}`);
}
res.json({
worldState,
issues,
repoExists: stateRes.status !== 404,
connected: GITEA_TOKEN !== ''
});
} catch (error: any) {
console.error('Diagnostic error:', error);
res.status(500).json({ error: error.message });
}
});
// Helper for Gitea Proxy
const createGiteaProxy = (baseUrl: string, token: string) => async (req: express.Request, res: express.Response) => {
const path = req.params[0] + (req.url.includes('?') ? req.url.slice(req.url.indexOf('?')) : '');
const url = `${baseUrl}/${path}`;
if (!token) {
console.warn(`Gitea Proxy Warning: No token provided for ${baseUrl}`);
}
try {
const response = await fetch(url, {
method: req.method,
headers: {
'Content-Type': 'application/json',
'Authorization': `token ${token}`,
},
body: ['GET', 'HEAD'].includes(req.method) ? undefined : JSON.stringify(req.body),
});
const data = await response.text();
res.status(response.status).send(data);
} catch (error: any) {
console.error(`Gitea Proxy Error (${baseUrl}):`, error);
res.status(500).json({ error: error.message });
}
};
// Gitea Proxy - Primary (Local)
app.get('/api/gitea/check', async (req, res) => {
try {
const response = await fetch(`${GITEA_URL}/user`, {
headers: { 'Authorization': `token ${GITEA_TOKEN}` }
});
if (response.ok) {
const user = await response.json();
res.json({ status: 'connected', user: user.username });
} else {
res.status(response.status).json({ status: 'error', message: `Gitea returned ${response.status}` });
}
} catch (error: any) {
res.status(500).json({ status: 'error', message: error.message });
}
});
app.all('/api/gitea/*', createGiteaProxy(GITEA_URL, GITEA_TOKEN));
// Gitea Proxy - Backup (Remote)
app.get('/api/gitea-remote/check', async (req, res) => {
try {
const response = await fetch(`${REMOTE_GITEA_URL}/user`, {
headers: { 'Authorization': `token ${REMOTE_GITEA_TOKEN}` }
});
if (response.ok) {
const user = await response.json();
res.json({ status: 'connected', user: user.username });
} else {
res.status(response.status).json({ status: 'error', message: `Gitea returned ${response.status}` });
}
} catch (error: any) {
res.status(500).json({ status: 'error', message: error.message });
}
});
app.all('/api/gitea-remote/*', createGiteaProxy(REMOTE_GITEA_URL, REMOTE_GITEA_TOKEN));
// WebSocket Upgrade Handler
httpServer.on('upgrade', (request, socket, head) => {
const pathname = new URL(request.url!, `http://${request.headers.host}`).pathname;
if (pathname === '/api/world/ws') {
wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request);
});
} else {
socket.destroy();
}
});
// Health Check
app.get('/api/health', (req, res) => {
res.json({ status: 'ok' });
});
// Vite middleware for development
if (process.env.NODE_ENV !== 'production') {
const vite = await createViteServer({
server: { middlewareMode: true },
appType: 'spa',
});
app.use(vite.middlewares);
} else {
const distPath = path.join(process.cwd(), 'dist');
app.use(express.static(distPath));
app.get('*', (req, res) => {
res.sendFile(path.join(distPath, 'index.html'));
});
}
httpServer.listen(PORT, '0.0.0.0', () => {
console.log(`Server running on http://localhost:${PORT}`);
});
}
startServer();