blockmine 1.16.2 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/backend/cli.js +57 -52
- package/backend/package.json +27 -26
- package/backend/prisma/migrations/20250723160648_add_bot_sort_order/migration.sql +2 -0
- package/backend/prisma/schema.prisma +229 -228
- package/backend/src/api/routes/bots.js +526 -101
- package/backend/src/api/routes/eventGraphs.js +459 -459
- package/backend/src/api/routes/logs.js +245 -0
- package/backend/src/core/BotManager.js +901 -855
- package/backend/src/core/BotProcess.js +35 -10
- package/backend/src/core/commands/dev.js +20 -0
- package/backend/src/server.js +2 -0
- package/frontend/dist/assets/index-BpUwmzIs.js +8347 -0
- package/frontend/dist/assets/index-D3DCCCQP.css +1 -0
- package/frontend/dist/index.html +2 -2
- package/frontend/package.json +3 -0
- package/package.json +1 -1
- package/frontend/dist/assets/index-ComgCgjP.js +0 -8331
- package/frontend/dist/assets/index-_stfadil.css +0 -1
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
|
|
7
|
+
const debugOnly = (req, res, next) => {
|
|
8
|
+
if (process.env.DEBUG === 'true' || process.env.NODE_ENV === 'development') {
|
|
9
|
+
next();
|
|
10
|
+
} else {
|
|
11
|
+
res.status(403).json({
|
|
12
|
+
success: false,
|
|
13
|
+
error: 'Доступ к логам разрешен только в режиме отладки'
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
let logBuffer = [];
|
|
19
|
+
const MAX_LOG_BUFFER = 1000;
|
|
20
|
+
|
|
21
|
+
const originalConsoleLog = console.log;
|
|
22
|
+
const originalConsoleError = console.error;
|
|
23
|
+
const originalConsoleWarn = console.warn;
|
|
24
|
+
const originalConsoleInfo = console.info;
|
|
25
|
+
|
|
26
|
+
function addToLogBuffer(level, ...args) {
|
|
27
|
+
const timestamp = new Date().toISOString();
|
|
28
|
+
const message = args.map(arg =>
|
|
29
|
+
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
|
|
30
|
+
).join(' ');
|
|
31
|
+
|
|
32
|
+
const logEntry = {
|
|
33
|
+
timestamp,
|
|
34
|
+
level,
|
|
35
|
+
message,
|
|
36
|
+
pid: process.pid
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
logBuffer.push(logEntry);
|
|
40
|
+
|
|
41
|
+
if (logBuffer.length > MAX_LOG_BUFFER) {
|
|
42
|
+
logBuffer = logBuffer.slice(-MAX_LOG_BUFFER);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
console.log = (...args) => {
|
|
47
|
+
addToLogBuffer('log', ...args);
|
|
48
|
+
originalConsoleLog.apply(console, args);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
console.error = (...args) => {
|
|
52
|
+
addToLogBuffer('error', ...args);
|
|
53
|
+
originalConsoleError.apply(console, args);
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
console.warn = (...args) => {
|
|
57
|
+
addToLogBuffer('warn', ...args);
|
|
58
|
+
originalConsoleWarn.apply(console, args);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
console.info = (...args) => {
|
|
62
|
+
addToLogBuffer('info', ...args);
|
|
63
|
+
originalConsoleInfo.apply(console, args);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
router.get('/', debugOnly, (req, res) => {
|
|
67
|
+
try {
|
|
68
|
+
const {
|
|
69
|
+
level,
|
|
70
|
+
limit = 100,
|
|
71
|
+
offset = 0,
|
|
72
|
+
search,
|
|
73
|
+
from,
|
|
74
|
+
to
|
|
75
|
+
} = req.query;
|
|
76
|
+
|
|
77
|
+
let filteredLogs = [...logBuffer];
|
|
78
|
+
|
|
79
|
+
if (level && level !== 'all') {
|
|
80
|
+
filteredLogs = filteredLogs.filter(log => log.level === level);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (search) {
|
|
84
|
+
const searchLower = search.toLowerCase();
|
|
85
|
+
filteredLogs = filteredLogs.filter(log =>
|
|
86
|
+
log.message.toLowerCase().includes(searchLower)
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (from) {
|
|
91
|
+
const fromDate = new Date(from);
|
|
92
|
+
filteredLogs = filteredLogs.filter(log =>
|
|
93
|
+
new Date(log.timestamp) >= fromDate
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (to) {
|
|
98
|
+
const toDate = new Date(to);
|
|
99
|
+
filteredLogs = filteredLogs.filter(log =>
|
|
100
|
+
new Date(log.timestamp) <= toDate
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const total = filteredLogs.length;
|
|
105
|
+
const logs = filteredLogs
|
|
106
|
+
.slice(parseInt(offset), parseInt(offset) + parseInt(limit))
|
|
107
|
+
.reverse();
|
|
108
|
+
|
|
109
|
+
res.json({
|
|
110
|
+
success: true,
|
|
111
|
+
data: {
|
|
112
|
+
logs,
|
|
113
|
+
pagination: {
|
|
114
|
+
total,
|
|
115
|
+
limit: parseInt(limit),
|
|
116
|
+
offset: parseInt(offset),
|
|
117
|
+
hasMore: parseInt(offset) + parseInt(limit) < total
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error('Ошибка при получении логов:', error);
|
|
124
|
+
res.status(500).json({
|
|
125
|
+
success: false,
|
|
126
|
+
error: 'Ошибка при получении логов'
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
router.delete('/', debugOnly, (req, res) => {
|
|
132
|
+
try {
|
|
133
|
+
logBuffer = [];
|
|
134
|
+
res.json({
|
|
135
|
+
success: true,
|
|
136
|
+
message: 'Логи очищены'
|
|
137
|
+
});
|
|
138
|
+
} catch (error) {
|
|
139
|
+
console.error('Ошибка при очистке логов:', error);
|
|
140
|
+
res.status(500).json({
|
|
141
|
+
success: false,
|
|
142
|
+
error: 'Ошибка при очистке логов'
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
router.get('/stats', debugOnly, (req, res) => {
|
|
148
|
+
try {
|
|
149
|
+
const stats = {
|
|
150
|
+
total: logBuffer.length,
|
|
151
|
+
byLevel: {
|
|
152
|
+
log: logBuffer.filter(log => log.level === 'log').length,
|
|
153
|
+
error: logBuffer.filter(log => log.level === 'error').length,
|
|
154
|
+
warn: logBuffer.filter(log => log.level === 'warn').length,
|
|
155
|
+
info: logBuffer.filter(log => log.level === 'info').length
|
|
156
|
+
},
|
|
157
|
+
timeRange: {
|
|
158
|
+
oldest: logBuffer.length > 0 ? logBuffer[0].timestamp : null,
|
|
159
|
+
newest: logBuffer.length > 0 ? logBuffer[logBuffer.length - 1].timestamp : null
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
res.json({
|
|
164
|
+
success: true,
|
|
165
|
+
data: stats
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
} catch (error) {
|
|
169
|
+
console.error('Ошибка при получении статистики логов:', error);
|
|
170
|
+
res.status(500).json({
|
|
171
|
+
success: false,
|
|
172
|
+
error: 'Ошибка при получении статистики логов'
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
router.get('/stream', debugOnly, (req, res) => {
|
|
178
|
+
res.writeHead(200, {
|
|
179
|
+
'Content-Type': 'text/event-stream',
|
|
180
|
+
'Cache-Control': 'no-cache',
|
|
181
|
+
'Connection': 'keep-alive',
|
|
182
|
+
'Access-Control-Allow-Origin': '*',
|
|
183
|
+
'Access-Control-Allow-Headers': 'Cache-Control'
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const sendLog = (log) => {
|
|
187
|
+
res.write(`data: ${JSON.stringify(log)}\n\n`);
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const recentLogs = logBuffer.slice(-10);
|
|
191
|
+
recentLogs.forEach(sendLog);
|
|
192
|
+
|
|
193
|
+
const logHandler = (log) => {
|
|
194
|
+
sendLog(log);
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
if (!global.logStreamHandlers) {
|
|
198
|
+
global.logStreamHandlers = [];
|
|
199
|
+
}
|
|
200
|
+
global.logStreamHandlers.push(logHandler);
|
|
201
|
+
|
|
202
|
+
req.on('close', () => {
|
|
203
|
+
const index = global.logStreamHandlers.indexOf(logHandler);
|
|
204
|
+
if (index > -1) {
|
|
205
|
+
global.logStreamHandlers.splice(index, 1);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
function broadcastLog(log) {
|
|
211
|
+
if (global.logStreamHandlers) {
|
|
212
|
+
global.logStreamHandlers.forEach(handler => {
|
|
213
|
+
try {
|
|
214
|
+
handler(log);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error('Ошибка при отправке лога клиенту:', error);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const originalAddToLogBuffer = addToLogBuffer;
|
|
223
|
+
addToLogBuffer = function(level, ...args) {
|
|
224
|
+
const timestamp = new Date().toISOString();
|
|
225
|
+
const message = args.map(arg =>
|
|
226
|
+
typeof arg === 'object' ? JSON.stringify(arg, null, 2) : String(arg)
|
|
227
|
+
).join(' ');
|
|
228
|
+
|
|
229
|
+
const logEntry = {
|
|
230
|
+
timestamp,
|
|
231
|
+
level,
|
|
232
|
+
message,
|
|
233
|
+
pid: process.pid
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
logBuffer.push(logEntry);
|
|
237
|
+
|
|
238
|
+
if (logBuffer.length > MAX_LOG_BUFFER) {
|
|
239
|
+
logBuffer = logBuffer.slice(-MAX_LOG_BUFFER);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
broadcastLog(logEntry);
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
module.exports = router;
|