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

V1.3.8 handle exception gracefully when a url doesn't resolve #63

Merged
merged 13 commits into from
Jul 6, 2018

Conversation

sanakanchha
Copy link
Contributor

Whenever a url doesn't resolve(due to network connectivity, incorrect url etc.), this lib throws an exception which wasn't handled gracefully.

@coveralls
Copy link

coveralls commented Jul 3, 2018

Coverage Status

Coverage decreased (-0.4%) to 94.875% when pulling a7b3000 on v1.3.8 into d5197da on develop.

lib/key.js Outdated
// handle any uncaught exceptions
.catch((err) => {

return err.message;
Copy link
Contributor

Choose a reason for hiding this comment

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

This should be return reject(err);

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't it be return Promise.reject(err)? I think reject is outside of the scope..

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, good catch!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I had it this way initially. Unfortunately, the unhandled promise rejection didn't get fixed killing the realtime app.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

However, I could either go with Promise.resolve(err); or just the way it is in order to send a graceful message to the realtime app.

Copy link
Contributor

Choose a reason for hiding this comment

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

maybe add a catch for the yield ensureAuthHeaders call here and then if it catches the error emit the error?

Copy link
Contributor

Choose a reason for hiding this comment

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

if ensureAuthHeaders fails, the co should bubble the exception as a rejected Promise. However, notice that the co function is not being returned... add a return statement before co and this will probably help.

Copy link
Contributor

Choose a reason for hiding this comment

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

or rewrite a bit...

self.connect = (socketEventSubscriber) => (co(function *() {
// teh codez herr
});

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay, working on a fix. on the player.js file, thank you.
We found an issue with socket-io-client where it doesn't try to reconnect if failed during during authorization. Craig is looking into whether upgrading socket-io-client is a solution.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

test/lib/key.js Outdated
@@ -279,7 +279,7 @@ describe('key', () => {
});

describe('#ensureAuthHeaders', () => {
it('should require clientId', (done) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

If you remove the callback here but don't use async and await then the test won't run / complete the way it is intended to. If you'd like to head this route, the better step is to upgrade the mocha dependency, but this is a relatively in-depth task because there may need to be a lot more adjustments made in the SDK to support this.

test/lib/key.js Outdated
});
});

it('should require secret', (done) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as above - this is not having the intended effect, the test is not running.

lib/player.js Outdated
clientId = authHeaders[CLIENT_ID];

socket.io.opts.query = ['clientId=', clientId, '&', 'token=', authToken].join('');
if(authHeaders != null) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This condition will always be true because you are always returning an error from the call to ensureAuthHeaders or it actually returns headers

Copy link
Contributor

Choose a reason for hiding this comment

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

also, you would never try to connect at all meaning the reconnect logic won't be hit at all

lib/player.js Outdated

err = JSON.parse(err);
if(err.code == 401) {
socket.disconnect();
Copy link
Contributor

Choose a reason for hiding this comment

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

indentation is off here

@sanakanchha
Copy link
Contributor Author

@brozeph , @cmerchant , @rmomii the same PR with new changes if you could take a look would be great.

lib/player.js Outdated
options = {};
}

if (validation.isEmpty(socketEventSubscriber) || !socketEventSubscriber.emit) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This works, but we're really not checking to see if the socketEventSubscriber is an EventEmitter per se, only that it has a property named emit and not even that it's a function. Might be worthwhile thinking through how to validate if the emit is a function as well.

if ([
  validation.isEmpty(socketEventSubscriber),
  validation.isEmpty(socketEventSubscriber.emit),
  typeof socketEventSubscriber.emit !== 'function'
].some((val) => val)) {
  throw new Error('socketEventSubscriber must be an instance of event.EventEmitter');
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

taken care of

lib/player.js Outdated
clientId = authHeaders[CLIENT_ID];

url = [protocol, '://', options.host || settings.host].join('');
query = ['clientId=', clientId, '&', 'token=', authToken].join('');
Copy link
Contributor

Choose a reason for hiding this comment

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

query = ['clientId=', clientId, '&token=', authToken].join('');

Copy link
Contributor Author

Choose a reason for hiding this comment

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

taken care of

lib/player.js Outdated
socket.on('reconnecting', (attempt) => {
let connection = {
'connectionAttempt' : attempt,
'headerReset' : false,
Copy link
Contributor

Choose a reason for hiding this comment

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

How is headerReset used by clients... there is also an isReconnect that's present on other connection objects emitted and this field isn't consistent with those. Is this by design and is this well understood by the consuming code? Seems like this could lead to some confusion...

Copy link
Contributor

Choose a reason for hiding this comment

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

it is used by realtime app. It should be documented in the sdk readme

Copy link
Contributor

Choose a reason for hiding this comment

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

the main reason is that we are emiting a connected event for both connect and reconnect. It lets the consumer be aware of this situation. In the realtime app case, it is used for logging

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can get rid of headerReset. That seems to be a relic of an earlier implementation. @deepakdahal please double check that before removing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

The tests are there, but do we actually use it anywhere? If not, we should remove it and the tests...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay, headerReset has been removed both from test and code

authToken = authHeaders[AUTH_TOKEN];
clientId = authHeaders[CLIENT_ID];

url = [protocol, '://', options.host || settings.host].join('');
Copy link
Contributor

Choose a reason for hiding this comment

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

Will it ever be possible that options.host and settings.host are both defined. What would happen in this case in forming the url?

Copy link
Contributor

Choose a reason for hiding this comment

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

options.host should take precedent over settings.host if this were to be the case... the idea here is that you configure the SDK at initialization, but you have the ability to override on a per call basis for über flexibility

@cmerchant
Copy link
Contributor

I thought there was some co function that needed a return value. Where is that?

Copy link
Contributor

@brozeph brozeph left a comment

Choose a reason for hiding this comment

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

Getting close!

lib/player.js Outdated
validation.isEmpty(socketEventSubscriber),
validation.isEmpty(socketEventSubscriber.emit),
typeof socketEventSubscriber.emit !== 'function'
].some((val) => val)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

de-indent the line 😺

Copy link
Contributor Author

Choose a reason for hiding this comment

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

taken care of

lib/player.js Outdated
socket.on('reconnecting', (attempt) => {
let connection = {
'connectionAttempt' : attempt,
'headerReset' : false,
Copy link
Contributor

Choose a reason for hiding this comment

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

The tests are there, but do we actually use it anywhere? If not, we should remove it and the tests...

@sanakanchha
Copy link
Contributor Author

@brozeph @cmerchant I should have covered everything :)

@cmerchant
Copy link
Contributor

Looks good to me

@brozeph brozeph merged commit f4de53a into develop Jul 6, 2018
@brozeph brozeph deleted the v1.3.8 branch July 6, 2018 17:48
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.

None yet

5 participants