Skip to content

Commit

Permalink
interfaces refactoring (#251)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: Rename RequestParams to RequestOptions
BREAKING CHANGE: Removed *All from UploadAction
BREAKING CHANGE: Strongly typed response body
  • Loading branch information
kukhariev committed Jul 26, 2020
1 parent 43c263a commit 8bfaa1c
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 45 deletions.
4 changes: 2 additions & 2 deletions integrations/ng10/src/app/on-push/on-push.component.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, OnDestroy } from '@angular/core';
import {
b64,
RequestParams,
RequestOptions,
Uploader,
UploaderX,
UploadState,
Expand Down Expand Up @@ -70,7 +70,7 @@ const hasher = {
}
};

async function injectDigestHeader(this: UploaderX, req: RequestParams): Promise<RequestParams> {
async function injectDigestHeader(this: UploaderX, req: RequestOptions): Promise<RequestOptions> {
if (hasher.isSupported && req.method === 'PUT' && req.body instanceof Blob) {
const headers = req.headers || {};
const sha = await hasher.getDigest(req.body);
Expand Down
12 changes: 5 additions & 7 deletions src/uploadx/lib/error-handler.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { ErrorHandler } from './error-handler';

describe('ErrorHandler', () => {
describe('constructor', () => {
it('should set to defaults if no parameters are specified', () => {
const errorHandler = new ErrorHandler();
expect(errorHandler.attempts).toBe(1);
expect(errorHandler.min).toBe(500);
expect(errorHandler.max).toBe(60_000);
});
it('should set to defaults if no parameters are specified', () => {
const errorHandler = new ErrorHandler();
expect(errorHandler.attempts).toBe(0);
expect(ErrorHandler.min).toBe(500);
expect(ErrorHandler.max).toBe(60_000);
});
});
40 changes: 21 additions & 19 deletions src/uploadx/lib/error-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,32 @@
* @internal
*/
export enum ErrorType {
Restart,
NotFound,
Auth,
Retryable,
FatalError
Fatal
}

/**
* @internal
*/
export class ErrorHandler {
static maxAttempts = 8;
static shouldRestartCodes = [404, 410];
static authErrorCodes = [401];
static shouldRetryCodes = [423, 429];
min = 500;
max = this.min * 120;
factor = 2;
attempts = 1;
private delay: number;
static min = 500;
static max = ErrorHandler.min * 120;
static factor = 2;
public attempts = 0;
private delay: number = ErrorHandler.min;
private code? = -1;

constructor() {
this.delay = this.min;
}

kind(code: number): ErrorType {
if (code === this.code) {
this.attempts++;
if (this.attempts > ErrorHandler.maxAttempts) {
return ErrorType.FatalError;
if (this.attempts >= ErrorHandler.maxAttempts) {
return ErrorType.Fatal;
}
} else {
this.reset();
Expand All @@ -39,24 +38,27 @@ export class ErrorHandler {
return ErrorType.Auth;
}
if (ErrorHandler.shouldRestartCodes.includes(code)) {
return ErrorType.Restart;
return ErrorType.NotFound;
}
if (code < 400 || code >= 500 || ErrorHandler.shouldRetryCodes.includes(code)) {
return ErrorType.Retryable;
}
return ErrorType.FatalError;
return ErrorType.Fatal;
}

wait(): Promise<number> {
return new Promise(resolve => {
this.delay = Math.min(this.delay * this.factor, this.max);
setTimeout(() => resolve(this.attempts), this.delay + Math.floor(Math.random() * this.min));
this.delay = Math.min(this.delay * ErrorHandler.factor, ErrorHandler.max);
setTimeout(
() => resolve(this.attempts),
this.delay + Math.floor(Math.random() * ErrorHandler.min)
);
});
}

reset(): void {
this.delay = this.min;
this.attempts = 1;
this.delay = ErrorHandler.min;
this.attempts = 0;
this.code = -1;
}
}
10 changes: 2 additions & 8 deletions src/uploadx/lib/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ export interface RequestOptions {
progress?: boolean;
}

/**
* @deprecated since 3.5.1
* use `RequestOptions` instead
*/
export type RequestParams = RequestOptions;

export type UploadStatus =
| 'added'
| 'queue'
Expand All @@ -35,7 +29,7 @@ export type UploadStatus =
| 'paused'
| 'retry';

export type UploadAction = 'uploadAll' | 'upload' | 'cancel' | 'cancelAll' | 'pauseAll' | 'pause';
export type UploadAction = 'upload' | 'cancel' | 'pause';

/**
* Read only upload stream events
Expand All @@ -56,7 +50,7 @@ export interface UploadState {
readonly remaining: number;

/** HTTP response body */
readonly response: ResponseBody | undefined;
readonly response: ResponseBody;

/** HTTP response status code */
readonly responseStatus: number;
Expand Down
16 changes: 7 additions & 9 deletions src/uploadx/lib/uploader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ import { createHash, DynamicChunk, isNumber, noop, unfunc } from './utils';
const actionToStatusMap: { [K in UploadAction]: UploadStatus } = {
pause: 'paused',
upload: 'queue',
cancel: 'cancelled',
uploadAll: 'queue',
pauseAll: 'paused',
cancelAll: 'cancelled'
cancel: 'cancelled'
};

/**
Expand All @@ -30,7 +27,7 @@ export abstract class Uploader implements UploadState {
readonly name: string;
readonly size: number;
readonly uploadId: string;
response: ResponseBody | undefined;
response: ResponseBody = null;
responseStatus!: number;
progress!: number;
remaining!: number;
Expand Down Expand Up @@ -134,7 +131,7 @@ export abstract class Uploader implements UploadState {
this.start().then(_ => {});
} catch (e) {
e instanceof Error && console.error(e);
if (this.errorHandler.kind(this.responseStatus) !== ErrorType.FatalError) {
if (this.errorHandler.kind(this.responseStatus) !== ErrorType.Fatal) {
this.status = 'retry';
await this.errorHandler.wait();
this.status = 'queue';
Expand Down Expand Up @@ -165,9 +162,9 @@ export abstract class Uploader implements UploadState {
const errType = this.errorHandler.kind(this.responseStatus);
if (this.responseStatus === 413) {
DynamicChunk.maxSize = this.chunkSize /= 2;
} else if (errType === ErrorType.FatalError) {
} else if (errType === ErrorType.Fatal) {
this.status = 'error';
} else if (errType === ErrorType.Restart) {
} else if (errType === ErrorType.NotFound) {
this.url = '';
this.status = 'queue';
} else if (errType === ErrorType.Auth) {
Expand Down Expand Up @@ -260,13 +257,14 @@ export abstract class Uploader implements UploadState {
xhr.upload.onprogress = this.onProgress();
}
this.responseStatus = 0;
this.response = undefined;
this.response = null;
this.responseType && (xhr.responseType = this.responseType);
this.options.withCredentials && (xhr.withCredentials = true);
const _headers = { ...this.headers, ...(req.headers || {}) };
Object.keys(_headers).forEach(key => xhr.setRequestHeader(key, String(_headers[key])));
xhr.onload = (evt: ProgressEvent) => {
this.responseStatus = xhr.status;
// TODO: check null body status
this.response = this.responseStatus !== 204 ? this.getResponseBody(xhr) : '';
this.responseStatus >= 400 ? reject(evt) : resolve(evt);
};
Expand Down

0 comments on commit 8bfaa1c

Please sign in to comment.