roboto-js 1.4.49 → 1.5.0
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/dist/cjs/index.cjs +77 -58
- package/dist/cjs/rbt_api.cjs +198 -160
- package/dist/cjs/rbt_file.cjs +70 -426
- package/dist/esm/index.js +3 -0
- package/dist/esm/rbt_api.js +24 -5
- package/dist/esm/rbt_file.js +61 -166
- package/package.json +3 -2
- package/src/index.js +3 -0
- package/src/rbt_api.js +26 -5
- package/src/rbt_file.js +64 -210
package/dist/esm/rbt_file.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
import { Upload } from 'tus-js-client';
|
|
1
2
|
import _ from 'lodash';
|
|
2
3
|
import EventEmitter from 'eventemitter3';
|
|
3
4
|
export default class RbtFile extends EventEmitter {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
constructor(record, axiosInstance, localDb) {
|
|
5
|
+
constructor(record, axiosInstance) {
|
|
7
6
|
super(); // Call the constructor of EventEmitter
|
|
7
|
+
|
|
8
|
+
this.isRbtFile = true;
|
|
8
9
|
this.id = record.id;
|
|
9
10
|
this._axios = axiosInstance;
|
|
10
11
|
this._internalData = record;
|
|
11
12
|
this._data = record.data ? record.data : record.dataJson ? JSON.parse(record.dataJson) : {};
|
|
12
|
-
this._localDb = localDb;
|
|
13
13
|
this.progress = 0;
|
|
14
|
-
this.fileHeader = {};
|
|
15
14
|
}
|
|
16
15
|
get(path) {
|
|
17
16
|
return _.get(this._data, path);
|
|
@@ -24,6 +23,13 @@ export default class RbtFile extends EventEmitter {
|
|
|
24
23
|
...this._data
|
|
25
24
|
};
|
|
26
25
|
}
|
|
26
|
+
setData(data) {
|
|
27
|
+
// Use lodash's merge to deeply merge the incoming data into _data
|
|
28
|
+
_.merge(this._data, data);
|
|
29
|
+
return {
|
|
30
|
+
...this._data
|
|
31
|
+
}; // Return the updated _data as a new object
|
|
32
|
+
}
|
|
27
33
|
toRecord() {
|
|
28
34
|
return {
|
|
29
35
|
...this._internalData,
|
|
@@ -53,7 +59,7 @@ export default class RbtFile extends EventEmitter {
|
|
|
53
59
|
}
|
|
54
60
|
try {
|
|
55
61
|
const record = this.toRecord();
|
|
56
|
-
const response = await this._axios.
|
|
62
|
+
const response = await this._axios.delete(`/object_service/deleteObject/${this.id}`);
|
|
57
63
|
if (response.data.ok === false) {
|
|
58
64
|
throw new Error(response.data.message);
|
|
59
65
|
}
|
|
@@ -64,171 +70,60 @@ export default class RbtFile extends EventEmitter {
|
|
|
64
70
|
throw e; // Propagate the error
|
|
65
71
|
}
|
|
66
72
|
}
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
uploadFile(file) {
|
|
74
|
+
const upload = new Upload(file, {
|
|
75
|
+
endpoint: this._axios.defaults.baseURL + "/file_service/files",
|
|
76
|
+
retryDelays: [0, 1000, 3000, 5000],
|
|
77
|
+
metadata: {
|
|
78
|
+
rbtfileid: this.id,
|
|
79
|
+
filename: file.name,
|
|
80
|
+
filetype: file.type
|
|
81
|
+
},
|
|
82
|
+
onError: error => {
|
|
83
|
+
console.error("Failed because:", error);
|
|
84
|
+
this.emit('error', error);
|
|
85
|
+
},
|
|
86
|
+
onProgress: (bytesUploaded, bytesTotal) => {
|
|
87
|
+
console.log("File progress", bytesUploaded, bytesTotal);
|
|
88
|
+
const percentage = (bytesUploaded / bytesTotal * 100).toFixed(2);
|
|
89
|
+
this.setProgress(percentage / 100); // Update progress normalized between 0 and 1
|
|
90
|
+
},
|
|
91
|
+
onSuccess: () => {
|
|
92
|
+
console.log("File uploaded to:", upload.url);
|
|
93
|
+
|
|
94
|
+
// Remove the `options.endpoint` from the start of the `url`
|
|
95
|
+
const m1 = upload.url.match(/\/([^\/]+)$/);
|
|
96
|
+
const remoteId = m1 ? m1[1] : null;
|
|
97
|
+
this.setData({
|
|
98
|
+
'remoteId': remoteId,
|
|
99
|
+
'sourceFile': {
|
|
100
|
+
name: upload.file.name,
|
|
101
|
+
size: upload.file.size,
|
|
102
|
+
type: upload.file.type,
|
|
103
|
+
lastModified: upload.file.lastModified
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
this.save().then(() => {
|
|
107
|
+
this.emit('success', upload.url);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
75
110
|
});
|
|
76
|
-
|
|
111
|
+
|
|
112
|
+
// Check if there are any previous uploads to continue.
|
|
113
|
+
// upload.findPreviousUploads().then(function (previousUploads) {
|
|
114
|
+
// // Found previous uploads so we select the first one.
|
|
115
|
+
// if (previousUploads.length) {
|
|
116
|
+
// upload.resumeFromPreviousUpload(previousUploads[0])
|
|
117
|
+
// }
|
|
118
|
+
|
|
119
|
+
// // Start the upload
|
|
120
|
+
// upload.start();
|
|
121
|
+
// })
|
|
122
|
+
upload.start();
|
|
77
123
|
}
|
|
78
124
|
setProgress(newProgress) {
|
|
79
125
|
this.progress = newProgress;
|
|
80
126
|
console.log(`Progress: ${this.progress * 100}%`);
|
|
81
127
|
this.emit('progress', this.progress); // Emit a progress event
|
|
82
128
|
}
|
|
83
|
-
async readAndStoreFile(file) {
|
|
84
|
-
let offset = 0;
|
|
85
|
-
this.fileHeader = {
|
|
86
|
-
id: this.id,
|
|
87
|
-
name: file.name,
|
|
88
|
-
size: file.size,
|
|
89
|
-
ext: this._extractFileExtension(file.name),
|
|
90
|
-
mimeType: file.type,
|
|
91
|
-
numFrames: Math.ceil(file.size / RbtFile.FRAME_SIZE)
|
|
92
|
-
};
|
|
93
|
-
while (offset < file.size) {
|
|
94
|
-
const chunk = file.slice(offset, offset + RbtFile.FRAME_SIZE);
|
|
95
|
-
await new Promise((resolve, reject) => {
|
|
96
|
-
const reader = new FileReader();
|
|
97
|
-
reader.onload = async e => {
|
|
98
|
-
const arrayBuffer = e.target.result;
|
|
99
|
-
const frameIndex = offset / RbtFile.FRAME_SIZE;
|
|
100
|
-
await this._storeChunkInIDB(arrayBuffer, frameIndex, this.fileHeader);
|
|
101
|
-
this.setProgress((frameIndex + 1) / this.fileHeader.numFrames);
|
|
102
|
-
resolve();
|
|
103
|
-
};
|
|
104
|
-
reader.onerror = () => reject(reader.error);
|
|
105
|
-
reader.readAsArrayBuffer(chunk);
|
|
106
|
-
});
|
|
107
|
-
offset += RbtFile.FRAME_SIZE;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
_extractFileExtension(fileName) {
|
|
111
|
-
// Find the last dot in the filename
|
|
112
|
-
const lastDotIndex = fileName.lastIndexOf('.');
|
|
113
|
-
|
|
114
|
-
// No dot found, or the dot is the first character (hidden files)
|
|
115
|
-
if (lastDotIndex === -1 || lastDotIndex === 0) return '';
|
|
116
|
-
|
|
117
|
-
// Extract the extension
|
|
118
|
-
return fileName.substring(lastDotIndex + 1);
|
|
119
|
-
}
|
|
120
|
-
async _storeChunkInIDB(chunk, frameIndex, fileHeader) {
|
|
121
|
-
const db = this._localDb;
|
|
122
|
-
if (!db) {
|
|
123
|
-
console.error('Database not initialized');
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
const tx = db.transaction('files', 'readwrite');
|
|
127
|
-
const frameKey = `${this.id}_${frameIndex}`; // Unique key combining id and frameIndex
|
|
128
|
-
await tx.store.put({
|
|
129
|
-
key: frameKey,
|
|
130
|
-
chunk,
|
|
131
|
-
fileHeader
|
|
132
|
-
}, frameKey);
|
|
133
|
-
await tx.done;
|
|
134
|
-
}
|
|
135
|
-
async _readFrameFromIDB(frameIndex) {
|
|
136
|
-
const db = this._localDb;
|
|
137
|
-
if (!db) {
|
|
138
|
-
console.error('Database not initialized');
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
|
-
const frameKey = `${this.id}_${frameIndex}`; // Same key as used in _storeChunkInIDB
|
|
142
|
-
const tx = db.transaction('files', 'readonly');
|
|
143
|
-
const frame = await tx.store.get(frameKey);
|
|
144
|
-
return frame ? frame.chunk : null;
|
|
145
|
-
}
|
|
146
|
-
async uploadFile() {
|
|
147
|
-
if (!this.fileHeader || !this.fileHeader.numFrames) {
|
|
148
|
-
throw new Error("File not ready for upload.");
|
|
149
|
-
}
|
|
150
|
-
this.fileRecord = this.toRecord();
|
|
151
|
-
let frameRes;
|
|
152
|
-
for (let frameIndex = 0; frameIndex < this.fileHeader.numFrames; frameIndex++) {
|
|
153
|
-
try {
|
|
154
|
-
const frameData = await this._readFrameFromIDB(frameIndex);
|
|
155
|
-
if (!frameData) {
|
|
156
|
-
throw new Error(`Failed to read frame ${frameIndex}`);
|
|
157
|
-
}
|
|
158
|
-
frameRes = await this._uploadFrameToServer(frameData, frameIndex, this.fileHeader, this.fileRecord);
|
|
159
|
-
|
|
160
|
-
// Update progress after each frame is uploaded
|
|
161
|
-
this.setProgress((frameIndex + 1) / this.fileHeader.numFrames);
|
|
162
|
-
} catch (error) {
|
|
163
|
-
console.error(`Error uploading frame ${frameIndex}:`, error);
|
|
164
|
-
throw error; // Stop the upload process if an error occurs
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
//
|
|
169
|
-
// DONE UPLOADING, PROCESSING
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
try {
|
|
173
|
-
const statusRes = await this._checkUploadStatusUntilDone(this.fileRecord);
|
|
174
|
-
this.set('remoteSrc', statusRes.remoteSrc);
|
|
175
|
-
this.set('progress', 1);
|
|
176
|
-
await this.save();
|
|
177
|
-
} catch (error) {
|
|
178
|
-
console.error('Error during upload status check:', error);
|
|
179
|
-
// Handle error, possibly update UI or retry logic
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
async _uploadFrameToServer(frameData, frameIndex, fileHeader, fileRecord) {
|
|
183
|
-
const base64Data = this.convertToBase64(frameData);
|
|
184
|
-
const payload = ["@filekit.ffs_server_receiveAndStore_toS3_flow", {
|
|
185
|
-
"fileObject": fileRecord,
|
|
186
|
-
// using fileRecord from newFile.toRecord()
|
|
187
|
-
"fileHeader": fileHeader,
|
|
188
|
-
"frameIndex": frameIndex,
|
|
189
|
-
"frameData": `rpcBase64:${base64Data}`,
|
|
190
|
-
"timeout": 86400000
|
|
191
|
-
}];
|
|
192
|
-
console.log(payload);
|
|
193
|
-
const response = await this._axios.post('/file_service/ffs_runFlow', payload);
|
|
194
|
-
if (!response || response.status != 200) {
|
|
195
|
-
throw new Error('Error uploading frame to server');
|
|
196
|
-
}
|
|
197
|
-
return response;
|
|
198
|
-
}
|
|
199
|
-
async _checkUploadStatusUntilDone(fileRecord) {
|
|
200
|
-
return new Promise((resolve, reject) => {
|
|
201
|
-
const intervalId = setInterval(async () => {
|
|
202
|
-
try {
|
|
203
|
-
const statusRes = await this._uploadGetStatusUpdate(fileRecord);
|
|
204
|
-
if (statusRes.data && statusRes.data.fileHeader && statusRes.data.fileHeader.status === 'DONE') {
|
|
205
|
-
clearInterval(intervalId); // Stop the interval
|
|
206
|
-
resolve(statusRes.data.fileHeader); // Resolve the promise with the final status
|
|
207
|
-
} else {
|
|
208
|
-
// Optionally update progress or handle other status cases here
|
|
209
|
-
//this.emit('progress', statusRes.progress); // Emit progress updates if available
|
|
210
|
-
}
|
|
211
|
-
} catch (error) {
|
|
212
|
-
clearInterval(intervalId); // Stop the interval on error
|
|
213
|
-
reject(error); // Reject the promise if there's an error
|
|
214
|
-
}
|
|
215
|
-
}, 2000); // Check every 2 seconds
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
async _uploadGetStatusUpdate(fileRecord) {
|
|
219
|
-
const payload = ["@filekit.ffs_server_receiveAndStore_toS3_flow", {
|
|
220
|
-
"fileObject": fileRecord,
|
|
221
|
-
// using fileRecord from newFile.toRecord()
|
|
222
|
-
"getStatusUpdate": true
|
|
223
|
-
}];
|
|
224
|
-
console.log(payload);
|
|
225
|
-
const response = await this._axios.post('/file_service/ffs_runFlow', payload);
|
|
226
|
-
if (!response || response.status != 200) {
|
|
227
|
-
throw new Error('Error getting upload status');
|
|
228
|
-
}
|
|
229
|
-
return response;
|
|
230
|
-
}
|
|
231
|
-
convertToBase64(buffer) {
|
|
232
|
-
return btoa(new Uint8Array(buffer).reduce((data, byte) => data + String.fromCharCode(byte), ''));
|
|
233
|
-
}
|
|
234
129
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "roboto-js",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "dist/cjs/index.cjs",
|
|
@@ -25,7 +25,8 @@
|
|
|
25
25
|
"crypto-js": "^4.1.1",
|
|
26
26
|
"eventemitter3": "^5.0.1",
|
|
27
27
|
"idb": "^8.0.0",
|
|
28
|
-
"lodash": "^4.17.21"
|
|
28
|
+
"lodash": "^4.17.21",
|
|
29
|
+
"tus-js-client": "^4.2.3"
|
|
29
30
|
},
|
|
30
31
|
"devDependencies": {
|
|
31
32
|
"@babel/cli": "^7.23.9",
|
package/src/index.js
CHANGED
package/src/rbt_api.js
CHANGED
|
@@ -296,12 +296,12 @@ export default class RbtApi {
|
|
|
296
296
|
|
|
297
297
|
if (this.requestCache[authtoken]) {
|
|
298
298
|
// If there's already a pending promise to refresh this token, return it
|
|
299
|
-
console.log('RBTTOK Using cached promise for token refresh');
|
|
299
|
+
//console.log('RBTTOK Using cached promise for token refresh');
|
|
300
300
|
return this.requestCache[authtoken];
|
|
301
301
|
}
|
|
302
302
|
|
|
303
303
|
try {
|
|
304
|
-
console.log('RBTTOK Req', authtoken);
|
|
304
|
+
//console.log('RBTTOK Req', authtoken);
|
|
305
305
|
// Create a new promise for the token refresh and store it in the cache
|
|
306
306
|
const promise = this.axios.post('/user_service/refreshAuthToken', [authtoken]);
|
|
307
307
|
this.requestCache[authtoken] = promise;
|
|
@@ -309,7 +309,7 @@ export default class RbtApi {
|
|
|
309
309
|
// Await the promise to get the response
|
|
310
310
|
const response = await promise;
|
|
311
311
|
|
|
312
|
-
console.log('RBTTOK Response ',response);
|
|
312
|
+
//console.log('RBTTOK Response ',response);
|
|
313
313
|
// Once the promise resolves, delete it from the cache to allow future refreshes
|
|
314
314
|
delete this.requestCache[authtoken];
|
|
315
315
|
|
|
@@ -403,6 +403,27 @@ export default class RbtApi {
|
|
|
403
403
|
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
async loadFiles(ids) {
|
|
407
|
+
try {
|
|
408
|
+
// Use the bulk load method with the provided IDs
|
|
409
|
+
const responses = await this.load('<@filekit.file>', ids);
|
|
410
|
+
|
|
411
|
+
if (!responses || !Array.isArray(responses)) {
|
|
412
|
+
return []; // Return an empty array if no responses or invalid data
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
// Map over the responses to create RbtFile instances
|
|
416
|
+
return responses.map(response => {
|
|
417
|
+
const record = response.toRecord();
|
|
418
|
+
return new RbtFile(record, this.axios, this.localDb);
|
|
419
|
+
});
|
|
420
|
+
} catch (e) {
|
|
421
|
+
this._handleError(e); // Handle errors (log or process as needed)
|
|
422
|
+
return []; // Return an empty array on failure
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
|
|
406
427
|
|
|
407
428
|
/**
|
|
408
429
|
* Creates a new object of the given type.
|
|
@@ -655,7 +676,7 @@ export default class RbtApi {
|
|
|
655
676
|
}
|
|
656
677
|
if (status === 'DONE' && onDone){
|
|
657
678
|
// Provide the current progress to the callback function
|
|
658
|
-
console.log('Finish (request) ',response);
|
|
679
|
+
//console.log('Finish (request) ',response);
|
|
659
680
|
onDone(response);
|
|
660
681
|
}
|
|
661
682
|
|
|
@@ -710,7 +731,7 @@ export default class RbtApi {
|
|
|
710
731
|
// If the task is still in progress, start polling for updates
|
|
711
732
|
if (response.status === 'DONE' && onDone){
|
|
712
733
|
// Provide the current progress to the callback function
|
|
713
|
-
console.log('Finish (progress) ',response);
|
|
734
|
+
//console.log('Finish (progress) ',response);
|
|
714
735
|
onDone(response);
|
|
715
736
|
}
|
|
716
737
|
if (response.status === 'ERROR' && onError){
|
package/src/rbt_file.js
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
import { Upload } from 'tus-js-client';
|
|
2
2
|
import _ from 'lodash';
|
|
3
3
|
import EventEmitter from 'eventemitter3';
|
|
4
4
|
|
|
5
|
-
export default class RbtFile extends EventEmitter{
|
|
6
|
-
|
|
7
|
-
static FRAME_SIZE = 1024 * 1024; // 1MB, for example
|
|
8
|
-
|
|
9
|
-
constructor(record, axiosInstance, localDb) {
|
|
5
|
+
export default class RbtFile extends EventEmitter {
|
|
10
6
|
|
|
7
|
+
constructor(record, axiosInstance) {
|
|
11
8
|
super(); // Call the constructor of EventEmitter
|
|
9
|
+
|
|
10
|
+
this.isRbtFile = true;
|
|
12
11
|
this.id = record.id;
|
|
13
12
|
this._axios = axiosInstance;
|
|
14
13
|
this._internalData = record;
|
|
15
14
|
this._data = record.data ? record.data : (record.dataJson ? JSON.parse(record.dataJson) : {});
|
|
16
|
-
this._localDb = localDb;
|
|
17
15
|
this.progress = 0;
|
|
18
|
-
|
|
19
|
-
this.fileHeader = {};
|
|
20
16
|
}
|
|
21
17
|
|
|
22
18
|
get(path) {
|
|
@@ -31,6 +27,12 @@ export default class RbtFile extends EventEmitter{
|
|
|
31
27
|
return { ...this._data };
|
|
32
28
|
}
|
|
33
29
|
|
|
30
|
+
setData(data) {
|
|
31
|
+
// Use lodash's merge to deeply merge the incoming data into _data
|
|
32
|
+
_.merge(this._data, data);
|
|
33
|
+
return { ...this._data }; // Return the updated _data as a new object
|
|
34
|
+
}
|
|
35
|
+
|
|
34
36
|
toRecord() {
|
|
35
37
|
return {
|
|
36
38
|
...this._internalData,
|
|
@@ -52,7 +54,6 @@ export default class RbtFile extends EventEmitter{
|
|
|
52
54
|
}
|
|
53
55
|
|
|
54
56
|
this._internalData = response.data;
|
|
55
|
-
|
|
56
57
|
return this;
|
|
57
58
|
|
|
58
59
|
} catch (e) {
|
|
@@ -68,7 +69,7 @@ export default class RbtFile extends EventEmitter{
|
|
|
68
69
|
|
|
69
70
|
try {
|
|
70
71
|
const record = this.toRecord();
|
|
71
|
-
const response = await this._axios.
|
|
72
|
+
const response = await this._axios.delete(`/object_service/deleteObject/${this.id}`);
|
|
72
73
|
|
|
73
74
|
if (response.data.ok === false) {
|
|
74
75
|
throw new Error(response.data.message);
|
|
@@ -83,210 +84,63 @@ export default class RbtFile extends EventEmitter{
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
87
|
+
uploadFile(file) {
|
|
88
|
+
|
|
89
|
+
const upload = new Upload(file, {
|
|
90
|
+
endpoint: this._axios.defaults.baseURL+"/file_service/files",
|
|
91
|
+
retryDelays: [0, 1000, 3000, 5000],
|
|
92
|
+
metadata: {
|
|
93
|
+
rbtfileid: this.id,
|
|
94
|
+
filename: file.name,
|
|
95
|
+
filetype: file.type,
|
|
96
|
+
},
|
|
97
|
+
onError: error => {
|
|
98
|
+
console.error("Failed because:", error);
|
|
99
|
+
this.emit('error', error);
|
|
100
|
+
},
|
|
101
|
+
onProgress: (bytesUploaded, bytesTotal) => {
|
|
102
|
+
console.log("File progress", bytesUploaded, bytesTotal);
|
|
103
|
+
const percentage = (bytesUploaded / bytesTotal * 100).toFixed(2);
|
|
104
|
+
this.setProgress(percentage / 100); // Update progress normalized between 0 and 1
|
|
105
|
+
},
|
|
106
|
+
onSuccess: () => {
|
|
107
|
+
console.log("File uploaded to:", upload.url);
|
|
108
|
+
|
|
109
|
+
// Remove the `options.endpoint` from the start of the `url`
|
|
110
|
+
const m1 = upload.url.match(/\/([^\/]+)$/);
|
|
111
|
+
const remoteId = m1 ? m1[1] : null;
|
|
112
|
+
|
|
113
|
+
this.setData({
|
|
114
|
+
'remoteId': remoteId,
|
|
115
|
+
'sourceFile': {
|
|
116
|
+
name: upload.file.name,
|
|
117
|
+
size: upload.file.size,
|
|
118
|
+
type: upload.file.type,
|
|
119
|
+
lastModified: upload.file.lastModified,
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
this.save().then(() => {
|
|
123
|
+
this.emit('success', upload.url);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// Check if there are any previous uploads to continue.
|
|
129
|
+
// upload.findPreviousUploads().then(function (previousUploads) {
|
|
130
|
+
// // Found previous uploads so we select the first one.
|
|
131
|
+
// if (previousUploads.length) {
|
|
132
|
+
// upload.resumeFromPreviousUpload(previousUploads[0])
|
|
133
|
+
// }
|
|
134
|
+
|
|
135
|
+
// // Start the upload
|
|
136
|
+
// upload.start();
|
|
137
|
+
// })
|
|
138
|
+
upload.start();
|
|
94
139
|
}
|
|
95
140
|
|
|
96
141
|
setProgress(newProgress) {
|
|
97
142
|
this.progress = newProgress;
|
|
98
143
|
console.log(`Progress: ${this.progress * 100}%`);
|
|
99
144
|
this.emit('progress', this.progress); // Emit a progress event
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
async readAndStoreFile(file) {
|
|
105
|
-
let offset = 0;
|
|
106
|
-
this.fileHeader = {
|
|
107
|
-
id: this.id,
|
|
108
|
-
name: file.name,
|
|
109
|
-
size: file.size,
|
|
110
|
-
ext: this._extractFileExtension(file.name),
|
|
111
|
-
mimeType: file.type,
|
|
112
|
-
numFrames: Math.ceil(file.size / RbtFile.FRAME_SIZE)
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
while (offset < file.size) {
|
|
116
|
-
const chunk = file.slice(offset, offset + RbtFile.FRAME_SIZE);
|
|
117
|
-
await new Promise((resolve, reject) => {
|
|
118
|
-
const reader = new FileReader();
|
|
119
|
-
reader.onload = async (e) => {
|
|
120
|
-
const arrayBuffer = e.target.result;
|
|
121
|
-
const frameIndex = offset / RbtFile.FRAME_SIZE;
|
|
122
|
-
await this._storeChunkInIDB(arrayBuffer, frameIndex, this.fileHeader);
|
|
123
|
-
this.setProgress((frameIndex + 1) / this.fileHeader.numFrames);
|
|
124
|
-
resolve();
|
|
125
|
-
};
|
|
126
|
-
reader.onerror = () => reject(reader.error);
|
|
127
|
-
reader.readAsArrayBuffer(chunk);
|
|
128
|
-
});
|
|
129
|
-
offset += RbtFile.FRAME_SIZE;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
_extractFileExtension(fileName) {
|
|
134
|
-
// Find the last dot in the filename
|
|
135
|
-
const lastDotIndex = fileName.lastIndexOf('.');
|
|
136
|
-
|
|
137
|
-
// No dot found, or the dot is the first character (hidden files)
|
|
138
|
-
if (lastDotIndex === -1 || lastDotIndex === 0) return '';
|
|
139
|
-
|
|
140
|
-
// Extract the extension
|
|
141
|
-
return fileName.substring(lastDotIndex + 1);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
async _storeChunkInIDB(chunk, frameIndex, fileHeader) {
|
|
145
|
-
const db = this._localDb;
|
|
146
|
-
if (!db) {
|
|
147
|
-
console.error('Database not initialized');
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
const tx = db.transaction('files', 'readwrite');
|
|
151
|
-
const frameKey = `${this.id}_${frameIndex}`; // Unique key combining id and frameIndex
|
|
152
|
-
await tx.store.put({ key: frameKey, chunk, fileHeader }, frameKey);
|
|
153
|
-
await tx.done;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
async _readFrameFromIDB(frameIndex) {
|
|
157
|
-
const db = this._localDb;
|
|
158
|
-
if (!db) {
|
|
159
|
-
console.error('Database not initialized');
|
|
160
|
-
return null;
|
|
161
|
-
}
|
|
162
|
-
const frameKey = `${this.id}_${frameIndex}`; // Same key as used in _storeChunkInIDB
|
|
163
|
-
const tx = db.transaction('files', 'readonly');
|
|
164
|
-
const frame = await tx.store.get(frameKey);
|
|
165
|
-
|
|
166
|
-
return frame ? frame.chunk : null;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
async uploadFile() {
|
|
170
|
-
if (!this.fileHeader || !this.fileHeader.numFrames) {
|
|
171
|
-
throw new Error("File not ready for upload.");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
this.fileRecord = this.toRecord();
|
|
175
|
-
|
|
176
|
-
let frameRes;
|
|
177
|
-
|
|
178
|
-
for (let frameIndex = 0; frameIndex < this.fileHeader.numFrames; frameIndex++) {
|
|
179
|
-
try {
|
|
180
|
-
const frameData = await this._readFrameFromIDB(frameIndex);
|
|
181
|
-
if (!frameData) {
|
|
182
|
-
throw new Error(`Failed to read frame ${frameIndex}`);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
frameRes = await this._uploadFrameToServer(frameData, frameIndex, this.fileHeader, this.fileRecord);
|
|
186
|
-
|
|
187
|
-
// Update progress after each frame is uploaded
|
|
188
|
-
this.setProgress((frameIndex + 1) / this.fileHeader.numFrames);
|
|
189
|
-
} catch (error) {
|
|
190
|
-
console.error(`Error uploading frame ${frameIndex}:`, error);
|
|
191
|
-
throw error; // Stop the upload process if an error occurs
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
//
|
|
197
|
-
// DONE UPLOADING, PROCESSING
|
|
198
|
-
//
|
|
199
|
-
|
|
200
|
-
try {
|
|
201
|
-
const statusRes = await this._checkUploadStatusUntilDone(this.fileRecord);
|
|
202
|
-
|
|
203
|
-
this.set('remoteSrc', statusRes.remoteSrc);
|
|
204
|
-
this.set('progress', 1);
|
|
205
|
-
await this.save();
|
|
206
|
-
} catch (error) {
|
|
207
|
-
console.error('Error during upload status check:', error);
|
|
208
|
-
// Handle error, possibly update UI or retry logic
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
async _uploadFrameToServer(frameData, frameIndex, fileHeader, fileRecord) {
|
|
214
|
-
|
|
215
|
-
const base64Data = this.convertToBase64(frameData);
|
|
216
|
-
const payload = [
|
|
217
|
-
"@filekit.ffs_server_receiveAndStore_toS3_flow",
|
|
218
|
-
{
|
|
219
|
-
"fileObject": fileRecord, // using fileRecord from newFile.toRecord()
|
|
220
|
-
"fileHeader": fileHeader,
|
|
221
|
-
"frameIndex": frameIndex,
|
|
222
|
-
"frameData": `rpcBase64:${base64Data}`,
|
|
223
|
-
"timeout": 86400000
|
|
224
|
-
}
|
|
225
|
-
];
|
|
226
|
-
|
|
227
|
-
console.log(payload);
|
|
228
|
-
|
|
229
|
-
const response = await this._axios.post('/file_service/ffs_runFlow', payload);
|
|
230
|
-
|
|
231
|
-
if (!response || response.status != 200) {
|
|
232
|
-
throw new Error('Error uploading frame to server');
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return response;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
async _checkUploadStatusUntilDone(fileRecord) {
|
|
240
|
-
|
|
241
|
-
return new Promise((resolve, reject) => {
|
|
242
|
-
const intervalId = setInterval(async () => {
|
|
243
|
-
try {
|
|
244
|
-
const statusRes = await this._uploadGetStatusUpdate(fileRecord);
|
|
245
|
-
if (statusRes.data && statusRes.data.fileHeader && statusRes.data.fileHeader.status === 'DONE') {
|
|
246
|
-
clearInterval(intervalId); // Stop the interval
|
|
247
|
-
resolve(statusRes.data.fileHeader); // Resolve the promise with the final status
|
|
248
|
-
} else {
|
|
249
|
-
// Optionally update progress or handle other status cases here
|
|
250
|
-
//this.emit('progress', statusRes.progress); // Emit progress updates if available
|
|
251
|
-
}
|
|
252
|
-
} catch (error) {
|
|
253
|
-
clearInterval(intervalId); // Stop the interval on error
|
|
254
|
-
reject(error); // Reject the promise if there's an error
|
|
255
|
-
}
|
|
256
|
-
}, 2000); // Check every 2 seconds
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
async _uploadGetStatusUpdate(fileRecord){
|
|
264
|
-
|
|
265
|
-
const payload = [
|
|
266
|
-
"@filekit.ffs_server_receiveAndStore_toS3_flow",
|
|
267
|
-
{
|
|
268
|
-
"fileObject": fileRecord, // using fileRecord from newFile.toRecord()
|
|
269
|
-
"getStatusUpdate": true
|
|
270
|
-
}
|
|
271
|
-
];
|
|
272
|
-
|
|
273
|
-
console.log(payload);
|
|
274
|
-
|
|
275
|
-
const response = await this._axios.post('/file_service/ffs_runFlow', payload);
|
|
276
|
-
|
|
277
|
-
if (!response || response.status != 200) {
|
|
278
|
-
throw new Error('Error getting upload status');
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return response;
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
convertToBase64(buffer) {
|
|
287
|
-
return btoa(
|
|
288
|
-
new Uint8Array(buffer)
|
|
289
|
-
.reduce((data, byte) => data + String.fromCharCode(byte), '')
|
|
290
|
-
);
|
|
291
145
|
}
|
|
292
146
|
}
|