Release v0.6.26: OpenBao settings synchronization with per-setting conflicts
This commit is contained in:
+70
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
#include "storage.h"
|
||||
#include <memory>
|
||||
|
||||
namespace ks
|
||||
{
|
||||
struct SyncConfig
|
||||
{
|
||||
bool enabled{};
|
||||
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<SyncHttpResponse(const std::wstring &method, const std::wstring &path,
|
||||
const std::wstring &token, const Bytes &body)>;
|
||||
// An injectable transport permits protocol regression tests without a live vault.
|
||||
std::unique_ptr<SyncProvider> 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<SyncConflict> &);
|
||||
std::vector<SyncConflict> decodeSyncConflicts(const Bytes &);
|
||||
Bytes encodeSyncChoices(const std::vector<SyncChoice> &);
|
||||
std::vector<SyncChoice> decodeSyncChoices(const Bytes &);
|
||||
std::wstring syncValueText(const Bytes &);
|
||||
struct SyncMerge
|
||||
{
|
||||
Bytes local, remote, base;
|
||||
std::vector<SyncConflict> conflicts;
|
||||
};
|
||||
SyncMerge mergeSyncProfile(const Bytes &base, const Bytes &local, const Bytes &remote,
|
||||
const std::vector<SyncChoice> &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<Layout> &);
|
||||
enum class SyncAction { Automatic, Download, Upload };
|
||||
struct SyncResult
|
||||
{
|
||||
bool success{};
|
||||
Bytes settings;
|
||||
uint64_t revision{};
|
||||
std::wstring status;
|
||||
Bytes base;
|
||||
std::vector<SyncConflict> conflicts;
|
||||
};
|
||||
SyncResult synchronize(SyncProvider &, const Bytes &base, const Bytes &local, SyncAction,
|
||||
const std::function<void(const Bytes &)> &validate = {}, const std::vector<SyncChoice> &choices = {});
|
||||
Bytes loadSyncBase(const std::filesystem::path &, const SyncConfig &);
|
||||
void saveSyncBase(const std::filesystem::path &, const SyncConfig &, const Bytes &);
|
||||
}
|
||||
Reference in New Issue
Block a user