// SPDX-License-Identifier: MIT // Copyright (c) 2026 Thibault Ducray // // This file is part of MyPwdTool's open-source sync/encryption core — see // LICENSE-SYNC-CRYPTO.md at the repo root and https://mypwdtool.com/open-source/. // The rest of this application is proprietary and NOT covered by this license. package fr.tducray.mypwdtool.sync import fr.tducray.mypwdtool.vault.Entry import java.util.UUID /** * Port of `Sync/SyncOutbox.swift` — a trivial in-memory FIFO, deliberately not persisted (the * local vault DB is the source of truth). Not just "requeued next time that entry changes" — * SyncManager's poll loop also retries a non-empty outbox on every tick now (added 2026-09-05: * previously the outbox was *only* ever drained in direct response to enqueueUpsert/enqueueDelete, * so if the very first drain attempt's guards failed — e.g. peers not yet populated right after a * fresh join — the items sat stuck forever with nothing to retry them until an unrelated edit * happened to touch the outbox again; reproduced live importing a backup immediately after * joining a sync group, entries never reached the other device). */ class SyncOutbox { data class Item(val op: SyncOp, val entryId: UUID, val updatedAt: String, val entry: Entry?) private val lock = Object() private val items = mutableListOf() fun enqueue(item: Item) { synchronized(lock) { items.add(item) } } fun drain(): List = synchronized(lock) { val drained = items.toList() items.clear() drained } val isEmpty: Boolean get() = synchronized(lock) { items.isEmpty() } }