files.com 1.0.412 → 1.0.414
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/_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()
|