// Copyright 2020 The Casbin Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { Enforcer, newEnforcerWithClass } from './enforcer'; // CachedEnforcer wraps Enforcer and provides decision cache export class CachedEnforcer extends Enforcer { private enableCache = true; private m = new Map(); // invalidateCache deletes all the existing cached decisions. public invalidateCache(): void { this.m = new Map(); } // setEnableCache determines whether to enable cache on e nforce(). When enableCache is enabled, cached result (true | false) will be returned for previous decisions. public setEnableCache(enableCache: boolean): void { this.enableCache = enableCache; } private static canCache(...rvals: any[]): boolean { return rvals.every((n) => typeof n === 'string'); } private static getCacheKey(...rvals: string[]): string { return rvals.join('$$'); } private getCache(key: string): boolean | undefined { return this.m.get(key); } private setCache(key: string, value: boolean): void { this.m.set(key, value); } // enforce decides whether a "subject" can access a "object" with the operation "action", input parameters are usually: (sub, obj, act). // if rvals is not string , ingore the cache public async enforce(...rvals: any[]): Promise { if (!this.enableCache) { return super.enforce(...rvals); } let key = ''; const cache = CachedEnforcer.canCache(...rvals); if (cache) { key = CachedEnforcer.getCacheKey(...rvals); const res = this.getCache(key); if (res !== undefined) { return res; } } const res = await super.enforce(...rvals); if (cache) { this.setCache(key, res); } return res; } } // newCachedEnforcer creates a cached enforcer via string or DB. export async function newCachedEnforcer(...params: any[]): Promise { return newEnforcerWithClass(CachedEnforcer, ...params); }