-
Notifications
You must be signed in to change notification settings - Fork 937
Add nonresumable uploadBytes to modular Storage #4084
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
): RequestInfo<Metadata> { | ||
const urlPart = location.bucketOnlyServerUrl(); | ||
const headers: { [prop: string]: string } = { | ||
'Content-Type': 'application/octet-stream' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should it always be octet-stream
? the original logic indicates it's a fallback when metadata.contentType
and blob.type()
are undefined. Perhaps it doesn't matter since we can treat everything as arbitrary binary data?
(metadata && metadata['contentType']) ||
(blob && blob.type()) ||
'application/octet-stream'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally (in the old resumable setup) the content type in the header doesn't actually match the metadata.contentType field because the metadata has a specific content type as seen in the logic above, and the request header Content-Type is always multipart
. Since we're doing away with multipart
I guess it would be best to make the header match the metadata.
Whoops, I misunderstood what |
d8f09c1
to
c4c6e32
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good (but somewhat hard to review due to the import/formatting changes). I wonder if you have been able to compute the size difference?
packages/storage/src/reference.ts
Outdated
* Uploads data to this object's location. | ||
* The upload is not resumable. | ||
* @public | ||
* @param ref - Storage Reference where data should be uploaded. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Storage reference" or "StorageReference" ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, exported type name is just Reference
. I guess I should rename it since it's publicly exposed.
packages/storage/compat/reference.ts
Outdated
const data = dataFromString(format, value); | ||
const metadataClone = { ...metadata } as Metadata; | ||
if (metadataClone['contentType'] == null && data.contentType != null) { | ||
metadataClone['contentType'] = data.contentType!; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the bang needed here? Doesn't the !=
check catch both null
and undefined
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed, seems like it was left over from back when it was using type.isDef
instead of != null
.
"test:browser:compat:unit": "karma start --single-run --compat --unit", | ||
"test:browser:exp:unit": "karma start --single-run --exp --unit", | ||
"test:browser:compat:integration": "karma start --single-run --compat --integration", | ||
"test:browser:exp:integration": "karma start --single-run --exp --integration", | ||
"test:browser:compat": "karma start --single-run --compat", | ||
"test:browser:exp": "karma start --single-run --exp", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we add these new test targets to the CI rule?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These were for development testing convenience, CI tests everything. If it's too messy I guess I can remove them, should be able to pass these args to yarn test:browser
using --
I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please leave them. It makes everyone's life easier.
packages/storage/src/reference.ts
Outdated
* @param data - The data to upload. | ||
* @param metadata - Metadata for the newly uploaded string. | ||
* @param metadata - Metadata for the newly uploaded data. | ||
* @returns An UploadTaskNonResumableSnapshot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @returns An UploadTaskNonResumableSnapshot | |
* @returns An UploadTaskSnapshot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
packages/storage/src/reference.ts
Outdated
* @param value - The string to upload. | ||
* @param format - The format of the string to upload. | ||
* @param metadata - Metadata for the newly uploaded object. | ||
* @param metadata - Metadata for the newly uploaded string. | ||
* @returns An UploadTask that lets you control and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @returns An UploadTask that lets you control and | |
* @returns UploadTaskSnapshot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
packages/storage/src/reference.ts
Outdated
} | ||
|
||
/** | ||
* Base code for nonresumable upload, used by uploadString and uploadBytes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Base code for nonresumable upload, used by uploadString and uploadBytes. | |
* Shared code for nonresumable upload, used by uploadString and uploadBytes. |
Optional.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
packages/storage/src/reference.ts
Outdated
|
||
/** | ||
* Uploads data to this object's location. | ||
* The upload is resumable and exposes progress updates. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* The upload is resumable and exposes progress updates. | |
* The upload can be paused, resumed and exposes progress updates. |
Suggesting this because the Web SDK doesn't actually allow you to resume an upload with an Upload URL (as far as I can tell). Instead, the user can only resume uploads with an UploadTask that they paused.
Android let's users actually resume an upload with an Upload URL: https://firebase.google.com/docs/reference/android/com/google/firebase/storage/StorageReference#putFile(android.net.Uri,%20com.google.firebase.storage.StorageMetadata,%20android.net.Uri)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
packages/storage/src/task.ts
Outdated
import { | ||
createResumableUpload, | ||
getResumableUploadStatus, | ||
resumableUploadChunkSize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resumableUploadChunkSize, | |
RESUMABLE_UPLOAD_CHUNK_SIZE, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
it('uploadString throws', async () => { | ||
expect(() => uploadString(root, 'raw', StringFormat.RAW)).to.throw( | ||
'storage/invalid-root-operation' | ||
); | ||
}); | ||
it('uploadBytes throws', async () => { | ||
expect(() => uploadBytes(root, new Blob(['a']))).to.throw( | ||
'storage/invalid-root-operation' | ||
); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it('uploadString throws', async () => { | |
expect(() => uploadString(root, 'raw', StringFormat.RAW)).to.throw( | |
'storage/invalid-root-operation' | |
); | |
}); | |
it('uploadBytes throws', async () => { | |
expect(() => uploadBytes(root, new Blob(['a']))).to.throw( | |
'storage/invalid-root-operation' | |
); | |
}); | |
it('uploadString throws', () => { | |
expect(() => uploadString(root, 'raw', StringFormat.RAW)).to.throw( | |
'storage/invalid-root-operation' | |
); | |
}); | |
it('uploadBytes throws', () => { | |
expect(() => uploadBytes(root, new Blob(['a']))).to.throw( | |
'storage/invalid-root-operation' | |
); | |
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -114,8 +115,17 @@ export class ReferenceCompat implements types.Reference { | |||
metadata?: Metadata | |||
): types.UploadTask { | |||
this._throwIfRoot('putString'); | |||
const data = dataFromString(format, value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious - could this method just call put
with new FbsBlob(data.data, true)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean call uploadBytes
instead of having a shared _nonResumableUpload function? I guess the only drawback would be an extra _throwIfRoot call that won't do anything.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
common/api-review/storage.api.md
Outdated
// Warning: (ae-forgotten-export) The symbol "ListOptions" needs to be exported by the entry point index.d.ts | ||
// Warning: (ae-forgotten-export) The symbol "ListResult" needs to be exported by the entry point index.d.ts |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should address these warnings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partially addressed. There are a lot of files to fix so I will do a full pass on all files in another PR.
@@ -279,10 +277,13 @@ export function metadataForUpload_( | |||
return metadataClone; | |||
} | |||
|
|||
/** | |||
* Prepare RequestInfo for resumable uploads as Content-Type: multipart. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Prepare RequestInfo for resumable uploads as Content-Type: multipart. | |
* Prepare RequestInfo for uploads as Content-Type: multipart. |
It is used for both resumable and non-resumable uploads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, fixed.
packages/storage/src/tasksnapshot.ts
Outdated
export interface UploadTaskSnapshot { | ||
readonly metadata: Metadata; | ||
readonly ref: StorageReference; | ||
} | ||
|
||
export interface UploadTaskResumableSnapshot { | ||
readonly bytesTransferred: number; | ||
readonly totalBytes: number; | ||
readonly state: TaskState; | ||
readonly metadata: Metadata; | ||
readonly task: UploadTask; | ||
readonly ref: StorageReference; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
res
Outdated
@@ -0,0 +1,998 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops
async function buildForTests( | ||
config: TestConfig, | ||
buildAppExp = false, | ||
buildAppCompat = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was the script broken because of the missing argument until now? but the workflow seems to work fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It used to be accessible anyway because it was a global variable (not window global, like top level in the file) so it worked but maybe in an unexpected way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM from my end (please wait for Fei's LGTM as well). Consider calling uploadBytes
from uploadString
.
"test:browser:compat:unit": "karma start --single-run --compat --unit", | ||
"test:browser:exp:unit": "karma start --single-run --exp --unit", | ||
"test:browser:compat:integration": "karma start --single-run --compat --integration", | ||
"test:browser:exp:integration": "karma start --single-run --exp --integration", | ||
"test:browser:compat": "karma start --single-run --compat", | ||
"test:browser:exp": "karma start --single-run --exp", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please leave them. It makes everyone's life easier.
packages/storage/src/reference.ts
Outdated
* @param ref - StorageReference where data should be uploaded. | ||
* @param data - The data to upload. | ||
* @param metadata - Metadata for the newly uploaded data. | ||
* @returns An UploadTaskSnapshot |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @returns An UploadTaskSnapshot | |
* @returns An UploadTask |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
packages/storage/src/reference.ts
Outdated
ref: Reference, | ||
metadata: Metadata | ||
ref: StorageReference, | ||
metadata: Record<string, unknown> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about Partial<Metadata>
? I think that makes the intent very clear.
2615765
to
b0612cc
Compare
b0612cc
to
91c5e61
Compare
Adding
uploadBytes
to storage-exp. This is a new method that does a non-resumable upload which requires less code than the resumable upload. We expect people to use this by default and only use the resumable version when needed, so it gets the default-sounding name and the resumable upload is nameduploadBytesResumable
.uploadBytes
has to generate anUploadTaskSnapshot
with less properties (notask
,state
,bytesTransferred
...do we still needtotalBytes
? not sure) so I created a separate class, and again gave it the default sounding name, while the old one is namedUploadTaskResumableSnapshot
.