-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
144 lines (124 loc) · 4.63 KB
/
server.js
File metadata and controls
144 lines (124 loc) · 4.63 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
const fs = require('fs');
const fsp = require('fs').promises; // Using the promises-based API
const http = require('http');
const path = require('path');
const WebSocket = require('ws');
const LOG_FILE_PATH = path.resolve(__dirname, './test.log');
const PORT = 8080;
const INITIAL_LINES = 15;
const LOG_GENERATION_INTERVAL = 1900; // Generate a new log every 3 seconds
//! http server
const server = http.createServer((req, res) => {
const clientHtmlPath = path.resolve(__dirname, 'index.html');
fs.readFile(clientHtmlPath, (err, data) => {
if (err) {
console.error('Error loading index.html:', err);
res.writeHead(500);
res.end('Error loading index.html');
return;
}
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(data);
});
});
//! client side server
const wss = new WebSocket.Server({ server });
const clients = new Set();
wss.on('connection', async (ws) => {
console.log('Client connected');
clients.add(ws);
try {
const lines = await readLastNLines(LOG_FILE_PATH, INITIAL_LINES);
ws.send(lines.join('\n') + '\n');
} catch (err) {
console.error(`Error reading initial lines from ${LOG_FILE_PATH}:`, err.message);
ws.send(`--- Error: Could not read log file. Ensure '${LOG_FILE_PATH}' exists. ---`);
}
ws.on('close', () => {
console.log('Client disconnected');
clients.delete(ws);
});
});
function broadcast(message) {
for (const client of clients) {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
}
}
//! readLines function
async function readLastNLines(filePath, n) {
let filehandle;
try {
filehandle = await fsp.open(filePath, 'r');
const { size } = await filehandle.stat();
let position = size;
let buffer = Buffer.alloc(1024 * 8);
let lines = [];
let lineCount = 0;
while (position > 0 && lineCount <= n) {
const readLength = Math.min(position, buffer.length);
position -= readLength;
const { bytesRead } = await filehandle.read(buffer, 0, readLength, position);
const chunk = buffer.toString('utf8', 0, bytesRead);
const chunkLines = chunk.split('\n');
lines = chunkLines.concat(lines);
lineCount += chunkLines.length - 1;
}
const finalLines = lines.filter(line => line.length > 0);
return finalLines.slice(-n);
} finally {
if (filehandle) await filehandle.close();
}
}
//! file tracker
if (!fs.existsSync(LOG_FILE_PATH)) {
console.warn(`Warning: Log file not found at ${LOG_FILE_PATH}.`);
}
let lastKnownSize = fs.statSync(LOG_FILE_PATH).size;
const watcher = fs.watch(LOG_FILE_PATH, (eventType) => {
if (eventType === 'change') {
fs.stat(LOG_FILE_PATH, (err, stats) => {
if (err) {
lastKnownSize = 0;
return;
}
const currentSize = stats.size;
if (currentSize > lastKnownSize) {
const stream = fs.createReadStream(LOG_FILE_PATH, { start: lastKnownSize, end: currentSize, encoding: 'utf8' });
stream.on('data', (chunk) => {
broadcast(chunk);
});
stream.on('end', () => { lastKnownSize = currentSize; });
} else if (currentSize < lastKnownSize) {
lastKnownSize = currentSize;
broadcast('\n--- Log file was truncated. ---\n');
}
});
}
});
watcher.on('error', (err) => console.error('Watcher Error:', err));
//? log generator
const MOCK_LOG_MESSAGES = [
'INFO: User authenticated successfully. UserID: usr_12345',
'INFO: Processing transaction batch #5821.',
'WARN: High memory usage detected: 92%.',
'INFO: Database connection established.',
'ERROR: Failed to connect to external API: service timeout.',
'INFO: Cache cleared successfully.',
'DEBUG: Request received on /api/v1/data.',
];
setInterval(() => {
const message = MOCK_LOG_MESSAGES[Math.floor(Math.random() * MOCK_LOG_MESSAGES.length)];
const timestamp = new Date();
const logLine = `${timestamp} - ${message}\n`;
fs.appendFile(LOG_FILE_PATH, logLine, (err) => {
if (err) console.error('Error writing to log file:', err);
});
}, LOG_GENERATION_INTERVAL);
//! server start
server.listen(PORT, () => {
console.log(`Server is listening on http://localhost:${PORT}`);
console.log(`Watching for changes in ${LOG_FILE_PATH}`);
console.log(`Generating a new log entry every ${LOG_GENERATION_INTERVAL / 1000} seconds.`);
});