feat(sync): reconcile secondary Graph calendars
Read documented Graph v1 calendarView pages for secondary calendars and publish each finite window only after the complete bounded listing validates. Add schema-v2 per-window event membership so moved-out occurrences are evicted without being mislabeled as remote tombstones, while overlapping windows retain shared instances. Verified: 18/18 fresh normal, 18/18 -Werror, and 18/18 ASan/UBSan tests.
This commit is contained in:
@@ -76,6 +76,16 @@ struct PullPage {
|
||||
bool operator==(const PullPage&) const = default;
|
||||
};
|
||||
|
||||
// A provider's complete view of one finite calendar window. Membership is
|
||||
// replaced only after the provider listing has completed successfully.
|
||||
struct CompleteWindow {
|
||||
std::vector<CachedEvent> events;
|
||||
std::vector<CachedEventInstance> instances;
|
||||
SyncCheckpoint checkpoint;
|
||||
|
||||
bool operator==(const CompleteWindow&) const = default;
|
||||
};
|
||||
|
||||
struct CacheSnapshot {
|
||||
std::vector<CachedAccount> accounts;
|
||||
std::vector<CachedCalendar> calendars;
|
||||
@@ -88,7 +98,7 @@ struct CacheSnapshot {
|
||||
|
||||
class SyncCache {
|
||||
public:
|
||||
static constexpr int current_schema_version = 1;
|
||||
static constexpr int current_schema_version = 2;
|
||||
|
||||
explicit SyncCache(std::filesystem::path path);
|
||||
~SyncCache();
|
||||
@@ -112,6 +122,12 @@ public:
|
||||
// events retain their last raw payload and have no instances.
|
||||
void apply_pull_page(const PullPage& page);
|
||||
|
||||
// Atomically replaces membership for one complete, finite provider window.
|
||||
// Returned events become live and have their instances replaced. Events
|
||||
// omitted from the window lose cached instances only when no other complete
|
||||
// window references them; omission is not treated as a remote tombstone.
|
||||
void replace_complete_window(const CompleteWindow& window);
|
||||
|
||||
[[nodiscard]] CacheSnapshot snapshot() const;
|
||||
|
||||
private:
|
||||
|
||||
@@ -29,9 +29,9 @@ public:
|
||||
};
|
||||
|
||||
// Read-only Microsoft Graph v1.0 synchronization. Calendar discovery covers
|
||||
// every calendar returned by /me/calendars. Stable v1.0 event delta is exposed
|
||||
// only for the signed-in user's primary calendar; this class deliberately does
|
||||
// not call beta or undocumented per-calendar delta routes.
|
||||
// every calendar returned by /me/calendars. Stable v1.0 event delta is used for
|
||||
// the primary calendar and complete calendarView reconciliation for secondary
|
||||
// calendars; this class does not call beta or undocumented delta routes.
|
||||
class MicrosoftGraphSync {
|
||||
public:
|
||||
MicrosoftGraphSync(HttpTransport& transport, storage::SyncCache& cache);
|
||||
@@ -51,6 +51,12 @@ public:
|
||||
void sync_primary_calendar_window(const MicrosoftGraphCredentials& credentials,
|
||||
const MicrosoftGraphWindow& window);
|
||||
|
||||
// Reads every page of the documented Graph v1.0 calendarView for one
|
||||
// active, non-primary calendar. The cache window is replaced only after the
|
||||
// listing completes, so a failed or malformed page leaves it unchanged.
|
||||
void sync_secondary_calendar_window(const MicrosoftGraphCredentials& credentials,
|
||||
std::string calendar_id, const MicrosoftGraphWindow& window);
|
||||
|
||||
private:
|
||||
HttpTransport& transport_;
|
||||
storage::SyncCache& cache_;
|
||||
|
||||
Reference in New Issue
Block a user