blob: 070bc2007ce51f6e1bd2054fdaf23347f25307e7 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library fuchsia.ledger.cloud;
using fuchsia.mem;
// This file defines a cloud service that can be used by Ledger to power cloud
// sync.
/// Identifier for a commit, controlled by Ledger.
using CommitIdentifier = bytes:128;
/// Identifier for an object, controlled by Ledger.
using ObjectIdentifier = bytes:128;
/// Identifier for an entry, controlled by Ledger.
using EntryIdentifier = bytes:64;
/// Fingerprint, controlled by Ledger and used to watch for cloud erasure.
using Fingerprint = bytes:32;
/// Response status for cloud provider operations.
enum Status : int32 {
OK = 0;
AUTH_ERROR = 1;
ARGUMENT_ERROR = 2;
INTERNAL_ERROR = 3;
NETWORK_ERROR = 4;
NOT_FOUND = 5;
PARSE_ERROR = 6;
SERVER_ERROR = 7;
NOT_SUPPORTED = 8;
UNKNOWN_ERROR = -1;
};
/// Cloud service that powers cloud sync for a single user. Top-level interface
/// of this file.
///
/// Closing the client connection to CloudProvider shuts down all controllers
/// (DeviceSets, PageClouds) that were produced by it.
[Discoverable]
protocol CloudProvider {
/// Retrieves the controller for the user device set.
GetDeviceSet(request<DeviceSet> device_set) -> (Status status);
/// Retrieves the controller for cloud sync of a particular page.
GetPageCloud(bytes app_id, bytes page_id, request<PageCloud> page_cloud)
-> (Status status);
};
/// Cloud registry of devices participating in cloud sync.
///
/// Closing the client connection to DeviceSet disconnects all watchers set on
/// it.
protocol DeviceSet {
/// Verifies that the device fingerprint in the cloud is still in the list of
/// devices, ensuring that the cloud was not erased since the last sync.
CheckFingerprint(Fingerprint fingerprint) -> (Status status);
/// Adds the device fingerprint to the list of devices in the cloud.
SetFingerprint(Fingerprint fingerprint) -> (Status status);
/// Watches the given `fingerprint` in the cloud so that `watcher` is notified
/// when the fingerprint is erased.
///
/// At most one watcher can be set at any given time. If more than one watcher
/// is set, only the one set most recently receives notifications.
///
/// The returned status is:
///
/// - OK, if setting the watcher succeeded,
/// - `NOT_FOUND`, if the fingerprint was not found in the cloud
/// - `NETWORK_ERROR`, if the watcher couldn't be set due to a network error
///
/// If the returned status is not OK, the corresponding error call is also made
/// on the watcher.
SetWatcher(Fingerprint fingerprint, DeviceSetWatcher watcher)
-> (Status status);
/// Erases the entire registry of devices. This makes all devices detect that
/// cloud has been erased.
Erase() -> (Status status);
};
/// Watcher for push notifications from the cloud registry of devices
/// participating in cloud sync.
protocol DeviceSetWatcher {
/// Called when cloud provider detects that the cloud storage was erased. No
/// further calls are made on the watcher after this is called.
OnCloudErased();
/// Called when an error occured. Most common errors are:
/// - `NOT_FOUND`, if the fingerprint was not found in the cloud when registering the watcher.
/// - `NETWORK_ERROR` if the network connection is lost.
///
/// No further calls are made on the watcher after this is called.
OnError(Status status);
};
/// Contains a Buffer containing the FIDL serialization of Commits.
struct CommitPack {
fuchsia.mem.Buffer buffer;
};
/// An opaque representation of a position in the stream of commits handled by
/// a PageCloud instance.
struct PositionToken {
bytes opaque_id;
};
/// A commit as seen by the cloud.
table Commit {
/// A unique commit identifier, chosen by Ledger. Required.
///
/// Two commits uploaded with the same identifier are to be considered
/// identical: they will have the same parents if present, and the cloud may
/// return the data and the diff from any of the uploads.
1: CommitIdentifier id;
/// Opaque data stored by Ledger. Required.
2: bytes data;
/// A diff describing the content of the page at this commit. Optional.
///
/// Ledger will not send a diff for all commits: it may omit the diff when it
/// determines the content of the commit will not be used by any other Ledger
/// instance. During the transition to diffs, diff-unaware Ledgers will also
/// omit the diff.
/// The cloud provider should not include diffs in the commits it sends to
/// Ledger.
// TODO(LE-823): update once the transition to diffs is complete.
3: Diff diff;
};
/// Specification of a page state used as base for a diff.
xunion PageState {
/// The state is the empty page.
EmptyPage empty_page;
/// The state is the content of a page at the commit with the given
/// identifier.
CommitIdentifier at_commit;
};
struct EmptyPage {
};
/// A diff from a base state to a commit.
///
/// Diffs are sequences of insertions and deletions. Updates are encoded as a
/// deletion followed by an insertion. The cloud can match insertions and
/// deletions by an entry identifier chosen by Ledger (because of encryption,
/// the data will not match between insertions and deletions).
table Diff {
/// Page state used as a reference point for the diff.
///
/// Ledger only uses as base state a commit that is already known to the
/// cloud, or the empty page.
1: PageState base_state;
/// List of changes from the base state to the commit.
///
/// The changes are to be applied in order.
2: vector<DiffEntry>:MAX changes;
};
/// An entry in a Diff.
table DiffEntry {
/// Identifier of the entry. Required.
1: EntryIdentifier entry_id;
/// Insertion or deletion. Required.
2: Operation operation;
/// Data representing the content of the entry.
///
/// Required in diffs sent from Ledger. The cloud provider may omit this
/// information if the operation is a deletion. If an entry id was inserted/
/// deleted multiple times, the cloud provider can send any of the values.
3: bytes:512 data;
/// An optional reference to an object, given by its identifier.
///
/// Sent by Ledger when the value of the entry is not inlined in the `data`
/// field. The cloud provider may always omit this field in diffs.
4: ObjectIdentifier reference;
};
enum Operation : uint8 {
INSERTION = 1;
DELETION = 2;
};
/// A list of commits for serialization in CommitPack.
struct Commits {
vector<Commit>:MAX commits;
};
/// A list of references for serialization in ReferencePack.
struct References {
vector<ObjectIdentifier>:MAX references;
};
/// Contains a Buffer containing the FIDL serialization of Diff.
struct DiffPack {
fuchsia.mem.Buffer buffer;
};
/// Contains a Buffer containing the FIDL serialization of References.
///
/// If the Buffer is absent, the reference list is treated as empty.
struct ReferencePack {
fuchsia.mem.Buffer? buffer;
};
/// Handler for cloud sync of a single page.
///
/// Implementation of this class manages a *commit log*, which is an append-only
/// list of commits produced by all devices that participate in syncing this
/// page. Position of commits within the log are references using position
/// tokens, allowing the caller to retrieve the commits added to the cloud since
/// the previous read. (plus possibly more - see comments for GetCommits() and
/// SetWatcher().)
///
/// Closing the client connection to PageCloud disconnects all watchers set on
/// it.
protocol PageCloud {
/// Adds the given commits to the commit log in the cloud.
///
/// The commits are added in one batch, on the receiving side they are
/// delivered in the same order in a single OnNewCommits() call.
AddCommits(CommitPack commits) -> (Status status);
/// Retrieves commits from the cloud.
///
/// All commits newer than `min_position_token` are guaranteed to be returned.
/// In addition to that, the response may include additional commits older
/// than or at `min_position_token`. Passing null `min_position_token`
/// retrieves all commits.
///
/// If the resulting `status` is `OK`, `commits` contains all matching commits
/// (might be empty) and `position_token` contains the position token of the
/// most recent of the `commits` (equivalent to `min_position_token` if
/// `commits` is empty).
GetCommits(PositionToken? min_position_token)
-> (Status status, CommitPack? commits, PositionToken? position_token);
/// Uploads the given object to the cloud under the given id.
///
/// If the object already exists in the cloud this method returns OK.
AddObject(ObjectIdentifier id, fuchsia.mem.Buffer buffer, ReferencePack references)
-> (Status status);
/// Retrieves the object of the given id from the cloud.
///
/// If the resulting `status` is `OK`, `buffer` will contain the object
/// content. If the resulting `status` is not `OK`, `buffer` will be null.
GetObject(ObjectIdentifier id)
-> (Status status, fuchsia.mem.Buffer? buffer);
/// Watches the cloud for push notifications.
///
/// At most one watcher can be set at any given time. If more than one watcher
/// is set, only the one set most recently receives notifications.
///
/// All commits newer than `min_position_token` added to the cloud before or
/// after making this call are guaranteed to be delivered to `watcher`. In
/// addition to that, additional commits older than or at `min_position_token`
/// may be delivered to. If `min_position_token` is null, notifications for
/// all commits are delivered.
SetWatcher(PositionToken? min_position_token, PageCloudWatcher watcher)
-> (Status status);
/// Fetches a diff for the commit with the given |commit_id|.
///
/// The base of the diff is either the empty page or a commit in
/// `possible_bases`. The bases may be unknown to the cloud if they have
/// been pruned from the cloud, but not from the Ledger. During the
/// migration to diffs, the cloud provider may also choose as a base any
/// commit that has been uploaded without diff. In that case, the tree at
/// this commit should be downloaded using GetObject.
// TODO(LE-823): update once the transition to diffs is complete.
GetDiff(CommitIdentifier commit_id, vector<CommitIdentifier>:32 possible_bases)
-> (Status status, DiffPack? diff);
};
/// Watcher for push notifications from cloud sync of a single page.
protocol PageCloudWatcher {
/// Called when new commits are added to the commit log in the cloud.
///
/// The method takes the list of new `commits` along with the `position_token`
/// of the most recent of them.
///
/// No subsequent calls are made until Ledger calls the callback of the
/// previous one.
OnNewCommits(CommitPack commits, PositionToken position_token) -> ();
/// Called when a new object is added to the cloud.
///
/// The method takes the `id` and the content of the new object.
///
/// No subsequent calls are made until Ledger calls the callback of the
/// previous one.
OnNewObject(ObjectIdentifier id, fuchsia.mem.Buffer buffer) -> ();
/// Called when an error occurs.
///
/// No further calls are made on the watcher after this is called. Ledger
/// can then re-establish the watcher by calling SetWatcher() again.
///
/// The status is one of:
///
/// - `AUTH_ERROR`, if the auth token needs a refresh
/// - `NETWORK_ERROR`, if the connection was dropped
/// - `PARSE_ERROR`, if an invalid server notification was received
OnError(Status status);
};