Add global presence heartbeat and online tracking

This commit is contained in:
2026-02-26 10:53:56 +01:00
parent 60442b4335
commit 5eeef54e46
6 changed files with 56 additions and 1 deletions
+2
View File
@@ -27,10 +27,12 @@ def create_app():
from .routes.auth import auth_bp
from .routes.main import main_bp
from .routes.friends import friends_bp
from .routes.presence import presence_bp
app.register_blueprint(main_bp)
app.register_blueprint(auth_bp)
app.register_blueprint(friends_bp)
app.register_blueprint(presence_bp)
init_db(app)
+9
View File
@@ -66,4 +66,13 @@ def init_db(app):
);
"""
)
# Lightweight migration support for existing databases.
user_columns = {
row["name"]
for row in db.execute("PRAGMA table_info(users)").fetchall()
}
if "last_seen_at" not in user_columns:
db.execute("ALTER TABLE users ADD COLUMN last_seen_at TIMESTAMP")
db.commit()
+24
View File
@@ -0,0 +1,24 @@
from flask import Blueprint, jsonify
from flask_login import login_required, current_user
from app.db import get_db
presence_bp = Blueprint("presence", __name__)
def _mark_current_user_online() -> None:
db = get_db()
db.execute(
"UPDATE users SET last_seen_at = CURRENT_TIMESTAMP WHERE id = ?",
(current_user.id,),
)
db.commit()
@presence_bp.route("/api/presence/ping", methods=["POST"])
@login_required
def presence_ping():
if not current_user.is_authenticated: # should not happen due to @login_required, but just in case
return ("", 204)
_mark_current_user_online()
return jsonify({"status": "ok"})
+18
View File
@@ -0,0 +1,18 @@
(function startPresenceHeartbeat() {
const ping = function () {
fetch("/api/presence/ping", {
method: "POST",
credentials: "same-origin",
keepalive: true,
headers: {
"Content-Type": "application/json",
},
body: "{}",
}).catch(function () {
// ignore network issues; next interval will retry
});
};
ping();
setInterval(ping, 15000);
})();
+1
View File
@@ -49,5 +49,6 @@
{% endif %} {% endwith %} {% block content %}{% endblock %}
</main>
</div>
<script src="{{ url_for('static', filename='js/presence.js') }}"></script>
</body>
</html>
+1
View File
@@ -20,5 +20,6 @@
</div>
{% endif %} {% endwith %} {% block content %}{% endblock %}
</main>
<script src="{{ url_for('static', filename='js/presence.js') }}"></script>
</body>
</html>