core-3nweb-client-lib 0.43.20 → 0.44.1
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 +233 -160
- package/build/core/index.d.ts +1 -0
- package/build/core/index.js +3 -2
- package/build/core/storage/index.d.ts +1 -0
- package/build/core/storage/index.js +4 -1
- package/build/core/storage/synced/storage.d.ts +1 -0
- package/build/core/storage/synced/storage.js +4 -1
- package/build/core-ipc/file.d.ts +47 -0
- package/build/core-ipc/file.js +121 -2
- package/build/core-ipc/fs.js +55 -62
- package/build/lib-client/asmail/recipient.js +4 -2
- package/build/lib-client/cryptor/cryptor-wasm.js +1 -1
- package/build/lib-client/cryptor/cryptor.wasm +0 -0
- package/build/lib-client/fs-utils/files.js +5 -1
- package/build/lib-client/ws-utils.js +2 -7
- package/build/lib-client/xsp-fs/common.d.ts +2 -0
- package/build/lib-client/xsp-fs/common.js +2 -1
- package/build/lib-client/xsp-fs/exceptions.js +1 -1
- package/build/lib-client/xsp-fs/file-node.d.ts +3 -0
- package/build/lib-client/xsp-fs/file-node.js +55 -3
- package/build/lib-client/xsp-fs/file.d.ts +3 -0
- package/build/lib-client/xsp-fs/file.js +5 -1
- package/build/lib-client/xsp-fs/folder-node.d.ts +5 -4
- package/build/lib-client/xsp-fs/folder-node.js +257 -368
- package/build/lib-client/xsp-fs/fs.d.ts +6 -2
- package/build/lib-client/xsp-fs/fs.js +33 -2
- package/build/lib-client/xsp-fs/link-node.js +1 -1
- package/build/lib-client/xsp-fs/node-in-fs.d.ts +21 -0
- package/build/lib-client/xsp-fs/node-in-fs.js +172 -3
- package/build/lib-common/exceptions/file.d.ts +1 -1
- package/build/lib-common/exceptions/file.js +3 -2
- package/build/lib-common/ipc/generic-ipc.js +33 -28
- package/build/lib-common/ipc/ws-ipc.d.ts +2 -0
- package/build/lib-common/ipc/ws-ipc.js +35 -8
- package/build/lib-common/map-of-sets.d.ts +1 -0
- package/build/lib-common/map-of-sets.js +3 -0
- package/build/protos/asmail.proto.js +3315 -883
- package/build/protos/file.proto.js +1974 -0
- package/build/protos/fs.proto.js +3301 -869
- package/package.json +1 -1
- package/protos/file.proto +44 -0
- package/protos/fs.proto +42 -27
|
@@ -184,34 +184,15 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
184
184
|
const newState = this.currentState;
|
|
185
185
|
const { renamedNodes, addedNodes, removedNodes } = identifyChanges(originalState.nodes, newState.nodes);
|
|
186
186
|
for (const node of removedNodes) {
|
|
187
|
-
const event =
|
|
188
|
-
|
|
189
|
-
src: 'sync',
|
|
190
|
-
path: this.name,
|
|
191
|
-
newVersion: this.version,
|
|
192
|
-
name: node.name
|
|
193
|
-
};
|
|
194
|
-
this.broadcastEvent(event, false, node.objId);
|
|
187
|
+
const { event, childObjId } = this.makeEntryRemovalEvent(this.version, 'sync', node);
|
|
188
|
+
this.broadcastEvent(event, false, childObjId);
|
|
195
189
|
}
|
|
196
190
|
for (const node of addedNodes) {
|
|
197
|
-
const event =
|
|
198
|
-
|
|
199
|
-
src: 'sync',
|
|
200
|
-
entry: nodeInfoToListingEntry(node),
|
|
201
|
-
path: this.name,
|
|
202
|
-
newVersion: this.version
|
|
203
|
-
};
|
|
204
|
-
this.broadcastEvent(event, false, node.objId);
|
|
191
|
+
const { event, childObjId } = this.makeEntryAdditionEvent(this.version, 'sync', node);
|
|
192
|
+
this.broadcastEvent(event, false, childObjId);
|
|
205
193
|
}
|
|
206
194
|
for (const { objId, oldName, newName } of renamedNodes) {
|
|
207
|
-
const event =
|
|
208
|
-
type: 'entry-renaming',
|
|
209
|
-
src: 'sync',
|
|
210
|
-
oldName,
|
|
211
|
-
newName,
|
|
212
|
-
path: this.name,
|
|
213
|
-
newVersion: this.version
|
|
214
|
-
};
|
|
195
|
+
const event = this.makeEntryRenamingEvent(this.version, 'sync', newName, oldName);
|
|
215
196
|
this.broadcastEvent(event, false, objId);
|
|
216
197
|
}
|
|
217
198
|
return removedNodes;
|
|
@@ -228,6 +209,38 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
228
209
|
this.callRemoveObjOn('sync', nodeToRm);
|
|
229
210
|
}
|
|
230
211
|
}
|
|
212
|
+
makeEntryAdditionEvent(newVersion, src, node, moveLabel) {
|
|
213
|
+
const event = {
|
|
214
|
+
type: 'entry-addition',
|
|
215
|
+
src,
|
|
216
|
+
entry: nodeInfoToListingEntry(node),
|
|
217
|
+
path: this.name,
|
|
218
|
+
newVersion,
|
|
219
|
+
moveLabel
|
|
220
|
+
};
|
|
221
|
+
return { event, childObjId: node.objId };
|
|
222
|
+
}
|
|
223
|
+
makeEntryRemovalEvent(newVersion, src, { name, objId }, moveLabel) {
|
|
224
|
+
const event = {
|
|
225
|
+
type: 'entry-removal',
|
|
226
|
+
src,
|
|
227
|
+
path: this.name,
|
|
228
|
+
newVersion,
|
|
229
|
+
name,
|
|
230
|
+
moveLabel
|
|
231
|
+
};
|
|
232
|
+
return { event, childObjId: objId };
|
|
233
|
+
}
|
|
234
|
+
makeEntryRenamingEvent(newVersion, src, newName, oldName) {
|
|
235
|
+
return {
|
|
236
|
+
type: 'entry-renaming',
|
|
237
|
+
src,
|
|
238
|
+
oldName,
|
|
239
|
+
newName,
|
|
240
|
+
path: this.name,
|
|
241
|
+
newVersion
|
|
242
|
+
};
|
|
243
|
+
}
|
|
231
244
|
callRemoveObjOn(src, node) {
|
|
232
245
|
if (node.type === 'folder') {
|
|
233
246
|
node.removeFolderObj(src);
|
|
@@ -358,64 +371,67 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
358
371
|
return [];
|
|
359
372
|
}
|
|
360
373
|
delete state.nodes[childInfo.name];
|
|
361
|
-
|
|
362
|
-
type: 'entry-removal',
|
|
363
|
-
path: this.name,
|
|
364
|
-
src: 'local',
|
|
365
|
-
name: childInfo.name,
|
|
366
|
-
newVersion: version
|
|
367
|
-
};
|
|
368
|
-
return { event, childObjId: childInfo.objId };
|
|
374
|
+
return this.makeEntryRemovalEvent(version, 'local', childInfo);
|
|
369
375
|
}).catch(noop);
|
|
370
376
|
const fileExc = (0, file_1.makeFileException)('notFound', childInfo.name, exc);
|
|
371
377
|
fileExc.inconsistentStateOfFS = true;
|
|
372
378
|
throw fileExc;
|
|
373
379
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
380
|
+
// XXX should we keep this, when merge with certain inputs will do same action
|
|
381
|
+
// async adoptItemsFromRemoteVersion(opts: OptionsToAdoptAllRemoteItems|undefined): Promise<number|undefined> {
|
|
382
|
+
// const { state, remote } = await this.syncStatus();
|
|
383
|
+
// if ((state !== 'conflicting') && (state !== 'behind')) {
|
|
384
|
+
// return;
|
|
385
|
+
// }
|
|
386
|
+
// const remoteVersion = versionFromRemoteBranch(remote!, opts?.remoteVersion);
|
|
387
|
+
// if (!remoteVersion) {
|
|
388
|
+
// throw 'something';
|
|
389
|
+
// }
|
|
390
|
+
// const { folderInfo: remoteState } = await this.readRemoteVersion(remoteVersion);
|
|
391
|
+
// const synced = undefined;
|
|
392
|
+
// return await this.doChangeWhileTrackingVersion(opts?.localVersion, async (state, newVersion) => {
|
|
393
|
+
// const { inRemote, nameOverlaps, differentKeys } = diffNodes(state, remoteState, synced);
|
|
394
|
+
// if (differentKeys) {
|
|
395
|
+
// throw makeFSSyncException(this.name, {
|
|
396
|
+
// message: `There are different keys, and implementation for it is not implemented, yet.`
|
|
397
|
+
// });
|
|
398
|
+
// }
|
|
399
|
+
// const events: { event: FSEvent; childObjId: string; }[] = [];
|
|
400
|
+
// if (!inRemote) {
|
|
401
|
+
// return events;
|
|
402
|
+
// }
|
|
403
|
+
// const addedNodes = new Set<string>();
|
|
404
|
+
// if (nameOverlaps) {
|
|
405
|
+
// const postfix = opts?.postfixForNameOverlaps;
|
|
406
|
+
// if ((postfix === undefined) || (postfix.length < 0)) {
|
|
407
|
+
// // XXX better exception
|
|
408
|
+
// throw 'something';
|
|
409
|
+
// }
|
|
410
|
+
// for (const itemName of nameOverlaps) {
|
|
411
|
+
// const node = remoteState.nodes[itemName];
|
|
412
|
+
// let newName = `${itemName}${postfix}`;
|
|
413
|
+
// while (state.nodes[newName]) {
|
|
414
|
+
// newName = `${newName}${postfix}`;
|
|
415
|
+
// }
|
|
416
|
+
// node.name = newName;
|
|
417
|
+
// state.nodes[newName] = node;
|
|
418
|
+
// addedNodes.add(itemName);
|
|
419
|
+
// const { event, childObjId } = this.makeEntryAdditionEvent(newVersion, 'sync', node);
|
|
420
|
+
// events.push({ event, childObjId });
|
|
421
|
+
// }
|
|
422
|
+
// }
|
|
423
|
+
// for (const { name: itemName } of inRemote) {
|
|
424
|
+
// if (addedNodes.has(itemName)) {
|
|
425
|
+
// continue;
|
|
426
|
+
// }
|
|
427
|
+
// const node = remoteState.nodes[itemName];
|
|
428
|
+
// state.nodes[itemName] = node;
|
|
429
|
+
// const { event, childObjId } = this.makeEntryAdditionEvent(newVersion, 'sync', node);
|
|
430
|
+
// events.push({ event, childObjId });
|
|
431
|
+
// }
|
|
432
|
+
// return events;
|
|
433
|
+
// });
|
|
434
|
+
// }
|
|
419
435
|
/**
|
|
420
436
|
* If no initial local version given, then this performs like doTransition(change) method.
|
|
421
437
|
* When initial local version is given and check, exceptions are thrown if versions mismatch,
|
|
@@ -578,16 +594,10 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
578
594
|
else {
|
|
579
595
|
throw new Error(`Unknown type of node: ${type}`);
|
|
580
596
|
}
|
|
581
|
-
addToTransitionState(state, node, key);
|
|
597
|
+
const nodeInfo = addToTransitionState(state, node, key);
|
|
582
598
|
this.storage.nodes.set(node);
|
|
583
|
-
const event =
|
|
584
|
-
|
|
585
|
-
path: this.name,
|
|
586
|
-
src: 'local',
|
|
587
|
-
newVersion: version,
|
|
588
|
-
entry: nodeToListingEntry(node)
|
|
589
|
-
};
|
|
590
|
-
return { event, childObjId: node.objId };
|
|
599
|
+
const { event, childObjId } = this.makeEntryAdditionEvent(version, 'local', nodeInfo);
|
|
600
|
+
return { event, childObjId };
|
|
591
601
|
});
|
|
592
602
|
return node;
|
|
593
603
|
});
|
|
@@ -603,28 +613,21 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
603
613
|
}
|
|
604
614
|
async removeChild(f) {
|
|
605
615
|
await this.doTransition(async (state, version) => {
|
|
606
|
-
const
|
|
607
|
-
if (!
|
|
616
|
+
const child = state.nodes[f.name];
|
|
617
|
+
if (!child || (child.objId !== f.objId)) {
|
|
608
618
|
throw new Error(`Not a child given: name==${f.name}, objId==${f.objId}, parentId==${f.parentId}, this folder objId==${this.objId}`);
|
|
609
619
|
}
|
|
610
620
|
delete state.nodes[f.name];
|
|
611
|
-
|
|
612
|
-
type: 'entry-removal',
|
|
613
|
-
path: this.name,
|
|
614
|
-
src: 'local',
|
|
615
|
-
name: f.name,
|
|
616
|
-
newVersion: version
|
|
617
|
-
};
|
|
618
|
-
return { event, childObjId: f.objId };
|
|
621
|
+
return this.makeEntryRemovalEvent(version, 'local', child);
|
|
619
622
|
});
|
|
620
623
|
// explicitly do not wait on a result of child's delete, cause if it fails
|
|
621
624
|
// we just get traceable garbage, yet, the rest of a live/non-deleted tree
|
|
622
625
|
// stays consistent
|
|
623
626
|
this.callRemoveObjOn('local', f);
|
|
624
627
|
}
|
|
625
|
-
changeChildName(
|
|
628
|
+
changeChildName(oldName, newName) {
|
|
626
629
|
return this.doTransition(async (state, version) => {
|
|
627
|
-
const child = state.nodes[
|
|
630
|
+
const child = state.nodes[oldName];
|
|
628
631
|
delete state.nodes[child.name];
|
|
629
632
|
state.nodes[newName] = child;
|
|
630
633
|
child.name = newName;
|
|
@@ -632,15 +635,10 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
632
635
|
if (childNode) {
|
|
633
636
|
childNode.name = newName;
|
|
634
637
|
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
src: 'local',
|
|
639
|
-
newName,
|
|
640
|
-
oldName: initName,
|
|
641
|
-
newVersion: version
|
|
638
|
+
return {
|
|
639
|
+
event: this.makeEntryRenamingEvent(version, 'local', newName, oldName),
|
|
640
|
+
childObjId: child.objId
|
|
642
641
|
};
|
|
643
|
-
return { event, childObjId: child.objId };
|
|
644
642
|
});
|
|
645
643
|
}
|
|
646
644
|
async moveChildTo(childName, dst, nameInDst) {
|
|
@@ -659,19 +657,11 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
659
657
|
await this.moveChildOut(childName, childJSON.objId, moveLabel);
|
|
660
658
|
}
|
|
661
659
|
}
|
|
662
|
-
async moveChildOut(name,
|
|
660
|
+
async moveChildOut(name, _childObjId, moveLabel) {
|
|
663
661
|
await this.doTransition(async (state, version) => {
|
|
664
662
|
const child = state.nodes[name];
|
|
665
663
|
delete state.nodes[name];
|
|
666
|
-
|
|
667
|
-
type: 'entry-removal',
|
|
668
|
-
path: this.name,
|
|
669
|
-
src: 'local',
|
|
670
|
-
name,
|
|
671
|
-
newVersion: version,
|
|
672
|
-
moveLabel
|
|
673
|
-
};
|
|
674
|
-
return { event, childObjId };
|
|
664
|
+
return this.makeEntryRemovalEvent(version, 'local', child, moveLabel);
|
|
675
665
|
});
|
|
676
666
|
}
|
|
677
667
|
async moveChildIn(newName, child, moveLabel) {
|
|
@@ -679,15 +669,8 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
679
669
|
await this.doTransition(async (state, version) => {
|
|
680
670
|
child.name = newName;
|
|
681
671
|
state.nodes[child.name] = child;
|
|
682
|
-
const event =
|
|
683
|
-
|
|
684
|
-
path: this.name,
|
|
685
|
-
src: 'local',
|
|
686
|
-
entry: nodeInfoToListingEntry(child),
|
|
687
|
-
newVersion: version,
|
|
688
|
-
moveLabel
|
|
689
|
-
};
|
|
690
|
-
return { event, childObjId: child.objId };
|
|
672
|
+
const { event, childObjId } = this.makeEntryAdditionEvent(version, 'local', child, moveLabel);
|
|
673
|
+
return { event, childObjId };
|
|
691
674
|
});
|
|
692
675
|
}
|
|
693
676
|
async getFolderInThisSubTree(path, createIfMissing = false, exclusiveCreate = false) {
|
|
@@ -1030,14 +1013,7 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1030
1013
|
return this.doChangeWhileTrackingVersion(initLocalVersion, async (state, newVersion) => {
|
|
1031
1014
|
remoteChildNode.name = childName;
|
|
1032
1015
|
state.nodes[remoteChildNode.name] = remoteChildNode;
|
|
1033
|
-
|
|
1034
|
-
type: 'entry-addition',
|
|
1035
|
-
path: this.name,
|
|
1036
|
-
src: 'sync',
|
|
1037
|
-
entry: nodeInfoToListingEntry(remoteChildNode),
|
|
1038
|
-
newVersion
|
|
1039
|
-
};
|
|
1040
|
-
return { event, childObjId: remoteChildNode.objId };
|
|
1016
|
+
return this.makeEntryAdditionEvent(newVersion, 'sync', remoteChildNode);
|
|
1041
1017
|
});
|
|
1042
1018
|
}
|
|
1043
1019
|
async replaceLocalChildWithRemote(remoteChildNode, initLocalVersion) {
|
|
@@ -1045,22 +1021,9 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1045
1021
|
const newVersion = await this.doChangeWhileTrackingVersion(initLocalVersion, async (state, newVersion) => {
|
|
1046
1022
|
origChildNode = state.nodes[remoteChildNode.name];
|
|
1047
1023
|
state.nodes[remoteChildNode.name] = remoteChildNode;
|
|
1048
|
-
const additionEvent = {
|
|
1049
|
-
type: 'entry-addition',
|
|
1050
|
-
path: this.name,
|
|
1051
|
-
src: 'sync',
|
|
1052
|
-
entry: nodeInfoToListingEntry(remoteChildNode),
|
|
1053
|
-
newVersion
|
|
1054
|
-
};
|
|
1055
|
-
const rmEvent = {
|
|
1056
|
-
type: 'entry-removal',
|
|
1057
|
-
path: this.name,
|
|
1058
|
-
src: 'sync',
|
|
1059
|
-
name: origChildNode.name
|
|
1060
|
-
};
|
|
1061
1024
|
return [
|
|
1062
|
-
|
|
1063
|
-
|
|
1025
|
+
this.makeEntryRemovalEvent(newVersion, 'sync', origChildNode),
|
|
1026
|
+
this.makeEntryAdditionEvent(newVersion, 'sync', remoteChildNode)
|
|
1064
1027
|
];
|
|
1065
1028
|
});
|
|
1066
1029
|
const origChild = await this.getOrMakeChildNodeForInfo(origChildNode);
|
|
@@ -1074,57 +1037,23 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1074
1037
|
return await this.crypto.read(srcOfRemote);
|
|
1075
1038
|
}
|
|
1076
1039
|
async diffCurrentAndRemote(remoteVersion) {
|
|
1077
|
-
const
|
|
1078
|
-
|
|
1079
|
-
if (state === 'behind') {
|
|
1080
|
-
isCurrentLocal = false;
|
|
1081
|
-
}
|
|
1082
|
-
else if (state === 'conflicting') {
|
|
1083
|
-
isCurrentLocal = true;
|
|
1084
|
-
}
|
|
1085
|
-
else {
|
|
1040
|
+
const v = await this.getRemoteVersionToDiff(remoteVersion);
|
|
1041
|
+
if (!v) {
|
|
1086
1042
|
return;
|
|
1087
1043
|
}
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
const { folderInfo, attrs, xattrs } = await this.readRemoteVersion(remoteVersion);
|
|
1091
|
-
return this.diffWithRemote(isCurrentLocal, remoteVersion, folderInfo, attrs, xattrs);
|
|
1044
|
+
else if (v.rm) {
|
|
1045
|
+
return v.rmDiff;
|
|
1092
1046
|
}
|
|
1093
1047
|
else {
|
|
1094
|
-
|
|
1048
|
+
const { isCurrentLocal, remoteVersion, syncedVersion } = v;
|
|
1049
|
+
const remote = await this.readRemoteVersion(remoteVersion);
|
|
1050
|
+
const synced = await this.readRemoteVersion(syncedVersion);
|
|
1051
|
+
return {
|
|
1052
|
+
...this.commonDiffWithRemote(isCurrentLocal, remoteVersion, remote, syncedVersion, synced),
|
|
1053
|
+
...diffNodes(this.currentState, remote.folderInfo, synced.folderInfo),
|
|
1054
|
+
};
|
|
1095
1055
|
}
|
|
1096
1056
|
}
|
|
1097
|
-
diffWithArchivedRemote(isCurrentLocal) {
|
|
1098
|
-
return {
|
|
1099
|
-
currentVersion: this.version,
|
|
1100
|
-
isCurrentLocal,
|
|
1101
|
-
isRemoteRemoved: true,
|
|
1102
|
-
ctime: {
|
|
1103
|
-
current: new Date(this.attrs.ctime)
|
|
1104
|
-
},
|
|
1105
|
-
mtime: {
|
|
1106
|
-
current: new Date(this.attrs.ctime)
|
|
1107
|
-
}
|
|
1108
|
-
};
|
|
1109
|
-
}
|
|
1110
|
-
diffWithRemote(isCurrentLocal, remoteVersion, folderInfo, attrs, xattrs) {
|
|
1111
|
-
const { ctime, mtime } = diffAttrs(this.attrs, attrs);
|
|
1112
|
-
const { inCurrent, inRemote, nameOverlaps, differentKeys, differentNames } = diffNodes(this.currentState, folderInfo);
|
|
1113
|
-
return {
|
|
1114
|
-
currentVersion: this.version,
|
|
1115
|
-
isCurrentLocal,
|
|
1116
|
-
isRemoteRemoved: false,
|
|
1117
|
-
remoteVersion,
|
|
1118
|
-
inCurrent,
|
|
1119
|
-
inRemote,
|
|
1120
|
-
nameOverlaps,
|
|
1121
|
-
differentKeys,
|
|
1122
|
-
differentNames,
|
|
1123
|
-
ctime,
|
|
1124
|
-
mtime,
|
|
1125
|
-
xattrs: diffXAttrs(this.xattrs, xattrs)
|
|
1126
|
-
};
|
|
1127
|
-
}
|
|
1128
1057
|
async getRemoteItemNode(remoteItemName, remoteVersion) {
|
|
1129
1058
|
const remoteChildNodeInfo = await this.getRemoteChildNodeInfo(remoteItemName, remoteVersion);
|
|
1130
1059
|
return await this.getOrMakeChildNodeForInfo(remoteChildNodeInfo, false);
|
|
@@ -1132,6 +1061,85 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
1132
1061
|
getStorage() {
|
|
1133
1062
|
return this.storage;
|
|
1134
1063
|
}
|
|
1064
|
+
async mergeCurrentAndRemoteVersions(opts) {
|
|
1065
|
+
const diff = await this.diffCurrentAndRemote(opts === null || opts === void 0 ? void 0 : opts.remoteVersion);
|
|
1066
|
+
if (!diff) {
|
|
1067
|
+
return;
|
|
1068
|
+
}
|
|
1069
|
+
else if (diff.isRemoteRemoved) {
|
|
1070
|
+
return -1;
|
|
1071
|
+
}
|
|
1072
|
+
else if (!diff.isCurrentLocal) {
|
|
1073
|
+
await this.adoptRemote({ remoteVersion: diff.remoteVersion });
|
|
1074
|
+
return this.version;
|
|
1075
|
+
}
|
|
1076
|
+
if ((opts === null || opts === void 0 ? void 0 : opts.localVersion) && (opts.localVersion !== diff.currentVersion)) {
|
|
1077
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
1078
|
+
versionMismatch: true,
|
|
1079
|
+
message: `Given local version ${opts.localVersion} is not equal to current ${diff.currentVersion}`
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
const { added, removed, renamed, rekeyed, nameOverlaps } = diff;
|
|
1083
|
+
if (rekeyed) {
|
|
1084
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
1085
|
+
message: `There are different keys, and implementation for it is not implemented, yet.`
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
if (nameOverlaps && !(opts === null || opts === void 0 ? void 0 : opts.postfixForNameOverlaps)) {
|
|
1089
|
+
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
1090
|
+
nameOverlaps,
|
|
1091
|
+
message: `There are name overlaps, but prefix for adding to remote item names isn't given.`
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
const remote = await this.readRemoteVersion(diff.remoteVersion);
|
|
1095
|
+
return await this.doChangeWhileTrackingVersion(diff.currentVersion, async (state, newVersion) => {
|
|
1096
|
+
const nodes = state.nodes;
|
|
1097
|
+
const remoteNodes = remote.folderInfo.nodes;
|
|
1098
|
+
const events = [];
|
|
1099
|
+
if (removed) {
|
|
1100
|
+
for (const { name, removedIn } of removed) {
|
|
1101
|
+
if (removedIn === 'r') {
|
|
1102
|
+
const node = nodes[name];
|
|
1103
|
+
delete nodes[name];
|
|
1104
|
+
events.push(this.makeEntryRemovalEvent(newVersion, 'sync', node));
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
if (renamed) {
|
|
1109
|
+
for (const { local, remote, renamedIn } of renamed) {
|
|
1110
|
+
if (renamedIn === 'r') {
|
|
1111
|
+
const node = nodes[local];
|
|
1112
|
+
(0, assert_1.assert)(!!node);
|
|
1113
|
+
node.name = remote;
|
|
1114
|
+
nodes[node.name] = node;
|
|
1115
|
+
events.push({
|
|
1116
|
+
event: this.makeEntryRenamingEvent(newVersion, 'sync', remote, local),
|
|
1117
|
+
childObjId: node.objId
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
else if (renamedIn === 'l&r') {
|
|
1121
|
+
// XXX use mtime to suggest which name to adopt -- TODO
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
if (added) {
|
|
1126
|
+
for (const { name, addedIn } of added) {
|
|
1127
|
+
if (addedIn === 'r') {
|
|
1128
|
+
const node = remoteNodes[name];
|
|
1129
|
+
(0, assert_1.assert)(!!node);
|
|
1130
|
+
if (nameOverlaps === null || nameOverlaps === void 0 ? void 0 : nameOverlaps.includes(name)) {
|
|
1131
|
+
while (nodes[node.name]) {
|
|
1132
|
+
node.name = `${node.name}${opts === null || opts === void 0 ? void 0 : opts.postfixForNameOverlaps}`;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
nodes[node.name] = node;
|
|
1136
|
+
events.push(this.makeEntryAdditionEvent(newVersion, 'sync', node));
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return events;
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1135
1143
|
}
|
|
1136
1144
|
exports.FolderNode = FolderNode;
|
|
1137
1145
|
Object.freeze(FolderNode.prototype);
|
|
@@ -1156,18 +1164,6 @@ function nodeInfoToListingEntry({ name, isFile, isFolder, isLink }) {
|
|
|
1156
1164
|
return { name };
|
|
1157
1165
|
}
|
|
1158
1166
|
}
|
|
1159
|
-
function nodeToListingEntry({ name, type }) {
|
|
1160
|
-
switch (type) {
|
|
1161
|
-
case 'file':
|
|
1162
|
-
return { name, isFolder: true };
|
|
1163
|
-
case 'folder':
|
|
1164
|
-
return { name, isFolder: true };
|
|
1165
|
-
case 'link':
|
|
1166
|
-
return { name, isLink: true };
|
|
1167
|
-
default:
|
|
1168
|
-
return { name };
|
|
1169
|
-
}
|
|
1170
|
-
}
|
|
1171
1167
|
function addToTransitionState(state, f, key) {
|
|
1172
1168
|
const nodeInfo = {
|
|
1173
1169
|
name: f.name,
|
|
@@ -1187,170 +1183,82 @@ function addToTransitionState(state, f, key) {
|
|
|
1187
1183
|
throw new Error(`Unknown type of file system entity: ${f.type}`);
|
|
1188
1184
|
}
|
|
1189
1185
|
state.nodes[nodeInfo.name] = nodeInfo;
|
|
1186
|
+
return nodeInfo;
|
|
1190
1187
|
}
|
|
1191
|
-
function
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
current: new Date(current.mtime),
|
|
1199
|
-
remote: new Date(remote.mtime)
|
|
1200
|
-
}
|
|
1201
|
-
};
|
|
1202
|
-
}
|
|
1203
|
-
function diffNodes(current, remote) {
|
|
1204
|
-
const inRemote = [];
|
|
1205
|
-
const nodesInCurrentById = new Map();
|
|
1206
|
-
for (const node of Object.values(current.nodes)) {
|
|
1207
|
-
nodesInCurrentById.set(node.objId, node);
|
|
1208
|
-
}
|
|
1188
|
+
function diffNodes(current, remote, synced) {
|
|
1189
|
+
const currentNodesById = orderByIds(current.nodes);
|
|
1190
|
+
const syncedNodesById = orderByIds(synced.nodes);
|
|
1191
|
+
const removed = [];
|
|
1192
|
+
const renamed = [];
|
|
1193
|
+
const added = [];
|
|
1194
|
+
const rekeyed = [];
|
|
1209
1195
|
const nameOverlaps = [];
|
|
1210
|
-
const differentNames = [];
|
|
1211
|
-
const differentKeys = [];
|
|
1212
1196
|
for (const remoteNode of Object.values(remote.nodes)) {
|
|
1213
|
-
const localNode =
|
|
1197
|
+
const localNode = currentNodesById.get(remoteNode.objId);
|
|
1214
1198
|
if (localNode) {
|
|
1215
|
-
if (localNode.name
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1199
|
+
if (localNode.name === remoteNode.name) {
|
|
1200
|
+
// nodes are same
|
|
1201
|
+
}
|
|
1202
|
+
else {
|
|
1203
|
+
const syncedNode = syncedNodesById.get(remoteNode.objId);
|
|
1204
|
+
(0, assert_1.assert)(!!synced);
|
|
1205
|
+
const localChanged = (syncedNode.name !== localNode.name);
|
|
1206
|
+
const remoteChanged = (syncedNode.name !== remoteNode.name);
|
|
1207
|
+
renamed.push({
|
|
1208
|
+
local: localNode.name,
|
|
1209
|
+
remote: remoteNode.name,
|
|
1210
|
+
renamedIn: (localChanged ? (remoteChanged ? 'l&r' : 'l') : 'r')
|
|
1219
1211
|
});
|
|
1212
|
+
if (current.nodes[remoteNode.name]) {
|
|
1213
|
+
nameOverlaps.push(remoteNode.name);
|
|
1214
|
+
}
|
|
1220
1215
|
}
|
|
1221
|
-
if (!areBytesEqual(localNode.key, remoteNode.key)) {
|
|
1222
|
-
|
|
1216
|
+
if (!(0, node_in_fs_1.areBytesEqual)(localNode.key, remoteNode.key)) {
|
|
1217
|
+
const syncedNode = syncedNodesById.get(remoteNode.objId);
|
|
1218
|
+
(0, assert_1.assert)(!!synced);
|
|
1219
|
+
const localChanged = !(0, node_in_fs_1.areBytesEqual)(localNode.key, syncedNode.key);
|
|
1220
|
+
const remoteChanged = !(0, node_in_fs_1.areBytesEqual)(localNode.key, syncedNode.key);
|
|
1221
|
+
rekeyed.push({
|
|
1222
|
+
local: localNode.name,
|
|
1223
|
+
remote: remoteNode.name,
|
|
1224
|
+
rekeyedIn: (localChanged ? (remoteChanged ? 'l&r' : 'l') : 'r')
|
|
1225
|
+
});
|
|
1223
1226
|
}
|
|
1224
|
-
|
|
1227
|
+
currentNodesById.delete(localNode.objId);
|
|
1225
1228
|
}
|
|
1226
1229
|
else {
|
|
1227
|
-
|
|
1230
|
+
const syncedNode = syncedNodesById.get(remoteNode.objId);
|
|
1231
|
+
if (syncedNode) {
|
|
1232
|
+
removed.push({ name: remoteNode.name, removedIn: 'l' });
|
|
1233
|
+
}
|
|
1234
|
+
else {
|
|
1235
|
+
added.push({ name: remoteNode.name, addedIn: 'r' });
|
|
1236
|
+
}
|
|
1228
1237
|
if (current.nodes[remoteNode.name]) {
|
|
1229
1238
|
nameOverlaps.push(remoteNode.name);
|
|
1230
1239
|
}
|
|
1231
1240
|
}
|
|
1232
1241
|
}
|
|
1233
|
-
const
|
|
1234
|
-
|
|
1235
|
-
|
|
1242
|
+
for (const localNode of currentNodesById.values()) {
|
|
1243
|
+
const syncedNode = syncedNodesById.get(localNode.objId);
|
|
1244
|
+
if (!syncedNode) {
|
|
1245
|
+
added.push({ name: localNode.name, addedIn: 'l' });
|
|
1246
|
+
}
|
|
1236
1247
|
}
|
|
1237
1248
|
return {
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1249
|
+
removed: ((removed.length > 0) ? removed : undefined),
|
|
1250
|
+
renamed: ((renamed.length > 0) ? renamed : undefined),
|
|
1251
|
+
added: ((added.length > 0) ? added : undefined),
|
|
1252
|
+
rekeyed: ((rekeyed.length > 0) ? rekeyed : undefined),
|
|
1241
1253
|
nameOverlaps: ((nameOverlaps.length > 0) ? nameOverlaps : undefined),
|
|
1242
|
-
differentKeys: ((differentKeys.length > 0) ? differentKeys : undefined)
|
|
1243
1254
|
};
|
|
1244
1255
|
}
|
|
1245
|
-
function
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
for (const { name: nameInCurrent } of inCurrent) {
|
|
1250
|
-
if (inRemote.find(({ name }) => (name === nameInCurrent))) {
|
|
1251
|
-
nameOverlaps.push(nameInCurrent);
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
if (nameOverlaps.length > 0) {
|
|
1255
|
-
return { inCurrent, inRemote, nameOverlaps };
|
|
1256
|
-
}
|
|
1257
|
-
else {
|
|
1258
|
-
return { inCurrent, inRemote };
|
|
1259
|
-
}
|
|
1260
|
-
}
|
|
1261
|
-
else {
|
|
1262
|
-
return { inCurrent };
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
else {
|
|
1266
|
-
if (inRemote) {
|
|
1267
|
-
return { inRemote };
|
|
1268
|
-
}
|
|
1269
|
-
else {
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
function diffXAttrs(current, remote) {
|
|
1275
|
-
const haveCurrentXAttrs = (current && (current.list().length > 0));
|
|
1276
|
-
const haveRemoteXAttrs = (remote && (remote.list().length > 0));
|
|
1277
|
-
if (haveCurrentXAttrs && haveRemoteXAttrs) {
|
|
1278
|
-
const inCurrent = getOnlyNotEqualXAttrs(current, remote);
|
|
1279
|
-
const inRemote = getOnlyNotEqualXAttrs(remote, current);
|
|
1280
|
-
return combineCheckingNameOverlaps(inCurrent, inRemote);
|
|
1281
|
-
}
|
|
1282
|
-
else if (haveCurrentXAttrs && !haveRemoteXAttrs) {
|
|
1283
|
-
return { inCurrent: allXAttrsToDiff(current) };
|
|
1284
|
-
}
|
|
1285
|
-
else if (!haveCurrentXAttrs && haveRemoteXAttrs) {
|
|
1286
|
-
return { inRemote: allXAttrsToDiff(remote) };
|
|
1287
|
-
}
|
|
1288
|
-
else {
|
|
1289
|
-
return;
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
function allXAttrsToDiff(src) {
|
|
1293
|
-
const collected = [];
|
|
1294
|
-
for (const name of src.list()) {
|
|
1295
|
-
const value = src.get(name);
|
|
1296
|
-
if (value !== undefined) {
|
|
1297
|
-
collected.push({ name, value });
|
|
1298
|
-
}
|
|
1256
|
+
function orderByIds(nodes) {
|
|
1257
|
+
const nodesById = new Map();
|
|
1258
|
+
for (const node of Object.values(nodes)) {
|
|
1259
|
+
nodesById.set(node.objId, node);
|
|
1299
1260
|
}
|
|
1300
|
-
return
|
|
1301
|
-
}
|
|
1302
|
-
function getOnlyNotEqualXAttrs(src, exclude) {
|
|
1303
|
-
const collected = [];
|
|
1304
|
-
for (const name of src.list()) {
|
|
1305
|
-
const valueInSrc = src.get(name);
|
|
1306
|
-
if (valueInSrc === undefined) {
|
|
1307
|
-
continue;
|
|
1308
|
-
}
|
|
1309
|
-
const valueInExclude = exclude.get(name);
|
|
1310
|
-
if ((valueInExclude === undefined)
|
|
1311
|
-
|| !areXAttrValuesEqual(valueInSrc, valueInExclude)) {
|
|
1312
|
-
collected.push({ name, value: valueInSrc });
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
return ((collected.length > 0) ? collected : undefined);
|
|
1316
|
-
}
|
|
1317
|
-
function areXAttrValuesEqual(v1, v2) {
|
|
1318
|
-
if (Buffer.isBuffer(v1) || ArrayBuffer.isView(v1)) {
|
|
1319
|
-
if (Buffer.isBuffer(v2) || ArrayBuffer.isView(v2)) {
|
|
1320
|
-
return areBytesEqual(v1, v2);
|
|
1321
|
-
}
|
|
1322
|
-
{
|
|
1323
|
-
return false;
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
else if (typeof v1 === 'string') {
|
|
1327
|
-
if (typeof v2 === 'string') {
|
|
1328
|
-
return (v1 === v2);
|
|
1329
|
-
}
|
|
1330
|
-
else {
|
|
1331
|
-
return false;
|
|
1332
|
-
}
|
|
1333
|
-
}
|
|
1334
|
-
else {
|
|
1335
|
-
if (Buffer.isBuffer(v2) || ArrayBuffer.isView(v2)
|
|
1336
|
-
|| (typeof v2 === 'string')) {
|
|
1337
|
-
return false;
|
|
1338
|
-
}
|
|
1339
|
-
else {
|
|
1340
|
-
return (0, json_utils_1.deepEqual)(v1, v2);
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
function areBytesEqual(b1, b2) {
|
|
1345
|
-
if (b1.length !== b2.length) {
|
|
1346
|
-
return false;
|
|
1347
|
-
}
|
|
1348
|
-
for (let i = 0; i < b1.length; i += 1) {
|
|
1349
|
-
if (b1[i] !== b2[i]) {
|
|
1350
|
-
return false;
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
return true;
|
|
1261
|
+
return nodesById;
|
|
1354
1262
|
}
|
|
1355
1263
|
function identifyChanges(originalNodes, newNodes) {
|
|
1356
1264
|
const removedNodes = [];
|
|
@@ -1383,23 +1291,4 @@ function identifyChanges(originalNodes, newNodes) {
|
|
|
1383
1291
|
}
|
|
1384
1292
|
return { addedNodes, removedNodes, renamedNodes };
|
|
1385
1293
|
}
|
|
1386
|
-
function versionFromRemoteBranch(remote, remoteVersion) {
|
|
1387
|
-
var _a;
|
|
1388
|
-
if (remote.isArchived) {
|
|
1389
|
-
return;
|
|
1390
|
-
}
|
|
1391
|
-
if (remoteVersion) {
|
|
1392
|
-
if ((remoteVersion !== remote.latest)
|
|
1393
|
-
&& !((_a = remote.archived) === null || _a === void 0 ? void 0 : _a.includes(remoteVersion))) {
|
|
1394
|
-
throw (0, exceptions_1.makeFSSyncException)(this.name, {
|
|
1395
|
-
versionMismatch: true,
|
|
1396
|
-
message: `Unknown remote version ${remoteVersion}`
|
|
1397
|
-
});
|
|
1398
|
-
}
|
|
1399
|
-
return remoteVersion;
|
|
1400
|
-
}
|
|
1401
|
-
else {
|
|
1402
|
-
return remote.latest;
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
1294
|
Object.freeze(exports);
|