-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
146 lines (129 loc) · 4.48 KB
/
Copy pathserver.js
File metadata and controls
146 lines (129 loc) · 4.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
const net = require('net');
const http = require('http');
const fs = require('fs');
const path = require('path');
const RESPParser = require('./parser');
const { handleCommand } = require('./commands');
const store = require('./store');
// Stats
const stats = {
startTime: Date.now(),
commandsProcessed: 0,
connections: 0
};
// --- TCP Server ---
const tcpServer = net.createServer((socket) => {
stats.connections++;
const parser = new RESPParser();
socket.on('data', (data) => {
parser.append(data);
for (const command of parser.parse()) {
stats.commandsProcessed++;
const result = handleCommand(command);
const resp = encodeRESP(result);
socket.write(resp);
}
});
socket.on('error', (err) => {
console.error('Socket error:', err);
});
socket.on('close', () => {
stats.connections--;
});
});
function encodeRESP(data) {
if (data === null) {
return '$-1\r\n';
} else if (data instanceof Error) {
return `-${data.message}\r\n`;
} else if (typeof data === 'string') {
if (data === 'OK' || data === 'PONG') {
return `+${data}\r\n`;
}
return `$${Buffer.byteLength(data)}\r\n${data}\r\n`;
} else if (typeof data === 'number') {
return `:${data}\r\n`;
} else if (Array.isArray(data)) {
let resp = `*${data.length}\r\n`;
for(const item of data) {
resp += encodeRESP(item);
}
return resp;
}
return '-ERR internal error\r\n';
}
const TCP_PORT = 6379;
tcpServer.listen(TCP_PORT, () => {
console.log(`Mini Redis TCP server running on port ${TCP_PORT}`);
});
// --- HTTP Server ---
const httpServer = http.createServer((req, res) => {
if (req.method === 'GET' && req.url === '/stats') {
const uptime = Math.floor((Date.now() - stats.startTime) / 1000);
const data = {
uptime,
commandsProcessed: stats.commandsProcessed,
connections: stats.connections,
keyCount: store.data.size,
memory: process.memoryUsage().rss
};
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(data));
return;
}
if (req.method === 'GET') {
let filePath = path.join(__dirname, 'public', req.url === '/' ? 'index.html' : req.url);
const extname = path.extname(filePath);
let contentType = 'text/html';
switch (extname) {
case '.js': contentType = 'text/javascript'; break;
case '.css': contentType = 'text/css'; break;
}
fs.readFile(filePath, (err, content) => {
if (err) {
if(err.code == 'ENOENT') {
res.writeHead(404);
res.end('404 Not Found');
} else {
res.writeHead(500);
res.end('500 Internal Server Error');
}
} else {
res.writeHead(200, { 'Content-Type': contentType });
res.end(content, 'utf-8');
}
});
} else if (req.method === 'POST' && req.url === '/cmd') {
let body = '';
req.on('data', chunk => { body += chunk.toString(); });
req.on('end', () => {
try {
stats.commandsProcessed++;
const { command } = JSON.parse(body);
// Naive command parsing: split by spaces, preserving quotes could be added later
const args = command.trim().split(/\s+/);
// Helper to handle simple quoted strings if needed,
// but for now simple split is fine for basic commands.
const result = handleCommand(args);
// Convert Error to simple object for JSON
if (result instanceof Error) {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: result.message }));
} else {
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ result }));
}
} catch (e) {
res.writeHead(400);
res.end(JSON.stringify({ error: 'Invalid request' }));
}
});
} else {
res.writeHead(404);
res.end();
}
});
const HTTP_PORT = 8080;
httpServer.listen(HTTP_PORT, () => {
console.log(`Mini Redis Web Interface running at http://localhost:${HTTP_PORT}`);
});