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

Chore: Adding download reachability checks to Downloads, Document and Image Viewers #669

Merged
merged 5 commits into from
Mar 2, 2018
Merged

Chore: Adding download reachability checks to Downloads, Document and Image Viewers #669

merged 5 commits into from
Mar 2, 2018

Conversation

jeremypress
Copy link
Contributor

No description provided.

@boxcla
Copy link

boxcla commented Feb 16, 2018

Verified that @jeremypress has signed the CLA. Thanks for the pull request!

* @param {string} downloadHost - Download URL host
* @return {void}
*/
export function setDownloadHostNotificationShown(downloadHost) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Need to clean up params for these various methods to make them all consistent

* @return {boolean} - HTTP response
*/
export function isCustomDownloadHost(url) {
return url && !url.startsWith(DEFAULT_DOWNLOAD_HOST_PREFIX) && !!url.match(/^https:\/\/dl\d+\./);
Copy link
Contributor

Choose a reason for hiding this comment

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

Move the capture statement to a constant, then you can use it here and in places like replaceDownloadHostWithDefaultUrl()

@@ -97,6 +107,9 @@ class BaseViewer extends EventEmitter {
/** @property {boolean} - Whether viewer is being used on a touch device */
hasTouch;

/** @property {boolean} - Has the viewer retried downloading the content */
haveRetried = false;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you be a little more descriptive with this property name? haveRetried is pretty vague

Copy link
Contributor Author

Choose a reason for hiding this comment

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

haveRetriedContentDownload?

handleDownloadError(err, downloadURL) {
if (this.haveRetried) {
/* eslint-disable no-console */
console.error(err);
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 want to put console.error(err) inside of the code that emits preview_error events, we can throttle back the number of console statements that exist in our codebase! Up to you :)

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 do! But we would need to remove them all in one to avoid double printing, so I'm leaving this for now and then we can go back and do a commit where we grab them all.

@tonyjin
Copy link
Contributor

tonyjin commented Feb 21, 2018

Add your diagram to the PR description please!

@@ -745,6 +767,9 @@ class Preview extends EventEmitter {
this.throttledMousemoveHandler
);

// Set up the notification
this.ui.setupNotification();
Copy link
Contributor

Choose a reason for hiding this comment

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

Please work with @pramodsum to make sure this doesn't muck with annotations. I remember we've had a few issues with the location of setupNotification() before.

Copy link
Contributor

Choose a reason for hiding this comment

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

Were you able to resolve this @jeremypress @pramodsum?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it wasn't actually annotations related but CSS related. #583

I checked that the draw annotations notification was still good after my change.

@jeremypress
Copy link
Contributor Author

Diagram: download reachability

/**
* Replaces the hostname of a download URL with the default hostname, https://dl.
*
* @private
Copy link
Contributor

@tonyjin tonyjin Feb 21, 2018

Choose a reason for hiding this comment

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

Not private if you're exporting it :) Don't really care if you add @public or not to all of these, but keep it consistent.

errorHandler(err) {
/* eslint-disable no-console */
console.error(err);
/* eslint-enable no-console */
Copy link
Contributor

@tonyjin tonyjin Feb 21, 2018

Choose a reason for hiding this comment

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

Did you mean to take these out? They're stripped out in the production build but are occasionally useful on dev.

Copy link
Contributor Author

@jeremypress jeremypress Feb 21, 2018

Choose a reason for hiding this comment

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

I'm moving them all to the handleDownloadError call in base viewer so we only need to console.error once for any potential download error.

@@ -52,13 +53,14 @@ class ImageViewer extends ImageBaseViewer {

const { representation, viewer } = this.options;
const template = representation.content.url_template;
const downloadURL = this.createContentUrlWithAuthParams(template, viewer.ASSET);
Copy link
Contributor

Choose a reason for hiding this comment

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

downloadUrl* to keep consistent with other Url in the code

setDownloadReachability(data.download_url).then(() => {
if (isDownloadHostBlocked()) {
// If download is unreachable, try again with default
openUrlInsideIframe(defaultDownloadUrl);
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any opportunity for a double download here? e.g. can the first download succeed but then this reachability check fail?

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 don't believe so. The only way the reachability check fails is if the network request itself fails. This is different from any bad status 500, 404 etc. which will be treated as "successes" because we get a valid HTTP status.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately we have no way of checking the success of the download due to it coming from an iframe. @DanDeMicco mentioned other methods that we might want to move to that would give us more control over download status.

return (
downloadUrl && !downloadUrl.startsWith(DEFAULT_DOWNLOAD_HOST_PREFIX) && !!downloadUrl.match(DEFAULT_HOST_REGEX)
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Does your code work properly on dev with dl.jpress.inside-box.net and dl.app.jpress.inside-box.net? I don't think it's super important for the fallback logic to work on dev since there's only one download host, but please make sure we can't get stuck into some edge case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes this works on dev since I only check the DL, but this will have to change due to your comment below.

* @return {string} - The updated download URL
*/
export function replaceDownloadHostWithDefault(downloadUrl) {
return downloadUrl.replace(DEFAULT_HOST_REGEX, DEFAULT_DOWNLOAD_HOST_PREFIX);
Copy link
Contributor

Choose a reason for hiding this comment

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

Some AWS or accelerated hosts have weird patterns like https://ec2apne1.boxcloud.com, I'm not sure your regex would capture that

Copy link
Contributor Author

@jeremypress jeremypress Feb 21, 2018

Choose a reason for hiding this comment

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

womp, that is good information to know. I'll need to rethink my whole custom host/default host checking strategy. Good catch.

* @param {string} contentTemplate - Content download URL template
* @return {string|undefined} Should the notification be shown
*/
export function downloadNotificationToShow(contentTemplate) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This function signature is a bit confusing to me. The JSDoc for returns implies it should return a {boolean} and JSDoc description implies this should return a notification ID of some kind.

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 used to return a boolean, I'll update the return description.

@@ -53,3 +54,9 @@ export const LOAD_METRIC = {
downloadResponseTime: 'download_response_time', // Time it took for TTFB when requesting a rep.
fullDocumentLoadTime: 'full_document_load_time' // How long it took to load the document so it could be previewed.
};

// Events around download reachability
export const DOWNLOAD_REACHABILITY_METRICS = {
Copy link
Contributor

Choose a reason for hiding this comment

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

🎉

*/
handleDownloadError(err, downloadURL) {
if (this.hasRetriedContentDownload) {
this.triggerError(err);
Copy link
Contributor

Choose a reason for hiding this comment

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

You may want to make sure that this error complies with our new PreviewError

@@ -82,7 +81,9 @@ class ImageBaseViewer extends BaseViewer {
this.loaded = true;
this.emit(VIEWER_EVENT.load);
})
.catch(this.errorHandler);
.catch(() => {
// No-op, this prmise should always resolve
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems funky to not track an error if it occurs. Can we remove this, and allow for an uncaught error, then (if it's possible for this to error)?


describe('setDownloadHostFallback()', () => {
it('should set the download host fallback key to be true', () => {
expect(sessionStorage.getItem(DOWNLOAD_HOST_FALLBACK_KEY) === 'true').to.be.false;
Copy link
Contributor

Choose a reason for hiding this comment

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

This looks a bit weird

expect(sessionStorage.getItem(DOWNLOAD_HOST_FALLBACK_KEY)).to.equal('true')

@@ -163,6 +169,7 @@ class Preview extends EventEmitter {
this.handleFileInfoResponse = this.handleFileInfoResponse.bind(this);
this.handleFetchError = this.handleFetchError.bind(this);
this.handleViewerEvents = this.handleViewerEvents.bind(this);
this.handleViewerMetrics = this.handleViewerMetrics.bind(this);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Forgot this in my last PR :)

@@ -745,6 +767,9 @@ class Preview extends EventEmitter {
this.throttledMousemoveHandler
);

// Set up the notification
this.ui.setupNotification();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, it wasn't actually annotations related but CSS related. #583

I checked that the draw annotations notification was still good after my change.

@jeremypress jeremypress merged commit 6468d63 into box:master Mar 2, 2018
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.

5 participants