core-3nweb-client-lib 0.43.7 → 0.43.9
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 +82 -4
- package/build/core/storage/synced/obj-files.d.ts +1 -0
- package/build/core/storage/synced/obj-files.js +16 -0
- package/build/core/storage/synced/obj-status.d.ts +1 -0
- package/build/core/storage/synced/obj-status.js +18 -0
- package/build/core/storage/synced/storage.d.ts +6 -2
- package/build/core/storage/synced/storage.js +12 -17
- package/build/core/storage/synced/upsyncer.d.ts +10 -1
- package/build/core/storage/synced/upsyncer.js +72 -9
- package/build/core-ipc/file.d.ts +27 -4
- package/build/core-ipc/file.js +90 -94
- package/build/core-ipc/fs.js +68 -132
- package/build/lib-client/fs-utils/files.js +6 -0
- package/build/lib-client/objs-on-disk/obj-on-disk.d.ts +1 -0
- package/build/lib-client/objs-on-disk/obj-on-disk.js +8 -1
- package/build/lib-client/xsp-fs/common.d.ts +13 -21
- package/build/lib-client/xsp-fs/common.js +4 -16
- package/build/lib-client/xsp-fs/file-node.d.ts +3 -2
- package/build/lib-client/xsp-fs/file-node.js +17 -11
- package/build/lib-client/xsp-fs/file.d.ts +5 -0
- package/build/lib-client/xsp-fs/file.js +26 -13
- package/build/lib-client/xsp-fs/folder-node.d.ts +7 -1
- package/build/lib-client/xsp-fs/folder-node.js +18 -10
- package/build/lib-client/xsp-fs/fs.d.ts +5 -0
- package/build/lib-client/xsp-fs/fs.js +33 -26
- package/build/lib-client/xsp-fs/link-node.d.ts +3 -0
- package/build/lib-client/xsp-fs/link-node.js +5 -1
- package/build/lib-client/xsp-fs/node-in-fs.d.ts +20 -6
- package/build/lib-client/xsp-fs/node-in-fs.js +69 -14
- package/build/lib-client/xsp-fs/node-persistence.d.ts +1 -0
- package/build/lib-client/xsp-fs/node-persistence.js +4 -0
- package/build/lib-common/big-endian.js +2 -2
- package/build/lib-common/processes/labelled-exec-pools.js +1 -3
- package/build/protos/asmail.proto.js +1614 -1588
- package/build/protos/file.proto.js +1258 -541
- package/build/protos/fs.proto.js +1459 -1433
- package/package.json +4 -4
- package/protos/file.proto +31 -15
- package/protos/fs.proto +13 -22
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2018 - 2020, 2022 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2018 - 2020, 2022, 2025 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -200,6 +200,13 @@ class ObjOnDisk {
|
|
|
200
200
|
doesFileNeedDownload() {
|
|
201
201
|
return (this.segsThatNeedDownload().length === 0);
|
|
202
202
|
}
|
|
203
|
+
numOfBytesNeedingDownload() {
|
|
204
|
+
let totalLen = 0;
|
|
205
|
+
for (const { len } of this.segsThatNeedDownload()) {
|
|
206
|
+
totalLen += len;
|
|
207
|
+
}
|
|
208
|
+
return totalLen;
|
|
209
|
+
}
|
|
203
210
|
async downloadMissingSections() {
|
|
204
211
|
const needDownload = this.segsThatNeedDownload();
|
|
205
212
|
for (const chunk of needDownload) {
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ScryptGenParams } from '../key-derivation';
|
|
2
|
-
import { AsyncSBoxCryptor, Subscribe, ObjSource } from 'xsp-files';
|
|
3
|
-
import { Observable } from 'rxjs';
|
|
4
|
-
import { LogError } from '../logging/log-to-file';
|
|
5
|
-
export { AsyncSBoxCryptor } from 'xsp-files';
|
|
6
|
-
export { FolderInJSON } from './folder-node';
|
|
1
|
+
import type { ScryptGenParams } from '../key-derivation';
|
|
2
|
+
import type { AsyncSBoxCryptor, Subscribe, ObjSource } from 'xsp-files';
|
|
3
|
+
import type { Observable } from 'rxjs';
|
|
4
|
+
import type { LogError } from '../logging/log-to-file';
|
|
5
|
+
export type { AsyncSBoxCryptor } from 'xsp-files';
|
|
6
|
+
export type { FolderInJSON } from './folder-node';
|
|
7
7
|
type StorageType = web3n.files.FSType;
|
|
8
8
|
type FolderEvent = web3n.files.FolderEvent;
|
|
9
9
|
type FileEvent = web3n.files.FileEvent;
|
|
@@ -12,6 +12,7 @@ type SyncStatus = web3n.files.SyncStatus;
|
|
|
12
12
|
type OptionsToAdopteRemote = web3n.files.OptionsToAdopteRemote;
|
|
13
13
|
type FSSyncException = web3n.files.FSSyncException;
|
|
14
14
|
type FileException = web3n.files.FileException;
|
|
15
|
+
type UploadEvent = web3n.files.UploadEvent;
|
|
15
16
|
export type FSChangeSrc = web3n.files.FSChangeEvent['src'];
|
|
16
17
|
export interface Node {
|
|
17
18
|
objId: string;
|
|
@@ -20,18 +21,6 @@ export interface Node {
|
|
|
20
21
|
}
|
|
21
22
|
export type NodeType = 'file' | 'link' | 'folder';
|
|
22
23
|
export type ObjId = string | null;
|
|
23
|
-
/**
|
|
24
|
-
* This is a container for file system nodes.
|
|
25
|
-
*
|
|
26
|
-
* Current implementation performs two functions: container for nodes, and a
|
|
27
|
-
* provider of node type, corresponding to given object.
|
|
28
|
-
* The later function, used by synced storage for conflict resolution, takes
|
|
29
|
-
* advantage of container not forgeting nodes, like cache may do.
|
|
30
|
-
* So, at least for local storage's sake, this container may be refactored to
|
|
31
|
-
* act more like cache, and even then we shouldn't forget about cascading keys
|
|
32
|
-
* and a need to keep parent nodes in memory, while child nodes are in
|
|
33
|
-
* use/cache.
|
|
34
|
-
*/
|
|
35
24
|
export declare class NodesContainer {
|
|
36
25
|
private nodes;
|
|
37
26
|
private promises;
|
|
@@ -51,7 +40,7 @@ export interface NodeEvent {
|
|
|
51
40
|
objId: ObjId;
|
|
52
41
|
parentObjId?: ObjId;
|
|
53
42
|
childObjId?: ObjId;
|
|
54
|
-
event: FolderEvent | FileEvent | RemoteEvent;
|
|
43
|
+
event: FolderEvent | FileEvent | RemoteEvent | UploadEvent;
|
|
55
44
|
}
|
|
56
45
|
export interface Storage {
|
|
57
46
|
readonly type: StorageType;
|
|
@@ -113,13 +102,16 @@ export interface SyncedStorage extends Storage {
|
|
|
113
102
|
getRootKeyDerivParamsFromServer(): Promise<ScryptGenParams>;
|
|
114
103
|
adoptRemote(objId: ObjId, opts: OptionsToAdopteRemote | undefined): Promise<number | undefined>;
|
|
115
104
|
updateStatusInfo(objId: ObjId): Promise<SyncStatus>;
|
|
116
|
-
isObjOnDisk(objId: ObjId): Promise<boolean>;
|
|
117
105
|
isRemoteVersionOnDisk(objId: ObjId, version: number): Promise<'partial' | 'complete' | 'none'>;
|
|
118
106
|
download(objId: ObjId, version: number): Promise<void>;
|
|
119
|
-
|
|
107
|
+
startUpload(objId: ObjId, localVersion: number, uploadVersion: number, uploadHeader: UploadHeaderChange | undefined, createOnRemote: boolean, eventSink: (event: UploadEvent) => void): Promise<{
|
|
108
|
+
uploadTaskId: number;
|
|
109
|
+
completion: Promise<void>;
|
|
110
|
+
}>;
|
|
120
111
|
dropCachedLocalObjVersionsLessOrEqual(objId: ObjId, localVersion: number): void;
|
|
121
112
|
uploadObjRemoval(objId: ObjId): Promise<void>;
|
|
122
113
|
status(objId: ObjId): Promise<SyncedObjStatus>;
|
|
114
|
+
getNumOfBytesNeedingDownload(objId: ObjId, version: number): Promise<number | 'unknown'>;
|
|
123
115
|
suspendNetworkActivity(): void;
|
|
124
116
|
resumeNetworkActivity(): void;
|
|
125
117
|
}
|
|
@@ -21,18 +21,6 @@ exports.wrapStorageImplementation = wrapStorageImplementation;
|
|
|
21
21
|
exports.wrapSyncStorageImplementation = wrapSyncStorageImplementation;
|
|
22
22
|
exports.isSyncedStorage = isSyncedStorage;
|
|
23
23
|
exports.setPathInExc = setPathInExc;
|
|
24
|
-
/**
|
|
25
|
-
* This is a container for file system nodes.
|
|
26
|
-
*
|
|
27
|
-
* Current implementation performs two functions: container for nodes, and a
|
|
28
|
-
* provider of node type, corresponding to given object.
|
|
29
|
-
* The later function, used by synced storage for conflict resolution, takes
|
|
30
|
-
* advantage of container not forgeting nodes, like cache may do.
|
|
31
|
-
* So, at least for local storage's sake, this container may be refactored to
|
|
32
|
-
* act more like cache, and even then we shouldn't forget about cascading keys
|
|
33
|
-
* and a need to keep parent nodes in memory, while child nodes are in
|
|
34
|
-
* use/cache.
|
|
35
|
-
*/
|
|
36
24
|
class NodesContainer {
|
|
37
25
|
constructor() {
|
|
38
26
|
this.nodes = new Map();
|
|
@@ -125,23 +113,23 @@ function wrapSyncStorageImplementation(impl) {
|
|
|
125
113
|
for (const [field, value] of Object.entries(storageWrap)) {
|
|
126
114
|
wrap[field] = value;
|
|
127
115
|
}
|
|
128
|
-
wrap.getRootKeyDerivParamsFromServer =
|
|
129
|
-
impl.getRootKeyDerivParamsFromServer.bind(impl);
|
|
116
|
+
wrap.getRootKeyDerivParamsFromServer = impl.getRootKeyDerivParamsFromServer.bind(impl);
|
|
130
117
|
wrap.getObjSrcOfRemoteVersion = impl.getObjSrcOfRemoteVersion.bind(impl);
|
|
131
118
|
wrap.archiveVersionOnServer = impl.archiveVersionOnServer.bind(impl);
|
|
132
119
|
wrap.isRemoteVersionOnDisk = impl.isRemoteVersionOnDisk.bind(impl);
|
|
133
120
|
wrap.download = impl.download.bind(impl);
|
|
134
|
-
wrap.
|
|
121
|
+
wrap.startUpload = impl.startUpload.bind(impl);
|
|
135
122
|
wrap.uploadObjRemoval = impl.uploadObjRemoval.bind(impl);
|
|
136
123
|
wrap.dropCachedLocalObjVersionsLessOrEqual = impl.dropCachedLocalObjVersionsLessOrEqual.bind(impl);
|
|
137
124
|
wrap.adoptRemote = impl.adoptRemote.bind(impl);
|
|
138
125
|
wrap.updateStatusInfo = impl.updateStatusInfo.bind(impl);
|
|
139
126
|
wrap.suspendNetworkActivity = impl.suspendNetworkActivity.bind(impl);
|
|
140
127
|
wrap.resumeNetworkActivity = impl.resumeNetworkActivity.bind(impl);
|
|
128
|
+
wrap.getNumOfBytesNeedingDownload = impl.getNumOfBytesNeedingDownload.bind(impl);
|
|
141
129
|
return Object.freeze(wrap);
|
|
142
130
|
}
|
|
143
131
|
function isSyncedStorage(storage) {
|
|
144
|
-
return !!storage.
|
|
132
|
+
return !!storage.startUpload;
|
|
145
133
|
}
|
|
146
134
|
function setPathInExc(exc, path) {
|
|
147
135
|
if ((exc.type === 'fs-sync') || (exc.type === 'file')) {
|
|
@@ -12,6 +12,7 @@ type FileByteSource = web3n.files.FileByteSource;
|
|
|
12
12
|
type FileByteSink = web3n.files.FileByteSink;
|
|
13
13
|
type XAttrsChanges = web3n.files.XAttrsChanges;
|
|
14
14
|
type VersionedReadFlags = web3n.files.VersionedReadFlags;
|
|
15
|
+
type Stats = web3n.files.Stats;
|
|
15
16
|
interface FileAttrs {
|
|
16
17
|
attrs: CommonAttrs;
|
|
17
18
|
size: number;
|
|
@@ -19,7 +20,7 @@ interface FileAttrs {
|
|
|
19
20
|
}
|
|
20
21
|
declare class FilePersistance extends NodePersistance {
|
|
21
22
|
constructor(zNonce: Uint8Array, key: Uint8Array, cryptor: AsyncSBoxCryptor);
|
|
22
|
-
|
|
23
|
+
getFileAttrs(objSrc: ObjSource): Promise<FileAttrs>;
|
|
23
24
|
getFileSource(objSrc: ObjSource): Promise<FileByteSource>;
|
|
24
25
|
readBytes(objSrc: ObjSource, start: number | undefined, end: number | undefined): Promise<Uint8Array | undefined>;
|
|
25
26
|
saveBytes(bytes: Uint8Array | Uint8Array[], version: number, attrs: CommonAttrs, xattrs: XAttrs | undefined): Promise<Subscribe>;
|
|
@@ -42,7 +43,7 @@ export declare class FileNode extends NodeInFS<FilePersistance> {
|
|
|
42
43
|
private static initWithAttrs;
|
|
43
44
|
protected setCurrentStateFrom(src: ObjSource): Promise<void>;
|
|
44
45
|
private setUpdatedState;
|
|
45
|
-
|
|
46
|
+
getStats(flags?: VersionedReadFlags): Promise<Stats>;
|
|
46
47
|
readSrc(flags: VersionedReadFlags | undefined): Promise<{
|
|
47
48
|
src: FileByteSource;
|
|
48
49
|
version: number;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2020, 2022 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2020, 2022, 2025 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -29,19 +29,16 @@ const assert_1 = require("../../lib-common/assert");
|
|
|
29
29
|
const attrs_1 = require("./attrs");
|
|
30
30
|
const file_1 = require("../../lib-common/exceptions/file");
|
|
31
31
|
const node_persistence_1 = require("./node-persistence");
|
|
32
|
-
async function fileAttrsFrom(payload) {
|
|
33
|
-
const attrs = payload.getAttrs();
|
|
34
|
-
const xattrs = await payload.getXAttrs();
|
|
35
|
-
return { attrs: attrs_1.CommonAttrs.fromAttrs(attrs), size: attrs.size, xattrs };
|
|
36
|
-
}
|
|
37
32
|
class FilePersistance extends node_persistence_1.NodePersistance {
|
|
38
33
|
constructor(zNonce, key, cryptor) {
|
|
39
34
|
super(zNonce, key, cryptor);
|
|
40
35
|
Object.seal(this);
|
|
41
36
|
}
|
|
42
|
-
async
|
|
37
|
+
async getFileAttrs(objSrc) {
|
|
43
38
|
const payload = await super.readonlyPayload(objSrc);
|
|
44
|
-
|
|
39
|
+
const attrs = payload.getAttrs();
|
|
40
|
+
const xattrs = await payload.getXAttrs();
|
|
41
|
+
return { attrs: attrs_1.CommonAttrs.fromAttrs(attrs), size: attrs.size, xattrs };
|
|
45
42
|
}
|
|
46
43
|
async getFileSource(objSrc) {
|
|
47
44
|
const payload = await this.readonlyPayload(objSrc);
|
|
@@ -122,15 +119,24 @@ class FileNode extends node_in_fs_1.NodeInFS {
|
|
|
122
119
|
return file;
|
|
123
120
|
}
|
|
124
121
|
async setCurrentStateFrom(src) {
|
|
125
|
-
const fileAttrs = await this.crypto.
|
|
122
|
+
const fileAttrs = await this.crypto.getFileAttrs(src);
|
|
126
123
|
this.setUpdatedState(src.version, fileAttrs);
|
|
127
124
|
}
|
|
128
125
|
setUpdatedState(version, fileAttrs) {
|
|
129
126
|
this.fileSize = fileAttrs.size;
|
|
130
127
|
super.setUpdatedParams(version, fileAttrs.attrs, fileAttrs.xattrs);
|
|
131
128
|
}
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
async getStats(flags) {
|
|
130
|
+
const { stats, attrs } = await this.getStatsAndSize(flags);
|
|
131
|
+
stats.size = (attrs ? attrs.size : this.fileSize);
|
|
132
|
+
if ((this.storage.type === 'synced')
|
|
133
|
+
|| (this.storage.type === 'share')) {
|
|
134
|
+
const bytesNeedDownload = await this.syncedStorage().getNumOfBytesNeedingDownload(this.objId, stats.version);
|
|
135
|
+
if (typeof bytesNeedDownload === 'number') {
|
|
136
|
+
stats.bytesNeedDownload = bytesNeedDownload;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return stats;
|
|
134
140
|
}
|
|
135
141
|
async readSrc(flags) {
|
|
136
142
|
const objSrc = await this.getObjSrcOfVersion(flags);
|
|
@@ -54,6 +54,7 @@ declare class V implements WritableFileVersionedAPI, N {
|
|
|
54
54
|
constructor(name: string, node: FileNode | undefined, makeOrGetNode: (() => Promise<FileNode>) | undefined, writable: boolean, isInSyncedStorage: boolean);
|
|
55
55
|
getNode(): Promise<FileNode>;
|
|
56
56
|
ensureIsWritable(): void;
|
|
57
|
+
stat(flags?: VersionedReadFlags): Promise<Stats>;
|
|
57
58
|
updateXAttrs(changes: XAttrsChanges): Promise<number>;
|
|
58
59
|
getXAttr(xaName: string, flags?: VersionedReadFlags): Promise<{
|
|
59
60
|
attr: any;
|
|
@@ -97,6 +98,10 @@ declare class V implements WritableFileVersionedAPI, N {
|
|
|
97
98
|
declare class S implements WritableFileSyncAPI {
|
|
98
99
|
private readonly n;
|
|
99
100
|
constructor(n: N);
|
|
101
|
+
startUpload(opts?: OptionsToUploadLocal): Promise<{
|
|
102
|
+
uploadVersion: number;
|
|
103
|
+
uploadTaskId: number;
|
|
104
|
+
} | undefined>;
|
|
100
105
|
upload(opts?: OptionsToUploadLocal): Promise<number | undefined>;
|
|
101
106
|
status(skipServerCheck?: boolean): Promise<SyncStatus>;
|
|
102
107
|
updateStatusInfo(): Promise<SyncStatus>;
|
|
@@ -54,18 +54,8 @@ class FileObject {
|
|
|
54
54
|
linkParams.readonly = !this.writable;
|
|
55
55
|
return linkParams;
|
|
56
56
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const attrs = node.getAttrs();
|
|
60
|
-
const stat = {
|
|
61
|
-
writable: this.writable,
|
|
62
|
-
size: node.size,
|
|
63
|
-
version: node.version,
|
|
64
|
-
isFile: true,
|
|
65
|
-
ctime: new Date(attrs.ctime),
|
|
66
|
-
mtime: new Date(attrs.mtime),
|
|
67
|
-
};
|
|
68
|
-
return stat;
|
|
57
|
+
stat() {
|
|
58
|
+
return this.v.stat();
|
|
69
59
|
}
|
|
70
60
|
async updateXAttrs(changes) {
|
|
71
61
|
await this.v.updateXAttrs(changes);
|
|
@@ -143,6 +133,12 @@ class V {
|
|
|
143
133
|
throw new Error(`File is not writable`);
|
|
144
134
|
}
|
|
145
135
|
}
|
|
136
|
+
async stat(flags) {
|
|
137
|
+
const node = await this.getNode();
|
|
138
|
+
const stats = await node.getStats(flags);
|
|
139
|
+
stats.writable = this.writable;
|
|
140
|
+
return stats;
|
|
141
|
+
}
|
|
146
142
|
async updateXAttrs(changes) {
|
|
147
143
|
this.ensureIsWritable();
|
|
148
144
|
const node = await this.getNode();
|
|
@@ -228,10 +224,27 @@ class S {
|
|
|
228
224
|
this.n = n;
|
|
229
225
|
Object.freeze(this);
|
|
230
226
|
}
|
|
227
|
+
async startUpload(opts) {
|
|
228
|
+
this.n.ensureIsWritable();
|
|
229
|
+
const node = await this.n.getNode();
|
|
230
|
+
const startedUpload = await node.startUpload(opts);
|
|
231
|
+
if (startedUpload) {
|
|
232
|
+
const { uploadTaskId, uploadVersion } = startedUpload;
|
|
233
|
+
return { uploadTaskId, uploadVersion };
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
231
239
|
async upload(opts) {
|
|
232
240
|
this.n.ensureIsWritable();
|
|
233
241
|
const node = await this.n.getNode();
|
|
234
|
-
const
|
|
242
|
+
const startedUpload = await node.startUpload(opts);
|
|
243
|
+
if (!startedUpload) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const { uploadVersion, completion } = startedUpload;
|
|
247
|
+
await completion;
|
|
235
248
|
return uploadVersion;
|
|
236
249
|
}
|
|
237
250
|
async status(skipServerCheck = false) {
|
|
@@ -13,6 +13,7 @@ type OptionsToAdopteRemote = web3n.files.OptionsToAdopteRemote;
|
|
|
13
13
|
type OptionsToAdoptRemoteItem = web3n.files.OptionsToAdoptRemoteItem;
|
|
14
14
|
type OptionsToUploadLocal = web3n.files.OptionsToUploadLocal;
|
|
15
15
|
type VersionedReadFlags = web3n.files.VersionedReadFlags;
|
|
16
|
+
type Stats = web3n.files.Stats;
|
|
16
17
|
export interface NodeInfo {
|
|
17
18
|
/**
|
|
18
19
|
* This is a usual file name.
|
|
@@ -74,6 +75,7 @@ export declare class FolderNode extends NodeInFS<FolderPersistance> {
|
|
|
74
75
|
private static readNodeFromObjBytes;
|
|
75
76
|
static rootFromLinkParams(storage: Storage, params: FolderLinkParams): Promise<FolderNode>;
|
|
76
77
|
static rootFromJSON(storage: Storage, name: string | undefined, folderJson: FolderInJSON): FolderNode;
|
|
78
|
+
getStats(flags?: VersionedReadFlags): Promise<Stats>;
|
|
77
79
|
protected setCurrentStateFrom(src: ObjSource): Promise<void>;
|
|
78
80
|
adoptRemote(opts: OptionsToAdopteRemote | undefined): Promise<void>;
|
|
79
81
|
private callRemoveObjOn;
|
|
@@ -142,7 +144,11 @@ export declare class FolderNode extends NodeInFS<FolderPersistance> {
|
|
|
142
144
|
private removeChildrenObjsInSyncedStorage;
|
|
143
145
|
private uploadRemovalOfObjs;
|
|
144
146
|
getParamsForLink(): LinkParameters<FolderLinkParams>;
|
|
145
|
-
|
|
147
|
+
startUpload(opts: OptionsToUploadLocal | undefined): Promise<{
|
|
148
|
+
uploadVersion: number;
|
|
149
|
+
completion: Promise<void>;
|
|
150
|
+
uploadTaskId: number;
|
|
151
|
+
} | undefined>;
|
|
146
152
|
private uploadRemovalOf;
|
|
147
153
|
private listRemovedInTreeToUploadRm;
|
|
148
154
|
protected needUpload(opts: OptionsToUploadLocal | undefined): Promise<{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2015 - 2020, 2022 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2015 - 2020, 2022, 2025 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -162,6 +162,10 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
162
162
|
rf.setUpdatedParams(0, attrs, xattrs);
|
|
163
163
|
return rf;
|
|
164
164
|
}
|
|
165
|
+
async getStats(flags) {
|
|
166
|
+
const { stats } = await this.getStatsAndSize(flags);
|
|
167
|
+
return stats;
|
|
168
|
+
}
|
|
165
169
|
async setCurrentStateFrom(src) {
|
|
166
170
|
const { folderInfo, attrs, xattrs } = await this.crypto.read(src);
|
|
167
171
|
this.currentState = folderInfo;
|
|
@@ -781,26 +785,30 @@ class FolderNode extends node_in_fs_1.NodeInFS {
|
|
|
781
785
|
};
|
|
782
786
|
return linkParams;
|
|
783
787
|
}
|
|
784
|
-
async
|
|
788
|
+
async startUpload(opts) {
|
|
785
789
|
try {
|
|
786
790
|
const toUpload = await this.needUpload(opts);
|
|
787
791
|
if (!toUpload) {
|
|
788
792
|
return;
|
|
789
793
|
}
|
|
794
|
+
const { localVersion, createOnRemote, uploadVersion } = toUpload;
|
|
790
795
|
if (toUpload.createOnRemote) {
|
|
791
|
-
return await
|
|
796
|
+
return await this.startUploadProcess(localVersion, createOnRemote, uploadVersion);
|
|
792
797
|
}
|
|
793
|
-
const storage = this.syncedStorage();
|
|
794
|
-
const { localVersion, uploadVersion } = toUpload;
|
|
795
798
|
const removedNodes = await this.getNodesRemovedBetweenVersions(localVersion, uploadVersion - 1);
|
|
796
|
-
const
|
|
797
|
-
await storage.upload(this.objId, localVersion, uploadVersion, uploadHeader, false);
|
|
799
|
+
const { completion, uploadTaskId } = await this.startUploadProcess(localVersion, createOnRemote, uploadVersion);
|
|
798
800
|
if (removedNodes.length > 0) {
|
|
799
801
|
// start upload of children's removal after folder's upload;
|
|
800
|
-
// we also don't await for chidren removal
|
|
801
|
-
this.uploadRemovalOf(removedNodes);
|
|
802
|
+
// we also don't await for chidren removal in returned completion
|
|
803
|
+
completion.then(() => this.uploadRemovalOf(removedNodes));
|
|
802
804
|
}
|
|
803
|
-
return
|
|
805
|
+
return {
|
|
806
|
+
completion: completion.catch(exc => {
|
|
807
|
+
throw (0, common_1.setPathInExc)(exc, this.name);
|
|
808
|
+
}),
|
|
809
|
+
uploadTaskId,
|
|
810
|
+
uploadVersion
|
|
811
|
+
};
|
|
804
812
|
}
|
|
805
813
|
catch (exc) {
|
|
806
814
|
throw (0, common_1.setPathInExc)(exc, this.name);
|
|
@@ -121,6 +121,7 @@ declare class V implements WritableFSVersionedAPI, N {
|
|
|
121
121
|
getOrCreateFile(path: string, flags: FileFlags): Promise<FileNode>;
|
|
122
122
|
get(path: string): Promise<NodeInFS<any>>;
|
|
123
123
|
ensureIsWritable(): void;
|
|
124
|
+
stat(path: string, flags?: VersionedReadFlags): Promise<Stats>;
|
|
124
125
|
updateXAttrs(path: string, changes: XAttrsChanges): Promise<number>;
|
|
125
126
|
getXAttr(path: string, xaName: string, flags?: VersionedReadFlags): Promise<{
|
|
126
127
|
attr: any;
|
|
@@ -161,6 +162,10 @@ declare class V implements WritableFSVersionedAPI, N {
|
|
|
161
162
|
declare class S implements WritableFSSyncAPI {
|
|
162
163
|
private readonly n;
|
|
163
164
|
constructor(n: N);
|
|
165
|
+
startUpload(path: string, opts?: OptionsToUploadLocal): Promise<{
|
|
166
|
+
uploadVersion: number;
|
|
167
|
+
uploadTaskId: number;
|
|
168
|
+
} | undefined>;
|
|
164
169
|
upload(path: string, opts?: OptionsToUploadLocal): Promise<number | undefined>;
|
|
165
170
|
status(path: string, skipServerCheck?: boolean): Promise<SyncStatus>;
|
|
166
171
|
updateStatusInfo(path: string): Promise<SyncStatus>;
|
|
@@ -204,31 +204,8 @@ class XspFS {
|
|
|
204
204
|
throw exc;
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const attrs = node.getAttrs();
|
|
210
|
-
const stats = {
|
|
211
|
-
ctime: new Date(attrs.ctime),
|
|
212
|
-
mtime: new Date(attrs.mtime),
|
|
213
|
-
version: node.version,
|
|
214
|
-
writable: this.writable,
|
|
215
|
-
};
|
|
216
|
-
if (node.type === 'file') {
|
|
217
|
-
stats.size = node.size;
|
|
218
|
-
stats.isFile = true;
|
|
219
|
-
return stats;
|
|
220
|
-
}
|
|
221
|
-
else if (node.type === 'folder') {
|
|
222
|
-
stats.isFolder = true;
|
|
223
|
-
return stats;
|
|
224
|
-
}
|
|
225
|
-
else if (node.type === 'link') {
|
|
226
|
-
stats.isLink = true;
|
|
227
|
-
return stats;
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
throw new Error(`Unknown type of fs node`);
|
|
231
|
-
}
|
|
207
|
+
stat(path) {
|
|
208
|
+
return this.v.stat(path);
|
|
232
209
|
}
|
|
233
210
|
async updateXAttrs(path, changes) {
|
|
234
211
|
await this.v.updateXAttrs(path, changes);
|
|
@@ -551,6 +528,12 @@ class V {
|
|
|
551
528
|
throw new Error(`FS is not writable`);
|
|
552
529
|
}
|
|
553
530
|
}
|
|
531
|
+
async stat(path, flags) {
|
|
532
|
+
const node = await this.get(path);
|
|
533
|
+
const stats = await node.getStats(flags);
|
|
534
|
+
stats.writable = this.writable;
|
|
535
|
+
return stats;
|
|
536
|
+
}
|
|
554
537
|
async updateXAttrs(path, changes) {
|
|
555
538
|
this.ensureIsWritable();
|
|
556
539
|
const node = await this.get(path);
|
|
@@ -723,11 +706,35 @@ class S {
|
|
|
723
706
|
this.n = n;
|
|
724
707
|
Object.freeze(this);
|
|
725
708
|
}
|
|
709
|
+
async startUpload(path, opts) {
|
|
710
|
+
this.n.ensureIsWritable();
|
|
711
|
+
const node = await this.n.get(path);
|
|
712
|
+
try {
|
|
713
|
+
const startedUpload = await node.startUpload(opts);
|
|
714
|
+
if (startedUpload) {
|
|
715
|
+
const { uploadTaskId, uploadVersion } = startedUpload;
|
|
716
|
+
return { uploadTaskId, uploadVersion };
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
catch (exc) {
|
|
723
|
+
throw (0, common_1.setPathInExc)(exc, path);
|
|
724
|
+
}
|
|
725
|
+
;
|
|
726
|
+
}
|
|
726
727
|
async upload(path, opts) {
|
|
727
728
|
this.n.ensureIsWritable();
|
|
728
729
|
const node = await this.n.get(path);
|
|
729
730
|
try {
|
|
730
|
-
|
|
731
|
+
const startedUpload = await node.startUpload(opts);
|
|
732
|
+
if (!startedUpload) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
const { completion, uploadVersion } = startedUpload;
|
|
736
|
+
await completion;
|
|
737
|
+
return uploadVersion;
|
|
731
738
|
}
|
|
732
739
|
catch (exc) {
|
|
733
740
|
throw (0, common_1.setPathInExc)(exc, path);
|
|
@@ -8,6 +8,8 @@ import { Storage, AsyncSBoxCryptor } from './common';
|
|
|
8
8
|
import { ObjSource, Subscribe } from 'xsp-files';
|
|
9
9
|
import { CommonAttrs, XAttrs } from './attrs';
|
|
10
10
|
import { NodePersistance } from './node-persistence';
|
|
11
|
+
type VersionedReadFlags = web3n.files.VersionedReadFlags;
|
|
12
|
+
type Stats = web3n.files.Stats;
|
|
11
13
|
declare class LinkPersistance extends NodePersistance {
|
|
12
14
|
constructor(zNonce: Uint8Array, key: Uint8Array, cryptor: AsyncSBoxCryptor);
|
|
13
15
|
read(src: ObjSource): Promise<{
|
|
@@ -25,6 +27,7 @@ export declare class LinkNode extends NodeInFS<LinkPersistance> {
|
|
|
25
27
|
static makeForNew(storage: Storage, parentId: string, name: string, key: Uint8Array): Promise<LinkNode>;
|
|
26
28
|
static makeForExisting(storage: Storage, parentId: string, name: string, objId: string, key: Uint8Array): Promise<LinkNode>;
|
|
27
29
|
protected setCurrentStateFrom(src: ObjSource): Promise<void>;
|
|
30
|
+
getStats(flags?: VersionedReadFlags): Promise<Stats>;
|
|
28
31
|
private setUpdatedState;
|
|
29
32
|
save(params: LinkParameters<any>, changes?: XAttrsChanges): Promise<void>;
|
|
30
33
|
private getLinkParams;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/*
|
|
3
|
-
Copyright (C) 2016 - 2018, 2020, 2022 3NSoft Inc.
|
|
3
|
+
Copyright (C) 2016 - 2018, 2020, 2022, 2025 3NSoft Inc.
|
|
4
4
|
|
|
5
5
|
This program is free software: you can redistribute it and/or modify it under
|
|
6
6
|
the terms of the GNU General Public License as published by the Free Software
|
|
@@ -103,6 +103,10 @@ class LinkNode extends node_in_fs_1.NodeInFS {
|
|
|
103
103
|
const { params, attrs, xattrs } = await this.crypto.read(src);
|
|
104
104
|
this.setUpdatedState(params, src.version, attrs, xattrs);
|
|
105
105
|
}
|
|
106
|
+
async getStats(flags) {
|
|
107
|
+
const { stats } = await this.getStatsAndSize(flags);
|
|
108
|
+
return stats;
|
|
109
|
+
}
|
|
106
110
|
setUpdatedState(params, version, attrs, xattrs) {
|
|
107
111
|
this.linkParams = params;
|
|
108
112
|
super.setUpdatedParams(version, attrs, xattrs);
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { FSChangeSrc, Node, NodeType, Storage, SyncedStorage
|
|
1
|
+
import { FSChangeSrc, Node, NodeType, Storage, SyncedStorage } from './common';
|
|
2
2
|
import { Observable } from 'rxjs';
|
|
3
3
|
import { CommonAttrs, XAttrs } from './attrs';
|
|
4
|
-
import { NodePersistance } from './node-persistence';
|
|
4
|
+
import { Attrs, NodePersistance } from './node-persistence';
|
|
5
5
|
import { ObjSource } from 'xsp-files';
|
|
6
|
-
export type FSEvent = web3n.files.FolderEvent | web3n.files.FileEvent;
|
|
6
|
+
export type FSEvent = web3n.files.FolderEvent | web3n.files.FileEvent | web3n.files.UploadEvent;
|
|
7
7
|
type RemoteEvent = web3n.files.RemoteEvent;
|
|
8
8
|
type XAttrsChanges = web3n.files.XAttrsChanges;
|
|
9
9
|
type SyncStatus = web3n.files.SyncStatus;
|
|
10
10
|
type OptionsToAdopteRemote = web3n.files.OptionsToAdopteRemote;
|
|
11
11
|
type OptionsToUploadLocal = web3n.files.OptionsToUploadLocal;
|
|
12
12
|
type VersionedReadFlags = web3n.files.VersionedReadFlags;
|
|
13
|
+
type Stats = web3n.files.Stats;
|
|
13
14
|
export declare abstract class NodeInFS<P extends NodePersistance> implements Node {
|
|
14
15
|
protected readonly storage: Storage;
|
|
15
16
|
readonly type: NodeType;
|
|
@@ -44,7 +45,11 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
|
|
|
44
45
|
lst: string[];
|
|
45
46
|
version: number;
|
|
46
47
|
}>;
|
|
47
|
-
|
|
48
|
+
abstract getStats(flags?: VersionedReadFlags): Promise<Stats>;
|
|
49
|
+
protected getStatsAndSize(flags?: VersionedReadFlags): Promise<{
|
|
50
|
+
stats: Stats;
|
|
51
|
+
attrs?: Attrs;
|
|
52
|
+
}>;
|
|
48
53
|
listVersions(): Promise<{
|
|
49
54
|
current?: number;
|
|
50
55
|
archived?: number[];
|
|
@@ -84,8 +89,17 @@ export declare abstract class NodeInFS<P extends NodePersistance> implements Nod
|
|
|
84
89
|
uploadVersion: number;
|
|
85
90
|
createOnRemote: boolean;
|
|
86
91
|
} | undefined>;
|
|
87
|
-
|
|
88
|
-
|
|
92
|
+
startUpload(opts: OptionsToUploadLocal | undefined): Promise<{
|
|
93
|
+
uploadVersion: number;
|
|
94
|
+
completion: Promise<void>;
|
|
95
|
+
uploadTaskId: number;
|
|
96
|
+
} | undefined>;
|
|
97
|
+
protected startUploadProcess(localVersion: number, createOnRemote: boolean, uploadVersion: number): Promise<{
|
|
98
|
+
uploadVersion: number;
|
|
99
|
+
completion: Promise<void>;
|
|
100
|
+
uploadTaskId: number;
|
|
101
|
+
}>;
|
|
102
|
+
private makeHeaderForUploadIfVersionChanges;
|
|
89
103
|
}
|
|
90
104
|
export declare function shouldReadCurrentVersion(flags: VersionedReadFlags | undefined): boolean;
|
|
91
105
|
export {};
|