Skip to content
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

Implementing FCM sendAll() API #453

Merged
merged 24 commits into from
Mar 14, 2019
Merged

Implementing FCM sendAll() API #453

merged 24 commits into from
Mar 14, 2019

Conversation

hiranya911
Copy link
Contributor

Implementing the following new API:

sendAll(messages: Message[], dryRun?: boolean): Promise<BatchResponse>

This implements a part of go/fcm-multicast. I've also implemented the following refactorings in order to keep the size of the messaging.ts module in check:

  • Moved all the type definitions and their util functions to a new messaging-types.ts module.
  • Moved the error handling/parsing logic to a new messaging-errors.ts module.

There's more room for refactoring here, but I would rather do that in separate PRs.

src/messaging/messaging-api-request.ts Outdated Show resolved Hide resolved
src/messaging/messaging-errors.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@bojeil-google bojeil-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mostly have nits and some recommendations for providing samples and splitting some code to make it easier to follow. It would make the review easier. I haven't covered the entire PR yet.

src/messaging/batch-request.ts Outdated Show resolved Hide resolved
src/messaging/batch-request.ts Outdated Show resolved Hide resolved
src/messaging/batch-request.ts Show resolved Hide resolved
src/utils/api-request.ts Show resolved Hide resolved
constructor(resp: LowLevelResponse) {
this.status = resp.status;
this.headers = resp.headers;
this.multipart = resp.multipart;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should you validate it is an actually multipart response?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is not exported, and we control the only place where it gets instantiated. So it should be fine.

src/utils/api-request.ts Outdated Show resolved Hide resolved
respStream.on('data', (chunk: Buffer) => {
responseBuffer.push(chunk);
});
const boundary = getMultipartBoundary(res.headers);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sendRequest has become too large, is there a way we can split it to be more manageable? or create smaller functions to handle different parts of the logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not easy due to the use of new Promise() but I think we can do some improvements. However, I'd rather do that as a separate PR.

src/utils/api-request.ts Show resolved Hide resolved
src/messaging/messaging.ts Outdated Show resolved Hide resolved
const headerLines: string[] = responseText.substring(0, endOfHeaderPos).split('\r\n');

const statusLine: string = headerLines[0];
const status: string = statusLine.trim().split(/\s/)[1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate that the array has >=2 elements and before that headerLines has at least 1 element.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

slice(1) returns an empty array when length is less than 2. So it's safe to iterate over it without a length check. Similarly, headerLines is the result of a split() call, which always returns an array with at least 1 element.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see that you are using split here and not slice:
statusLine.trim().split(/\s/)[1]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use split and slice for headerLines. For statusLine I added a check to cover the case of a malformed header. Although chances of it happening should be negligibly small.

@hiranya911
Copy link
Contributor Author

Thanks @bojeil-google. I've responded to your comments. PTAL.

src/messaging/batch-request.ts Show resolved Hide resolved
src/messaging/batch-request.ts Show resolved Hide resolved
const headerLines: string[] = responseText.substring(0, endOfHeaderPos).split('\r\n');

const statusLine: string = headerLines[0];
const status: string = statusLine.trim().split(/\s/)[1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only see that you are using split here and not slice:
statusLine.trim().split(/\s/)[1]

src/utils/api-request.ts Outdated Show resolved Hide resolved
test/unit/messaging/batch-requests.spec.ts Outdated Show resolved Hide resolved
test/unit/messaging/batch-requests.spec.ts Show resolved Hide resolved
});

function parseHttpRequest(text: string | Buffer): any {
const httpMessageParser = require('http-message-parser');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: I think we should minimize depending on low usage npm modules. In this case, this has ~2k weekly downloads. We have been bitten by some dependency on an npm module that was abandoned in the past.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We only use this in a couple of test cases. I can try to replace it with something else in a future PR.

).should.eventually.be.rejected.and.have.property('code', 'app/invalid-credential');
});

function checkSendResponseSuccess(response: SendResponse, messageId: string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: define helper functions on top of file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Moved to the top of the enclosing block. These helpers are scoped to a specific test case.

test/unit/utils/api-request.spec.ts Outdated Show resolved Hide resolved
test/unit/utils/api-request.spec.ts Outdated Show resolved Hide resolved
@hiranya911
Copy link
Contributor Author

Thanks @bojeil-google. I've addressed most of your comments.

* Implementing sendMulticast() API

* Added integration test

* Fixed a comment

* Readability improvement in the copy operation
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants