Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions backend/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from pathlib import Path
from datetime import datetime
import re

from fastapi import FastAPI, Depends, Request
from fastapi.middleware.cors import CORSMiddleware
Expand Down Expand Up @@ -53,6 +54,27 @@ def get_db():
db.close()


def _ping(host: str) -> float | None:
"""Return the ping time to ``host`` in milliseconds.

Returns ``None`` if the command fails or the output cannot be parsed.
"""
try:
result = subprocess.run(
["ping", "-c", "1", host],
capture_output=True,
text=True,
timeout=5,
)
if result.returncode == 0:
match = re.search(r"time[=<]([0-9.]+) ms", result.stdout)
if match:
return float(match.group(1))
except Exception:
pass
return None


@app.get("/", response_class=HTMLResponse, include_in_schema=False)
def read_root(request: Request, db: Session = Depends(get_db)):
"""Default homepage.
Expand All @@ -65,6 +87,10 @@ def read_root(request: Request, db: Session = Depends(get_db)):
client_ip = request.client.host
data = {"client_ip": client_ip, "test_target": "default"}

ping_ms = _ping(client_ip)
if ping_ms is not None:
data["ping_ms"] = ping_ms

try:
resp = requests.get(f"https://ipapi.co/{client_ip}/json/")
if resp.ok:
Expand Down Expand Up @@ -138,6 +164,12 @@ def create_test(
except Exception:
pass

if not data.get("ping_ms"):
host = data.get("test_target") or client_ip
ping_ms = _ping(host)
if ping_ms is not None:
data["ping_ms"] = ping_ms

db_record = models.TestRecord(**data)
db.add(db_record)
db.commit()
Expand Down
3 changes: 2 additions & 1 deletion backend/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,14 @@ <h1>Your Connection Info</h1>
{% if info.location %}<li>Location: {{ info.location }}</li>{% endif %}
{% if info.asn %}<li>ASN: {{ info.asn }}</li>{% endif %}
{% if info.isp %}<li>ISP: {{ info.isp }}</li>{% endif %}
{% if info.ping_ms %}<li>Ping: {{ '%.2f'|format(info.ping_ms) }} ms</li>{% endif %}
<li>Recorded at: {{ info.timestamp|short_ts }}</li>
</ul>

<h2>Recent Tests</h2>
<ul>
{% for r in records %}
<li>{{ r.client_ip|mask_ip }}{% if r.location %} - {{ r.location }}{% endif %} - {{ r.timestamp|short_ts }}</li>
<li>{{ r.client_ip|mask_ip }}{% if r.location %} - {{ r.location }}{% endif %}{% if r.ping_ms %} - {{ '%.2f'|format(r.ping_ms) }} ms{% endif %} - {{ r.timestamp|short_ts }}</li>
{% endfor %}
</ul>

Expand Down
4 changes: 4 additions & 0 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ function App() {
)}
{info.asn && <div>ASN: {info.asn}</div>}
{info.isp && <div>ISP: {info.isp}</div>}
{typeof info.ping_ms === 'number' && (
<div>Ping: {info.ping_ms.toFixed(2)} ms</div>
)}
<div className="text-sm text-gray-400">
Recorded at: {new Date(info.timestamp).toLocaleString()}
</div>
Expand All @@ -109,6 +112,7 @@ function App() {
<li key={r.id}>
{maskIp(r.client_ip)}
{r.location && r.location !== 'Unknown' && ` - ${r.location}`} -{' '}
{typeof r.ping_ms === 'number' && `${r.ping_ms.toFixed(2)} ms - `}
{new Date(r.timestamp).toLocaleString()}
</li>
))}
Expand Down