feat(sync): add Microsoft Graph read adapter
Add strict /me identity, atomic paged calendar discovery, and resumable primary-calendar v1 delta synchronization through the durable provider cache. Keep opaque continuations on trusted Graph URLs and retain credentials only per operation. Document that stable Graph v1 delta covers only the primary calendar; secondary calendars still require a v1 reconciliation or beta dependency decision. Verified: 18/18 normal, 18/18 -Werror, and 18/18 ASan/UBSan tests.
This commit is contained in:
59
include/nocal/sync/microsoft_graph.hpp
Normal file
59
include/nocal/sync/microsoft_graph.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include "nocal/storage/sync_cache.hpp"
|
||||
#include "nocal/sync/http.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace nocal::sync {
|
||||
|
||||
// Per-operation credentials for Microsoft Graph. The adapter never retains the
|
||||
// access token after the public operation returns.
|
||||
struct MicrosoftGraphCredentials {
|
||||
std::string account_id;
|
||||
std::string access_token;
|
||||
};
|
||||
|
||||
// A half-open UTC calendar window. Values are Unix epoch microseconds and are
|
||||
// serialized canonically before they become part of a durable checkpoint.
|
||||
struct MicrosoftGraphWindow {
|
||||
std::int64_t start_epoch_microseconds{0};
|
||||
std::int64_t end_epoch_microseconds{0};
|
||||
};
|
||||
|
||||
class MicrosoftGraphError : public std::runtime_error {
|
||||
public:
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
// 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.
|
||||
class MicrosoftGraphSync {
|
||||
public:
|
||||
MicrosoftGraphSync(HttpTransport& transport, storage::SyncCache& cache);
|
||||
|
||||
// Requires delegated User.Read. A complete and validated /me response is
|
||||
// persisted atomically; failures leave the cached account unchanged.
|
||||
storage::CachedAccount refresh_account(const MicrosoftGraphCredentials& credentials);
|
||||
|
||||
// Requires delegated Calendars.Read. Pagination is completed before the
|
||||
// cache listing is replaced, so a partial listing never deactivates data.
|
||||
void refresh_calendars(const MicrosoftGraphCredentials& credentials);
|
||||
|
||||
// Requires delegated Calendars.Read. Each validated page and its opaque
|
||||
// next/delta URL are committed in one cache transaction. A later-page
|
||||
// failure therefore resumes from the last committed cursor. Only HTTPS
|
||||
// continuations on graph.microsoft.com are accepted.
|
||||
void sync_primary_calendar_window(const MicrosoftGraphCredentials& credentials,
|
||||
const MicrosoftGraphWindow& window);
|
||||
|
||||
private:
|
||||
HttpTransport& transport_;
|
||||
storage::SyncCache& cache_;
|
||||
};
|
||||
|
||||
} // namespace nocal::sync
|
||||
Reference in New Issue
Block a user