Blame Raw
· · · 101 lines (3.2 KB)
0 contributors
1import http from 'node:http';
2import { readAllChunks, tryParse } from '../../src/util.js';
3
4export class MockServer {
5 /** @type {string} */
6 host;
7 /** @type {number} */
8 port;
9 /** @type {import('http').Server} */
10 server;
11
12 /**
13 * Creates an instance of MockServer.
14 * @param {object} [param] Options object.
15 * @param {string} [param.host] The hostname or IP address to bind the server to.
16 * @param {number} [param.port] The port number to listen on.
17 */
18 constructor({ host, port } = {}) {
19 this.host = host ?? '127.0.0.1';
20 this.port = port ?? 3000;
21 }
22
23 /**
24 * Handles Chat Completions requests.
25 * @param {object} jsonBody The parsed JSON body from the request.
26 * @returns {object} Mock response object.
27 */
28 handleChatCompletions(jsonBody) {
29 const messages = jsonBody?.messages;
30 const lastMessage = messages?.[messages.length - 1];
31 const mockResponse = {
32 choices: [
33 {
34 finish_reason: 'stop',
35 index: 0,
36 message: {
37 role: 'assistant',
38 reasoning_content: `${jsonBody?.model}\n${messages?.length}\n${jsonBody?.max_tokens}`,
39 content: String(lastMessage?.content ?? 'No prompt messages.'),
40 },
41 },
42 ],
43 created: 0,
44 model: jsonBody?.model,
45 };
46 return mockResponse;
47 }
48
49 /**
50 * Starts the mock server.
51 * @returns {Promise<void>}
52 */
53 async start() {
54 return new Promise((resolve, reject) => {
55 this.server = http.createServer(async (req, res) => {
56 try {
57 const body = await readAllChunks(req);
58 const jsonBody = tryParse(body.toString());
59 if (req.method === 'POST' && req.url === '/v1/chat/completions') {
60 const mockResponse = this.handleChatCompletions(jsonBody);
61 res.writeHead(200, { 'Content-Type': 'application/json' });
62 res.end(JSON.stringify(mockResponse));
63 } else {
64 res.writeHead(404);
65 res.end();
66 }
67 } catch (error) {
68 res.writeHead(500);
69 res.end();
70 }
71 });
72
73 this.server.on('error', (err) => {
74 reject(err);
75 });
76
77 this.server.listen(this.port, this.host, () => {
78 resolve();
79 });
80 });
81 }
82
83 /**
84 * Stops the mock server.
85 * @returns {Promise<void>}
86 */
87 async stop() {
88 return new Promise((resolve, reject) => {
89 if (!this.server) {
90 return reject(new Error('Server is not running.'));
91 }
92 this.server.closeAllConnections();
93 this.server.close(( /** @type {NodeJS.ErrnoException|undefined} */ err) => {
94 if (err && (err?.code !== 'ERR_SERVER_NOT_RUNNING')) {
95 return reject(err);
96 }
97 resolve();
98 });
99 });
100 }
101}