-
-
Notifications
You must be signed in to change notification settings - Fork 312
Add playtime tracking backend #4108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
evertonstz
wants to merge
17
commits into
bottlesdevs:main
Choose a base branch
from
evertonstz:add-playtime-tracking-backend
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Add playtime tracking backend #4108
evertonstz
wants to merge
17
commits into
bottlesdevs:main
from
evertonstz:add-playtime-tracking-backend
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…ineProgram Enhance the WineCommand and WineProgram classes to accept pre-run and post-run script arguments. Update the UI to include fields for these arguments in the launch options dialog.
…andling in WineExecutor
…lass handling in yaml utility
…ript arguments in launch options dialog
…ssFinishedPayload for improved clarity and structure.
…se shutdown on exit
…and WinePath, improving test clarity and maintainability.
… enabling tracking and setting heartbeat interval.
…uirements.dev.txt
|
Hi, sorry for the delay, would be better if they were 2 separated MRs. Also because the one dedicated to playtime tracking, could be a general one, including both frontend and backend. Do you like the idea? Code looks good but I did not test it yet. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Backend work to implement this request #1273
Used my previous PR as base #4102, I can try to separate them if needed
Playtime Tracking – Backend PR
Summary
This PR introduces robust, low-overhead playtime tracking to Bottles’ backend. It records per-program sessions, maintains a fast aggregate table for the UI, and is resilient to crashes and concurrent sessions. The solution is event-driven (signals), easy to toggle via GSettings, and thoroughly tested.
Motivation
Design Overview
Core tracker:
ProcessSessionTracker(bottles/backend/managers/playtime.py)$XDG_DATA_HOME/bottles/process_metrics.sqlitesessions(history) andplaytime_totals(materialized aggregate)last_seenperiodicallylast_seenEvent-driven lifecycle:
bottles/backend/state.py:Signals.ProgramStartedSignals.ProgramFinishedbottles/backend/models/process.py:ProcessStartedPayloadProcessFinishedPayload(status: Literal["success", "unknown"])WineExecutoremits these signals instead of calling the tracker directlyManagersubscribes to signals and calls the trackerPublic backend API consistency
Manager.playtime_start(...) -> Result[int]andManager.playtime_finish(...) -> Result[None]Result[T]Concurrency & durability
Manager)_lockguards all DB operations and_trackedupdates-walatexithandler ensures shutdown on normal process exitReliability & WAL behavior
PRAGMA wal_checkpoint(TRUNCATE)to avoid lingering-wal-walcan remain; SQLite replays it on next open. The tracker can also checkpoint at startup if neededRisks & Mitigations
-walon disk: mitigated by a final checkpoint on shutdown and automatic WAL replay by SQLite on next open, guarantees the db wont be written until next reconciliation_lockserializes connection usage; atomic finalization prevents torn updatesData Model
Schema is created on-demand by the tracker (
_ensure_schema()):sessions(history)id,bottle_id,bottle_name,bottle_path,program_id,program_name,program_path,started_at(epoch),ended_at(epoch),last_seen(epoch),duration_seconds,status(running|success|crash|forced|unknown)(bottle_id, program_id),(status)(bottle_id, program_id, started_at)playtime_totals(materialized aggregate)bottle_id,bottle_name,program_id,program_name,program_path,total_seconds,sessions_count,last_played(bottle_id, program_id)last_played DESCNotes:
program_id = sha1(f"{bottle_id}:{program_path}")to handle rename scenarios(bottle_id, program_id)again while running returns the existing session instead of inserting a new oneSettings (GSettings)
playtime-enabled(default: true): master toggleplaytime-heartbeat-interval(seconds, default: 60)Backend reads these in
Managerat startup. UI toggle is planned for Phase 3.Tests
Unit and integration tests added/updated:
ProgramStarted/Finishedand assert sessions/totalsManagerDev dependencies (tests)
mockerfixture for stubbing without verbose manual monkeypatching.PSA
This description was originally written in portuguese and translated by AI
Manual testing
I've been testing this for a couple of days and monitoring the database while simulating scenarios like force closes (inter bottle and multiple apps in same bottle), resets and day-to-day gaming, for now the tracking is spot-on and the heartbeat system is working flawlessly
I mainly work with distributed systems and have minimal experience developing desktop apps, so feel free to change anything in the code!