UNPKG

murlock

Version:

A distributed locking solution for NestJS, providing a decorator for critical sections with Redis-based synchronization.

116 lines 5.07 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.MurLock = void 0; const common_1 = require("@nestjs/common"); const exceptions_1 = require("../exceptions"); const murlock_service_1 = require("../murlock.service"); function getParameterNames(func) { const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm; const ARGUMENT_NAMES = /([^\s,]+)/g; const fnStr = func.toString().replace(STRIP_COMMENTS, ''); const result = fnStr .slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')) .match(ARGUMENT_NAMES); return result || []; } function MurLock(releaseTime, waitOrKeyParam, ...keyParams) { let wait; if (typeof waitOrKeyParam === 'number' || typeof waitOrKeyParam === 'function') { wait = waitOrKeyParam; } else { keyParams = [ ...(waitOrKeyParam === undefined ? [] : [waitOrKeyParam]), ...keyParams, ]; } const injectMurlockService = (0, common_1.Inject)(murlock_service_1.MurLockService); return (target, propertyKey, descriptor) => { injectMurlockService(target, 'murlockServiceDecorator'); const originalMethod = descriptor.value; const methodParameterNames = getParameterNames(originalMethod); function constructLockKey(args, lockKeyPrefix = 'default') { let lockKeyElements = []; if (lockKeyPrefix != 'custom') { lockKeyElements.push(target.constructor.name); lockKeyElements.push(propertyKey); } lockKeyElements.push(...keyParams.map((keyParam) => { const [source, path] = keyParam.split('.'); const parameterIndex = isNumber(source) ? Number(source) : methodParameterNames.indexOf(source); if (parameterIndex >= 0) { const parameterValue = findParameterValue({ args, source, parameterIndex, path, }); if (typeof parameterValue === 'undefined' || parameterValue === null) { throw new exceptions_1.MurLockException(`Parameter ${source} is undefined or null.`); } if (path && typeof parameterValue === 'object' && parameterValue !== null && path in parameterValue) { return parameterValue[path]; } return parameterValue instanceof Object ? parameterValue.toString() : parameterValue; } if (lockKeyPrefix == 'custom') { return source; } throw new exceptions_1.MurLockException(`Parameter ${source} not found in method arguments.`); })); return lockKeyElements.join(':'); } descriptor.value = function (...args) { return __awaiter(this, void 0, void 0, function* () { const murLockService = this.murlockServiceDecorator; const lockKey = constructLockKey(args, murLockService.options.lockKeyPrefix); if (!murLockService) { throw new exceptions_1.MurLockException('MurLockService is not available.'); } return murLockService.runWithLock(lockKey, releaseTime, wait, () => __awaiter(this, void 0, void 0, function* () { return originalMethod.apply(this, args); })); }); }; return descriptor; }; } exports.MurLock = MurLock; function isNumber(value) { const parsedValue = parseFloat(value); if (!isNaN(parsedValue)) { return true; } return false; } function isObject(value) { return value !== null && value instanceof Object && !Array.isArray(value); } function findParameterValue({ args, source, parameterIndex, path }) { if (isNumber(source) && path) { return args[source][path]; } if (args.length == 1 && isObject(args[0]) && !path) { return args[0][source]; } return args[parameterIndex]; } //# sourceMappingURL=murlock.decorator.js.map