@decaf-ts/for-nano
Version:
decaf-ts persistence adapter for CouchDB via nano
214 lines • 25.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NanoDispatch = void 0;
const core_1 = require("@decaf-ts/core");
const db_decorators_1 = require("@decaf-ts/db-decorators");
const for_couchdb_1 = require("@decaf-ts/for-couchdb");
/**
* @description Dispatcher for Nano database change events
* @summary Handles the subscription to and processing of database change events from a Nano database,
* notifying observers when documents are created, updated, or deleted
* @template DocumentScope - The Nano document scope type
* @param {number} [timeout=5000] - Timeout in milliseconds for change feed requests
* @class NanoDispatch
* @example
* ```typescript
* // Create a dispatcher for a Nano database
* const db = server.db.use('my_database');
* const adapter = new NanoAdapter(db);
* const dispatch = new NanoDispatch();
*
* // The dispatcher will automatically subscribe to changes
* // and notify observers when documents change
* ```
* @mermaid
* classDiagram
* class Dispatch {
* +initialize()
* +updateObservers()
* }
* class NanoDispatch {
* -observerLastUpdate?: string
* -attemptCounter: number
* -timeout: number
* +constructor(timeout)
* #changeHandler()
* #initialize()
* }
* Dispatch <|-- NanoDispatch
*/
class NanoDispatch extends core_1.Dispatch {
constructor(timeout = 5000) {
super();
this.timeout = timeout;
this.attemptCounter = 0;
}
/**
* @description Processes database change events
* @summary Handles the response from the Nano changes feed, processes the changes,
* and notifies observers about document changes
* @param {RequestError | null} error - Error object if the request failed
* @param response - The changes response from Nano
* @param {any} [headers] - Response headers (unused)
* @return {Promise<void>} A promise that resolves when all changes have been processed
* @mermaid
* sequenceDiagram
* participant D as NanoDispatch
* participant L as Logger
* participant O as Observers
* Note over D: Receive changes from Nano
* alt Error in response
* D->>L: Log error
* D-->>D: Return early
* end
* alt Response is string
* D->>D: Parse JSON from string
* end
* D->>D: Process changes
* D->>D: Group changes by table and operation
* loop For each table
* loop For each operation
* D->>O: updateObservers(table, operation, ids)
* D->>D: Update observerLastUpdate
* D->>L: Log successful dispatch
* end
* end
*/
async changeHandler(error, response,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
headers) {
const log = this.log.for(this.changeHandler);
if (error)
return log.error(`Error in change request: ${error}`);
try {
response = (typeof response === "string"
? response
.split("\n")
.filter((r) => !!r)
.map((r) => JSON.parse(r))
: response);
}
catch (e) {
return log.error(`Error parsing couchdb change feed: ${e}`);
}
const count = response.length;
if (count > 0) {
log.debug(`Received ${count} changes. processing...`);
const changes = response
.map((rec, i) => {
if (i === count - 1) {
if (this.observerLastUpdate ===
rec.last_seq)
log.error(`Invalid last update check: ${this.observerLastUpdate} !== ${rec.last_seq}`);
return;
}
const r = rec;
const [table, id] = r.id.split(for_couchdb_1.CouchDBKeys.SEPARATOR);
return {
table: table,
id: id,
operation: r.deleted
? db_decorators_1.OperationKeys.DELETE
: r.changes[r.changes.length - 1].rev.split("-")[0] === "1"
? db_decorators_1.OperationKeys.CREATE
: db_decorators_1.OperationKeys.UPDATE,
step: r.changes[r.changes.length - 1].rev,
};
})
.reduce((accum, r) => {
if (!r)
return accum;
const { table, id, operation, step } = r;
if (!accum[table])
accum[table] = {};
if (!accum[table][operation])
accum[table][operation] = { ids: new Set(), step: step };
accum[table][operation].ids.add(id);
accum[table][operation].step = step;
return accum;
}, {});
for (const table of Object.keys(changes)) {
for (const op of Object.keys(changes[table])) {
try {
await this.updateObservers(table, op, [
...changes[table][op].ids.values(),
]);
this.observerLastUpdate = changes[table][op].step;
log.verbose(`Observer refresh dispatched by ${op} for ${table}`);
log.debug(`pks: ${Array.from(changes[table][op].ids.values())}`);
}
catch (e) {
log.error(`Failed to dispatch observer refresh for ${table}, op ${op}: ${e}`);
}
}
}
}
}
/**
* @description Initializes the dispatcher and subscribes to database changes
* @summary Sets up the continuous changes feed subscription to the Nano database
* and handles reconnection attempts if the connection fails
* @return {Promise<void>} A promise that resolves when the subscription is established
* @mermaid
* sequenceDiagram
* participant D as NanoDispatch
* participant S as subscribeToCouch
* participant DB as Nano Database
* participant L as Logger
* D->>S: Call subscribeToCouch
* S->>S: Check adapter and native
* alt No adapter or native
* S-->>S: throw InternalError
* end
* S->>DB: changes(options, changeHandler)
* alt Success
* DB-->>S: Subscription established
* S-->>D: Promise resolves
* D->>L: Log successful subscription
* else Error
* DB-->>S: Error
* S->>S: Increment attemptCounter
* alt attemptCounter > 3
* S->>L: Log error
* S-->>D: Promise rejects
* else attemptCounter <= 3
* S->>L: Log retry
* S->>S: Wait timeout
* S->>S: Recursive call to subscribeToCouch
* end
* end
*/
async initialize() {
const log = this.log.for(this.initialize);
const subLog = log.for(subscribeToCouch);
async function subscribeToCouch() {
if (!this.adapter || !this.native)
throw new db_decorators_1.InternalError(`No adapter/native observed for dispatch`);
try {
this.native.changes({
feed: "continuous",
include_docs: false,
since: this.observerLastUpdate || "now",
timeout: this.timeout,
}, this.changeHandler.bind(this));
}
catch (e) {
if (++this.attemptCounter > 3)
return subLog.error(`Failed to subscribe to couchdb changes: ${e}`);
subLog.info(`Failed to subscribe to couchdb changes: ${e}. Retrying in 5 seconds...`);
await new Promise((resolve) => setTimeout(resolve, this.timeout));
return subscribeToCouch.call(this);
}
}
subscribeToCouch
.call(this)
.then(() => {
this.log.info(`Subscribed to couchdb changes`);
})
.catch((e) => {
throw new db_decorators_1.InternalError(`Failed to subscribe to couchdb changes: ${e}`);
});
}
}
exports.NanoDispatch = NanoDispatch;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTmFub0Rpc3BhdGNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL05hbm9EaXNwYXRjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSx5Q0FBMEM7QUFPMUMsMkRBQXVFO0FBQ3ZFLHVEQUFvRDtBQUVwRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQ0c7QUFDSCxNQUFhLFlBQWEsU0FBUSxlQUE0QjtJQUc1RCxZQUFvQixVQUFVLElBQUk7UUFDaEMsS0FBSyxFQUFFLENBQUM7UUFEVSxZQUFPLEdBQVAsT0FBTyxDQUFPO1FBRDFCLG1CQUFjLEdBQVcsQ0FBQyxDQUFDO0lBR25DLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09BOEJHO0lBQ08sS0FBSyxDQUFDLGFBQWEsQ0FDM0IsS0FBMEIsRUFDMUIsUUFBMEU7SUFDMUUsNkRBQTZEO0lBQzdELE9BQWE7UUFFYixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDN0MsSUFBSSxLQUFLO1lBQUUsT0FBTyxHQUFHLENBQUMsS0FBSyxDQUFDLDRCQUE0QixLQUFLLEVBQUUsQ0FBQyxDQUFDO1FBQ2pFLElBQUksQ0FBQztZQUNILFFBQVEsR0FBRyxDQUNULE9BQU8sUUFBUSxLQUFLLFFBQVE7Z0JBQzFCLENBQUMsQ0FBQyxRQUFRO3FCQUNMLEtBQUssQ0FBQyxJQUFJLENBQUM7cUJBQ1gsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO3FCQUNsQixHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQzlCLENBQUMsQ0FBQyxRQUFRLENBQ2dCLENBQUM7UUFDakMsQ0FBQztRQUFDLE9BQU8sQ0FBVSxFQUFFLENBQUM7WUFDcEIsT0FBTyxHQUFHLENBQUMsS0FBSyxDQUFDLHNDQUFzQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzlELENBQUM7UUFDRCxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDO1FBQzlCLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2QsR0FBRyxDQUFDLEtBQUssQ0FBQyxZQUFZLEtBQUsseUJBQXlCLENBQUMsQ0FBQztZQUN0RCxNQUFNLE9BQU8sR0FBRyxRQUFRO2lCQUNyQixHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUU7Z0JBQ2QsSUFBSSxDQUFDLEtBQUssS0FBSyxHQUFHLENBQUMsRUFBRSxDQUFDO29CQUNwQixJQUNFLElBQUksQ0FBQyxrQkFBa0I7d0JBQ3RCLEdBQStCLENBQUMsUUFBUTt3QkFFekMsR0FBRyxDQUFDLEtBQUssQ0FDUCw4QkFBOEIsSUFBSSxDQUFDLGtCQUFrQixRQUFTLEdBQStCLENBQUMsUUFBUSxFQUFFLENBQ3pHLENBQUM7b0JBQ0osT0FBTztnQkFDVCxDQUFDO2dCQUNELE1BQU0sQ0FBQyxHQUFHLEdBQWdDLENBQUM7Z0JBQzNDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMseUJBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQztnQkFDdEQsT0FBTztvQkFDTCxLQUFLLEVBQUUsS0FBSztvQkFDWixFQUFFLEVBQUUsRUFBRTtvQkFDTixTQUFTLEVBQUUsQ0FBQyxDQUFDLE9BQU87d0JBQ2xCLENBQUMsQ0FBQyw2QkFBYSxDQUFDLE1BQU07d0JBQ3RCLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRzs0QkFDekQsQ0FBQyxDQUFDLDZCQUFhLENBQUMsTUFBTTs0QkFDdEIsQ0FBQyxDQUFDLDZCQUFhLENBQUMsTUFBTTtvQkFDMUIsSUFBSSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRztpQkFDMUMsQ0FBQztZQUNKLENBQUMsQ0FBQztpQkFDRCxNQUFNLENBQ0wsQ0FDRSxLQVNDLEVBQ0QsQ0FBQyxFQUNELEVBQUU7Z0JBQ0YsSUFBSSxDQUFDLENBQUM7b0JBQUUsT0FBTyxLQUFLLENBQUM7Z0JBQ3JCLE1BQU0sRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsR0FBRyxDQUt0QyxDQUFDO2dCQUNGLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO29CQUFFLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQ3JDLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxDQUFDO29CQUMxQixLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsSUFBSSxHQUFHLEVBQUUsRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLENBQUM7Z0JBQzNELEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUNwQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztnQkFDcEMsT0FBTyxLQUFLLENBQUM7WUFDZixDQUFDLEVBQ0QsRUFBRSxDQUNILENBQUM7WUFFSixLQUFLLE1BQU0sS0FBSyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDekMsS0FBSyxNQUFNLEVBQUUsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUM7b0JBQzdDLElBQUksQ0FBQzt3QkFDSCxNQUFNLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTs0QkFDcEMsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRTt5QkFDbkMsQ0FBQyxDQUFDO3dCQUNILElBQUksQ0FBQyxrQkFBa0IsR0FBRyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDO3dCQUNsRCxHQUFHLENBQUMsT0FBTyxDQUFDLGtDQUFrQyxFQUFFLFFBQVEsS0FBSyxFQUFFLENBQUMsQ0FBQzt3QkFDakUsR0FBRyxDQUFDLEtBQUssQ0FBQyxRQUFRLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztvQkFDbkUsQ0FBQztvQkFBQyxPQUFPLENBQVUsRUFBRSxDQUFDO3dCQUNwQixHQUFHLENBQUMsS0FBSyxDQUNQLDJDQUEyQyxLQUFLLFFBQVEsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUNuRSxDQUFDO29CQUNKLENBQUM7Z0JBQ0gsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FpQ0c7SUFDZ0IsS0FBSyxDQUFDLFVBQVU7UUFDakMsTUFBTSxHQUFHLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQzFDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztRQUN6QyxLQUFLLFVBQVUsZ0JBQWdCO1lBQzdCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU07Z0JBQy9CLE1BQU0sSUFBSSw2QkFBYSxDQUFDLHlDQUF5QyxDQUFDLENBQUM7WUFFckUsSUFBSSxDQUFDO2dCQUNILElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUNqQjtvQkFDRSxJQUFJLEVBQUUsWUFBWTtvQkFDbEIsWUFBWSxFQUFFLEtBQUs7b0JBQ25CLEtBQUssRUFBRSxJQUFJLENBQUMsa0JBQWtCLElBQUksS0FBSztvQkFDdkMsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPO2lCQUN0QixFQUNELElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBUSxDQUNyQyxDQUFDO1lBQ0osQ0FBQztZQUFDLE9BQU8sQ0FBVSxFQUFFLENBQUM7Z0JBQ3BCLElBQUksRUFBRSxJQUFJLENBQUMsY0FBYyxHQUFHLENBQUM7b0JBQzNCLE9BQU8sTUFBTSxDQUFDLEtBQUssQ0FBQywyQ0FBMkMsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDdEUsTUFBTSxDQUFDLElBQUksQ0FDVCwyQ0FBMkMsQ0FBQyw0QkFBNEIsQ0FDekUsQ0FBQztnQkFDRixNQUFNLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUNsRSxPQUFPLGdCQUFnQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNyQyxDQUFDO1FBQ0gsQ0FBQztRQUVELGdCQUFnQjthQUNiLElBQUksQ0FBQyxJQUFJLENBQUM7YUFDVixJQUFJLENBQUMsR0FBRyxFQUFFO1lBQ1QsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsK0JBQStCLENBQUMsQ0FBQztRQUNqRCxDQUFDLENBQUM7YUFDRCxLQUFLLENBQUMsQ0FBQyxDQUFVLEVBQUUsRUFBRTtZQUNwQixNQUFNLElBQUksNkJBQWEsQ0FBQywyQ0FBMkMsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMxRSxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7Q0FDRjtBQS9NRCxvQ0ErTUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBEaXNwYXRjaCB9IGZyb20gXCJAZGVjYWYtdHMvY29yZVwiO1xuaW1wb3J0IHtcbiAgRGF0YWJhc2VDaGFuZ2VzUmVzcG9uc2UsXG4gIERhdGFiYXNlQ2hhbmdlc1Jlc3VsdEl0ZW0sXG4gIERvY3VtZW50U2NvcGUsXG4gIFJlcXVlc3RFcnJvcixcbn0gZnJvbSBcIm5hbm9cIjtcbmltcG9ydCB7IEludGVybmFsRXJyb3IsIE9wZXJhdGlvbktleXMgfSBmcm9tIFwiQGRlY2FmLXRzL2RiLWRlY29yYXRvcnNcIjtcbmltcG9ydCB7IENvdWNoREJLZXlzIH0gZnJvbSBcIkBkZWNhZi10cy9mb3ItY291Y2hkYlwiO1xuXG4vKipcbiAqIEBkZXNjcmlwdGlvbiBEaXNwYXRjaGVyIGZvciBOYW5vIGRhdGFiYXNlIGNoYW5nZSBldmVudHNcbiAqIEBzdW1tYXJ5IEhhbmRsZXMgdGhlIHN1YnNjcmlwdGlvbiB0byBhbmQgcHJvY2Vzc2luZyBvZiBkYXRhYmFzZSBjaGFuZ2UgZXZlbnRzIGZyb20gYSBOYW5vIGRhdGFiYXNlLFxuICogbm90aWZ5aW5nIG9ic2VydmVycyB3aGVuIGRvY3VtZW50cyBhcmUgY3JlYXRlZCwgdXBkYXRlZCwgb3IgZGVsZXRlZFxuICogQHRlbXBsYXRlIERvY3VtZW50U2NvcGUgLSBUaGUgTmFubyBkb2N1bWVudCBzY29wZSB0eXBlXG4gKiBAcGFyYW0ge251bWJlcn0gW3RpbWVvdXQ9NTAwMF0gLSBUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgY2hhbmdlIGZlZWQgcmVxdWVzdHNcbiAqIEBjbGFzcyBOYW5vRGlzcGF0Y2hcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBDcmVhdGUgYSBkaXNwYXRjaGVyIGZvciBhIE5hbm8gZGF0YWJhc2VcbiAqIGNvbnN0IGRiID0gc2VydmVyLmRiLnVzZSgnbXlfZGF0YWJhc2UnKTtcbiAqIGNvbnN0IGFkYXB0ZXIgPSBuZXcgTmFub0FkYXB0ZXIoZGIpO1xuICogY29uc3QgZGlzcGF0Y2ggPSBuZXcgTmFub0Rpc3BhdGNoKCk7XG4gKlxuICogLy8gVGhlIGRpc3BhdGNoZXIgd2lsbCBhdXRvbWF0aWNhbGx5IHN1YnNjcmliZSB0byBjaGFuZ2VzXG4gKiAvLyBhbmQgbm90aWZ5IG9ic2VydmVycyB3aGVuIGRvY3VtZW50cyBjaGFuZ2VcbiAqIGBgYFxuICogQG1lcm1haWRcbiAqIGNsYXNzRGlhZ3JhbVxuICogICBjbGFzcyBEaXNwYXRjaCB7XG4gKiAgICAgK2luaXRpYWxpemUoKVxuICogICAgICt1cGRhdGVPYnNlcnZlcnMoKVxuICogICB9XG4gKiAgIGNsYXNzIE5hbm9EaXNwYXRjaCB7XG4gKiAgICAgLW9ic2VydmVyTGFzdFVwZGF0ZT86IHN0cmluZ1xuICogICAgIC1hdHRlbXB0Q291bnRlcjogbnVtYmVyXG4gKiAgICAgLXRpbWVvdXQ6IG51bWJlclxuICogICAgICtjb25zdHJ1Y3Rvcih0aW1lb3V0KVxuICogICAgICNjaGFuZ2VIYW5kbGVyKClcbiAqICAgICAjaW5pdGlhbGl6ZSgpXG4gKiAgIH1cbiAqICAgRGlzcGF0Y2ggPHwtLSBOYW5vRGlzcGF0Y2hcbiAqL1xuZXhwb3J0IGNsYXNzIE5hbm9EaXNwYXRjaCBleHRlbmRzIERpc3BhdGNoPERvY3VtZW50U2NvcGU8YW55Pj4ge1xuICBwcml2YXRlIG9ic2VydmVyTGFzdFVwZGF0ZT86IHN0cmluZztcbiAgcHJpdmF0ZSBhdHRlbXB0Q291bnRlcjogbnVtYmVyID0gMDtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSB0aW1lb3V0ID0gNTAwMCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxuICAvKipcbiAgICogQGRlc2NyaXB0aW9uIFByb2Nlc3NlcyBkYXRhYmFzZSBjaGFuZ2UgZXZlbnRzXG4gICAqIEBzdW1tYXJ5IEhhbmRsZXMgdGhlIHJlc3BvbnNlIGZyb20gdGhlIE5hbm8gY2hhbmdlcyBmZWVkLCBwcm9jZXNzZXMgdGhlIGNoYW5nZXMsXG4gICAqIGFuZCBub3RpZmllcyBvYnNlcnZlcnMgYWJvdXQgZG9jdW1lbnQgY2hhbmdlc1xuICAgKiBAcGFyYW0ge1JlcXVlc3RFcnJvciB8IG51bGx9IGVycm9yIC0gRXJyb3Igb2JqZWN0IGlmIHRoZSByZXF1ZXN0IGZhaWxlZFxuICAgKiBAcGFyYW0gcmVzcG9uc2UgLSBUaGUgY2hhbmdlcyByZXNwb25zZSBmcm9tIE5hbm9cbiAgICogQHBhcmFtIHthbnl9IFtoZWFkZXJzXSAtIFJlc3BvbnNlIGhlYWRlcnMgKHVudXNlZClcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiBhbGwgY2hhbmdlcyBoYXZlIGJlZW4gcHJvY2Vzc2VkXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEQgYXMgTmFub0Rpc3BhdGNoXG4gICAqICAgcGFydGljaXBhbnQgTCBhcyBMb2dnZXJcbiAgICogICBwYXJ0aWNpcGFudCBPIGFzIE9ic2VydmVyc1xuICAgKiAgIE5vdGUgb3ZlciBEOiBSZWNlaXZlIGNoYW5nZXMgZnJvbSBOYW5vXG4gICAqICAgYWx0IEVycm9yIGluIHJlc3BvbnNlXG4gICAqICAgICBELT4+TDogTG9nIGVycm9yXG4gICAqICAgICBELS0+PkQ6IFJldHVybiBlYXJseVxuICAgKiAgIGVuZFxuICAgKiAgIGFsdCBSZXNwb25zZSBpcyBzdHJpbmdcbiAgICogICAgIEQtPj5EOiBQYXJzZSBKU09OIGZyb20gc3RyaW5nXG4gICAqICAgZW5kXG4gICAqICAgRC0+PkQ6IFByb2Nlc3MgY2hhbmdlc1xuICAgKiAgIEQtPj5EOiBHcm91cCBjaGFuZ2VzIGJ5IHRhYmxlIGFuZCBvcGVyYXRpb25cbiAgICogICBsb29wIEZvciBlYWNoIHRhYmxlXG4gICAqICAgICBsb29wIEZvciBlYWNoIG9wZXJhdGlvblxuICAgKiAgICAgICBELT4+TzogdXBkYXRlT2JzZXJ2ZXJzKHRhYmxlLCBvcGVyYXRpb24sIGlkcylcbiAgICogICAgICAgRC0+PkQ6IFVwZGF0ZSBvYnNlcnZlckxhc3RVcGRhdGVcbiAgICogICAgICAgRC0+Pkw6IExvZyBzdWNjZXNzZnVsIGRpc3BhdGNoXG4gICAqICAgICBlbmRcbiAgICogICBlbmRcbiAgICovXG4gIHByb3RlY3RlZCBhc3luYyBjaGFuZ2VIYW5kbGVyKFxuICAgIGVycm9yOiBSZXF1ZXN0RXJyb3IgfCBudWxsLFxuICAgIHJlc3BvbnNlOiAoRGF0YWJhc2VDaGFuZ2VzUmVzcG9uc2UgfCBEYXRhYmFzZUNoYW5nZXNSZXN1bHRJdGVtKVtdIHwgc3RyaW5nLFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnNcbiAgICBoZWFkZXJzPzogYW55XG4gICkge1xuICAgIGNvbnN0IGxvZyA9IHRoaXMubG9nLmZvcih0aGlzLmNoYW5nZUhhbmRsZXIpO1xuICAgIGlmIChlcnJvcikgcmV0dXJuIGxvZy5lcnJvcihgRXJyb3IgaW4gY2hhbmdlIHJlcXVlc3Q6ICR7ZXJyb3J9YCk7XG4gICAgdHJ5IHtcbiAgICAgIHJlc3BvbnNlID0gKFxuICAgICAgICB0eXBlb2YgcmVzcG9uc2UgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICA/IHJlc3BvbnNlXG4gICAgICAgICAgICAgIC5zcGxpdChcIlxcblwiKVxuICAgICAgICAgICAgICAuZmlsdGVyKChyKSA9PiAhIXIpXG4gICAgICAgICAgICAgIC5tYXAoKHIpID0+IEpTT04ucGFyc2UocikpXG4gICAgICAgICAgOiByZXNwb25zZVxuICAgICAgKSBhcyBEYXRhYmFzZUNoYW5nZXNSZXNwb25zZVtdO1xuICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgIHJldHVybiBsb2cuZXJyb3IoYEVycm9yIHBhcnNpbmcgY291Y2hkYiBjaGFuZ2UgZmVlZDogJHtlfWApO1xuICAgIH1cbiAgICBjb25zdCBjb3VudCA9IHJlc3BvbnNlLmxlbmd0aDtcbiAgICBpZiAoY291bnQgPiAwKSB7XG4gICAgICBsb2cuZGVidWcoYFJlY2VpdmVkICR7Y291bnR9IGNoYW5nZXMuIHByb2Nlc3NpbmcuLi5gKTtcbiAgICAgIGNvbnN0IGNoYW5nZXMgPSByZXNwb25zZVxuICAgICAgICAubWFwKChyZWMsIGkpID0+IHtcbiAgICAgICAgICBpZiAoaSA9PT0gY291bnQgLSAxKSB7XG4gICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgIHRoaXMub2JzZXJ2ZXJMYXN0VXBkYXRlID09PVxuICAgICAgICAgICAgICAocmVjIGFzIERhdGFiYXNlQ2hhbmdlc1Jlc3BvbnNlKS5sYXN0X3NlcVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgICBsb2cuZXJyb3IoXG4gICAgICAgICAgICAgICAgYEludmFsaWQgbGFzdCB1cGRhdGUgY2hlY2s6ICR7dGhpcy5vYnNlcnZlckxhc3RVcGRhdGV9ICE9PSAkeyhyZWMgYXMgRGF0YWJhc2VDaGFuZ2VzUmVzcG9uc2UpLmxhc3Rfc2VxfWBcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgICAgY29uc3QgciA9IHJlYyBhcyBEYXRhYmFzZUNoYW5nZXNSZXN1bHRJdGVtO1xuICAgICAgICAgIGNvbnN0IFt0YWJsZSwgaWRdID0gci5pZC5zcGxpdChDb3VjaERCS2V5cy5TRVBBUkFUT1IpO1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB0YWJsZTogdGFibGUsXG4gICAgICAgICAgICBpZDogaWQsXG4gICAgICAgICAgICBvcGVyYXRpb246IHIuZGVsZXRlZFxuICAgICAgICAgICAgICA/IE9wZXJhdGlvbktleXMuREVMRVRFXG4gICAgICAgICAgICAgIDogci5jaGFuZ2VzW3IuY2hhbmdlcy5sZW5ndGggLSAxXS5yZXYuc3BsaXQoXCItXCIpWzBdID09PSBcIjFcIlxuICAgICAgICAgICAgICAgID8gT3BlcmF0aW9uS2V5cy5DUkVBVEVcbiAgICAgICAgICAgICAgICA6IE9wZXJhdGlvbktleXMuVVBEQVRFLFxuICAgICAgICAgICAgc3RlcDogci5jaGFuZ2VzW3IuY2hhbmdlcy5sZW5ndGggLSAxXS5yZXYsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSlcbiAgICAgICAgLnJlZHVjZShcbiAgICAgICAgICAoXG4gICAgICAgICAgICBhY2N1bTogUmVjb3JkPFxuICAgICAgICAgICAgICBzdHJpbmcsXG4gICAgICAgICAgICAgIFJlY29yZDxcbiAgICAgICAgICAgICAgICBzdHJpbmcsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgaWRzOiBTZXQ8YW55PjtcbiAgICAgICAgICAgICAgICAgIHN0ZXA6IHN0cmluZztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgID4sXG4gICAgICAgICAgICByXG4gICAgICAgICAgKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXIpIHJldHVybiBhY2N1bTtcbiAgICAgICAgICAgIGNvbnN0IHsgdGFibGUsIGlkLCBvcGVyYXRpb24sIHN0ZXAgfSA9IHIgYXMge1xuICAgICAgICAgICAgICB0YWJsZTogc3RyaW5nO1xuICAgICAgICAgICAgICBpZDogc3RyaW5nO1xuICAgICAgICAgICAgICBvcGVyYXRpb246IE9wZXJhdGlvbktleXM7XG4gICAgICAgICAgICAgIHN0ZXA6IHN0cmluZztcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoIWFjY3VtW3RhYmxlXSkgYWNjdW1bdGFibGVdID0ge307XG4gICAgICAgICAgICBpZiAoIWFjY3VtW3RhYmxlXVtvcGVyYXRpb25dKVxuICAgICAgICAgICAgICBhY2N1bVt0YWJsZV1bb3BlcmF0aW9uXSA9IHsgaWRzOiBuZXcgU2V0KCksIHN0ZXA6IHN0ZXAgfTtcbiAgICAgICAgICAgIGFjY3VtW3RhYmxlXVtvcGVyYXRpb25dLmlkcy5hZGQoaWQpO1xuICAgICAgICAgICAgYWNjdW1bdGFibGVdW29wZXJhdGlvbl0uc3RlcCA9IHN0ZXA7XG4gICAgICAgICAgICByZXR1cm4gYWNjdW07XG4gICAgICAgICAgfSxcbiAgICAgICAgICB7fVxuICAgICAgICApO1xuXG4gICAgICBmb3IgKGNvbnN0IHRhYmxlIG9mIE9iamVjdC5rZXlzKGNoYW5nZXMpKSB7XG4gICAgICAgIGZvciAoY29uc3Qgb3Agb2YgT2JqZWN0LmtleXMoY2hhbmdlc1t0YWJsZV0pKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMudXBkYXRlT2JzZXJ2ZXJzKHRhYmxlLCBvcCwgW1xuICAgICAgICAgICAgICAuLi5jaGFuZ2VzW3RhYmxlXVtvcF0uaWRzLnZhbHVlcygpLFxuICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICB0aGlzLm9ic2VydmVyTGFzdFVwZGF0ZSA9IGNoYW5nZXNbdGFibGVdW29wXS5zdGVwO1xuICAgICAgICAgICAgbG9nLnZlcmJvc2UoYE9ic2VydmVyIHJlZnJlc2ggZGlzcGF0Y2hlZCBieSAke29wfSBmb3IgJHt0YWJsZX1gKTtcbiAgICAgICAgICAgIGxvZy5kZWJ1ZyhgcGtzOiAke0FycmF5LmZyb20oY2hhbmdlc1t0YWJsZV1bb3BdLmlkcy52YWx1ZXMoKSl9YCk7XG4gICAgICAgICAgfSBjYXRjaCAoZTogdW5rbm93bikge1xuICAgICAgICAgICAgbG9nLmVycm9yKFxuICAgICAgICAgICAgICBgRmFpbGVkIHRvIGRpc3BhdGNoIG9ic2VydmVyIHJlZnJlc2ggZm9yICR7dGFibGV9LCBvcCAke29wfTogJHtlfWBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBJbml0aWFsaXplcyB0aGUgZGlzcGF0Y2hlciBhbmQgc3Vic2NyaWJlcyB0byBkYXRhYmFzZSBjaGFuZ2VzXG4gICAqIEBzdW1tYXJ5IFNldHMgdXAgdGhlIGNvbnRpbnVvdXMgY2hhbmdlcyBmZWVkIHN1YnNjcmlwdGlvbiB0byB0aGUgTmFubyBkYXRhYmFzZVxuICAgKiBhbmQgaGFuZGxlcyByZWNvbm5lY3Rpb24gYXR0ZW1wdHMgaWYgdGhlIGNvbm5lY3Rpb24gZmFpbHNcbiAgICogQHJldHVybiB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgc3Vic2NyaXB0aW9uIGlzIGVzdGFibGlzaGVkXG4gICAqIEBtZXJtYWlkXG4gICAqIHNlcXVlbmNlRGlhZ3JhbVxuICAgKiAgIHBhcnRpY2lwYW50IEQgYXMgTmFub0Rpc3BhdGNoXG4gICAqICAgcGFydGljaXBhbnQgUyBhcyBzdWJzY3JpYmVUb0NvdWNoXG4gICAqICAgcGFydGljaXBhbnQgREIgYXMgTmFubyBEYXRhYmFzZVxuICAgKiAgIHBhcnRpY2lwYW50IEwgYXMgTG9nZ2VyXG4gICAqICAgRC0+PlM6IENhbGwgc3Vic2NyaWJlVG9Db3VjaFxuICAgKiAgIFMtPj5TOiBDaGVjayBhZGFwdGVyIGFuZCBuYXRpdmVcbiAgICogICBhbHQgTm8gYWRhcHRlciBvciBuYXRpdmVcbiAgICogICAgIFMtLT4+UzogdGhyb3cgSW50ZXJuYWxFcnJvclxuICAgKiAgIGVuZFxuICAgKiAgIFMtPj5EQjogY2hhbmdlcyhvcHRpb25zLCBjaGFuZ2VIYW5kbGVyKVxuICAgKiAgIGFsdCBTdWNjZXNzXG4gICAqICAgICBEQi0tPj5TOiBTdWJzY3JpcHRpb24gZXN0YWJsaXNoZWRcbiAgICogICAgIFMtLT4+RDogUHJvbWlzZSByZXNvbHZlc1xuICAgKiAgICAgRC0+Pkw6IExvZyBzdWNjZXNzZnVsIHN1YnNjcmlwdGlvblxuICAgKiAgIGVsc2UgRXJyb3JcbiAgICogICAgIERCLS0+PlM6IEVycm9yXG4gICAqICAgICBTLT4+UzogSW5jcmVtZW50IGF0dGVtcHRDb3VudGVyXG4gICAqICAgICBhbHQgYXR0ZW1wdENvdW50ZXIgPiAzXG4gICAqICAgICAgIFMtPj5MOiBMb2cgZXJyb3JcbiAgICogICAgICAgUy0tPj5EOiBQcm9taXNlIHJlamVjdHNcbiAgICogICAgIGVsc2UgYXR0ZW1wdENvdW50ZXIgPD0gM1xuICAgKiAgICAgICBTLT4+TDogTG9nIHJldHJ5XG4gICAqICAgICAgIFMtPj5TOiBXYWl0IHRpbWVvdXRcbiAgICogICAgICAgUy0+PlM6IFJlY3Vyc2l2ZSBjYWxsIHRvIHN1YnNjcmliZVRvQ291Y2hcbiAgICogICAgIGVuZFxuICAgKiAgIGVuZFxuICAgKi9cbiAgcHJvdGVjdGVkIG92ZXJyaWRlIGFzeW5jIGluaXRpYWxpemUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgbG9nID0gdGhpcy5sb2cuZm9yKHRoaXMuaW5pdGlhbGl6ZSk7XG4gICAgY29uc3Qgc3ViTG9nID0gbG9nLmZvcihzdWJzY3JpYmVUb0NvdWNoKTtcbiAgICBhc3luYyBmdW5jdGlvbiBzdWJzY3JpYmVUb0NvdWNoKHRoaXM6IE5hbm9EaXNwYXRjaCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgaWYgKCF0aGlzLmFkYXB0ZXIgfHwgIXRoaXMubmF0aXZlKVxuICAgICAgICB0aHJvdyBuZXcgSW50ZXJuYWxFcnJvcihgTm8gYWRhcHRlci9uYXRpdmUgb2JzZXJ2ZWQgZm9yIGRpc3BhdGNoYCk7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHRoaXMubmF0aXZlLmNoYW5nZXMoXG4gICAgICAgICAge1xuICAgICAgICAgICAgZmVlZDogXCJjb250aW51b3VzXCIsXG4gICAgICAgICAgICBpbmNsdWRlX2RvY3M6IGZhbHNlLFxuICAgICAgICAgICAgc2luY2U6IHRoaXMub2JzZXJ2ZXJMYXN0VXBkYXRlIHx8IFwibm93XCIsXG4gICAgICAgICAgICB0aW1lb3V0OiB0aGlzLnRpbWVvdXQsXG4gICAgICAgICAgfSxcbiAgICAgICAgICB0aGlzLmNoYW5nZUhhbmRsZXIuYmluZCh0aGlzKSBhcyBhbnlcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGU6IHVua25vd24pIHtcbiAgICAgICAgaWYgKCsrdGhpcy5hdHRlbXB0Q291bnRlciA+IDMpXG4gICAgICAgICAgcmV0dXJuIHN1YkxvZy5lcnJvcihgRmFpbGVkIHRvIHN1YnNjcmliZSB0byBjb3VjaGRiIGNoYW5nZXM6ICR7ZX1gKTtcbiAgICAgICAgc3ViTG9nLmluZm8oXG4gICAgICAgICAgYEZhaWxlZCB0byBzdWJzY3JpYmUgdG8gY291Y2hkYiBjaGFuZ2VzOiAke2V9LiBSZXRyeWluZyBpbiA1IHNlY29uZHMuLi5gXG4gICAgICAgICk7XG4gICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PiBzZXRUaW1lb3V0KHJlc29sdmUsIHRoaXMudGltZW91dCkpO1xuICAgICAgICByZXR1cm4gc3Vic2NyaWJlVG9Db3VjaC5jYWxsKHRoaXMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHN1YnNjcmliZVRvQ291Y2hcbiAgICAgIC5jYWxsKHRoaXMpXG4gICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgIHRoaXMubG9nLmluZm8oYFN1YnNjcmliZWQgdG8gY291Y2hkYiBjaGFuZ2VzYCk7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKChlOiB1bmtub3duKSA9PiB7XG4gICAgICAgIHRocm93IG5ldyBJbnRlcm5hbEVycm9yKGBGYWlsZWQgdG8gc3Vic2NyaWJlIHRvIGNvdWNoZGIgY2hhbmdlczogJHtlfWApO1xuICAgICAgfSk7XG4gIH1cbn1cbiJdfQ==