files.com 1.0.412 → 1.0.414
Sign up to get free protection for your applications and to get access to all the features.
- package/_VERSION +1 -1
- package/lib/Api.js +30 -18
- package/lib/Files.js +1 -1
- package/lib/isomorphic/File.node.js +21 -13
- package/lib/models/ActionNotificationExport.js +8 -5
- package/lib/models/ApiKey.js +8 -5
- package/lib/models/As2Partner.js +8 -5
- package/lib/models/As2Station.js +8 -5
- package/lib/models/Automation.js +8 -5
- package/lib/models/AutomationRun.js +8 -5
- package/lib/models/Behavior.js +15 -9
- package/lib/models/Bundle.js +8 -5
- package/lib/models/BundleNotification.js +8 -5
- package/lib/models/Clickwrap.js +8 -5
- package/lib/models/ExternalEvent.js +8 -5
- package/lib/models/File.js +212 -131
- package/lib/models/FileComment.js +8 -5
- package/lib/models/FileMigration.js +8 -5
- package/lib/models/Folder.js +14 -9
- package/lib/models/FormFieldSet.js +8 -5
- package/lib/models/GpgKey.js +8 -5
- package/lib/models/Group.js +8 -5
- package/lib/models/History.js +22 -13
- package/lib/models/HistoryExport.js +8 -5
- package/lib/models/Invoice.js +8 -5
- package/lib/models/Lock.js +15 -9
- package/lib/models/Message.js +8 -5
- package/lib/models/MessageComment.js +8 -5
- package/lib/models/MessageCommentReaction.js +8 -5
- package/lib/models/MessageReaction.js +8 -5
- package/lib/models/Notification.js +8 -5
- package/lib/models/Payment.js +8 -5
- package/lib/models/Priority.js +8 -5
- package/lib/models/Project.js +8 -5
- package/lib/models/PublicKey.js +8 -5
- package/lib/models/RemoteServer.js +15 -9
- package/lib/models/Request.js +8 -5
- package/lib/models/SftpHostKey.js +8 -5
- package/lib/models/ShareGroup.js +8 -5
- package/lib/models/Snapshot.js +8 -5
- package/lib/models/SsoStrategy.js +8 -5
- package/lib/models/Style.js +8 -5
- package/lib/models/User.js +8 -5
- package/lib/models/UserRequest.js +8 -5
- package/package.json +1 -1
- package/src/Files.js +1 -1
- package/src/models/File.js +86 -44
- package/test/src/index.js +30 -3
package/src/models/File.js
CHANGED
@@ -97,79 +97,121 @@ class File {
|
|
97
97
|
let length = 0
|
98
98
|
const concurrentUploads = []
|
99
99
|
|
100
|
+
let chunkBuffer = null
|
101
|
+
let streamEnded = false
|
102
|
+
|
103
|
+
const handleStreamEnd = async () => {
|
104
|
+
if (chunkBuffer !== null || !streamEnded) {
|
105
|
+
return
|
106
|
+
}
|
107
|
+
|
108
|
+
try {
|
109
|
+
if (chunks.length > 0) {
|
110
|
+
const buffer = Buffer.concat(chunks)
|
111
|
+
const nextFileUploadPart = await File._continueUpload(destinationPath, ++part, firstFileUploadPart, options)
|
112
|
+
|
113
|
+
const upload_uri = determinePartUploadUri(nextFileUploadPart)
|
114
|
+
|
115
|
+
// instantiate an httpsAgent dynamically if needed
|
116
|
+
const agent = options.getAgentForUrl?.(upload_uri) || options?.agent
|
117
|
+
|
118
|
+
concurrentUploads.push(Api.sendFilePart(upload_uri, 'PUT', buffer, { agent }))
|
119
|
+
}
|
120
|
+
|
121
|
+
await Promise.all(concurrentUploads)
|
122
|
+
|
123
|
+
const response = await File._completeUpload(firstFileUploadPart, options)
|
124
|
+
const createdFile = new File(response.data, options)
|
125
|
+
|
126
|
+
resolve(createdFile)
|
127
|
+
} catch (error) {
|
128
|
+
reject(error)
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
100
132
|
readableStream.on('error', error => { reject(error) })
|
101
133
|
|
134
|
+
// note that for a network stream, each chunk is typically less than partsize * 2, but
|
135
|
+
// if a stream has been created based on very large data, it's possible for a chunk to
|
136
|
+
// contain the entire file and we could get a single chunk with length >= partsize * 3
|
102
137
|
readableStream.on('data', async chunk => {
|
103
138
|
try {
|
104
|
-
|
105
|
-
const excessLength = nextLength - firstFileUploadPart.partsize
|
139
|
+
let excessLength = (length + chunk.length) - firstFileUploadPart.partsize
|
106
140
|
|
107
|
-
|
141
|
+
chunkBuffer = Buffer.from(chunk)
|
108
142
|
|
109
143
|
if (excessLength > 0) {
|
110
144
|
readableStream.pause()
|
111
145
|
|
112
|
-
|
113
|
-
|
146
|
+
while (chunkBuffer) {
|
147
|
+
// the amount to append this last part with to make it exactly the full partsize
|
148
|
+
const lengthForEndOfCurrentPart = chunkBuffer.length - excessLength
|
114
149
|
|
115
|
-
|
116
|
-
|
150
|
+
const lastChunkForCurrentPart = chunkBuffer.subarray(0, lengthForEndOfCurrentPart)
|
151
|
+
const chunkBufferAfterCurrentPart = chunkBuffer.subarray(lengthForEndOfCurrentPart)
|
117
152
|
|
118
|
-
|
153
|
+
chunks.push(lastChunkForCurrentPart)
|
119
154
|
|
120
|
-
|
121
|
-
|
155
|
+
const buffer = Buffer.concat(chunks)
|
156
|
+
const nextFileUploadPart = await File._continueUpload(destinationPath, ++part, firstFileUploadPart, options)
|
122
157
|
|
123
|
-
|
158
|
+
const upload_uri = determinePartUploadUri(nextFileUploadPart)
|
124
159
|
|
125
|
-
|
126
|
-
|
160
|
+
// instantiate an httpsAgent dynamically if needed
|
161
|
+
const agent = options.getAgentForUrl?.(upload_uri) || options?.agent
|
127
162
|
|
128
|
-
|
163
|
+
const uploadPromise = Api.sendFilePart(upload_uri, 'PUT', buffer, { agent })
|
129
164
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
165
|
+
if (firstFileUploadPart.parallel_parts) {
|
166
|
+
concurrentUploads.push(uploadPromise)
|
167
|
+
} else {
|
168
|
+
await uploadPromise
|
169
|
+
}
|
170
|
+
|
171
|
+
// determine if the remainder of the excess chunk data is too large to be a single part
|
172
|
+
const isNextChunkAtLeastOnePart = chunkBufferAfterCurrentPart.length >= firstFileUploadPart.partsize
|
173
|
+
|
174
|
+
// the excess data contains >= 1 full part, so we'll loop again to enqueue
|
175
|
+
// the next part for upload and continue processing any excess beyond that
|
176
|
+
if (isNextChunkAtLeastOnePart) {
|
177
|
+
chunks = []
|
178
|
+
length = 0
|
135
179
|
|
136
|
-
|
137
|
-
|
180
|
+
chunkBuffer = chunkBufferAfterCurrentPart
|
181
|
+
excessLength = chunkBuffer.length - firstFileUploadPart.partsize
|
182
|
+
// the excess data is less than a full part, so we'll enqueue it
|
183
|
+
} else if (chunkBufferAfterCurrentPart.length > 0) {
|
184
|
+
chunks = [chunkBufferAfterCurrentPart]
|
185
|
+
length = chunkBufferAfterCurrentPart.length
|
186
|
+
|
187
|
+
chunkBuffer = null
|
188
|
+
} else {
|
189
|
+
chunkBuffer = null
|
190
|
+
}
|
191
|
+
}
|
138
192
|
|
139
193
|
readableStream.resume()
|
140
194
|
} else {
|
141
195
|
chunks.push(chunkBuffer)
|
142
196
|
length += chunk.length
|
143
|
-
}
|
144
|
-
} catch (error) {
|
145
|
-
reject(error)
|
146
|
-
}
|
147
|
-
})
|
148
|
-
|
149
|
-
readableStream.on('end', async () => {
|
150
|
-
try {
|
151
|
-
if (chunks.length > 0) {
|
152
|
-
const buffer = Buffer.concat(chunks)
|
153
|
-
const nextFileUploadPart = await File._continueUpload(destinationPath, ++part, firstFileUploadPart, options)
|
154
|
-
|
155
|
-
const upload_uri = determinePartUploadUri(nextFileUploadPart)
|
156
197
|
|
157
|
-
|
158
|
-
const agent = options.getAgentForUrl?.(upload_uri) || options?.agent
|
159
|
-
|
160
|
-
concurrentUploads.push(Api.sendFilePart(upload_uri, 'PUT', buffer, { agent }))
|
198
|
+
chunkBuffer = null
|
161
199
|
}
|
162
200
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
const createdFile = new File(response.data, options)
|
167
|
-
|
168
|
-
resolve(createdFile)
|
201
|
+
if (streamEnded) {
|
202
|
+
handleStreamEnd()
|
203
|
+
}
|
169
204
|
} catch (error) {
|
170
205
|
reject(error)
|
171
206
|
}
|
172
207
|
})
|
208
|
+
|
209
|
+
// note that this event may occur while there is still data being processed above
|
210
|
+
readableStream.on('end', () => {
|
211
|
+
streamEnded = true
|
212
|
+
|
213
|
+
handleStreamEnd()
|
214
|
+
})
|
173
215
|
})
|
174
216
|
|
175
217
|
return file
|
package/test/src/index.js
CHANGED
@@ -142,7 +142,7 @@ const testSuite = async () => {
|
|
142
142
|
}
|
143
143
|
|
144
144
|
/* to run this test, put a file (or symlink) at huge-file.ext * /
|
145
|
-
const
|
145
|
+
const testUploadFileForHugeFile = async () => {
|
146
146
|
const sourceFilePath = '../huge-file.ext'
|
147
147
|
|
148
148
|
const displayName = `huge-file__${nonce}.ext`
|
@@ -161,7 +161,33 @@ const testSuite = async () => {
|
|
161
161
|
|
162
162
|
await file.delete()
|
163
163
|
|
164
|
-
Logger.info('*****
|
164
|
+
Logger.info('***** testUploadFileForHugeFile() succeeded! *****')
|
165
|
+
}
|
166
|
+
|
167
|
+
/* to run this test, put a file (or symlink) at huge-file.ext * /
|
168
|
+
const testUploadDataForHugeFile = async () => {
|
169
|
+
const sourceFilePath = '../huge-file.ext'
|
170
|
+
|
171
|
+
const displayName = `huge-file__${nonce}.ext`
|
172
|
+
const destinationPath = `${SDK_TEST_ROOT_FOLDER}/${displayName}`
|
173
|
+
|
174
|
+
const fs = require('fs/promises')
|
175
|
+
const data = await fs.readFile(sourceFilePath, { encoding: "utf8" })
|
176
|
+
|
177
|
+
const file = await File.uploadData(destinationPath, data)
|
178
|
+
|
179
|
+
invariant(!!file.path, 'Uploaded file response object should have a path')
|
180
|
+
invariant(file.display_name === displayName, 'Uploaded file response object should have the same display_name as the file we uploaded')
|
181
|
+
|
182
|
+
const foundFile = await File.find(destinationPath)
|
183
|
+
|
184
|
+
invariant(foundFile.path === destinationPath, 'Found file should have the same path as the file we uploaded')
|
185
|
+
invariant(foundFile.display_name === displayName, 'Found file should have the same display_name as the file we uploaded')
|
186
|
+
invariant(typeof foundFile.getDownloadUri() === 'undefined', 'Found file should not have a download uri yet')
|
187
|
+
|
188
|
+
await file.delete()
|
189
|
+
|
190
|
+
Logger.info('***** testUploadDataForHugeFile() succeeded! *****')
|
165
191
|
}
|
166
192
|
/**/
|
167
193
|
|
@@ -242,7 +268,8 @@ const testSuite = async () => {
|
|
242
268
|
await testFolderListAutoPagination()
|
243
269
|
await testUploadAndDownloadToFile()
|
244
270
|
await testUploadAndDownloadToString()
|
245
|
-
// await
|
271
|
+
// await testUploadDataForHugeFile() // to run this test, put a file (or symlink) at huge-file.ext
|
272
|
+
// await testUploadFileForHugeFile() // to run this test, put a file (or symlink) at huge-file.ext
|
246
273
|
await testSession()
|
247
274
|
await testFailure()
|
248
275
|
await testUserListAndUpdate()
|