scoll
scoll

Reputation: 127

How can I obtain result of function inside setInterval?

I am trying to let my user renew their SSO token by the following steps:

-If detecting expiry, prompt user with modal asking User to Sign in: -If user confirms (clicks 'launch'), launch window with sso url -Once launched, detect token from new window, set it as new access token, and close window

The window is launched inside of a setInterval function, and I do not know how to return the boolean result of whether a success occurred of this to the calling function. Below is the relevant code, how can I return the boolean result from inside setInterval?

refreshSSO opens the matDialog. If user selects 'launch', opens goes to doAuth to launch SSO window and detect new token

  refreshSSO(): Observable<boolean> {
    const refresh_uri = <sso endpoint>;
    const config = matDialogHelpers.getDefaultConfig({});
    const matDialogRef: MatDialogRef<LaunchRefreshComponent> = this.matDialog.open(LaunchRefreshComponent, config);

    return matDialogRef.afterClosed().pipe(
      map(
      next => {
        if (next === 'launch') {
          return this.popupAuth(refresh_uri);
        } else {
          return false;
        }
      })
    );
  }
  popupAuth(authUrl: string): boolean {
    this.intervalId = window.setInterval(() => { this.insideInterval(authUrl); }, this.intervalLength);
    return this.intervalId;
  }

insideInterval opens the window with the sso, counts down the time, and checks for new accessToken. If found, sets the token, returns true, and closes. If time runs out, returns false and closes.

  insideInterval(authUrl: string): boolean {
    let windowHandle: Window;  
    let loopCount = this.loopCount;
    /* Create the window object by passing url and optional window title */
    windowHandle = this.createOauthWindow(authUrl, 'OAuth login');
    if (loopCount-- < 0) {
      window.clearInterval(this.intervalId);
      windowHandle.close();
      return false;
    } else {
      let href: string;  // For referencing window url
      try {
        href = windowHandle.location.href; // set window location to href string
      } catch (e) {
        console.log('Error:', e); // Handle any errors here
      }
      if (href != null) {
        /* As i was getting code and oauth-token i added for same, you can replace with your expected variables */
        if (href.match('access_token')) {
          // for twitter
          window.clearInterval(this.intervalId);
          const newToken = this.getQueryString('access_token', href);
          localStorage.setItem('accessToken', newToken);
          windowHandle.close();
          return true;
        }
      }
    }
  }

createOauthWindow simply opens a pop-up with the given URL

  createOauthWindow(url: string, name = 'Authorization', width = 500, height = 600, left = 0, top = 0) {
    if (url == null) {
      return null;
    }
    const options = `width=${width},height=${height},left=${left},top=${top}`;
    return window.open(url, name, options);
  }

Upvotes: 0

Views: 64

Answers (1)

tropicana
tropicana

Reputation: 1433

Consider keeping it RxJs: https://www.learnrxjs.io/learn-rxjs/operators/creation/timer

 popupAuth(authUrl: string): Observable<boolean> {
   return timer(this.intervalLength, this.intervalLength).pipe(
     map(() => this.insideInterval(authUrl))
   )
 }

Then, you can use the appropriate map inside refreshSSO.

Check out this article: https://blog.angular-university.io/rxjs-higher-order-mapping/

For example:

refreshSSO(): Observable<boolean> {
    const refresh_uri = <sso endpoint>;
    const config = matDialogHelpers.getDefaultConfig({});
    const matDialogRef: MatDialogRef<LaunchRefreshComponent> = this.matDialog.open(LaunchRefreshComponent, config);

    return matDialogRef.afterClosed().pipe(
      mergeMap(
        next => {
          if (next === 'launch') {
            return this.popupAuth(refresh_uri); // This might not complete, unless you take care of it. Look into take/takeUntil/takeWhile operators. 
          } else {
            return of(false); // This one will complete immediately.
          }
      })
    );
  }

Remember to complete or unsubscribe from the Observable to prevent leaks.

For example:

const subscription = this.refreshSSO().subscribe((value) => {
  if(value == isWhatNeeded) {
    subscription.unsubscribe();
  } 
});

Upvotes: 2

Related Questions