.
This commit is contained in:
19
.dockerignore
Normal file
19
.dockerignore
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.Python
|
||||||
|
.env
|
||||||
|
.venv
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
*.sqlite3
|
||||||
|
*.db
|
||||||
|
analysis.py
|
||||||
|
db.py
|
||||||
|
pyproject.toml
|
||||||
|
README.md
|
||||||
|
run_speedtest.py
|
||||||
|
uv.lock
|
||||||
|
.dockerignore
|
||||||
|
.python-version
|
||||||
36
Dockerfile
Normal file
36
Dockerfile
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# Use a lightweight Python base image
|
||||||
|
FROM python:3.13-slim
|
||||||
|
|
||||||
|
# Set environment variables to prevent Python from writing pyc files
|
||||||
|
# and to flush stdout/stderr immediately (useful for docker logs)
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
# Set the working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y git && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Install dependencies first (for better caching)
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Copy the rest of the application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Create a directory for the database mount (optional but good for clarity)
|
||||||
|
RUN mkdir -p /data
|
||||||
|
|
||||||
|
# Default environment variable for the database path inside the container
|
||||||
|
ENV DB_PATH="/data/speedtest.db"
|
||||||
|
ENV PORT=5000
|
||||||
|
|
||||||
|
# Expose the port the app runs on
|
||||||
|
EXPOSE 5000
|
||||||
|
|
||||||
|
# Run using Gunicorn
|
||||||
|
# -b 0.0.0.0:5000: Bind to all interfaces on port 5000
|
||||||
|
# --access-logfile -: Log access to stdout
|
||||||
|
CMD ["gunicorn", "--workers", "1", "--bind", "0.0.0.0:5000", "--access-logfile", "-", "app:app"]
|
||||||
67
analysis.py
67
analysis.py
@@ -1,67 +0,0 @@
|
|||||||
import sqlite3
|
|
||||||
import os
|
|
||||||
from datetime import datetime
|
|
||||||
import pytz
|
|
||||||
import time
|
|
||||||
|
|
||||||
from config import DB_PATH
|
|
||||||
|
|
||||||
def get_conn() -> sqlite3.Connection:
|
|
||||||
uri = f"file:{os.path.abspath(DB_PATH)}?cache=shared"
|
|
||||||
conn = sqlite3.connect(uri, uri=True, check_same_thread=False)
|
|
||||||
conn.row_factory = sqlite3.Row
|
|
||||||
conn.execute("PRAGMA journal_mode=WAL;")
|
|
||||||
conn.execute("PRAGMA synchronous=NORMAL;")
|
|
||||||
conn.execute("PRAGMA temp_store=MEMORY;")
|
|
||||||
conn.execute("PRAGMA cache_size=-20000;") # ~20MB cache
|
|
||||||
return conn
|
|
||||||
|
|
||||||
CONN = get_conn()
|
|
||||||
|
|
||||||
# ---------------------- Utilities ----------------------
|
|
||||||
|
|
||||||
def ts_to_iso(ts: float | int | str) -> str:
|
|
||||||
try:
|
|
||||||
t = float(ts)
|
|
||||||
except Exception:
|
|
||||||
return str(ts)
|
|
||||||
return datetime.fromtimestamp(t, tz=pytz.timezone("Europe/Berlin")).isoformat()
|
|
||||||
|
|
||||||
# ---------------------- API Endpoints ----------------------
|
|
||||||
|
|
||||||
def api_series(q_from: float, q_to: float):
|
|
||||||
params = []
|
|
||||||
where = []
|
|
||||||
if q_from is not None:
|
|
||||||
where.append("timestamp >= ?")
|
|
||||||
params.append(q_from)
|
|
||||||
if q_to is not None:
|
|
||||||
where.append("timestamp <= ?")
|
|
||||||
params.append(q_to)
|
|
||||||
where_sql = ("WHERE " + " AND ".join(where)) if where else ""
|
|
||||||
|
|
||||||
sql = (
|
|
||||||
f"SELECT timestamp, down_90th, up_90th FROM speed_tests {where_sql} "
|
|
||||||
"ORDER BY timestamp ASC;"
|
|
||||||
)
|
|
||||||
|
|
||||||
rows = []
|
|
||||||
for i, r in enumerate(CONN.execute(sql, params)):
|
|
||||||
rows.append({
|
|
||||||
"t": float(r["timestamp"]),
|
|
||||||
"t_iso": ts_to_iso(r["timestamp"]),
|
|
||||||
"down_90th": None if r["down_90th"] is None else float(r["down_90th"]),
|
|
||||||
"up_90th": None if r["up_90th"] is None else float(r["up_90th"]),
|
|
||||||
})
|
|
||||||
|
|
||||||
return rows
|
|
||||||
|
|
||||||
rows = api_series(1756220400, time.time())
|
|
||||||
|
|
||||||
does_not_work = 0
|
|
||||||
|
|
||||||
for r in rows:
|
|
||||||
if r["down_90th"] is None or r["up_90th"] is None:
|
|
||||||
does_not_work += 1
|
|
||||||
|
|
||||||
print(f"Working percentage: {100 - (does_not_work / len(rows))*100}% ({does_not_work}/{len(rows)})")
|
|
||||||
55
requirements.txt
Normal file
55
requirements.txt
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# This file was autogenerated by uv via the following command:
|
||||||
|
# uv export --format requirements-txt -o requirements.txt --no-hashes
|
||||||
|
blinker==1.9.0
|
||||||
|
# via flask
|
||||||
|
certifi==2025.11.12
|
||||||
|
# via requests
|
||||||
|
charset-normalizer==3.4.4
|
||||||
|
# via requests
|
||||||
|
click==8.3.1
|
||||||
|
# via flask
|
||||||
|
cloudflarepycli @ git+https://github.com/cato447/cloudflarepycli@26477fb5511839648a774f1685426925b5b44311
|
||||||
|
# via speed-logger
|
||||||
|
colorama==0.4.6 ; sys_platform == 'win32'
|
||||||
|
# via click
|
||||||
|
flask==3.1.2
|
||||||
|
# via speed-logger
|
||||||
|
getmac==0.9.5
|
||||||
|
# via speed-logger
|
||||||
|
gunicorn==23.0.0
|
||||||
|
# via speed-logger
|
||||||
|
idna==3.11
|
||||||
|
# via requests
|
||||||
|
itsdangerous==2.2.0
|
||||||
|
# via flask
|
||||||
|
jinja2==3.1.6
|
||||||
|
# via flask
|
||||||
|
markupsafe==3.0.3
|
||||||
|
# via
|
||||||
|
# flask
|
||||||
|
# jinja2
|
||||||
|
# werkzeug
|
||||||
|
numpy==2.4.0
|
||||||
|
# via pandas
|
||||||
|
packaging==25.0
|
||||||
|
# via gunicorn
|
||||||
|
pandas==2.3.3
|
||||||
|
# via speed-logger
|
||||||
|
prometheus-client==0.23.1
|
||||||
|
# via speed-logger
|
||||||
|
python-dateutil==2.9.0.post0
|
||||||
|
# via pandas
|
||||||
|
pytz==2025.2
|
||||||
|
# via
|
||||||
|
# pandas
|
||||||
|
# speed-logger
|
||||||
|
requests==2.32.5
|
||||||
|
# via cloudflarepycli
|
||||||
|
six==1.17.0
|
||||||
|
# via python-dateutil
|
||||||
|
tzdata==2025.3
|
||||||
|
# via pandas
|
||||||
|
urllib3==2.6.2
|
||||||
|
# via requests
|
||||||
|
werkzeug==3.1.4
|
||||||
|
# via flask
|
||||||
Reference in New Issue
Block a user