Commit graph

25 commits

Author SHA1 Message Date
Lukas Brübach
80ca738541 [DeckSync] Move the client signal handlers out of the constructor lambdas 2026-11-08 19:49:39 +01:00
Lukas Brübach
d1d4c70999 [DeckSync] Drop ineffective UniqueConnection flags on lambda connects 2026-11-08 19:49:39 +01:00
Lukas Brübach
068c388a80 [DeckSync] Address auto-sync review: disconnect, backfill and modal conflicts
- Fail the run when the connection drops while a sync is running, and clear
  the active conflict, so the queue is not sent on a dead client and a
  re-login as another account never receives this profile's uploads.
- Backfill last_modified from upload_time in the 37 -> 38 migration and drop
  the "last_modified is null" arm from the sync-check query, so rows that
  predate the column stop reporting as changed on every poll.
- Skip conflicts during auto runs and report how many were skipped, instead
  of opening the modal conflict dialog from a timer or a file-watcher event.
2026-11-08 19:49:39 +01:00
Lukas Brübach
5a550a57ba Fix ZeldaZach review for PR 7496: deck path in ctor, server-time baseline, single-query sync check 2026-11-08 19:49:39 +01:00
Lukas Brübach
ff695d265d [Client+Server] Auto deck sync with change polling 2026-11-08 19:49:39 +01:00
BruebachL
b10abad3a3 Apply suggestion from @ZeldaZach
Co-authored-by: Zach H <zahalpern+github@gmail.com>
2026-11-08 19:49:32 +01:00
BruebachL
b611e8ea6f Apply suggestion from @ZeldaZach
Co-authored-by: Zach H <zahalpern+github@gmail.com>
2026-11-08 19:49:32 +01:00
Lukas Brübach
26ffd1cfae Address review findings 2026-11-08 19:49:32 +01:00
Lukas Brübach
f8c2e1105a [DeckSync] Address conflict review nits: enum class and designated initializers 2026-11-08 19:49:32 +01:00
Lukas Brübach
9d93a39980 Fix remaining review threads on the conflict classification
- Remove the duplicated download loop and the stray '<' plus extra brace
  that left the head unbuildable.
- Skip the fallback upload under DownloadMode so a local-only deck is not
  pushed when the user asked for downloads only.
- Treat a server row without a hash as unknown rather than changed, so
  pre-migration decks are not re-downloaded on every sync.
2026-11-08 19:49:32 +01:00
Lukas Brübach
1dc6b81f8b Fix ZeldaZach review for PR 7495: three-way baseHash check before conflict 2026-11-08 19:49:32 +01:00
Lukas Brübach
dae947aeeb [Client] Sync conflict dialog, onboarding and conflict default 2026-11-08 19:49:32 +01:00
Lukas Brübach
d0cd13fce7 [DeckSync] Drop the queued download when a local delete wins
The unmatched-server-rows pass queued a download for every row with no
local file, including rows whose sidecar record is being deleted in the
same run. The delete ran first, so the download then failed with
NameNotFound and the summary reported a clean delete as removed plus
skipped. Cancel the pending download for the deleted row id instead; a
failed delete keeps it, which preserves the restore-the-file fallback.
2026-11-08 19:49:22 +01:00
Lukas Brübach
885b7f82ae Address review findings 2026-11-08 19:49:22 +01:00
Lukas Brübach
34e28dfa22 [DeckSync] Address tombstone review nits: log category and designated initializer 2026-11-08 19:49:22 +01:00
Lukas Brübach
70b75018be [DeckSync] Address tombstone review: remote deletes, revival and purge clock
- Treat a record whose server row is gone as a remote delete only when the
  local file still matches the sidecar's base hash. An edit made after the
  remote delete is newer than the delete, so it uploads and revives the row
  instead of being removed.
- Revive a tombstone with the same user and guid in cmdDeckUpload instead of
  inserting a second row next to it, so the deck keeps its id and version
  history and the promise in servatrice.ini.example holds.
- Run tombstone purging on its own clock, driven by the new
  [deck_sync] purge_interval option, so disabling share cleanup no longer
  disables purging silently.
- Write the base snapshot through QSaveFile and log a failed commit, so a
  crash or a full disk cannot leave a truncated base for DeckDiff::merge().
2026-11-08 19:49:22 +01:00
Lukas Brübach
4f715b0800 Fix ZeldaZach review for PR 7494: match by remoteId/guid before remote-delete, only tombstone when file truly missing 2026-11-08 19:49:22 +01:00
Lukas Brübach
674547fca0 [Server+Client] Tombstone deck deletes with purge and base snapshots 2026-11-08 19:49:22 +01:00
Lukas Brübach
6eef7a6849 Address review findings 2026-11-08 16:18:10 +01:00
Lukas Brübach
997eee835e [DeckSync] Match server rows by identity and hash the whole deck
Sync keyed local files to server rows by path, but the server names a row
after the deck, not after the file, so any deck whose file name and deck name
differ uploaded again on every run. A second pass then brought the server copy
back as an extra local file.

- Match by the sidecar's row id, then guid, then content, and only then by the
  server path, so renaming either side no longer duplicates a deck.
- Key the server tree by row id: the server allows several rows with the same
  name in one folder, and keying by path silently dropped all but one.
- Stop discarding rows whose name contains '/' ("U/W Control"). They stay
  matchable, and only the download file name is sanitised.
- Build the download path from the folder plus a sanitised row name, including
  every folder segment, so a hostile server name cannot escape the deck folder.
- Download a colliding server row under a unique name and count it, instead of
  skipping it without a trace.
- Hash the whole deck instead of the card hash: SHA-1 over the native deck
  string covers name, printings, banner, tokens and sideboard plans. The client
  and the server hash the exact bytes they exchange, so both agree.

Adds deck_content_hash_test for the client/server hashing invariant and for the
name-only change the card hash cannot see.
2026-11-07 23:49:18 +01:00
Lukas Brübach
cc89c32191 [DeckSync] Pass the sync summary through the signal and tidy the manager API
- Emit SyncSummary from syncFinished() instead of four positional ints, and
  build it from a single currentSummary() helper, so the counts cannot drift
  between the status message and the signal.
- Use a designated initializer for LocalFile, like the other records.
- Drop setClient() and setColorIdentityProvider(): both fields are already
  constructor parameters and the setters had no callers. setProfile() and
  setDeckPath() stay, since the tab re-reads them before every run.
- Fix the include paths in tab_deck_storage.h and the narrowing conversion of
  the tree item id, so the branch builds again.
2026-11-07 23:49:18 +01:00
BruebachL
c2a1508a2e [DeckSync] Use designated initializer for ServerFile per review 2026-11-07 23:48:56 +01:00
BruebachL
2db9760170 [DeckSync] Prefer ctor params for set-once client/provider per review 2026-11-07 23:48:56 +01:00
Lukas Brübach
1cac2ae7b2 Fix ZeldaZach review for PR 7493: match uploads by sidecar remoteId/guid, validate server paths 2026-11-07 23:24:52 +01:00
Lukas Brübach
53c15b1298 [Client] Manual deck collection sync with Sync Now action 2026-11-07 23:24:52 +01:00