1 | # gcs-resumable-upload
|
2 | > Upload a file to Google Cloud Storage with built-in resumable behavior
|
3 |
|
4 | ```sh
|
5 | $ npm install gcs-resumable-upload
|
6 | ```
|
7 | ```js
|
8 | const {upload} = require('gcs-resumable-upload');
|
9 | const fs = require('fs');
|
10 |
|
11 | fs.createReadStream('titanic.mov')
|
12 | .pipe(upload({ bucket: 'legally-owned-movies', file: 'titanic.mov' }))
|
13 | .on('progress', (progress) => {
|
14 | console.log('Progress event:')
|
15 | console.log('\t bytes: ', progress.bytesWritten);
|
16 | })
|
17 | .on('finish', () => {
|
18 | // Uploaded!
|
19 | });
|
20 | ```
|
21 |
|
22 | Or from the command line:
|
23 |
|
24 | ```sh
|
25 | $ npm install -g gcs-resumable-upload
|
26 | $ cat titanic.mov | gcs-upload legally-owned-movies titanic.mov
|
27 | ```
|
28 |
|
29 | If somewhere during the operation, you lose your connection to the internet or your tough-guy brother slammed your laptop shut when he saw what you were uploading, the next time you try to upload to that file, it will resume automatically from where you left off.
|
30 |
|
31 | ## How it works
|
32 |
|
33 | This module stores a file using [ConfigStore](https://www.npmjs.com/package/configstore) that is written to when you first start an upload. It is aliased by the file name you are uploading to and holds the first 16kb chunk of data* as well as the unique resumable upload URI. ([Resumable uploads are complicated](https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#resumable))
|
34 |
|
35 | If your upload was interrupted, next time you run the code, we ask the API how much data it has already, then simply dump all of the data coming through the pipe that it already has.
|
36 |
|
37 | After the upload completes, the entry in the config file is removed. Done!
|
38 |
|
39 | \* The first 16kb chunk is stored to validate if you are sending the same data when you resume the upload. If not, a new resumable upload is started with the new data.
|
40 |
|
41 | ## Authentication
|
42 |
|
43 | Oh, right. This module uses [google-auth-library](https://www.npmjs.com/package/google-auth-library) and accepts all of the configuration that module does to strike up a connection as `config.authConfig`. See [`authConfig`](https://github.com/google/google-auth-library-nodejs/#choosing-the-correct-credential-type-automatically).
|
44 |
|
45 | ## API
|
46 |
|
47 | ```js
|
48 | const {gcsResumableUpload} = require('gcs-resumable-upload')
|
49 | const upload = gcsResumableUpload(config)
|
50 | ```
|
51 |
|
52 | `upload` is an instance of [`Duplexify`](https://www.npmjs.com/package/duplexify).
|
53 |
|
54 | ---
|
55 | <a name="methods"></a>
|
56 | ### Methods
|
57 |
|
58 | #### upload.createURI(callback)
|
59 |
|
60 | ##### callback(err, resumableURI)
|
61 |
|
62 | ###### callback.err
|
63 |
|
64 | - Type: `Error`
|
65 |
|
66 | Invoked if the authorization failed or the request to start a resumable session failed.
|
67 |
|
68 | ###### callback.resumableURI
|
69 |
|
70 | - Type: `String`
|
71 |
|
72 | The resumable upload session URI.
|
73 |
|
74 |
|
75 | #### upload.deleteConfig()
|
76 |
|
77 | This will remove the config data associated with the provided file.
|
78 |
|
79 | ---
|
80 | <a name="config"></a>
|
81 | ### Configuration
|
82 |
|
83 | #### config
|
84 |
|
85 | - Type: `object`
|
86 |
|
87 | Configuration object.
|
88 |
|
89 | ##### config.authClient
|
90 |
|
91 | - Type: [`GoogleAuth`](https://www.npmjs.com/package/google-auth-library)
|
92 | - *Optional*
|
93 |
|
94 | If you want to re-use an auth client from [google-auth-library](https://www.npmjs.com/package/google-auth-library), pass an instance here.
|
95 |
|
96 | ##### config.authConfig
|
97 |
|
98 | - Type: `object`
|
99 | - *Optional*
|
100 |
|
101 | See [`authConfig`](https://github.com/google/google-auth-library-nodejs/#choosing-the-correct-credential-type-automatically).
|
102 |
|
103 | ##### config.bucket
|
104 |
|
105 | - Type: `string`
|
106 | - **Required**
|
107 |
|
108 | The name of the destination bucket.
|
109 |
|
110 | ##### config.configPath
|
111 |
|
112 | - Type: `string`
|
113 | - *Optional*
|
114 |
|
115 | Where the gcs-resumable-upload configuration file should be stored on your system. This maps to the [configstore option by the same name](https://github.com/yeoman/configstore/tree/0df1ec950d952b1f0dfb39ce22af8e505dffc71a#configpath).
|
116 |
|
117 | ##### config.customRequestOptions
|
118 |
|
119 | - Type: `object`
|
120 | - *Optional*
|
121 |
|
122 | For each API request we send, you may specify custom request options that we'll add onto the request. The request options follow the gaxios API: https://github.com/googleapis/gaxios#request-options.
|
123 |
|
124 | For example, to set your own HTTP headers:
|
125 |
|
126 | ```js
|
127 | const stream = upload({
|
128 | customRequestOptions: {
|
129 | headers: {
|
130 | 'X-My-Header': 'My custom value',
|
131 | },
|
132 | },
|
133 | })
|
134 | ```
|
135 |
|
136 | ##### config.file
|
137 |
|
138 | - Type: `string`
|
139 | - **Required**
|
140 |
|
141 | The name of the destination file.
|
142 |
|
143 | ##### config.generation
|
144 |
|
145 | - Type: `number`
|
146 | - *Optional*
|
147 |
|
148 | This will cause the upload to fail if the current generation of the remote object does not match the one provided here.
|
149 |
|
150 | ##### config.key
|
151 |
|
152 | - Type: `string|buffer`
|
153 | - *Optional*
|
154 |
|
155 | A [customer-supplied encryption key](https://cloud.google.com/storage/docs/encryption#customer-supplied).
|
156 |
|
157 | ##### config.kmsKeyName
|
158 |
|
159 | - Type: `string`
|
160 | - *Optional*
|
161 |
|
162 | Resource name of the Cloud KMS key, of the form `projects/my-project/locations/global/keyRings/my-kr/cryptoKeys/my-key`, that will be used to encrypt the object. Overrides the object metadata's `kms_key_name` value, if any.
|
163 |
|
164 | ##### config.metadata
|
165 |
|
166 | - Type: `object`
|
167 | - *Optional*
|
168 |
|
169 | Any metadata you wish to set on the object.
|
170 |
|
171 | ###### *config.metadata.contentLength*
|
172 |
|
173 | Set the length of the file being uploaded.
|
174 |
|
175 | ###### *config.metadata.contentType*
|
176 |
|
177 | Set the content type of the incoming data.
|
178 |
|
179 | ##### config.offset
|
180 |
|
181 | - Type: `number`
|
182 | - *Optional*
|
183 |
|
184 | The starting byte of the upload stream, for [resuming an interrupted upload](https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload#resume-upload).
|
185 |
|
186 | ##### config.origin
|
187 |
|
188 | - Type: `string`
|
189 | - *Optional*
|
190 |
|
191 | Set an Origin header when creating the resumable upload URI.
|
192 |
|
193 | ##### config.predefinedAcl
|
194 |
|
195 | - Type: `string`
|
196 | - *Optional*
|
197 |
|
198 | Apply a predefined set of access controls to the created file.
|
199 |
|
200 | Acceptable values are:
|
201 |
|
202 | - **`authenticatedRead`** - Object owner gets `OWNER` access, and `allAuthenticatedUsers` get `READER` access.
|
203 | - **`bucketOwnerFullControl`** - Object owner gets `OWNER` access, and project team owners get `OWNER` access.
|
204 | - **`bucketOwnerRead`** - Object owner gets `OWNER` access, and project team owners get `READER` access.
|
205 | - **`private`** - Object owner gets `OWNER` access.
|
206 | - **`projectPrivate`** - Object owner gets `OWNER` access, and project team members get access according to their roles.
|
207 | - **`publicRead`** - Object owner gets `OWNER` access, and `allUsers` get `READER` access.
|
208 |
|
209 | ##### config.private
|
210 |
|
211 | - Type: `boolean`
|
212 | - *Optional*
|
213 |
|
214 | Make the uploaded file private. (Alias for `config.predefinedAcl = 'private'`)
|
215 |
|
216 | ##### config.public
|
217 |
|
218 | - Type: `boolean`
|
219 | - *Optional*
|
220 |
|
221 | Make the uploaded file public. (Alias for `config.predefinedAcl = 'publicRead'`)
|
222 |
|
223 | ##### config.uri
|
224 |
|
225 | - Type: `string`
|
226 | - *Optional*
|
227 |
|
228 | If you already have a resumable URI from a previously-created resumable upload, just pass it in here and we'll use that.
|
229 |
|
230 | ##### config.userProject
|
231 |
|
232 | - Type: `string`
|
233 | - *Optional*
|
234 |
|
235 | If the bucket being accessed has `requesterPays` functionality enabled, this can be set to control which project is billed for the access of this file.
|
236 |
|
237 | ##### config.retryOptions
|
238 |
|
239 | - Type: `object`
|
240 | - *Optional*
|
241 |
|
242 | Parameters used to control retrying operations.
|
243 |
|
244 | ```js
|
245 | interface RetryOptions {
|
246 | retryDelayMultiplier?: number;
|
247 | totalTimeout?: number;
|
248 | maxRetryDelay?: number;
|
249 | autoRetry?: boolean;
|
250 | maxRetries?: number;
|
251 | retryableErrorFn?: (err: ApiError) => boolean;
|
252 | }
|
253 | ```
|
254 |
|
255 | ##### config.retryOptions.retryDelayMultiplier
|
256 |
|
257 | - Type: `number`
|
258 | - *Optional*
|
259 |
|
260 | Base number used for exponential backoff. Default 2.
|
261 |
|
262 | ##### config.retryOptions.totalTimeout
|
263 |
|
264 | - Type: `number`
|
265 | - *Optional*
|
266 |
|
267 | Upper bound on the total amount of time to attempt retrying, in seconds. Default: 600.
|
268 |
|
269 | ##### config.retryOptions.maxRetryDelay
|
270 |
|
271 | - Type: `number`
|
272 | - *Optional*
|
273 |
|
274 | The maximum time to delay between retries, in seconds. Default: 64.
|
275 |
|
276 | ##### config.retryOptions.autoRetry
|
277 |
|
278 | - Type: `boolean`
|
279 | - *Optional*
|
280 |
|
281 | Whether or not errors should be retried. Default: true.
|
282 |
|
283 | ##### config.retryOptions.maxRetries
|
284 |
|
285 | - Type: `number`
|
286 | - *Optional*
|
287 |
|
288 | The maximum number of retries to attempt. Default: 5.
|
289 |
|
290 | ##### config.retryOptions.retryableErrorFn
|
291 |
|
292 | - Type: `function`
|
293 | - *Optional*
|
294 |
|
295 | Custom function returning a boolean indicating whether or not to retry an error.
|
296 |
|
297 |
|
298 | ##### config.chunkSize
|
299 |
|
300 | - Type: `number`
|
301 | - *Optional*
|
302 |
|
303 | Enables [Multiple chunk upload](https://cloud.google.com/storage/docs/performing-resumable-uploads#chunked-upload) mode and sets each request size to this amount.
|
304 |
|
305 | This only makes sense to use for larger files. The chunk size should be a multiple of 256 KiB (256 x 1024 bytes). Larger chunk sizes typically make uploads more efficient. We recommend using at least 8 MiB for the chunk size.
|
306 |
|
307 | Review [documentation](https://cloud.google.com/storage/docs/performing-resumable-uploads) for guidance and best practices.
|
308 |
|
309 | ---
|
310 | <a name="events"></a>
|
311 | ### Events
|
312 |
|
313 | #### .on('error', function (err) {})
|
314 |
|
315 | ##### err
|
316 |
|
317 | - Type: `Error`
|
318 |
|
319 | Invoked if the authorization failed, the request failed, or the file wasn't successfully uploaded.
|
320 |
|
321 | #### .on('response', function (response) {})
|
322 |
|
323 | ##### resp
|
324 |
|
325 | - Type: `Object`
|
326 |
|
327 | The [response object from Gaxios](https://github.com/JustinBeckwith/gaxios/blob/88a47e000625d8192689acac5c40c0b1e1d963a2/src/gaxios.ts#L197-L203).
|
328 |
|
329 | ##### metadata
|
330 |
|
331 | - Type: `Object`
|
332 |
|
333 | The file's new metadata.
|
334 |
|
335 | #### .on('progress', function (progress) {})
|
336 |
|
337 | #### progress
|
338 |
|
339 | - Type: `Object`
|
340 |
|
341 | ##### progress.bytesWritten
|
342 |
|
343 | - Type: `number`
|
344 |
|
345 | ##### progress.contentLength
|
346 |
|
347 | - Type: `number`
|
348 |
|
349 | Progress event provides upload stats like Transferred Bytes and content length.
|
350 |
|
351 | #### .on('finish', function () {})
|
352 |
|
353 | The file was uploaded successfully.
|
354 |
|
355 | ---
|
356 | <a name="static-methods"></a>
|
357 | ### Static Methods
|
358 |
|
359 | ```js
|
360 | const {createURI} = require('gcs-resumable-upload')
|
361 | ````
|
362 |
|
363 | #### createURI([config](#config), callback)
|
364 |
|
365 | ##### callback(err, resumableURI)
|
366 |
|
367 | ###### callback.err
|
368 |
|
369 | - Type: `Error`
|
370 |
|
371 | Invoked if the authorization failed or the request to start a resumable session failed.
|
372 |
|
373 | ###### callback.resumableURI
|
374 |
|
375 | - Type: `String`
|
376 |
|
377 | The resumable upload session URI.
|
378 |
|
\ | No newline at end of file |