mirror of
https://github.com/larsbaunwall/vscode-copilot-bridge.git
synced 2025-10-05 22:22:59 +00:00
refactor(extension): extract config/state/logging/models/messages/http modules (SRP)
Co-Authored-By: Lars Baunwall <larslb@thinkability.dk>
This commit is contained in:
parent
f4e6b390e3
commit
c8afe9ee17
16 changed files with 634 additions and 623 deletions
78
src/http/server.ts
Normal file
78
src/http/server.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
const polka = require('polka');
|
||||
import type { Server } from 'http';
|
||||
import { getBridgeConfig } from '../config';
|
||||
import { state } from '../state';
|
||||
import { isAuthorized } from './auth';
|
||||
import { handleHealthCheck } from './routes/health';
|
||||
import { handleModelsRequest } from './routes/models';
|
||||
import { handleChatCompletion } from './routes/chat';
|
||||
import { writeErrorResponse } from './utils';
|
||||
import { ensureOutput, verbose } from '../log';
|
||||
import { updateStatusAfterStart } from '../status';
|
||||
|
||||
export const startServer = async (): Promise<void> => {
|
||||
if (state.server) return;
|
||||
const config = getBridgeConfig();
|
||||
ensureOutput();
|
||||
|
||||
const app = polka();
|
||||
|
||||
app.use((req: any, res: any, next: any) => {
|
||||
verbose(`HTTP ${req.method} ${req.url}`);
|
||||
if (!isAuthorized(req, config.token)) {
|
||||
writeErrorResponse(res, 401, 'unauthorized', 'invalid_request_error', 'unauthorized');
|
||||
return;
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/healthz', async (_req: any, res: any) => {
|
||||
await handleHealthCheck(res, config.verbose);
|
||||
});
|
||||
|
||||
app.get('/v1/models', async (_req: any, res: any) => {
|
||||
await handleModelsRequest(res);
|
||||
});
|
||||
|
||||
app.post('/v1/chat/completions', async (req: any, res: any) => {
|
||||
if (state.activeRequests >= config.maxConcurrent) {
|
||||
res.writeHead(429, { 'Content-Type': 'application/json', 'Retry-After': '1' });
|
||||
res.end(JSON.stringify({
|
||||
error: {
|
||||
message: 'too many requests',
|
||||
type: 'rate_limit_error',
|
||||
code: 'rate_limit_exceeded',
|
||||
},
|
||||
}));
|
||||
verbose(`429 throttled (active=${state.activeRequests}, max=${config.maxConcurrent})`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await handleChatCompletion(req, res);
|
||||
} catch (e: any) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
writeErrorResponse(res, 500, msg || 'internal_error', 'server_error', 'internal_error');
|
||||
}
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const srv: Server = app.listen(config.port, config.host, (err?: any) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
state.server = srv;
|
||||
updateStatusAfterStart();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
srv.on('error', reject);
|
||||
});
|
||||
};
|
||||
|
||||
export const stopServer = async (): Promise<void> => {
|
||||
await new Promise<void>((resolve) => {
|
||||
if (!state.server) return resolve();
|
||||
state.server.close(() => resolve());
|
||||
});
|
||||
state.server = undefined;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue