@mwcp/kmore
Version:
midway component for knex, supports declarative transaction and OpenTelemetry
250 lines • 9.09 kB
JavaScript
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