| // 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); |
| }; |