summaryrefslogtreecommitdiffstats
path: root/services/interfaces/mozIBridgedSyncEngine.idl
blob: 72683abf2211daed479ad7e98c410656ba411ac8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozIServicesLogSink.idl"
#include "nsISupports.idl"

interface nsIVariant;

// A generic callback called with a result. Variants are automatically unboxed
// in JavaScript: for example, a `UTF8String` will be passed as a string
// argument; an `Int32` or `Int64` as a number. Methods that don't return a
// value, like `setLastSync` or `setUploaded`, will pass a `null` variant to
// `handleSuccess`. For all callback types in this file, either `handleSuccess`
// or `handleError` is guaranteed to be called once.
[scriptable, uuid(9b7dd2a3-df99-4469-9ea9-61b222098695)]
interface mozIBridgedSyncEngineCallback : nsISupports {
    void handleSuccess(in nsIVariant result);
    void handleError(in nsresult code, in AUTF8String message);
};

// A callback called after the engine applies incoming records. This is separate
// from `mozIBridgedSyncEngineCallback` because variants can't hold an
// `Array<T>` type.
[scriptable, uuid(2776cdd5-799a-4009-b2f3-356d940a5244)]
interface mozIBridgedSyncEngineApplyCallback : nsISupports {
    // Notifies Sync that the bridged engine has finished applying incoming
    // records, and has outgoing records. Sync encrypts and uploads these
    // records, and notifies the engine that the upload succeeded by
    // calling `engine.setUploaded(uploadedOutgoingRecordIds, ...)`.
    void handleSuccess(in Array<AUTF8String> outgoingEnvelopesAsJSON);

    // Notifies Sync that the bridged engine failed to apply the staged records.
    void handleError(in nsresult code, in AUTF8String message);
};

// A bridged engine is implemented in Rust. It handles storage internally, and
// exposes a minimal interface for the JS Sync code to control it.
[scriptable, uuid(3b2b80be-c30e-4498-8065-01809cfe8d47)]
interface mozIBridgedSyncEngine : nsISupports {
    // The storage version for this engine's collection. If the version in the
    // server's `meta/global` record is newer than ours, we'll refuse to sync,
    // since we might not understand the data; if it's older, we'll wipe the
    // collection on the server, and upload our data as if on a first sync.
    readonly attribute long storageVersion;

    // Whether this engine tolerates skipped records, where a "skipped" record
    // is one that would cause the server's published limits to be exceeded
    // (for example, a single record where the payload is larger than the
    // server accepts.)
    // If this returns true, we will just skip the record without even attempting
    // to upload. If this is false, we'll abort the entire batch.
    // If the engine allows this, it will need to detect this scenario by noticing
    // the ID is not in the 'success' records reported to `setUploaded`.
    // (Note that this is not to be confused with the fact server's can currently
    // reject records as part of a POST - but we hope to remove this ability from
    // the server API. Note also that this is not bullet-proof - if the count of
    // records is high, it's possible that we will have committed a previous
    // batch before we hit the relevant limits, so things might have been written.
    // We hope to fix this by ensuring batch limits are such that this is
    // impossible)
    readonly attribute boolean allowSkippedRecord;

    // Wires up the Sync logging machinery to the bridged engine. This can be
    // `null`, in which case any logs from the engine will be discarded.
    attribute mozIServicesLogSink logger;

    // Returns the last sync time, in milliseconds, for this engine's
    // collection. This is used to build the collection URL for fetching
    // incoming records, and as the initial value of the `X-I-U-S` header on
    // upload. If the engine persists incoming records in a permanent (non-temp)
    // table, `getLastSync` can return a "high water mark" that's the newer of
    // the collection's last sync time, and the most recent record modification
    // time. This avoids redownloading incoming records that were previously
    // downloaded, but not applied.
    void getLastSync(in mozIBridgedSyncEngineCallback callback);

    // Sets the last sync time, in milliseconds. This is used to fast-forward
    // the last sync time for the engine's collection after fetching all
    // records, and after each `setUploaded` call with the `X-L-M` header from
    // the server. It may be called multiple times per sync.
    void setLastSync(in long long lastSyncMillis,
                     in mozIBridgedSyncEngineCallback callback);

    // Returns the sync ID for this engine's collection. Used for testing;
    // Sync only calls `ensureCurrentSyncId` and `resetSyncId`. On success,
    // calls `callback.handleSuccess(in AUTF8String currentSyncId)`.
    void getSyncId(in mozIBridgedSyncEngineCallback callback);

    // Generates a new sync ID for this engine, and resets all local Sync
    // metadata, including the last sync time and any change flags, to start
    // over as a first sync. On success, calls
    // `callback.handleSuccess(newSyncId)`, where `newSyncId` is
    // `AUTF8String` variant. Sync will upload the new sync ID in the
    // `meta/global` record.
    void resetSyncId(in mozIBridgedSyncEngineCallback callback);

    // Ensures that the local sync ID for the engine matches the sync ID for
    // the collection on the server. On a mismatch, the engine can:
    //   1. Reset all local Sync state, adopt `newSyncId` as the new sync ID,
    //      and call `callback.handleSuccess(newSyncId)`. Most engines should
    //      do this.
    //   2. Ignore the given `newSyncId`, use its existing local sync ID
    //      without resetting any state, and call
    //      `callback.handleSuccess(existingSyncId)`. This is useful if, for
    //      example, the underlying database has been restored from a backup,
    //      and the engine would like to force a reset and first sync on all
    //      other devices.
    //   3. Ignore the given `newSyncId`, reset all local Sync state, and
    //      generate a fresh sync ID, as if `resetSyncId`. This resets the
    //      engine's state everywhere, locally and on all other devices.
    // If the callback is called with a different sync ID than `newSyncId`,
    // Sync will reupload `meta/global` with the different ID. Otherwise, it
    // will assume that the engine has adopted the `newSyncId`, and do nothing.
    void ensureCurrentSyncId(in AUTF8String newSyncId,
                             in mozIBridgedSyncEngineCallback callback);

    // Notifies the engine that sync is starting. The engine can use this method
    // to set up temp tables for merging, for example. This will only be called
    // once per sync, and before any `storeIncoming` calls.
    void syncStarted(in mozIBridgedSyncEngineCallback callback);

    // Stages a batch of incoming records, and calls the `callback` when
    // done. This method may be called multiple times per sync, once per
    // incoming batch, and always after `syncStarted`. Flushing incoming records
    // more often incurs more writes to disk, but avoids redownloading and
    // reapplying more records if syncing is interrupted. Typically, engines
    // will stage incoming records in an SQLite temp table, and merge them with
    // the local database when `apply` is called.
    void storeIncoming(in Array<AUTF8String> incomingEnvelopesAsJSON,
                       in mozIBridgedSyncEngineCallback callback);

    // Applies all the staged records, and calls the `callback` with
    // outgoing records to upload. This will always be called after
    // `storeIncoming`, and only once per sync. Application should be atomic:
    // either all incoming records apply successfully, or none.
    void apply(in mozIBridgedSyncEngineApplyCallback callback);

    // Notifies the engine that Sync successfully uploaded the records with the
    // given IDs. This method may be called multiple times per sync, once per
    // batch upload. This will always be called after `apply`.
    void setUploaded(in long long newTimestampMillis,
                     in Array<AUTF8String> uploadedIds,
                     in mozIBridgedSyncEngineCallback callback);

    // Notifies the engine that syncing has finished, and the engine shouldn't
    // expect any more `setUploaded` calls. At this point, any outgoing records
    // that weren't passed to `setUploaded` should be assumed failed. This is
    // guaranteed to be called even if the sync fails. This will only be called
    // once per sync.
    void syncFinished(in mozIBridgedSyncEngineCallback callback);

    // Resets all local Sync metadata, including the sync ID, last sync time,
    // and any change flags, but preserves all data. After a reset, the engine will
    // sync as if for the first time.
    void reset(in mozIBridgedSyncEngineCallback callback);

    // Erases all locally stored data and metadata for this engine.
    void wipe(in mozIBridgedSyncEngineCallback callback);
};