Implementing Session Timeout service for Ionic/Angular, with Timer Reset with each new user interaction

可紊 提交于 2021-02-10 20:39:31

问题


I'm trying to adapt some code I've created for a session timeout. Whenever a user interacts with the function, I want to reset the timer to start counting down again. I'm having difficulty working out how to inject similar code to this example

C# code - I'm trying to integrate:


var update = new Subject<bool>();
var res =
    update
        .Select(x => Observable.Interval(TimeSpan.FromSeconds(10.0)))
        .Switch();
res
    .Subscribe(_ => Console.WriteLine("Status sent."));
update.OnNext(true);

res
    .Subscribe(_ =>
    {
        update.OnNext(true);
        Console.WriteLine("Status sent.");
    });

From what I can tell the Typescript RxJS equivalents of C# flavour of the RxJS library and my variable name mapping are:

C#/example Typescript/mine
update resetManager
.Select .map (from here - (see tab title))
.OnNext .next
.Interval .timer

I was thinking I could insert a do and chain the resetManager - but since one is a boolean and the other is AuthState I seem to be running into difficulties.

I'm wondering if a RxJS guru can advise. Cheers.


import { Injectable }           from '@angular/core';
import { Observable }           from 'rxjs/Observable';
import { BehaviorSubject }      from 'rxjs/BehaviorSubject';
import                               'rxjs/add/operator/map';
import                               'rxjs/add/operator/filter';
import                               'rxjs/add/Observable/timer';
import                               'rxjs/add/operator/do';
import                               'rxjs/add/operator/switch';
@Injectable()
export class AuthService {
  private authState:    AuthState;
  private authManager:  BehaviorSubject<AuthState>;
  public  authChange$:  Observable<AuthState>;
  private resetManager: Subject<boolean>;
  constructor() {
    this.authManager = new BehaviorSubject(AuthState.LOGGED_OUT);
    this.authChange$ = this.authManager.asObservable();
    this.authChange$
      .filter((authState:AuthState) => authState === AuthState.LOGGED_IN)
      .map(   (authState:AuthState) => Observable.timer(SESSION_TIMEOUT))
      .do(    () => 
        console.log('Logged In. Session Timout counting down from now'))
      .switch()
      .subscribe( () => {console.log('Timer ended: Logging out')
                         this.logout();
                        });
  }

  login() {
    this.setAuthState(AuthState.LOGGED_IN);
  }
  logout() {
    this.setAuthState(AuthState.LOGGED_OUT);
  }

  resetSessionTimer() {
    this.resetManager.next(true);
  } 

  emitAuthState():void {
    this.authManager.next(this.authState);
  }

  private setAuthState(newAuthState:AuthState):void {
    console.log('AuthService: setAuthState: ', 
        AuthState[newAuthState.toString()]);
    if (newAuthState != this.authState) {
      this.authState = newAuthState;
      this.emitAuthState();
    }
  }

export enum AuthState {
  LOGGED_IN,
  LOGGED_OUT
}

const SESSION_TIMEOUT = 5000;

回答1:


I finally worked out how to do this...

import { Events }               from 'ionic-angular';
import { Observable }           from 'rxjs/Observable';
import { Subscription }         from 'rxjs/Subscription';
import                               'rxjs/add/observable/interval';
import                               'rxjs/add/operator/mapTo';
import                               'rxjs/add/observable/defer';
import                               'rxjs/add/observable/of';
import                               'rxjs/add/operator/merge';
import                               'rxjs/add/operator/scan';
import                               'rxjs/add/operator/filter';
import                               'rxjs/add/operator/switchMap';
import { BehaviorSubject }      from 'rxjs/BehaviorSubject';

export  enum AuthState {
  LOGGED_IN,
  LOGGED_OUT
}

const SESSION_TIMEOUT = 10; // seconds

export class AuthService {
  private timer:         number;
  private tick$:         Observable<number>;
  private countDown$:    Observable<number>;
  private subscriptions:Subscription[];

  constructor(
    private events:Events
  ) {
    this.tick$ =Observable.interval(1000).mapTo(-1);
    this.countDown$ = Observable
      .defer(() => Observable.of(this.timer))
      .merge(this.tick$)
      .scan((acc,curr) => acc + curr)
    this.events.subscribe(RESET_COUNTDOWN, (action:string) => {
      this.resetSessionTimer(action);
    });
  }

  beginCountDown() {
    let sub:Subscription;
    while (this.subscriptions.length > 0) {
      sub = this.subscriptions.pop();
      sub.unsubscribe();
    };
    this.timer = SESSION_TIMEOUT;
    sub = this.countDown$
      .filter(timer => timer >= 0)
      .subscribe(timer => 
        {this.timer = timer;
         if (this.timer === 1) {
           this.logout();
         }
         console.log(this.timer);
        });
    this.subscriptions.push(sub);
  }

  resetSessionTimer(action:string) {
    console.log('AuthService: resetSessionTimer(): ' + action);
    this.beginCountDown();
  } 

  emitAuthState():void {
    this.authManager.next(this.authState);
  }

  private setAuthState(newAuthState:AuthState):void {
    if (newAuthState != this.authState) {
      this.authState = newAuthState;
      this.emitAuthState();
    }
  }
  login(
   clickStream$: BehaviorSubject<any>
  ) {

     this.response$ = clickStream$.switchMap(click =>  {
                      return this.webServiceUtil.testLogin();
                                                      }
                                            );
     this.response$.subscribe((response:Response) => {
          this.setAuthState(AuthState.LOGGED_IN);
      },
     (err:any)          => {
         this.setAuthState(AuthState.LOGGED_OUT);  
     })
  }

  logout() {
      if (this.authState === AuthState.LOGGED_IN) {
         this.setAuthState(AuthState.LOGGED_OUT);
      }
  }
}

A RESET_COUNTDOWN event can get fired on things like a change of page or when doing HTTP requests. That will force the countdown to begin again, whilst only ever having one subscription, hence the keeping track of an array of subscriptions.. That you immediately cancel on reset.



来源:https://stackoverflow.com/questions/45816050/implementing-session-timeout-service-for-ionic-angular-with-timer-reset-with-ea

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!