Tony_89
Tony_89

Reputation: 817

Angular2 trigger observable at certain time

So firstly a bit of context. I have an angular 2 dashboard, it sits behind a login and has signalr integrated too. For request sent via angular's http client i can use a url interceptor check if the token has expired and if so request a new token from the api. This works great for all authenticated calls except with signalr.

With signalr upon logging in we establish a connection and send up the bearer token as part of the query string. However since signalr is separate is does not use angular s http client and therefore the url interceptor is not hit. I have been thinking of different ways to handle this and for me the cleanest one would be to subscribe to an observable that fires when the token expires.

So now my question is if i have an expiration date, can i write an observable that triggers say when expiration time is five minutes before the current time. This way i could subscribe to that observable in my signalr service and disconnect and connect with the updated auth token. I can provide code samples if needed but i don't know how much help they will be with my question.

Thank you for any help with this.

Upvotes: 0

Views: 1869

Answers (2)

Ashish Ranjan
Ashish Ranjan

Reputation: 12960

I don't know about signalr but I can give a solution for your requirement.

You can use timer from rxjs, this is just like setTimeout(), but just an Observable.

Create Date Objects for the expirationDate and another for five minutes before expiration date. Subtract them to find the time in which Observable should fire.

Pass the time in milliseconds to the timer where you can do your subscription. Once the API call is done, call the same method again to reInitialize the timer.

timerSubs: Subscription;  // to cancel existing timer   
ngOnInit() {
    this.calculateTimeForTimer()
}

calculateTimeForTimer() {
    let expirationDate = new Date();
    expirationDate.setTime(expirationDate.getTime() + 10 * 1000); // 10 seconds from now.
    // in your case use your own duration/date of expiration
    let alertDate = new Date(expirationDate);
    alertDate.setTime(alertDate.getTime() - 5 * 1000); // 5 seconds before expiration
    // in your case subtract 5 minutes instead of 5 seconds
    let timeDuration = (expirationDate.getTime() - alertDate.getTime());
    this._startTimer(timeDuration);
}

private _startTimer(timeDuration) {
    if (this.timerSubs) {
        this.timerSubs.unsubscribe();
    }

    this.timerSubs = timer(timeDuration).subscribe((data) => {
      // make the API call, and then calculate appropriate duartion and call startTimer() again
      of("This is your new Token").pipe(delay(2000)).subscribe((apiData) => {
          console.log("Data from API", apiData);
          this.calculateTimeForTimer();
      })
    })
}

See a sample here, it has 10 seconds as expiration date from current time. https://stackblitz.com/edit/angular-bhupgg

Upvotes: 1

Woot
Woot

Reputation: 1809

This observer would do that

const tokenTimeout = timeout;
let currentTime = new Date();

return new Observable(observer => {

  while(tokenTimeout > currentTime) {
    currentTime = new Date();
  }

  observer.next();
  observer.complete();
});

As an alternative, when you register a client connection on the server register their token time out with the client registration, then when sending a message to the client check the timeout, and if it's elapsed first send a message to the client to renew their token, then on the client side in JS have a method that renews the token. This article talks about registering client connections. I think this would have less of a potential to fail.

Upvotes: 0

Related Questions