2
\$\begingroup\$

Just started to use rxjs few weeks ago, I think I'm getting most of it right, but my code seems to be not that efficient and prone to bugs I haven't run into yet!

I need to be able to send http requests my app is online(1) and when the user is authenticated(2) and when there's anything to send(3). I'm pretty sure there's a smart way to combine those 3 conditions the "rxjs" way :)

SuperHttpRequest

class SuperHttpRequest extends HttpRequest<any> {

  _id: string; // Used for localStorage

  constructor(method: string, url: string, body: any, _id?: string) {
    super(method, url, body);
    this._id = _id || UUID.UUID();
  }
}

HttpRequestHandler

@Injectable()
class HttpRequestHandler extends ReplaySubject<SuperHttpRequest> {

  nbItemsInQueue$: ReplaySubject<Number>; // Needed by a component (sync progress), would be better to use the combined http request time
  private requests: SuperHttpRequest[];
  private requestsSubcription: Subscription;

  constructor(
    private network: Network, // Ionic service
    private http: HttpClient,
    private localStore: LocalStore<SuperHttpRequest[]>,
    private authService: AuthenticationService) {

    super();

    this.requests = [];
    this.nbItemsInQueue$ = new ReplaySubject(this.requests.length);

    this.localStore.get('http-request')
      .then(requests => {
        if (requests) {
          requests.forEach(request => {
            this.next(new SuperHttpRequest(request.method, request.url, request.body, request._id));
          });
        }
      });

    this.nbItemsInQueue$
      .subscribe(() => this.localStore.set('http-request', this.requests));

    this.authService.currentUser$
      .subscribe(user => {
        if (!user) { if (this.requestsSubcription) { this.requestsSubcription.unsubscribe(); } }
        else {
          this.requestsSubcription = this
            .takeWhile(() => {
              if (navigator.onLine) { return true; }
              else { throw Error(); }
            })
            .retryWhen(() => this.network.onConnect())
            .subscribe(request => this.handleHttpRequest(user, request));
        }
      });
  }

  private handleHttpRequest(user: Credentials, request: SuperHttpRequest) {
    this.http.request(request.clone({ setHeaders: { Authorization: `Bearer ${user.token}` } }))
      .retryWhen(error => {
        return error
          .mergeMap((error: any) => {   
            if (error.status === 503) {
              return of(error.status).delay(2000)
            }
            return Observable.throw({ error: 'No retry' });
          })
          .take(5)
          .concat(Observable.throw({ error: 'Sorry, there was an error (after 5 retries)' }));
      })
      .subscribe(res => {
        if (res instanceof HttpResponse) {
          remove(this.requests, (req) => req._id === request._id);
          this.nbItemsInQueue$.next(this.requests.length);
        }
      });
  }

  next(request: SuperHttpRequest) {
    this.requests.push(request);
    this.nbItemsInQueue$.next(this.requests.length);
    super.next(request);
  }

}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.