Skip to content

Commit

Permalink
v1.2.7 - ALSession.ready() Helper
Browse files Browse the repository at this point in the history
Added hooks to ALSession to allow external session checkers to signal
when they start and end.

Updated AlSessionDetector to use the startDetection() and endDetection()
methods in ALSession.

Added a new public method `ALSession.ready()` that is only resolved when
    1.  At least one session detection cycle has completed execution
    2.  No session detection cycles are currently in flight
    3.  The user is either unauthenticated OR the acting account has been resolved

Unlike `ALSession.resolved()`, which only resolves in authenticated
contexts, `ALSession.ready()` will resolve for unauthenticated users,
and indicates the stability of the session state.
  • Loading branch information
mcnielsen committed Apr 8, 2020
1 parent e96aaaf commit 79e23c1
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 3 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@al/session",
"version": "1.2.6",
"version": "1.2.7",
"license": "MIT",
"description": "A client for maintaining Alert Logic session data",
"author": {
Expand Down
34 changes: 33 additions & 1 deletion src/al-session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ export class AlSessionInstance
new AlEntitlementCollection(),
new AlFoxSnapshot() );
protected managedAccounts:AIMSAccount[] = [];
protected resolutionGuard = new AlBehaviorPromise<boolean>(); // This functions as a mutex so that access to resolvedAccount is only available at appropriate times
protected resolutionGuard = new AlBehaviorPromise<boolean>(); // This functions as a mutex so that access to resolvedAccount is only available at appropriate times.
protected detectionGuard = new AlBehaviorPromise<boolean>(); // resolved after first session detection cycle with no outstanding session detection or account resolution processes in flight.
protected detectionProcesses = 0;
protected storage = AlCabinet.persistent( "al_session" );
protected options:AlSessionOptions = {
resolveAccountMetadata: true,
Expand Down Expand Up @@ -501,6 +503,18 @@ export class AlSessionInstance
return this.sessionData.authentication.account.accessible_locations;
}

/**
* Convenience method to defer logic until ALSession has reached a stable state.
* For the purposes of this service, "ready" is defined as having completed one or more session detection
* cycles AND ( user is unauthenticated OR acting account is resolved ).
*/
public async ready(): Promise<void> {
await this.detectionGuard; // resolves when first detection process is complete and no other detection cycles are in progress
if ( this.isActive() ) {
await this.resolved(); // resolves when acting account information has been loaded and processed
}
}

/**
* Convenience method to wait until authentication status and metadata have been resolved.
*
Expand Down Expand Up @@ -555,6 +569,24 @@ export class AlSessionInstance
return this.resolutionGuard.then( () => AIMSClient.getManagedAccounts( this.getActingAccountId(), { active: true } ) );
}

/**
* Allows an external mechanism to indicate that it is detecting a session.
*/
public startDetection() {
this.detectionProcesses += 1;
this.detectionGuard.rescind();
}

/**
* Allows an external mechanism to indicate that it is done detecting a session.
*/
public endDetection() {
this.detectionProcesses -= 1;
if ( this.detectionProcesses === 0 ) {
this.detectionGuard.resolve( true );
}
}

/**
* Private Internal/Utility Methods
*/
Expand Down
6 changes: 5 additions & 1 deletion src/utilities/al-session-detector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,15 @@ export class AlSessionDetector
public detectSession( preferredActingAccountId:string = null ): Promise<boolean> {

if ( AlSessionDetector.detectionPromise ) {
// If we're already in the middle of detection, return the promise for the current detectino cycle rather than allowing multiple overlapping
// If we're already in the middle of detection, return the promise for the current detection cycle rather than allowing multiple overlapping
// checks to run simultaneously. No muss, no fuss!
return AlSessionDetector.detectionPromise;
}

AlSessionDetector.detectionPromise = new Promise( ( resolve, reject ) => {

AlSession.startDetection();

/**
* Does AlSession say we're active? If so, then yey!
*/
Expand Down Expand Up @@ -175,6 +177,7 @@ export class AlSessionDetector
}
this.authenticated = false;
AlSessionDetector.detectionPromise = null;
AlSession.endDetection();
resolve( false );
}

Expand All @@ -186,6 +189,7 @@ export class AlSessionDetector
onDetectionSuccess = ( resolve:{(result:any):any} ) => {
this.authenticated = true;
AlSessionDetector.detectionPromise = null;
AlSession.endDetection();
resolve( true );
}

Expand Down
40 changes: 40 additions & 0 deletions test/al-session.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,45 @@ describe('AlSession', () => {
} );
} );

describe( ".ready()", () => {
it("detection guard should block in its initial state", () => {
expect( session['detectionGuard']['fulfilled'] ).to.equal( false );
} );
it("detection guard should be resolved after a session detection cycle in an unauthenticated state", () => {
session.startDetection();
session.endDetection();
expect( session['detectionGuard']['fulfilled'] ).to.equal( true );
} );
it("it should resolve after session detection/authentication resolved", ( done ) => {
// Dear World: this is an absolutely gruesome test... my apologies. Sincerely, Kevin.
session.startDetection();
setTimeout( () => {
session.setAuthentication( exampleSession ).then( () => {
session['resolutionGuard'].rescind(); // pretend we're resolving an acting account
session.endDetection();
let resolved = false;
session.ready().then( () => {
console.log("Got session ready!" );
resolved = true;
}, ( error ) => {
expect( true ).to.equal( false );
} );

setTimeout( () => {
expect( resolved ).to.equal( false );
session['resolutionGuard'].resolve( true );
setTimeout( () => {
expect( resolved ).to.equal( true );
done();
}, 1 );
}, 1 );
}, error => {
expect( true ).to.equal( false );
} );
}, 1 );
} );
} );

describe( ".getPrimaryEntitlementsSync()", () => {
it("should return null in an unauthenticated state", () => {
expect( session.getPrimaryEntitlementsSync() ).to.equal( null );
Expand Down Expand Up @@ -504,4 +543,5 @@ describe('AlSession', () => {
} );

} );

} );

0 comments on commit 79e23c1

Please sign in to comment.