source: simple_server_fixed.py@ 640ed89

Last change on this file since 640ed89 was 640ed89, checked in by istevanoska <ilinastevanoska@…>, 7 months ago

Initial commit

  • Property mode set to 100644
File size: 21.9 KB
Line 
1#!/usr/bin/env python3
2"""
3POPRAVEN SERVER - So azhuriranje na postoechki zapisi i detalni informacii
4"""
5
6from flask import Flask, request, jsonify
7import json
8import sqlite3
9from datetime import datetime, timedelta
10import os
11import socket
12
13app = Flask(__name__)
14
15DB_FILE = "lan_logs_fixed.db"
16LOG_DIR = "received_data_fixed"
17
18
19def init_database():
20 """Kreiraј pobolshana baza"""
21 os.makedirs(LOG_DIR, exist_ok=True)
22
23 conn = sqlite3.connect(DB_FILE)
24 c = conn.cursor()
25
26 # Tabela za kompjuteri (SEGA so edinstveno ime)
27 c.execute('''CREATE TABLE IF NOT EXISTS computers
28 (id INTEGER PRIMARY KEY AUTOINCREMENT,
29 name TEXT UNIQUE,
30 user TEXT,
31 ip TEXT,
32 os TEXT,
33 first_seen TIMESTAMP,
34 last_seen TIMESTAMP)''')
35
36 # Tabela za history (site podatoci)
37 c.execute('''CREATE TABLE IF NOT EXISTS computer_history
38 (id INTEGER PRIMARY KEY AUTOINCREMENT,
39 computer_id INTEGER,
40 cpu_usage REAL,
41 ram_usage REAL,
42 disk_usage REAL,
43 process_count INTEGER,
44 timestamp TIMESTAMP,
45 FOREIGN KEY(computer_id) REFERENCES computers(id))''')
46
47 # Tabela za procesi (so vremenska oznaka)
48 c.execute('''CREATE TABLE IF NOT EXISTS computer_processes
49 (id INTEGER PRIMARY KEY AUTOINCREMENT,
50 computer_id INTEGER,
51 pid INTEGER,
52 name TEXT,
53 cpu_percent REAL,
54 memory_mb REAL,
55 username TEXT,
56 timestamp TIMESTAMP,
57 FOREIGN KEY(computer_id) REFERENCES computers(id))''')
58
59 conn.commit()
60 conn.close()
61
62 print(f"✅ Database created: {DB_FILE}")
63
64
65@app.route('/receive', methods=['POST'])
66def receive_data():
67 try:
68 data = request.json
69
70 if not data:
71 return jsonify({"error": "No data"}), 400
72
73 info = data['info']
74 computer_name = info['computer_name']
75 timestamp = datetime.now()
76
77 conn = sqlite3.connect(DB_FILE)
78 c = conn.cursor()
79
80 # Proveri dali kompjuterot veќe postoi
81 c.execute("SELECT id FROM computers WHERE name = ?", (computer_name,))
82 result = c.fetchone()
83
84 if result:
85 # Kompjuterot postoi - azhuriraј go
86 computer_id = result[0]
87 c.execute('''UPDATE computers
88 SET user = ?, ip = ?, os = ?, last_seen = ?
89 WHERE id = ?''',
90 (info['user'], info['ip_address'], info['os'],
91 timestamp.isoformat(), computer_id))
92 else:
93 # Nov kompjuter - dodadi go
94 c.execute('''INSERT INTO computers
95 (name, user, ip, os, first_seen, last_seen)
96 VALUES (?, ?, ?, ?, ?, ?)''',
97 (computer_name, info['user'], info['ip_address'],
98 info['os'], timestamp.isoformat(), timestamp.isoformat()))
99 computer_id = c.lastrowid
100
101 # Dodadi vo history
102 c.execute('''INSERT INTO computer_history
103 (computer_id, cpu_usage, ram_usage, disk_usage,
104 process_count, timestamp)
105 VALUES (?, ?, ?, ?, ?, ?)''',
106 (computer_id, info['cpu_usage'], info['ram_usage'],
107 info['disk_usage'], len(data.get('processes', [])),
108 info['timestamp']))
109
110 # Zachuvaj gi procesite
111 for proc in data.get('processes', []):
112 c.execute('''INSERT INTO computer_processes
113 (computer_id, pid, name, username, timestamp)
114 VALUES (?, ?, ?, ?, ?)''',
115 (computer_id, proc.get('pid'), proc.get('name'),
116 proc.get('user'), info['timestamp']))
117
118 conn.commit()
119 conn.close()
120
121 # Zachuvaj vo JSON
122 save_json_file(data)
123
124 print(f"[{timestamp.strftime('%H:%M:%S')}] 📥 {computer_name}: "
125 f"CPU {info['cpu_usage']}% | RAM {info['ram_usage']}%")
126
127 return jsonify({
128 "status": "success",
129 "message": f"Data saved for {computer_name}",
130 "computer_id": computer_id,
131 "timestamp": timestamp.isoformat()
132 })
133
134 except Exception as e:
135 print(f"[-] Greshka: {e}")
136 return jsonify({"error": str(e)}), 500
137
138
139def save_json_file(data):
140 """Zachuvaj vo JSON"""
141 info = data['info']
142 computer_name = info['computer_name']
143 date_str = datetime.now().strftime("%Y%m%d")
144
145 # Kreiraј folder za kompjuterot
146 computer_dir = os.path.join(LOG_DIR, computer_name)
147 os.makedirs(computer_dir, exist_ok=True)
148
149 # Fajl za denes
150 filepath = os.path.join(computer_dir, f"{date_str}.json")
151
152 # Dodadi vo postoechki fajl ili kreiraј nov
153 if os.path.exists(filepath):
154 with open(filepath, 'r', encoding='utf-8') as f:
155 existing_data = json.load(f)
156 else:
157 existing_data = []
158
159 # Dodadi nov zapis
160 existing_data.append({
161 "timestamp": info['timestamp'],
162 "data": info,
163 "processes_count": len(data.get('processes', []))
164 })
165
166 # Zachuvaj
167 with open(filepath, 'w', encoding='utf-8') as f:
168 json.dump(existing_data, f, indent=2, ensure_ascii=False)
169
170
171@app.route('/')
172def dashboard():
173 """Glaven dashboard so site kompjuteri"""
174 conn = sqlite3.connect(DB_FILE)
175 c = conn.cursor()
176
177 # Zemaj gi site kompjuteri
178 c.execute('''SELECT name, user, ip, os, first_seen, last_seen
179 FROM computers
180 ORDER BY last_seen DESC''')
181
182 computers = []
183 for row in c.fetchall():
184 # Presmetaj kolku zapisi ima vo poslednite 24 chasa
185 c.execute('''SELECT COUNT(*) FROM computer_history
186 WHERE computer_id = (SELECT id FROM computers WHERE name = ?)
187 AND timestamp > datetime('now', '-24 hours')''',
188 (row[0],))
189 recent_logs = c.fetchone()[0]
190
191 # Zemaj gi poslednite 5 zapisi za CPU/RAM
192 c.execute('''SELECT cpu_usage, ram_usage, timestamp
193 FROM computer_history
194 WHERE computer_id = (SELECT id FROM computers WHERE name = ?)
195 ORDER BY timestamp DESC LIMIT 5''',
196 (row[0],))
197 recent_metrics = c.fetchall()
198
199 # Presmetaj prosek
200 avg_cpu = sum(m[0] for m in recent_metrics) / len(recent_metrics) if recent_metrics else 0
201 avg_ram = sum(m[1] for m in recent_metrics) / len(recent_metrics) if recent_metrics else 0
202
203 computers.append({
204 'name': row[0],
205 'user': row[1],
206 'ip': row[2],
207 'os': row[3],
208 'first_seen': row[4],
209 'last_seen': row[5],
210 'recent_logs': recent_logs,
211 'avg_cpu': round(avg_cpu, 1),
212 'avg_ram': round(avg_ram, 1),
213 'status': 'online' if (datetime.now() - datetime.fromisoformat(row[5])).seconds < 60 else 'offline'
214 })
215
216 conn.close()
217
218 # Generiraј HTML
219 html = '''
220 <!DOCTYPE html>
221 <html>
222 <head>
223 <title>LAN Log Server - Fixed Dashboard</title>
224 <meta charset="utf-8">
225 <style>
226 body { font-family: Arial, sans-serif; margin: 20px; background: #f5f5f5; }
227 .header { background: #2c3e50; color: white; padding: 20px; border-radius: 10px; margin-bottom: 20px; }
228 .computers-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 20px; }
229 .computer-card { background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
230 .computer-card:hover { box-shadow: 0 4px 10px rgba(0,0,0,0.2); cursor: pointer; }
231 .computer-name { font-size: 18px; font-weight: bold; margin-bottom: 10px; color: #2c3e50; }
232 .computer-info { color: #666; margin: 5px 0; }
233 .online { color: green; }
234 .offline { color: gray; }
235 .stats { display: flex; justify-content: space-between; margin-top: 15px; padding-top: 15px; border-top: 1px solid #eee; }
236 .stat { text-align: center; }
237 .stat-value { font-size: 20px; font-weight: bold; }
238 .stat-label { font-size: 12px; color: #888; }
239 .details-panel { display: none; position: fixed; top: 0; right: 0; width: 600px; height: 100%; background: white; box-shadow: -2px 0 10px rgba(0,0,0,0.1); padding: 20px; overflow-y: auto; z-index: 1000; }
240 .close-btn { float: right; cursor: pointer; font-size: 24px; }
241 .tab { display: none; }
242 .tab.active { display: block; }
243 .tab-buttons { display: flex; border-bottom: 1px solid #ddd; margin-bottom: 20px; }
244 .tab-button { padding: 10px 20px; cursor: pointer; border: none; background: none; }
245 .tab-button.active { border-bottom: 3px solid #2c3e50; font-weight: bold; }
246 table { width: 100%; border-collapse: collapse; margin-top: 10px; }
247 th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
248 th { background: #f5f5f5; }
249 </style>
250 <script>
251 function showComputerDetails(computerName) {
252 fetch(`/api/computer/${encodeURIComponent(computerName)}`)
253 .then(response => response.json())
254 .then(data => {
255 document.getElementById('details-panel').style.display = 'block';
256 populateDetails(data);
257 });
258 }
259
260 function populateDetails(data) {
261 // Popolni osnovni informacii
262 document.getElementById('details-title').textContent = data.computer.name;
263 document.getElementById('details-user').textContent = data.computer.user;
264 document.getElementById('details-ip').textContent = data.computer.ip;
265 document.getElementById('details-os').textContent = data.computer.os;
266 document.getElementById('details-first-seen').textContent = new Date(data.computer.first_seen).toLocaleString();
267 document.getElementById('details-last-seen').textContent = new Date(data.computer.last_seen).toLocaleString();
268 document.getElementById('details-total-logs').textContent = data.computer.total_logs;
269
270 // Popolni tabela za history
271 let historyTable = document.getElementById('history-table');
272 historyTable.innerHTML = '';
273 data.history.forEach(log => {
274 let row = historyTable.insertRow();
275 row.innerHTML = `
276 <td>${new Date(log.timestamp).toLocaleString()}</td>
277 <td>${log.cpu_usage}%</td>
278 <td>${log.ram_usage}%</td>
279 <td>${log.disk_usage}%</td>
280 <td>${log.process_count}</td>
281 `;
282 });
283
284 // Popolni tabela za procesi (posledni)
285 let processTable = document.getElementById('process-table');
286 processTable.innerHTML = '';
287 data.recent_processes.forEach(proc => {
288 let row = processTable.insertRow();
289 row.innerHTML = `
290 <td>${proc.pid}</td>
291 <td>${proc.name}</td>
292 <td>${proc.username}</td>
293 <td>${new Date(proc.timestamp).toLocaleTimeString()}</td>
294 `;
295 });
296
297 // Popolni chart (simple)
298 updateChart(data.history);
299 }
300
301 function updateChart(history) {
302 const ctx = document.getElementById('performance-chart').getContext('2d');
303
304 // Grupiraј po chas (za podobar prikaz)
305 const labels = history.slice(-20).map(h =>
306 new Date(h.timestamp).toLocaleTimeString()
307 );
308 const cpuData = history.slice(-20).map(h => h.cpu_usage);
309 const ramData = history.slice(-20).map(h => h.ram_usage);
310
311 if(window.myChart) {
312 window.myChart.destroy();
313 }
314
315 window.myChart = new Chart(ctx, {
316 type: 'line',
317 data: {
318 labels: labels,
319 datasets: [
320 {
321 label: 'CPU Usage %',
322 data: cpuData,
323 borderColor: 'rgb(255, 99, 132)',
324 backgroundColor: 'rgba(255, 99, 132, 0.2)',
325 tension: 0.4
326 },
327 {
328 label: 'RAM Usage %',
329 data: ramData,
330 borderColor: 'rgb(54, 162, 235)',
331 backgroundColor: 'rgba(54, 162, 235, 0.2)',
332 tension: 0.4
333 }
334 ]
335 },
336 options: {
337 responsive: true,
338 scales: {
339 y: {
340 beginAtZero: true,
341 max: 100
342 }
343 }
344 }
345 });
346 }
347
348 function closeDetails() {
349 document.getElementById('details-panel').style.display = 'none';
350 }
351
352 function switchTab(tabName) {
353 // Deaktiviraј site tabovi
354 document.querySelectorAll('.tab').forEach(tab => {
355 tab.classList.remove('active');
356 });
357 document.querySelectorAll('.tab-button').forEach(btn => {
358 btn.classList.remove('active');
359 });
360
361 // Aktiviraј izbraniot tab
362 document.getElementById(tabName + '-tab').classList.add('active');
363 document.querySelector(`[onclick="switchTab('${tabName}')"]`).classList.add('active');
364 }
365
366 // Aktiviraј prv tab na start
367 document.addEventListener('DOMContentLoaded', function() {
368 switchTab('history');
369 });
370 </script>
371 </head>
372 <body>
373 <div class="header">
374 <h1>🖥️ LAN Log Server - Fixed Dashboard</h1>
375 <p>Connected Computers: <span id="computer-count">''' + str(len(computers)) + '''</span></p>
376 <p>Server IP: ''' + socket.gethostbyname(socket.gethostname()) + ''':5555</p>
377 </div>
378
379 <h2>Connected Computers</h2>
380 <div class="computers-grid">
381 '''
382
383 for comp in computers:
384 html += f'''
385 <div class="computer-card" onclick="showComputerDetails('{comp['name']}')">
386 <div class="computer-name">{comp['name']}</div>
387 <div class="computer-info">👤 User: {comp['user']}</div>
388 <div class="computer-info">🌐 IP: {comp['ip']}</div>
389 <div class="computer-info">💻 OS: {comp['os']}</div>
390 <div class="computer-info">⏰ Last seen: {datetime.fromisoformat(comp['last_seen']).strftime('%H:%M:%S')}</div>
391 <div class="computer-info {'online' if comp['status'] == 'online' else 'offline'}">
392 ● {comp['status'].upper()}
393 </div>
394 <div class="stats">
395 <div class="stat">
396 <div class="stat-value">{comp['avg_cpu']}%</div>
397 <div class="stat-label">CPU</div>
398 </div>
399 <div class="stat">
400 <div class="stat-value">{comp['avg_ram']}%</div>
401 <div class="stat-label">RAM</div>
402 </div>
403 <div class="stat">
404 <div class="stat-value">{comp['recent_logs']}</div>
405 <div class="stat-label">Logs (24h)</div>
406 </div>
407 </div>
408 </div>
409 '''
410
411 html += '''
412 </div>
413
414 <!-- Details Panel -->
415 <div id="details-panel" class="details-panel">
416 <div class="close-btn" onclick="closeDetails()">×</div>
417 <h2 id="details-title">Computer Details</h2>
418
419 <div class="computer-info">
420 <p><strong>👤 User:</strong> <span id="details-user"></span></p>
421 <p><strong>🌐 IP:</strong> <span id="details-ip"></span></p>
422 <p><strong>💻 OS:</strong> <span id="details-os"></span></p>
423 <p><strong>📅 First Seen:</strong> <span id="details-first-seen"></span></p>
424 <p><strong>⏰ Last Seen:</strong> <span id="details-last-seen"></span></p>
425 <p><strong>📊 Total Logs:</strong> <span id="details-total-logs"></span></p>
426 </div>
427
428 <div class="tab-buttons">
429 <button class="tab-button active" onclick="switchTab('history')">History</button>
430 <button class="tab-button" onclick="switchTab('processes')">Processes</button>
431 <button class="tab-button" onclick="switchTab('charts')">Charts</button>
432 </div>
433
434 <div id="history-tab" class="tab active">
435 <h3>Performance History</h3>
436 <table>
437 <thead>
438 <tr>
439 <th>Time</th>
440 <th>CPU %</th>
441 <th>RAM %</th>
442 <th>Disk %</th>
443 <th>Processes</th>
444 </tr>
445 </thead>
446 <tbody id="history-table"></tbody>
447 </table>
448 </div>
449
450 <div id="processes-tab" class="tab">
451 <h3>Recent Processes</h3>
452 <table>
453 <thead>
454 <tr>
455 <th>PID</th>
456 <th>Name</th>
457 <th>User</th>
458 <th>Time</th>
459 </tr>
460 </thead>
461 <tbody id="process-table"></tbody>
462 </table>
463 </div>
464
465 <div id="charts-tab" class="tab">
466 <h3>Performance Chart</h3>
467 <canvas id="performance-chart" width="400" height="200"></canvas>
468 </div>
469 </div>
470
471 <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
472 <script>
473 // Auto-refresh na dashboard sekoj 30 sekundi
474 setInterval(() => {
475 location.reload();
476 }, 30000);
477 </script>
478 </body>
479 </html>
480 '''
481
482 return html
483
484
485@app.route('/api/computer/<computer_name>')
486def get_computer_details(computer_name):
487 """Dobi site detalni informacii za eden kompjuter"""
488 conn = sqlite3.connect(DB_FILE)
489 c = conn.cursor()
490
491 # Osnovni informacii
492 c.execute('''SELECT id, name, user, ip, os, first_seen, last_seen
493 FROM computers WHERE name = ?''', (computer_name,))
494 computer_data = c.fetchone()
495
496 if not computer_data:
497 conn.close()
498 return jsonify({"error": "Computer not found"}), 404
499
500 computer_id = computer_data[0]
501
502 # Broj na site zapisi
503 c.execute('SELECT COUNT(*) FROM computer_history WHERE computer_id = ?', (computer_id,))
504 total_logs = c.fetchone()[0]
505
506 # Site history zapisi
507 c.execute('''SELECT cpu_usage, ram_usage, disk_usage, process_count, timestamp
508 FROM computer_history
509 WHERE computer_id = ?
510 ORDER BY timestamp DESC LIMIT 100''', (computer_id,))
511 history = []
512 for row in c.fetchall():
513 history.append({
514 'cpu_usage': row[0],
515 'ram_usage': row[1],
516 'disk_usage': row[2],
517 'process_count': row[3],
518 'timestamp': row[4]
519 })
520
521 # Posledni procesi
522 c.execute('''SELECT pid, name, username, timestamp
523 FROM computer_processes
524 WHERE computer_id = ?
525 ORDER BY timestamp DESC LIMIT 50''', (computer_id,))
526 recent_processes = []
527 for row in c.fetchall():
528 recent_processes.append({
529 'pid': row[0],
530 'name': row[1],
531 'username': row[2],
532 'timestamp': row[3]
533 })
534
535 conn.close()
536
537 return jsonify({
538 'computer': {
539 'id': computer_data[0],
540 'name': computer_data[1],
541 'user': computer_data[2],
542 'ip': computer_data[3],
543 'os': computer_data[4],
544 'first_seen': computer_data[5],
545 'last_seen': computer_data[6],
546 'total_logs': total_logs
547 },
548 'history': history,
549 'recent_processes': recent_processes
550 })
551
552
553@app.route('/ping')
554def ping():
555 return jsonify({
556 'status': 'alive',
557 'server_time': datetime.now().isoformat()
558 })
559
560
561def get_local_ip():
562 try:
563 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
564 s.connect(("8.8.8.8", 80))
565 local_ip = s.getsockname()[0]
566 s.close()
567 return local_ip
568 except:
569 return "127.0.0.1"
570
571
572if __name__ == '__main__':
573 init_database()
574
575 local_ip = get_local_ip()
576
577 print("\n" + "=" * 70)
578 print("🚀 FIXED LAN LOG SERVER")
579 print("=" * 70)
580 print(f"🌐 Server IP: {local_ip}:5555")
581 print(f"📊 Dashboard: http://{local_ip}:5555/")
582 print(f"📊 Alternative: http://localhost:5555/")
583 print(f"🏥 Health check: http://{local_ip}:5555/ping")
584 print("\n📡 Data will be grouped by computer name")
585 print("✅ Each computer appears only once")
586 print("✅ Click on computer to see all collected data")
587 print("=" * 70 + "\n")
588
589 app.run(host='0.0.0.0', port=5555, debug=False)
Note: See TracBrowser for help on using the repository browser.