#pragma once #include "storage.h" #include namespace ks { struct SyncConfig { bool enabled{}; bool keepLocalLayouts{}; std::wstring provider = L"openbao", server, mount = L"kswitcher", path = L"personal/settings", authMount = L"userpass", username; bool operator==(const SyncConfig &) const = default; }; bool syncVisible(const std::filesystem::path &); SyncConfig loadSyncConfig(const std::filesystem::path &); void saveSyncConfig(const std::filesystem::path &, const SyncConfig &); void validateSyncConfig(const SyncConfig &); void saveSyncPassword(const SyncConfig &, const std::wstring &); void forgetSyncPassword(const SyncConfig &); struct SyncDocument { uint64_t revision{}; Bytes settings; }; class SyncProvider { public: virtual ~SyncProvider() = default; virtual SyncDocument read() = 0; virtual uint64_t write(const Bytes &, uint64_t expectedRevision) = 0; }; struct SyncHttpResponse { unsigned status{}; Bytes body; }; using SyncTransport = std::function; // An injectable transport permits protocol regression tests without a live vault. std::unique_ptr makeSyncProvider(const SyncConfig &, SyncTransport transport = {}); inline constexpr ULONGLONG SyncIntervalMs = 10 * 60 * 1000; struct SyncConflict { std::string key; std::wstring label; Bytes local, remote; }; struct SyncChoice { SyncConflict conflict; bool useLocal{}; }; Bytes encodeSyncConflicts(const std::vector &); std::vector decodeSyncConflicts(const Bytes &); Bytes encodeSyncChoices(const std::vector &); std::vector decodeSyncChoices(const Bytes &); std::wstring syncValueText(const Bytes &); struct SyncMerge { Bytes local, remote, base; std::vector conflicts; }; SyncMerge mergeSyncProfile(const Bytes &base, const Bytes &local, const Bytes &remote, const std::vector &choices = {}); Bytes mergeSyncSettings(const Bytes &base, const Bytes &local, const Bytes &remote); Bytes sharedSyncSettings(const Settings &); Settings restoreSyncSettings(const Bytes &, const Settings &, const std::vector &, bool keepLocalLayouts = false); enum class SyncAction { Automatic, Download, Upload }; struct SyncResult { bool success{}; Bytes settings; uint64_t revision{}; std::wstring status; Bytes base; std::vector conflicts; }; SyncResult synchronize(SyncProvider &, const Bytes &base, const Bytes &local, SyncAction, const std::function &validate = {}, const std::vector &choices = {}, bool keepLocalLayouts = false); Bytes loadSyncBase(const std::filesystem::path &, const SyncConfig &); void saveSyncBase(const std::filesystem::path &, const SyncConfig &, const Bytes &); }