core-3nweb-client-lib 0.44.1 → 0.44.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/api-defs/files.d.ts +21 -9
- package/build/core/id-manager/key-storage.d.ts +1 -0
- package/build/core/id-manager/key-storage.js +18 -3
- package/build/core/storage/synced/remote-events.d.ts +3 -0
- package/build/core/storage/synced/remote-events.js +24 -1
- package/build/core/storage/synced/storage.d.ts +1 -0
- package/build/core/storage/synced/storage.js +3 -0
- package/build/core-ipc/file.d.ts +4 -0
- package/build/core-ipc/file.js +22 -1
- package/build/core-ipc/fs.js +33 -9
- package/build/lib-client/fs-utils/files.js +4 -0
- package/build/lib-client/xsp-fs/common.d.ts +1 -0
- package/build/lib-client/xsp-fs/common.js +1 -0
- package/build/lib-client/xsp-fs/file-node.d.ts +1 -0
- package/build/lib-client/xsp-fs/file-node.js +3 -0
- package/build/lib-client/xsp-fs/file.d.ts +1 -0
- package/build/lib-client/xsp-fs/file.js +3 -0
- package/build/lib-client/xsp-fs/folder-node.js +39 -25
- package/build/lib-client/xsp-fs/fs.d.ts +1 -0
- package/build/lib-client/xsp-fs/fs.js +4 -16
- package/build/protos/asmail.proto.js +149 -378
- package/build/protos/fs.proto.js +149 -378
- package/package.json +1 -1
- package/protos/file.proto +4 -0
- package/protos/fs.proto +9 -9
|
@@ -622,6 +622,12 @@ declare namespace web3n.files {
|
|
|
622
622
|
|
|
623
623
|
interface ReadonlyFileSyncAPI {
|
|
624
624
|
|
|
625
|
+
/**
|
|
626
|
+
* When connection exception is caught, use this to await connection to continue.
|
|
627
|
+
* This returns a promise, resolvable when connected to storage server.
|
|
628
|
+
*/
|
|
629
|
+
whenConnected(): Promise<void>;
|
|
630
|
+
|
|
625
631
|
/**
|
|
626
632
|
* Returns synchronization status of this object.
|
|
627
633
|
* @param skipServerCheck is optional parameter to skip server check, that may be handy in offline
|
|
@@ -1404,6 +1410,12 @@ declare namespace web3n.files {
|
|
|
1404
1410
|
|
|
1405
1411
|
interface ReadonlyFSSyncAPI {
|
|
1406
1412
|
|
|
1413
|
+
/**
|
|
1414
|
+
* When connection exception is caught, use this to await connection to continue.
|
|
1415
|
+
* This returns a promise, resolvable when connected to storage server.
|
|
1416
|
+
*/
|
|
1417
|
+
whenConnected(): Promise<void>;
|
|
1418
|
+
|
|
1407
1419
|
/**
|
|
1408
1420
|
* Returns synchronization status of item at given path.
|
|
1409
1421
|
* @param path
|
|
@@ -1481,7 +1493,7 @@ declare namespace web3n.files {
|
|
|
1481
1493
|
*/
|
|
1482
1494
|
getRemoteFolderItem(path: string, remoteItemName: string, remoteVersion?: number): Promise<ReadonlyFS>;
|
|
1483
1495
|
|
|
1484
|
-
// XXX method to work around
|
|
1496
|
+
// XXX method to work around damaged files
|
|
1485
1497
|
// reloadFromServer(path: string): Promise<SyncStatus>;
|
|
1486
1498
|
|
|
1487
1499
|
}
|
|
@@ -1559,16 +1571,16 @@ declare namespace web3n.files {
|
|
|
1559
1571
|
interface FolderDiff extends CommonDiff {
|
|
1560
1572
|
|
|
1561
1573
|
/**
|
|
1562
|
-
* Items that were removed.
|
|
1574
|
+
* Items that were removed.
|
|
1563
1575
|
*
|
|
1564
1576
|
* Consider the following example.
|
|
1565
1577
|
* Item that is removed in local version is present in both remote and synced versions.
|
|
1566
1578
|
* Hence, difference between local and remote versions is due to removal in local branch.
|
|
1567
1579
|
*/
|
|
1568
1580
|
removed?: {
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
}
|
|
1581
|
+
inRemote?: string[];
|
|
1582
|
+
inLocal?: string[];
|
|
1583
|
+
};
|
|
1572
1584
|
|
|
1573
1585
|
/**
|
|
1574
1586
|
* Items that were renamed. Pointing to where renaming is done in remote (r), or local (l) branches.
|
|
@@ -1583,15 +1595,15 @@ declare namespace web3n.files {
|
|
|
1583
1595
|
}[];
|
|
1584
1596
|
|
|
1585
1597
|
/**
|
|
1586
|
-
* Items that were added.
|
|
1598
|
+
* Items that were added.
|
|
1587
1599
|
*
|
|
1588
1600
|
* When item added in remote branch, then it is present in remote version under the referenced name.
|
|
1589
1601
|
* Synced (older) state of folder doesn't have it, and neither does local.
|
|
1590
1602
|
*/
|
|
1591
1603
|
added?: {
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
}
|
|
1604
|
+
inRemote?: string[];
|
|
1605
|
+
inLocal?: string[];
|
|
1606
|
+
};
|
|
1595
1607
|
|
|
1596
1608
|
/**
|
|
1597
1609
|
* Items that reencrypted and now have different keys.
|
|
@@ -72,9 +72,6 @@ class IdKeysStorage {
|
|
|
72
72
|
this.fs = fs;
|
|
73
73
|
if (keysToSave) {
|
|
74
74
|
await this.fs.writeJSONFile(LOGIN_KEY_FILE_NAME, keysToSave);
|
|
75
|
-
// XXX must add work with not-online condition
|
|
76
|
-
await this.fs.v.sync.upload(LOGIN_KEY_FILE_NAME);
|
|
77
|
-
await this.fs.v.sync.upload('');
|
|
78
75
|
}
|
|
79
76
|
else {
|
|
80
77
|
try {
|
|
@@ -84,6 +81,24 @@ class IdKeysStorage {
|
|
|
84
81
|
throw (0, error_1.errWithCause)(exc, `Fail expection read of login MailerId keys from the storage`);
|
|
85
82
|
}
|
|
86
83
|
}
|
|
84
|
+
this.ensureDataFolderIsUploaded();
|
|
85
|
+
}
|
|
86
|
+
async ensureDataFolderIsUploaded() {
|
|
87
|
+
try {
|
|
88
|
+
const fileStatus = await this.fs.v.sync.status(LOGIN_KEY_FILE_NAME, false);
|
|
89
|
+
if (fileStatus.state === 'unsynced') {
|
|
90
|
+
await this.fs.v.sync.upload(LOGIN_KEY_FILE_NAME);
|
|
91
|
+
}
|
|
92
|
+
const folderStatus = await this.fs.v.sync.status('', true);
|
|
93
|
+
if (folderStatus.state === 'unsynced') {
|
|
94
|
+
await this.fs.v.sync.upload('');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
catch (exc) {
|
|
98
|
+
if (exc.type === 'connect') {
|
|
99
|
+
return this.fs.v.sync.whenConnected().then(() => this.ensureDataFolderIsUploaded());
|
|
100
|
+
}
|
|
101
|
+
}
|
|
87
102
|
}
|
|
88
103
|
}
|
|
89
104
|
exports.IdKeysStorage = IdKeysStorage;
|
|
@@ -19,10 +19,13 @@ export declare class RemoteEvents {
|
|
|
19
19
|
private readonly connectionEvents;
|
|
20
20
|
readonly connectionEvent$: Observable<StorageConnectionStatus>;
|
|
21
21
|
private readonly wsProc;
|
|
22
|
+
private deferredConnection;
|
|
22
23
|
constructor(remoteStorage: StorageOwner, files: ObjFiles, broadcastNodeEvent: Storage['broadcastNodeEvent'], logError: LogError);
|
|
23
24
|
private makeProc;
|
|
24
25
|
startListening(): void;
|
|
25
26
|
close(): Promise<void>;
|
|
27
|
+
whenConnected(): Promise<void>;
|
|
28
|
+
private signalConnected;
|
|
26
29
|
private absorbObjChange;
|
|
27
30
|
private absorbObjRemoval;
|
|
28
31
|
private absorbObjVersionArchival;
|
|
@@ -21,6 +21,7 @@ const rxjs_1 = require("rxjs");
|
|
|
21
21
|
const owner_1 = require("../../../lib-common/service-api/3nstorage/owner");
|
|
22
22
|
const operators_1 = require("rxjs/operators");
|
|
23
23
|
const ws_ipc_1 = require("../../../lib-common/ipc/ws-ipc");
|
|
24
|
+
const deferred_1 = require("../../../lib-common/processes/deferred");
|
|
24
25
|
function toStorageConnectionStatus(status, params) {
|
|
25
26
|
return (0, ws_ipc_1.addToStatus)(status, {
|
|
26
27
|
service: 'storage',
|
|
@@ -40,13 +41,25 @@ class RemoteEvents {
|
|
|
40
41
|
this.logError = logError;
|
|
41
42
|
this.connectionEvents = new rxjs_1.Subject();
|
|
42
43
|
this.connectionEvent$ = this.connectionEvents.asObservable().pipe((0, operators_1.share)());
|
|
44
|
+
this.deferredConnection = (0, deferred_1.defer)();
|
|
43
45
|
this.wsProc = new ws_ipc_1.WebSocketListening(SERVER_EVENTS_RESTART_WAIT_SECS, this.makeProc.bind(this));
|
|
44
46
|
Object.seal(this);
|
|
45
47
|
}
|
|
46
48
|
makeProc() {
|
|
47
49
|
return (0, rxjs_1.from)(this.remoteStorage.openEventSource().then(({ client, heartbeat }) => {
|
|
50
|
+
this.signalConnected();
|
|
48
51
|
heartbeat.subscribe({
|
|
49
|
-
next: ev =>
|
|
52
|
+
next: ev => {
|
|
53
|
+
this.connectionEvents.next(toStorageConnectionStatus(ev));
|
|
54
|
+
if (ev.type === 'heartbeat') {
|
|
55
|
+
this.signalConnected();
|
|
56
|
+
}
|
|
57
|
+
else if ((ev.type === 'heartbeat-skip') || (ev.type === 'disconnected')) {
|
|
58
|
+
if (!this.deferredConnection) {
|
|
59
|
+
this.deferredConnection = (0, deferred_1.defer)();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
50
63
|
});
|
|
51
64
|
return [
|
|
52
65
|
this.absorbObjChange(client),
|
|
@@ -65,6 +78,16 @@ class RemoteEvents {
|
|
|
65
78
|
this.connectionEvents.complete();
|
|
66
79
|
this.wsProc.close();
|
|
67
80
|
}
|
|
81
|
+
async whenConnected() {
|
|
82
|
+
var _a;
|
|
83
|
+
return (_a = this.deferredConnection) === null || _a === void 0 ? void 0 : _a.promise;
|
|
84
|
+
}
|
|
85
|
+
signalConnected() {
|
|
86
|
+
if (this.deferredConnection) {
|
|
87
|
+
this.deferredConnection.resolve();
|
|
88
|
+
this.deferredConnection = undefined;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
68
91
|
absorbObjChange(client) {
|
|
69
92
|
return (new rxjs_1.Observable(obs => client.subscribe(owner_1.events.objChanged.EVENT_NAME, obs)))
|
|
70
93
|
.pipe((0, operators_1.mergeMap)(async ({ newVer: newRemoteVersion, objId }) => {
|
|
@@ -62,5 +62,6 @@ export declare class SyncedStore implements ISyncedStorage {
|
|
|
62
62
|
suspendNetworkActivity(): void;
|
|
63
63
|
resumeNetworkActivity(): void;
|
|
64
64
|
get connectionEvent$(): Observable<import("./remote-events").StorageConnectionStatus>;
|
|
65
|
+
whenConnected(): Promise<void>;
|
|
65
66
|
}
|
|
66
67
|
export {};
|
|
@@ -248,6 +248,9 @@ class SyncedStore {
|
|
|
248
248
|
get connectionEvent$() {
|
|
249
249
|
return this.remoteEvents.connectionEvent$;
|
|
250
250
|
}
|
|
251
|
+
whenConnected() {
|
|
252
|
+
return this.remoteEvents.whenConnected();
|
|
253
|
+
}
|
|
251
254
|
}
|
|
252
255
|
exports.SyncedStore = SyncedStore;
|
|
253
256
|
Object.freeze(SyncedStore.prototype);
|
package/build/core-ipc/file.d.ts
CHANGED
|
@@ -151,6 +151,10 @@ export declare namespace vGetByteSink {
|
|
|
151
151
|
function wrapService(fn: WritableFileVersionedAPI['getByteSink'], expServices: CoreSideServices): ExposedFn;
|
|
152
152
|
function makeCaller(caller: Caller, objPath: string[]): WritableFileVersionedAPI['getByteSink'];
|
|
153
153
|
}
|
|
154
|
+
export declare namespace vsWhenConnected {
|
|
155
|
+
function wrapService(fn: ReadonlyFileSyncAPI['whenConnected']): ExposedFn;
|
|
156
|
+
function makeCaller(caller: Caller, objPath: string[]): ReadonlyFileSyncAPI['whenConnected'];
|
|
157
|
+
}
|
|
154
158
|
export declare namespace vsStartDownload {
|
|
155
159
|
const replyType: ProtoType<{
|
|
156
160
|
startedDownload?: {
|
package/build/core-ipc/file.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
this program. If not, see <http://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.vsDiffCurrentAndRemoteVersions = exports.vListVersions = exports.vsUpload = exports.vsStartUpload = exports.vsStartDownload = exports.vGetByteSink = exports.updateXAttrs = exports.vGetByteSource = exports.vReadJSON = exports.vReadTxt = exports.vReadBytes = exports.vListXAttrs = exports.vGetXAttr = exports.vStat = exports.readBytes = exports.fileMsgType = void 0;
|
|
19
|
+
exports.vsDiffCurrentAndRemoteVersions = exports.vListVersions = exports.vsUpload = exports.vsStartUpload = exports.vsStartDownload = exports.vsWhenConnected = exports.vGetByteSink = exports.updateXAttrs = exports.vGetByteSource = exports.vReadJSON = exports.vReadTxt = exports.vReadBytes = exports.vListXAttrs = exports.vGetXAttr = exports.vStat = exports.readBytes = exports.fileMsgType = void 0;
|
|
20
20
|
exports.makeFileCaller = makeFileCaller;
|
|
21
21
|
exports.exposeFileService = exposeFileService;
|
|
22
22
|
exports.packStats = packStats;
|
|
@@ -100,6 +100,7 @@ function makeFileCaller(caller, fileMsg) {
|
|
|
100
100
|
if (fileMsg.isSynced) {
|
|
101
101
|
const vsPath = (0, protobuf_msg_1.methodPathFor)(vPath, 'sync');
|
|
102
102
|
file.v.sync = {
|
|
103
|
+
whenConnected: vsWhenConnected.makeCaller(caller, vsPath),
|
|
103
104
|
status: vsStatus.makeCaller(caller, vsPath),
|
|
104
105
|
isRemoteVersionOnDisk: vsIsRemoteVersionOnDisk.makeCaller(caller, vsPath),
|
|
105
106
|
startDownload: vsStartDownload.makeCaller(caller, vsPath),
|
|
@@ -156,6 +157,7 @@ function exposeFileService(file, expServices) {
|
|
|
156
157
|
}
|
|
157
158
|
if (file.v.sync) {
|
|
158
159
|
implExp.v.sync = {
|
|
160
|
+
whenConnected: vsWhenConnected.wrapService(file.v.sync.whenConnected),
|
|
159
161
|
status: vsStatus.wrapService(file.v.sync.status),
|
|
160
162
|
isRemoteVersionOnDisk: vsIsRemoteVersionOnDisk.wrapService(file.v.sync.isRemoteVersionOnDisk),
|
|
161
163
|
startDownload: vsStartDownload.wrapService(file.v.sync.startDownload),
|
|
@@ -1084,6 +1086,25 @@ var vGetByteSink;
|
|
|
1084
1086
|
vGetByteSink.makeCaller = makeCaller;
|
|
1085
1087
|
})(vGetByteSink || (exports.vGetByteSink = vGetByteSink = {}));
|
|
1086
1088
|
Object.freeze(vGetByteSink);
|
|
1089
|
+
var vsWhenConnected;
|
|
1090
|
+
(function (vsWhenConnected) {
|
|
1091
|
+
function wrapService(fn) {
|
|
1092
|
+
return buf => {
|
|
1093
|
+
const promise = fn();
|
|
1094
|
+
return { promise };
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
vsWhenConnected.wrapService = wrapService;
|
|
1098
|
+
function makeCaller(caller, objPath) {
|
|
1099
|
+
const path = (0, protobuf_msg_1.methodPathFor)(objPath, 'whenConnected');
|
|
1100
|
+
return () => caller
|
|
1101
|
+
.startPromiseCall(path, undefined)
|
|
1102
|
+
.then(noop);
|
|
1103
|
+
}
|
|
1104
|
+
vsWhenConnected.makeCaller = makeCaller;
|
|
1105
|
+
})(vsWhenConnected || (exports.vsWhenConnected = vsWhenConnected = {}));
|
|
1106
|
+
Object.freeze(vsWhenConnected);
|
|
1107
|
+
function noop() { }
|
|
1087
1108
|
var vsStatus;
|
|
1088
1109
|
(function (vsStatus) {
|
|
1089
1110
|
function wrapService(fn) {
|
package/build/core-ipc/fs.js
CHANGED
|
@@ -101,6 +101,7 @@ function makeFSCaller(caller, fsMsg) {
|
|
|
101
101
|
if (fsMsg.isSynced) {
|
|
102
102
|
const vsPath = (0, protobuf_msg_1.methodPathFor)(vPath, 'sync');
|
|
103
103
|
fs.v.sync = {
|
|
104
|
+
whenConnected: file.vsWhenConnected.makeCaller(caller, vsPath),
|
|
104
105
|
status: vsStatus.makeCaller(caller, vsPath),
|
|
105
106
|
isRemoteVersionOnDisk: vsIsRemoteVersionOnDisk.makeCaller(caller, vsPath),
|
|
106
107
|
startDownload: vsDownload.makeCaller(caller, vsPath),
|
|
@@ -186,6 +187,7 @@ function exposeFSService(fs, expServices) {
|
|
|
186
187
|
}
|
|
187
188
|
if (fs.v.sync) {
|
|
188
189
|
implExp.v.sync = {
|
|
190
|
+
whenConnected: file.vsWhenConnected.wrapService(fs.v.sync.whenConnected),
|
|
189
191
|
status: vsStatus.wrapService(fs.v.sync.status),
|
|
190
192
|
isRemoteVersionOnDisk: vsIsRemoteVersionOnDisk.wrapService(fs.v.sync.isRemoteVersionOnDisk),
|
|
191
193
|
startDownload: vsDownload.wrapService(fs.v.sync.startDownload),
|
|
@@ -2213,10 +2215,8 @@ function folderDiffToMsg(diff) {
|
|
|
2213
2215
|
}
|
|
2214
2216
|
return {
|
|
2215
2217
|
...file.commonDiffToMsg(diff),
|
|
2216
|
-
added:
|
|
2217
|
-
|
|
2218
|
-
removed: (diff.removed && (diff.removed.length > 0) ?
|
|
2219
|
-
diff.removed.map(({ name, removedIn }) => ({ name, removedIn })) : undefined),
|
|
2218
|
+
added: diff.added,
|
|
2219
|
+
removed: diff.removed,
|
|
2220
2220
|
renamed: (diff.renamed && (diff.renamed.length > 0) ?
|
|
2221
2221
|
diff.renamed.map(({ local, remote, renamedIn }) => ({ local, remote, renamedIn })) : undefined),
|
|
2222
2222
|
rekeyed: (diff.rekeyed && (diff.rekeyed.length > 0) ?
|
|
@@ -2230,13 +2230,37 @@ function folderDiffFromMsg(msg) {
|
|
|
2230
2230
|
}
|
|
2231
2231
|
return {
|
|
2232
2232
|
...file.commonDiffFromMsg(msg),
|
|
2233
|
-
added: (msg.added
|
|
2234
|
-
removed: (msg.removed
|
|
2235
|
-
renamed: (msg.renamed
|
|
2236
|
-
rekeyed: (msg.rekeyed
|
|
2237
|
-
nameOverlaps: (msg.nameOverlaps
|
|
2233
|
+
added: reduceEmptyIn(msg.added),
|
|
2234
|
+
removed: reduceEmptyIn(msg.removed),
|
|
2235
|
+
renamed: reduceEmptyArr(msg.renamed),
|
|
2236
|
+
rekeyed: reduceEmptyArr(msg.rekeyed),
|
|
2237
|
+
nameOverlaps: reduceEmptyArr(msg.nameOverlaps),
|
|
2238
2238
|
};
|
|
2239
2239
|
}
|
|
2240
|
+
function reduceEmptyIn(c) {
|
|
2241
|
+
if (!c) {
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
if (c.inLocal && (c.inLocal.length > 0)) {
|
|
2245
|
+
if (c.inRemote && (c.inRemote.length > 0)) {
|
|
2246
|
+
return c;
|
|
2247
|
+
}
|
|
2248
|
+
else {
|
|
2249
|
+
return { inLocal: c.inLocal };
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
else {
|
|
2253
|
+
if (c.inRemote && (c.inRemote.length > 0)) {
|
|
2254
|
+
return { inRemote: c.inRemote };
|
|
2255
|
+
}
|
|
2256
|
+
else {
|
|
2257
|
+
return;
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
function reduceEmptyArr(arr) {
|
|
2262
|
+
return (arr && (arr.length > 0) ? arr : undefined);
|
|
2263
|
+
}
|
|
2240
2264
|
var vsDiffCurrentAndRemoteFolderVersions;
|
|
2241
2265
|
(function (vsDiffCurrentAndRemoteFolderVersions) {
|
|
2242
2266
|
const requestType = protobuf_type_1.ProtoType.for(fs_proto_1.fs.DiffCurrentAndRemoteFolderVersionsRequestBody);
|
|
@@ -86,6 +86,7 @@ function wrapWritableFileSyncAPI(sImpl) {
|
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
88
88
|
const w = {
|
|
89
|
+
whenConnected: sImpl.whenConnected.bind(sImpl),
|
|
89
90
|
status: sImpl.status.bind(sImpl),
|
|
90
91
|
startDownload: sImpl.startDownload.bind(sImpl),
|
|
91
92
|
isRemoteVersionOnDisk: sImpl.isRemoteVersionOnDisk.bind(sImpl),
|
|
@@ -140,6 +141,7 @@ function wrapReadonlyFileSyncAPI(sImpl) {
|
|
|
140
141
|
return;
|
|
141
142
|
}
|
|
142
143
|
const w = {
|
|
144
|
+
whenConnected: sImpl.whenConnected.bind(sImpl),
|
|
143
145
|
status: sImpl.status.bind(sImpl),
|
|
144
146
|
startDownload: sImpl.startDownload.bind(sImpl),
|
|
145
147
|
isRemoteVersionOnDisk: sImpl.isRemoteVersionOnDisk.bind(sImpl),
|
|
@@ -235,6 +237,7 @@ function wrapWritableFSSyncAPI(sImpl) {
|
|
|
235
237
|
return;
|
|
236
238
|
}
|
|
237
239
|
const w = {
|
|
240
|
+
whenConnected: sImpl.whenConnected.bind(sImpl),
|
|
238
241
|
status: sImpl.status.bind(sImpl),
|
|
239
242
|
startDownload: sImpl.startDownload.bind(sImpl),
|
|
240
243
|
isRemoteVersionOnDisk: sImpl.isRemoteVersionOnDisk.bind(sImpl),
|
|
@@ -303,6 +306,7 @@ function wrapReadonlyFSSyncAPI(sImpl) {
|
|
|
303
306
|
return;
|
|
304
307
|
}
|
|
305
308
|
const w = {
|
|
309
|
+
whenConnected: sImpl.whenConnected.bind(sImpl),
|
|
306
310
|
status: sImpl.status.bind(sImpl),
|
|
307
311
|
startDownload: sImpl.startDownload.bind(sImpl),
|
|
308
312
|
isRemoteVersionOnDisk: sImpl.isRemoteVersionOnDisk.bind(sImpl),
|
|
@@ -121,6 +121,7 @@ export interface SyncedStorage extends Storage {
|
|
|
121
121
|
suspendNetworkActivity(): void;
|
|
122
122
|
resumeNetworkActivity(): void;
|
|
123
123
|
connectionEvent$: Observable<StorageConnectionStatus>;
|
|
124
|
+
whenConnected(): Promise<void>;
|
|
124
125
|
}
|
|
125
126
|
export interface SyncedObjStatus extends LocalObjStatus {
|
|
126
127
|
syncStatus(): SyncStatus;
|
|
@@ -127,6 +127,7 @@ function wrapSyncStorageImplementation(impl) {
|
|
|
127
127
|
wrap.resumeNetworkActivity = impl.resumeNetworkActivity.bind(impl);
|
|
128
128
|
wrap.getNumOfBytesNeedingDownload = impl.getNumOfBytesNeedingDownload.bind(impl);
|
|
129
129
|
wrap.connectionEvent$ = impl.connectionEvent$;
|
|
130
|
+
wrap.whenConnected = impl.whenConnected.bind(impl);
|
|
130
131
|
return Object.freeze(wrap);
|
|
131
132
|
}
|
|
132
133
|
function isSyncedStorage(storage) {
|
|
@@ -44,6 +44,7 @@ export declare class FileNode extends NodeInFS<FilePersistance> {
|
|
|
44
44
|
private static initWithAttrs;
|
|
45
45
|
protected setCurrentStateFrom(src: ObjSource): Promise<void>;
|
|
46
46
|
private setUpdatedState;
|
|
47
|
+
getStorage(): Storage;
|
|
47
48
|
getStats(flags?: VersionedReadFlags): Promise<Stats>;
|
|
48
49
|
readSrc(flags: VersionedReadFlags | undefined): Promise<{
|
|
49
50
|
src: FileByteSource;
|
|
@@ -126,6 +126,9 @@ class FileNode extends node_in_fs_1.NodeInFS {
|
|
|
126
126
|
this.fileSize = fileAttrs.size;
|
|
127
127
|
super.setUpdatedParams(version, fileAttrs.attrs, fileAttrs.xattrs);
|
|
128
128
|
}
|
|
129
|
+
getStorage() {
|
|
130
|
+
return this.storage;
|
|
131
|
+
}
|
|
129
132
|
async getStats(flags) {
|
|
130
133
|
const { stats, attrs } = await this.getStatsAndSize(flags);
|
|
131
134
|
stats.size = (attrs ? attrs.size : this.fileSize);
|
|
@@ -100,6 +100,7 @@ declare class V implements WritableFileVersionedAPI, N {
|
|
|
100
100
|
declare class S implements WritableFileSyncAPI {
|
|
101
101
|
private readonly n;
|
|
102
102
|
constructor(n: N);
|
|
103
|
+
whenConnected(): Promise<void>;
|
|
103
104
|
startUpload(opts?: OptionsToUploadLocal): Promise<{
|
|
104
105
|
uploadVersion: number;
|
|
105
106
|
uploadTaskId: number;
|
|
@@ -224,6 +224,9 @@ class S {
|
|
|
224
224
|
this.n = n;
|
|
225
225
|
Object.freeze(this);
|
|
226
226
|
}
|
|
227
|
+
async whenConnected() {
|
|
228
|
+
return (await this.n.getNode()).getStorage().whenConnected();
|
|
229
|
+
}
|
|
227
230
|
async startUpload(opts) {
|
|
228
231
|
this.n.ensureIsWritable();
|
|
229
232
|
const node = await this.n.getNode();
|
|
@@ -1096,13 +1096,11 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1096
1096
|
const nodes = state.nodes;
|
|
1097
1097
|
const remoteNodes = remote.folderInfo.nodes;
|
|
1098
1098
|
const events = [];
|
|
1099
|
-
if (removed) {
|
|
1100
|
-
for (const
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
events.push(this.makeEntryRemovalEvent(newVersion, 'sync', node));
|
|
1105
|
-
}
|
|
1099
|
+
if (removed === null || removed === void 0 ? void 0 : removed.inRemote) {
|
|
1100
|
+
for (const name of removed.inRemote) {
|
|
1101
|
+
const node = nodes[name];
|
|
1102
|
+
delete nodes[name];
|
|
1103
|
+
events.push(this.makeEntryRemovalEvent(newVersion, 'sync', node));
|
|
1106
1104
|
}
|
|
1107
1105
|
}
|
|
1108
1106
|
if (renamed) {
|
|
@@ -1122,19 +1120,17 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1122
1120
|
}
|
|
1123
1121
|
}
|
|
1124
1122
|
}
|
|
1125
|
-
if (added) {
|
|
1126
|
-
for (const
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
node.name = `${node.name}${opts === null || opts === void 0 ? void 0 : opts.postfixForNameOverlaps}`;
|
|
1133
|
-
}
|
|
1123
|
+
if (added === null || added === void 0 ? void 0 : added.inRemote) {
|
|
1124
|
+
for (const name of added.inRemote) {
|
|
1125
|
+
const node = remoteNodes[name];
|
|
1126
|
+
(0, assert_1.assert)(!!node);
|
|
1127
|
+
if (nameOverlaps === null || nameOverlaps === void 0 ? void 0 : nameOverlaps.includes(name)) {
|
|
1128
|
+
while (nodes[node.name]) {
|
|
1129
|
+
node.name = `${node.name}${opts === null || opts === void 0 ? void 0 : opts.postfixForNameOverlaps}`;
|
|
1134
1130
|
}
|
|
1135
|
-
nodes[node.name] = node;
|
|
1136
|
-
events.push(this.makeEntryAdditionEvent(newVersion, 'sync', node));
|
|
1137
1131
|
}
|
|
1132
|
+
nodes[node.name] = node;
|
|
1133
|
+
events.push(this.makeEntryAdditionEvent(newVersion, 'sync', node));
|
|
1138
1134
|
}
|
|
1139
1135
|
}
|
|
1140
1136
|
return events;
|
|
@@ -1188,9 +1184,9 @@ function addToTransitionState(state, f, key) {
|
|
|
1188
1184
|
function diffNodes(current, remote, synced) {
|
|
1189
1185
|
const currentNodesById = orderByIds(current.nodes);
|
|
1190
1186
|
const syncedNodesById = orderByIds(synced.nodes);
|
|
1191
|
-
const removed = [];
|
|
1187
|
+
const removed = { inLocal: [], inRemote: [] };
|
|
1192
1188
|
const renamed = [];
|
|
1193
|
-
const added = [];
|
|
1189
|
+
const added = { inLocal: [], inRemote: [] };
|
|
1194
1190
|
const rekeyed = [];
|
|
1195
1191
|
const nameOverlaps = [];
|
|
1196
1192
|
for (const remoteNode of Object.values(remote.nodes)) {
|
|
@@ -1229,10 +1225,10 @@ function diffNodes(current, remote, synced) {
|
|
|
1229
1225
|
else {
|
|
1230
1226
|
const syncedNode = syncedNodesById.get(remoteNode.objId);
|
|
1231
1227
|
if (syncedNode) {
|
|
1232
|
-
removed.push(
|
|
1228
|
+
removed.inLocal.push(remoteNode.name);
|
|
1233
1229
|
}
|
|
1234
1230
|
else {
|
|
1235
|
-
added.push(
|
|
1231
|
+
added.inRemote.push(remoteNode.name);
|
|
1236
1232
|
}
|
|
1237
1233
|
if (current.nodes[remoteNode.name]) {
|
|
1238
1234
|
nameOverlaps.push(remoteNode.name);
|
|
@@ -1242,13 +1238,13 @@ function diffNodes(current, remote, synced) {
|
|
|
1242
1238
|
for (const localNode of currentNodesById.values()) {
|
|
1243
1239
|
const syncedNode = syncedNodesById.get(localNode.objId);
|
|
1244
1240
|
if (!syncedNode) {
|
|
1245
|
-
added.push(
|
|
1241
|
+
added.inLocal.push(localNode.name);
|
|
1246
1242
|
}
|
|
1247
1243
|
}
|
|
1248
1244
|
return {
|
|
1249
|
-
removed: (
|
|
1245
|
+
removed: reduceEmptyIn(removed),
|
|
1250
1246
|
renamed: ((renamed.length > 0) ? renamed : undefined),
|
|
1251
|
-
added: (
|
|
1247
|
+
added: reduceEmptyIn(added),
|
|
1252
1248
|
rekeyed: ((rekeyed.length > 0) ? rekeyed : undefined),
|
|
1253
1249
|
nameOverlaps: ((nameOverlaps.length > 0) ? nameOverlaps : undefined),
|
|
1254
1250
|
};
|
|
@@ -1291,4 +1287,22 @@ function identifyChanges(originalNodes, newNodes) {
|
|
|
1291
1287
|
}
|
|
1292
1288
|
return { addedNodes, removedNodes, renamedNodes };
|
|
1293
1289
|
}
|
|
1290
|
+
function reduceEmptyIn(c) {
|
|
1291
|
+
if (c.inLocal.length > 0) {
|
|
1292
|
+
if (c.inRemote.length > 0) {
|
|
1293
|
+
return c;
|
|
1294
|
+
}
|
|
1295
|
+
else {
|
|
1296
|
+
return { inLocal: c.inLocal };
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
else {
|
|
1300
|
+
if (c.inRemote.length > 0) {
|
|
1301
|
+
return { inRemote: c.inRemote };
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1294
1308
|
Object.freeze(exports);
|
|
@@ -166,6 +166,7 @@ declare class V implements WritableFSVersionedAPI, N {
|
|
|
166
166
|
declare class S implements WritableFSSyncAPI {
|
|
167
167
|
private readonly n;
|
|
168
168
|
constructor(n: N);
|
|
169
|
+
whenConnected(): Promise<void>;
|
|
169
170
|
startUpload(path: string, opts?: OptionsToUploadLocal): Promise<{
|
|
170
171
|
uploadVersion: number;
|
|
171
172
|
uploadTaskId: number;
|
|
@@ -708,6 +708,9 @@ class S {
|
|
|
708
708
|
this.n = n;
|
|
709
709
|
Object.freeze(this);
|
|
710
710
|
}
|
|
711
|
+
whenConnected() {
|
|
712
|
+
return this.n.getRootIfNotClosed('').getStorage().whenConnected();
|
|
713
|
+
}
|
|
711
714
|
async startUpload(path, opts) {
|
|
712
715
|
this.n.ensureIsWritable();
|
|
713
716
|
const node = await this.n.get(path);
|
|
@@ -859,24 +862,9 @@ class S {
|
|
|
859
862
|
throw (0, file_1.makeFileException)('notDirectory', `${path}/${remoteItemName}`);
|
|
860
863
|
}
|
|
861
864
|
}
|
|
862
|
-
// async adoptAllRemoteItems(
|
|
863
|
-
// path: string, opts?: OptionsToAdoptAllRemoteItems
|
|
864
|
-
// ): Promise<number|undefined> {
|
|
865
|
-
// const folderNode = await this.getFolderNode(path);
|
|
866
|
-
// return await folderNode.adoptItemsFromRemoteVersion(opts);
|
|
867
|
-
// }
|
|
868
865
|
async mergeFolderCurrentAndRemoteVersions(path, opts) {
|
|
869
866
|
const folderNode = await this.getFolderNode(path);
|
|
870
|
-
|
|
871
|
-
if (newLocalVersion && (newLocalVersion < 0)) {
|
|
872
|
-
const { folderPath } = split(path);
|
|
873
|
-
if (folderPath.length > 0) {
|
|
874
|
-
const parent = await this.n.get(folderPath.join('/'));
|
|
875
|
-
// XXX removing folder in parent -- what happens with children?
|
|
876
|
-
await parent.removeChild(folderNode);
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
return newLocalVersion;
|
|
867
|
+
return await folderNode.mergeCurrentAndRemoteVersions(opts);
|
|
880
868
|
}
|
|
881
869
|
}
|
|
882
870
|
Object.freeze(S.prototype);
|