First big step in moving towards DB storage instead of memory storage

This commit is contained in:
2025-09-03 18:28:08 +02:00
parent 5a7aa44d6c
commit 5ddafd3b98
5 changed files with 37 additions and 55 deletions

19
app.py
View File

@@ -5,8 +5,8 @@ from mem import services, app, db
import threading import threading
from flask_migrate import upgrade, stamp from flask_migrate import upgrade, stamp
from pathlib import Path from pathlib import Path
from models import service from models import service, log
from typing import Any, Optional, cast
# Init and upgrade # Init and upgrade
with app.app_context(): with app.app_context():
@@ -39,7 +39,20 @@ def homepage():
@app.route("/api/status") @app.route("/api/status")
def status(): def status():
return jsonify([s.to_dict() for s in services]) results: list[dict[str, Any]] = []
with app.app_context():
a = db.session.query(service).all()
for s in a:
b = cast(
Optional[log],
s.logs.order_by(
log.dateCreated.desc() # type: ignore
).first(),
)
if b:
results.append(s.to_dict() | b.to_dict())
return jsonify(results)
@app.route("/favicon.svg") @app.route("/favicon.svg")

View File

@@ -1,4 +1,4 @@
from typing import Any, Optional from typing import Any
from flask import Flask from flask import Flask
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate from flask_migrate import Migrate
@@ -7,12 +7,8 @@ from flask_migrate import Migrate
class service: class service:
id: int id: int
url: str url: str
status: Optional[int]
online: bool online: bool
public: bool public: bool
error: Optional[str]
ping: Optional[int]
icon_filetype: str
ping_type: int ping_type: int
def __init__( def __init__(
@@ -21,7 +17,6 @@ class service:
url: str = "", url: str = "",
label: str = "", label: str = "",
public: bool = True, public: bool = True,
icon_filetype: str = "svg",
ping_type: int = 0, ping_type: int = 0,
): ):
self.id = id self.id = id
@@ -30,38 +25,15 @@ class service:
self.label = label self.label = label
self.ping_type = ping_type self.ping_type = ping_type
self.online = False
self.status = None
self.error = None
self.ping = None
self.icon_filetype = icon_filetype
def to_dict(self) -> dict[str, Any]: def to_dict(self) -> dict[str, Any]:
return { return {
"url": self.url, "url": self.url,
"status": self.status,
"public": self.public, "public": self.public,
"online": self.online,
"error": self.error,
"ping": self.ping,
"label": self.label, "label": self.label,
"icon_filetype": self.icon_filetype,
"id": self.id, "id": self.id,
"ping_type": self.ping_type, "ping_type": self.ping_type,
} }
def set_status(self, status: Optional[int]):
self.status = status
def set_online(self, b: bool):
self.online = b
def set_error(self, s: Optional[str]):
self.error = s
def set_ping(self, n: Optional[int]):
self.ping = n
services: list[service] = [ services: list[service] = [
service(0, "https://git.ihatemen.uk/", "Gitea"), service(0, "https://git.ihatemen.uk/", "Gitea"),

View File

@@ -75,18 +75,18 @@
// Build all service divs as a single string // Build all service divs as a single string
main_body.innerHTML = services.map(s => ` main_body.innerHTML = services.map(s => `
<a href="${s.url}" class="d-block text-body text-decoration-none m-2 border border-3 ${s.online ? 'border-success' : 'border-danger'}" style="width: 175px"> <a href="${s.url}" class="d-block text-body text-decoration-none m-2 border border-3 ${s.ping ? 'border-success' : 'border-danger'}" style="width: 175px">
<div class="bg-body-tertiary d-flex flex-column align-items-center"> <div class="bg-body-tertiary d-flex flex-column align-items-center">
<div class="bg-dark w-100"> <div class="bg-dark w-100">
<h4 class="text-center text-truncate m-0 p-1">${s.label}</h4> <h4 class="text-center text-truncate m-0 p-1">${s.label}</h4>
</div> </div>
<div class="position-relative ratio ratio-1x1"> <div class="position-relative ratio ratio-1x1">
<div class="d-flex justify-content-center align-items-center"> <div class="d-flex justify-content-center align-items-center">
<img src="static/icons/${s.id}.${s.icon_filetype}" class="img-fluid w-75"> <img src="static/icons/${s.service_id - 1}.svg" class="img-fluid w-75">
</div> </div>
<div> <div>
${s.public ? `` : `<img src='static/lock.svg' class='img-fluid position-absolute bottom-0 end-0 w-25'>`} ${s.public_access ? `` : `<img src='static/lock.svg' class='img-fluid position-absolute bottom-0 end-0 w-25'>`}
<div class="position-absolute bottom-0 text-body bg-dark bg-opacity-75 px-1 rounded">${s.online ? s.ping + "ms" : ""}</div> <div class="position-absolute bottom-0 text-body bg-dark bg-opacity-75 px-1 rounded">${s.ping ? s.ping + "ms" : ""}</div>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -21,6 +21,14 @@ class log(db.Model):
self.dateCreated = datetime.now(timezone.utc) self.dateCreated = datetime.now(timezone.utc)
def to_dict(self) -> dict[str, Any]:
return {
"log_id": self.id,
"service_id": self.service_id,
"ping": self.ping,
"dateCreated": self.dateCreated,
}
class service(db.Model): class service(db.Model):
id: int = db.Column(db.Integer, primary_key=True) # TODO: Switch to UUID id: int = db.Column(db.Integer, primary_key=True) # TODO: Switch to UUID
@@ -29,7 +37,7 @@ class service(db.Model):
public_access: bool = db.Column(db.Boolean, nullable=False) public_access: bool = db.Column(db.Boolean, nullable=False)
ping_method: int = db.Column(db.Integer, nullable=False) ping_method: int = db.Column(db.Integer, nullable=False)
logs = db.relationship("log") logs = db.relationship("log", lazy="dynamic")
def __init__( def __init__(
self, url: str, label: str, public_access: bool, ping_method: int self, url: str, label: str, public_access: bool, ping_method: int
@@ -49,6 +57,6 @@ class service(db.Model):
"url": self.url, "url": self.url,
"public_access": self.public_access, "public_access": self.public_access,
"label": self.label, "label": self.label,
"id": self.id, "service_id": self.id,
"ping_method": self.ping_method, "ping_method": self.ping_method,
} }

View File

@@ -28,25 +28,14 @@ async def check_service(client: aiohttp.ClientSession, s: service) -> log:
case _: case _:
raise Exception("UNKNOWN PING TYPE") raise Exception("UNKNOWN PING TYPE")
after = time.perf_counter() after = time.perf_counter()
s.set_error(None) if r.status == 200:
s.set_online(r.status == 200) return log(service_id=s.id + 1, ping=int((after - before) * 1000))
s.set_status(r.status)
if r.status != 200:
s.set_ping(None)
else: else:
s.set_ping(int((after - before) * 1000)) return log(service_id=s.id + 1, ping=None)
except aiohttp.ConnectionTimeoutError: except aiohttp.ConnectionTimeoutError:
s.set_error("Connection Timeout") return log(service_id=s.id + 1, ping=None)
s.set_online(False) except Exception:
s.set_status(None) return log(service_id=s.id + 1, ping=None)
s.set_ping(None)
except Exception as e:
print(type(e))
s.set_error(str(e))
s.set_online(False)
s.set_status(None)
s.set_ping(None)
return log(service_id=s.id, ping=s.ping)
def start_async_loop(): def start_async_loop():