add recent connection
This commit is contained in:
parent
48a4316d66
commit
0e3d5e1c1f
76
app.py
76
app.py
@ -7,7 +7,10 @@ import mimetypes
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
from datetime import datetime, date, timedelta
|
from datetime import datetime, date, timedelta
|
||||||
import diskcache
|
import diskcache
|
||||||
|
import threading
|
||||||
import json
|
import json
|
||||||
|
import time
|
||||||
|
from flask_socketio import SocketIO
|
||||||
import geoip2.database
|
import geoip2.database
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from urllib.parse import urlparse, unquote
|
from urllib.parse import urlparse, unquote
|
||||||
@ -26,6 +29,13 @@ if os.environ.get('FLASK_ENV') == 'production':
|
|||||||
with open('folder_config.json') as file:
|
with open('folder_config.json') as file:
|
||||||
app.config['folder_config'] = json.load(file)
|
app.config['folder_config'] = json.load(file)
|
||||||
|
|
||||||
|
socketio = SocketIO(app)
|
||||||
|
|
||||||
|
# Global variables to track the number of connected clients and the background thread
|
||||||
|
clients_connected = 0
|
||||||
|
background_thread = None
|
||||||
|
thread_lock = threading.Lock()
|
||||||
|
|
||||||
def require_secret(f):
|
def require_secret(f):
|
||||||
@wraps(f)
|
@wraps(f)
|
||||||
def decorated_function(*args, **kwargs):
|
def decorated_function(*args, **kwargs):
|
||||||
@ -558,6 +568,68 @@ def crawl_and_cache(subpath):
|
|||||||
# Return the list of cached files as a JSON response
|
# Return the list of cached files as a JSON response
|
||||||
return json.dumps({"cached_files": cached_files}, indent=4), 200
|
return json.dumps({"cached_files": cached_files}, indent=4), 200
|
||||||
|
|
||||||
|
def query_recent_connections():
|
||||||
|
"""
|
||||||
|
Every 5 seconds, query the database for connections in the last 60 seconds,
|
||||||
|
sorted by timestamp (most recent first), and emit the data to clients.
|
||||||
|
This loop will exit when there are no connected clients.
|
||||||
|
"""
|
||||||
|
global clients_connected
|
||||||
|
while clients_connected > 0:
|
||||||
|
cutoff = datetime.now() - timedelta(seconds=60)
|
||||||
|
cutoff_iso = cutoff.isoformat()
|
||||||
|
|
||||||
|
# Query the SQLite database for recent connections
|
||||||
|
conn = sqlite3.connect('access_log.db')
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute('''
|
||||||
|
SELECT * FROM file_access_log
|
||||||
|
WHERE timestamp >= ?
|
||||||
|
ORDER BY timestamp DESC
|
||||||
|
''', (cutoff_iso,))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# Convert rows to dictionaries for the client, including all columns.
|
||||||
|
connections = []
|
||||||
|
for row in rows:
|
||||||
|
# Row order: (id, timestamp, full_path, ip_address, user_agent, referrer)
|
||||||
|
connections.append({
|
||||||
|
'id': row[0],
|
||||||
|
'timestamp': row[1],
|
||||||
|
'full_path': row[2],
|
||||||
|
'ip_address': row[3],
|
||||||
|
'user_agent': row[4],
|
||||||
|
'referrer': row[5]
|
||||||
|
})
|
||||||
|
|
||||||
|
# Emit the result over Socket.IO (to the default namespace)
|
||||||
|
socketio.emit('recent_connections', connections)
|
||||||
|
time.sleep(5)
|
||||||
|
# When no clients are connected, exit the thread.
|
||||||
|
print("No clients connected; stopping query thread.")
|
||||||
|
|
||||||
|
@socketio.on('connect')
|
||||||
|
def handle_connect():
|
||||||
|
global clients_connected, background_thread
|
||||||
|
clients_connected += 1
|
||||||
|
print("Client connected. Total clients:", clients_connected)
|
||||||
|
with thread_lock:
|
||||||
|
# Start the background task if it's not already running.
|
||||||
|
if background_thread is None or not background_thread.is_alive():
|
||||||
|
background_thread = socketio.start_background_task(query_recent_connections)
|
||||||
|
print("Started background query task.")
|
||||||
|
|
||||||
|
@socketio.on('disconnect')
|
||||||
|
def handle_disconnect():
|
||||||
|
global clients_connected
|
||||||
|
clients_connected -= 1
|
||||||
|
print("Client disconnected. Total clients:", clients_connected)
|
||||||
|
|
||||||
|
@app.route('/network')
|
||||||
|
def network():
|
||||||
|
return render_template('network.html')
|
||||||
|
|
||||||
# Catch-all route to serve the single-page application template.
|
# Catch-all route to serve the single-page application template.
|
||||||
@app.route('/', defaults={'path': ''})
|
@app.route('/', defaults={'path': ''})
|
||||||
@app.route('/<path:path>')
|
@app.route('/<path:path>')
|
||||||
@ -565,5 +637,5 @@ def crawl_and_cache(subpath):
|
|||||||
def index(path):
|
def index(path):
|
||||||
return render_template("app.html")
|
return render_template("app.html")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == '__main__':
|
||||||
app.run(debug=True, host='0.0.0.0')
|
socketio.run(app, debug=True, host='0.0.0.0')
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
flask
|
flask
|
||||||
|
flask_socketio
|
||||||
pillow
|
pillow
|
||||||
diskcache
|
diskcache
|
||||||
geoip2
|
geoip2
|
||||||
|
|||||||
@ -1,22 +1,23 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Web Analytics Dashboard</title>
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<!-- Using Bootstrap for responsive layout -->
|
<title>Dashboard - Verbindungsanalyse</title>
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
<style>
|
<style>
|
||||||
body { margin: 20px; }
|
body { margin: 20px; }
|
||||||
.card { margin-bottom: 20px; }
|
.card { margin-bottom: 20px; }
|
||||||
canvas { max-width: 100%; }
|
canvas { max-width: 100%; }
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="mb-4">Web Analytics Dashboard ({{ timeframe }})</h1>
|
<h1 class="mb-4">Dashboard - Verbindungsanalyse({{ timeframe }})</h1>
|
||||||
<!-- Timeframe selection buttons -->
|
<!-- Timeframe selection buttons -->
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<a href="{{ url_for('index') }}" class="btn btn-primary">Home</a>
|
<a href="{{ url_for('index') }}" class="btn btn-primary">Home</a>
|
||||||
|
<a href="{{ url_for('network') }}" class="btn btn-primary">Netzwerk</a>
|
||||||
<a href="{{ url_for('dashboard', timeframe='today') }}" class="btn btn-primary">Today</a>
|
<a href="{{ url_for('dashboard', timeframe='today') }}" class="btn btn-primary">Today</a>
|
||||||
<a href="{{ url_for('dashboard', timeframe='7days') }}" class="btn btn-primary">Last 7 Days</a>
|
<a href="{{ url_for('dashboard', timeframe='7days') }}" class="btn btn-primary">Last 7 Days</a>
|
||||||
<a href="{{ url_for('dashboard', timeframe='30days') }}" class="btn btn-primary">Last 30 Days</a>
|
<a href="{{ url_for('dashboard', timeframe='30days') }}" class="btn btn-primary">Last 30 Days</a>
|
||||||
|
|||||||
81
templates/network.html
Normal file
81
templates/network.html
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Recent Connections</title>
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
body { margin: 20px; }
|
||||||
|
canvas { max-width: 100%; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1 class="mb-4">kürzlich verbunden... (in der letzten Minute)</h1>
|
||||||
|
<div class="mb-3">
|
||||||
|
<a href="{{ url_for('index') }}" class="btn btn-primary">Home</a>
|
||||||
|
<a href="{{ url_for('dashboard') }}" class="btn btn-primary">Dashboard</a>
|
||||||
|
</div>
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="table-info">
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
|
<th>Full Path</th>
|
||||||
|
<th>IP Address</th>
|
||||||
|
<th>User Agent</th>
|
||||||
|
<th>Referrer</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="connectionsTableBody">
|
||||||
|
<!-- Rows will be dynamically inserted here -->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Socket.IO client library -->
|
||||||
|
<script src="https://cdn.socket.io/4.0.0/socket.io.min.js"></script>
|
||||||
|
<!-- Using vanilla JavaScript for dynamic DOM updates -->
|
||||||
|
<script>
|
||||||
|
const socket = io();
|
||||||
|
socket.on('recent_connections', function(data) {
|
||||||
|
const tbody = document.getElementById('connectionsTableBody');
|
||||||
|
tbody.innerHTML = ''; // Clear previous content
|
||||||
|
|
||||||
|
data.forEach(record => {
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
|
||||||
|
// Create cells for each column
|
||||||
|
const idCell = document.createElement('td');
|
||||||
|
idCell.textContent = record.id;
|
||||||
|
const timestampCell = document.createElement('td');
|
||||||
|
timestampCell.textContent = record.timestamp;
|
||||||
|
const fullPathCell = document.createElement('td');
|
||||||
|
fullPathCell.textContent = record.full_path;
|
||||||
|
const ipCell = document.createElement('td');
|
||||||
|
ipCell.textContent = record.ip_address;
|
||||||
|
const userAgentCell = document.createElement('td');
|
||||||
|
userAgentCell.textContent = record.user_agent;
|
||||||
|
const referrerCell = document.createElement('td');
|
||||||
|
referrerCell.textContent = record.referrer;
|
||||||
|
|
||||||
|
// Append cells to the row
|
||||||
|
row.appendChild(idCell);
|
||||||
|
row.appendChild(timestampCell);
|
||||||
|
row.appendChild(fullPathCell);
|
||||||
|
row.appendChild(ipCell);
|
||||||
|
row.appendChild(userAgentCell);
|
||||||
|
row.appendChild(referrerCell);
|
||||||
|
|
||||||
|
// Append the row to the table body
|
||||||
|
tbody.appendChild(row);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<!-- Bootstrap 5 JS Bundle -->
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user