UNPKG

@mwcp/kmore

Version:

midway component for knex, supports declarative transaction and OpenTelemetry

250 lines 9.09 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import assert from 'node:assert'; import { ApplicationContext, Singleton } from '@midwayjs/core'; import { getCallerStack } from '@waiting/shared-core'; import { genCallerKey, getSimpleCallers, } from './propagation/trx-status.helper.js'; const skipMethodNameSet = new Set([ 'aopCallback.around', 'aopDispatchAsync', 'aroundAsync', 'aroundFactory', 'classDecoratorExecutor', 'createAsync', 'registerPropagation', 'retrieveTopCallerKeyFromCallStack', ]); let CallerService = class CallerService { applicationContext; callerKeyFileMapIndex = new Map(); callerTreeMapIndex = new Map(); deleteCallerKeyFileMapIndex(scope) { this.callerKeyFileMapIndex.delete(scope); } deleteCallerTreeMapIndex(scope) { this.callerTreeMapIndex.delete(scope); } // #region Call stack retrieveCallerInfo(distance = 0, retrievePosition = false) { const callerInfo = getCallerStack(distance + 1, retrievePosition); return callerInfo; } retrieveTopCallerKeyFromCallStack(limit = 128) { const ret = []; const callers = getSimpleCallers(limit); if (!callers.length) { return ret; } for (let i = callers.length - 1; i > 1; i -= 1) { const caller = callers[i]; if (!caller) { continue; } if (!caller.className || !caller.funcName) { continue; } if (caller.funcName.includes('Clz.<')) { continue; } if (caller.path.startsWith('node:internal')) { continue; } if (skipMethodNameSet.has(caller.methodName)) { continue; } const key = genCallerKey(caller.className, caller.funcName); ret.push(key); } return ret; } // #region CallerKey retrieveFirstAncestorCallerKeyByCallerKey(dbSourceName, scope, key) { const sourceNameMap = this.callerTreeMapIndex.get(scope); if (!sourceNameMap?.size) { return; } const callerTreeMap = sourceNameMap.get(dbSourceName); if (!callerTreeMap?.size) { return; } let ret; for (const [pkey, arr] of callerTreeMap.entries()) { if (arr.includes(key)) { ret = pkey; } } return ret; } retrieveTopCallerKeyArrayByCallerKey(dbSourceName, scope, key) { const ret = []; const sourceNameMap = this.callerTreeMapIndex.get(scope); if (!sourceNameMap?.size) { return ret; } const callerTreeMap = sourceNameMap.get(dbSourceName); if (!callerTreeMap?.size) { return ret; } for (const [tkey, arr] of callerTreeMap.entries()) { if (!arr.includes(key)) { continue; } arr.forEach((kk) => { if (kk === tkey) { ret.push(tkey); } }); } return ret; } retrieveUniqueTopCallerKey(dbSourceName, scope, key) { assert(dbSourceName, 'dbSourceName is undefined'); const sourceNameMap = this.callerTreeMapIndex.get(scope); if (!sourceNameMap?.size) { return; } const callerTreeMap = sourceNameMap.get(dbSourceName); if (!callerTreeMap?.size) { return; } let ret; for (const [tkey, arr] of callerTreeMap.entries()) { if (!arr.includes(key)) { continue; } for (const kk of arr) { if (kk !== tkey) { continue; } if (ret) { // duplicate return; } else { ret = tkey; } } } return ret; } validateCallerKeyUnique(dbSourceName, scope, key, path) { const ret = this.getFilepathFromCallerKeyFileMapIndex(dbSourceName, scope, key); if (!ret) { return; } assert(ret === path, `callerKey "${key}" must unique in all project, but in files: - ${path} - ${ret} Should use different className or funcName`); } // #region callerTreeMapIndex updateCallerTreeMap(dbSourceName, scope, entryKey, value) { assert(entryKey, 'entryKey is undefined'); let sourceNameMap = this.callerTreeMapIndex.get(scope); if (!sourceNameMap) { sourceNameMap = new Map(); this.callerTreeMapIndex.set(scope, sourceNameMap); } let dbSourceCallerTreeMap = sourceNameMap.get(dbSourceName); if (!dbSourceCallerTreeMap) { dbSourceCallerTreeMap = new Map(); sourceNameMap.set(dbSourceName, dbSourceCallerTreeMap); } let arr = dbSourceCallerTreeMap.get(entryKey); if (!arr) { arr = [entryKey]; dbSourceCallerTreeMap.set(entryKey, arr); } assert(arr.length < 1024, `updateCallerTreeMap(): callerTreeMap entryKey "${entryKey}" length > 1024, maybe circular reference`); value && arr.push(value); } getCallerTreeArray(dbSourceName, scope, key) { const sourceNameMap = this.callerTreeMapIndex.get(scope); if (!sourceNameMap?.size) { return; } const dbSourceCallerTreeMap = sourceNameMap.get(dbSourceName); if (!dbSourceCallerTreeMap?.size) { return; } return dbSourceCallerTreeMap.get(key); } delLastCallerKeyFromCallerTreeMap(dbSourceName, scope, entryKey, key) { const callerTreeArray = this.getCallerTreeArray(dbSourceName, scope, entryKey); if (!callerTreeArray?.length) { return; } const pos = callerTreeArray.lastIndexOf(key); if (pos === -1) { return; } callerTreeArray.splice(pos, 1); } /** * If key is not the last one, throw error */ removeLastKeyFromCallerTreeArray(dbSourceName, scope, key) { const sourceNameMap = this.callerTreeMapIndex.get(scope); if (!sourceNameMap?.size) { return; } const dbSourceCallerTreeMap = sourceNameMap.get(dbSourceName); if (!dbSourceCallerTreeMap?.size) { return; } for (const [tkey, arr] of dbSourceCallerTreeMap.entries()) { if (!arr.includes(key)) { continue; } const lastKey = arr.at(-1); assert(lastKey, 'callerTreeMap lastKey is undefined, during trx commit/rollback'); if (lastKey !== key) { throw new Error(`callerTreeMap callerKey "${key}" is not the last one, can not remove, during trx commit/rollback - tkey: "${tkey}" - last: "${lastKey}" `); } arr.pop(); return; } } // #region callerKeyFileMapIndex setFilepathToCallerKeyFileMapIndex(dbSourceName, scope, key, path) { let sourceNameMap = this.callerKeyFileMapIndex.get(scope); if (!sourceNameMap) { sourceNameMap = new Map(); this.callerKeyFileMapIndex.set(scope, sourceNameMap); } let callerKeyFileMap = sourceNameMap.get(dbSourceName); if (!callerKeyFileMap) { callerKeyFileMap = new Map(); sourceNameMap.set(dbSourceName, callerKeyFileMap); } callerKeyFileMap.set(key, path); } getFilepathFromCallerKeyFileMapIndex(dbSourceName, scope, key) { const sourceNameMap = this.callerKeyFileMapIndex.get(scope); if (!sourceNameMap?.size) { return; } return sourceNameMap.get(dbSourceName)?.get(key); } delFilepathFromCallerKeyFileMapIndex(dbSourceName, scope, key) { this.callerKeyFileMapIndex.get(scope)?.get(dbSourceName)?.delete(key); } }; __decorate([ ApplicationContext(), __metadata("design:type", Object) ], CallerService.prototype, "applicationContext", void 0); CallerService = __decorate([ Singleton() ], CallerService); export { CallerService }; //# sourceMappingURL=caller.service.js.map