Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import dbg from 'debug'; import { ServerContextHandleManager } from './ServerContextHandleManager'; import { CtxtHandle } from '../../../lib/api'; import { SSOMethod } from '../interfaces'; const debug = dbg('node-expose-sspi:schManager'); type IPromiseFn = (value?: any) => void; interface AuthItem { resolve?: IPromiseFn; reject?: IPromiseFn; timeout: NodeJS.Timeout; } const TOO_LATE_ERROR_MSG = 'too many concurrent connections.'; export class SCHMWithSync extends ServerContextHandleManager { /** * The authentication currently being processed. * * @private * @type {AuthItem} * @memberof SCHMWithSync */ private authItem: AuthItem | undefined; /** * The queue of other authentication that are waiting. * * @private * @type {AuthItem[]} * @memberof SCHMWithSync */ private queue: AuthItem[] = []; private serverContextHandle: CtxtHandle | undefined; private method!: SSOMethod; constructor(private delayMax = 20000) { super(); } waitForReleased(): Promise<void> { return new Promise((resolve, reject) => { debug('waitForReleased: start promise'); const timeout = setTimeout(() => { this.interrupt(); }, this.delayMax); // if nobody else is currently authenticating then go now. if (this.authItem === undefined) { debug('waitForReleased: we can start now.'); this.authItem = { timeout }; return resolve(); } debug( 'someone is currently authenticating, go in the queue and wait for your turn.' ); this.queue.push({ resolve, reject, timeout }); debug('queue length', this.queue.length); }); } getMethod(): SSOMethod { return this.method; } setMethod(ssoMethod: SSOMethod): void { this.method = ssoMethod; } getHandle(): CtxtHandle | undefined { return this.serverContextHandle; } setHandle(contextHandle: CtxtHandle): void { this.serverContextHandle = contextHandle; } release(): void { if (this.authItem) { clearTimeout(this.authItem.timeout); } this.serverContextHandle = undefined; this.authItem = undefined; if (this.queue.length > 0) { // it means another client B was waiting for authenticating. // so we start authenticating this client B. this.authItem = this.queue.shift(); debug('releasing. queue length', this.queue.length); if (this.authItem?.resolve) { this.authItem.resolve(); } } } /** * after timeout, all the queue is removed and rejected. * does not go to its final state before timeout. * * * @param {AuthItem} authItem * @returns * @memberof ServerContextHandleManager */ interrupt(): void { while (this.queue.length > 0) { const ai = this.queue.pop(); if (ai) { clearTimeout(ai.timeout); if (ai.reject) { ai.reject(TOO_LATE_ERROR_MSG); } } } this.authItem = undefined; this.serverContextHandle = undefined; } } |