@things-factory/integration-base 10.0.0-beta.10 β 10.0.0-beta.108
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/controllers/scenario-controller.js +8 -6
- package/dist-server/controllers/scenario-controller.js.map +1 -1
- package/dist-server/engine/connection-manager.d.ts +19 -0
- package/dist-server/engine/connection-manager.js +148 -16
- package/dist-server/engine/connection-manager.js.map +1 -1
- package/dist-server/engine/connector/headless-connector.d.ts +12 -0
- package/dist-server/engine/connector/headless-connector.js +74 -31
- package/dist-server/engine/connector/headless-connector.js.map +1 -1
- package/dist-server/engine/connector/operato-connector.js +17 -6
- package/dist-server/engine/connector/operato-connector.js.map +1 -1
- package/dist-server/engine/connector/socket-server.js +12 -2
- package/dist-server/engine/connector/socket-server.js.map +1 -1
- package/dist-server/engine/evaluate-template.d.ts +22 -3
- package/dist-server/engine/evaluate-template.js +43 -4
- package/dist-server/engine/evaluate-template.js.map +1 -1
- package/dist-server/engine/task/script.js +25 -17
- package/dist-server/engine/task/script.js.map +1 -1
- package/dist-server/engine/task/socket-listener.js +29 -9
- package/dist-server/engine/task/socket-listener.js.map +1 -1
- package/dist-server/engine/task/utils/headless-request-with-recovery.js +29 -26
- package/dist-server/engine/task/utils/headless-request-with-recovery.js.map +1 -1
- package/dist-server/engine/types.d.ts +32 -0
- package/dist-server/engine/types.js.map +1 -1
- package/dist-server/service/connection/connection-mutation.d.ts +3 -0
- package/dist-server/service/connection/connection-mutation.js +25 -26
- package/dist-server/service/connection/connection-mutation.js.map +1 -1
- package/dist-server/service/connection/connection-query.js +11 -3
- package/dist-server/service/connection/connection-query.js.map +1 -1
- package/dist-server/service/connection/connection-subscription.js +13 -6
- package/dist-server/service/connection/connection-subscription.js.map +1 -1
- package/dist-server/service/connection/connection-type.d.ts +4 -1
- package/dist-server/service/connection/connection-type.js +21 -0
- package/dist-server/service/connection/connection-type.js.map +1 -1
- package/dist-server/service/connection/connection.d.ts +80 -2
- package/dist-server/service/connection/connection.js +59 -15
- package/dist-server/service/connection/connection.js.map +1 -1
- package/dist-server/service/domain-attribute/domain-attribute-query.d.ts +17 -0
- package/dist-server/service/domain-attribute/domain-attribute-query.js +76 -0
- package/dist-server/service/domain-attribute/domain-attribute-query.js.map +1 -0
- package/dist-server/service/domain-attribute/domain-attribute-type.d.ts +15 -0
- package/dist-server/service/domain-attribute/domain-attribute-type.js +46 -0
- package/dist-server/service/domain-attribute/domain-attribute-type.js.map +1 -0
- package/dist-server/service/domain-attribute/index.d.ts +3 -0
- package/dist-server/service/domain-attribute/index.js +8 -0
- package/dist-server/service/domain-attribute/index.js.map +1 -0
- package/dist-server/service/index.d.ts +1 -1
- package/dist-server/service/index.js +3 -1
- package/dist-server/service/index.js.map +1 -1
- package/dist-server/service/scenario/scenario-mutation.js +10 -0
- package/dist-server/service/scenario/scenario-mutation.js.map +1 -1
- package/dist-server/service/scenario/scenario-query.d.ts +3 -3
- package/dist-server/service/scenario/scenario-query.js +18 -11
- package/dist-server/service/scenario/scenario-query.js.map +1 -1
- package/dist-server/service/scenario-instance/scenario-instance-subscription.js +4 -4
- package/dist-server/service/scenario-instance/scenario-instance-subscription.js.map +1 -1
- package/dist-server/service/scenario-instance/scenario-instance-type.js +79 -0
- package/dist-server/service/scenario-instance/scenario-instance-type.js.map +1 -1
- package/dist-server/service/scenario-queue/scenario-queue-subscription.js +2 -2
- package/dist-server/service/scenario-queue/scenario-queue-subscription.js.map +1 -1
- package/dist-server/service/state-register/data-resolver.js +2 -2
- package/dist-server/service/state-register/data-resolver.js.map +1 -1
- package/dist-server/service/step/step-mutation.js +15 -0
- package/dist-server/service/step/step-mutation.js.map +1 -1
- package/dist-server/service/step/step-query.js +11 -2
- package/dist-server/service/step/step-query.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/utils/domain-inheritance.d.ts +29 -0
- package/dist-server/utils/domain-inheritance.js +98 -0
- package/dist-server/utils/domain-inheritance.js.map +1 -0
- package/package.json +10 -10
|
@@ -9,18 +9,20 @@ const auth_base_1 = require("@things-factory/auth-base");
|
|
|
9
9
|
const cache_service_1 = require("@things-factory/cache-service");
|
|
10
10
|
const scenario_engine_1 = require("../engine/scenario-engine");
|
|
11
11
|
const scenario_1 = require("../service/scenario/scenario");
|
|
12
|
+
const domain_inheritance_1 = require("../utils/domain-inheritance");
|
|
12
13
|
const debug = require('debug')('things-factory:integration-base:controller:run-scenario');
|
|
13
14
|
async function findScenario(scenarioName, domain) {
|
|
14
15
|
var repository = (0, shell_1.getRepository)(scenario_1.Scenario);
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (!scenario && domain.parentId) {
|
|
16
|
+
// ancestor λλ©μΈμ closest-first λ‘ μννμ¬ first hit μ¬μ©
|
|
17
|
+
const domainIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
|
|
18
|
+
var scenario = null;
|
|
19
|
+
for (const did of domainIds) {
|
|
20
20
|
scenario = await repository.findOne({
|
|
21
|
-
where: { domain: { id:
|
|
21
|
+
where: { domain: { id: did }, name: scenarioName },
|
|
22
22
|
relations: ['domain', 'steps', 'role', 'creator', 'updater']
|
|
23
23
|
});
|
|
24
|
+
if (scenario)
|
|
25
|
+
break;
|
|
24
26
|
}
|
|
25
27
|
return scenario;
|
|
26
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scenario-controller.js","sourceRoot":"","sources":["../../server/controllers/scenario-controller.ts"],"names":[],"mappings":";;AA0CA,oCASC;AAED,kCA2CC;AAED,sCAwBC;AAED,oCA0BC;AAtJD,iDAAiF;AACjF,yDAA4D;AAC5D,iEAA4D;AAE5D,+DAA0D;AAC1D,2DAAuD;
|
|
1
|
+
{"version":3,"file":"scenario-controller.js","sourceRoot":"","sources":["../../server/controllers/scenario-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { getRepository, Domain, GraphqlLocalClient } from '@things-factory/shell'\nimport { checkUserHasRole } from '@things-factory/auth-base'\nimport { cacheService } from '@things-factory/cache-service'\n\nimport { ScenarioEngine } from '../engine/scenario-engine'\nimport { Scenario } from '../service/scenario/scenario'\nimport { getDomainIdsWithAncestors } from '../utils/domain-inheritance'\nimport {\n ScenarioInstance,\n ScenarioInstanceRunResult,\n ScenarioInstanceStartResult\n} from '../service/scenario-instance/scenario-instance-type'\nimport { Step } from '../service/step/step-type'\n\nconst debug = require('debug')('things-factory:integration-base:controller:run-scenario')\n\nasync function findScenario(\n scenarioName: string,\n domain: Domain\n): Promise<{\n id: string\n ttl: number\n name: string\n steps: Step[]\n domain: Domain\n}> {\n var repository = getRepository(Scenario)\n\n // ancestor λλ©μΈμ closest-first λ‘ μννμ¬ first hit μ¬μ©\n const domainIds = await getDomainIdsWithAncestors(domain)\n var scenario: Scenario | null = null\n for (const did of domainIds) {\n scenario = await repository.findOne({\n where: { domain: { id: did }, name: scenarioName },\n relations: ['domain', 'steps', 'role', 'creator', 'updater']\n })\n if (scenario) break\n }\n\n return scenario as any\n}\n\nexport async function checkHasRole(scenario: Partial<Scenario>, context: ResolverContext): Promise<void> {\n const { domain, user } = context.state\n if (!(await checkUserHasRole(scenario.roleId, domain, user))) {\n throw new Error(\n context.t('error.scenario run unauthorized', {\n scenario: scenario.name\n })\n )\n }\n}\n\nexport async function runScenario(\n instanceName: string,\n scenarioName: string,\n variables: any,\n context: ResolverContext\n): Promise<ScenarioInstanceRunResult> {\n const { domain, user, lng } = context.state\n\n debug('runScenario', scenarioName, instanceName, variables)\n\n var scenario = await findScenario(scenarioName, domain)\n\n if (!scenario) {\n throw new Error(\n context.t('error.scenario not found', {\n scenario: scenarioName\n })\n )\n }\n\n await checkHasRole(scenario, context)\n\n if (scenario.ttl > 0) {\n const cachedValue = await cacheService.getFromCache(scenario.id, { domain: domain.id, variables: variables || {} })\n if (cachedValue) {\n return cachedValue.value\n }\n }\n\n /* μλλ¦¬μ€ μΈμ€ν΄μ€λ₯Ό μμ±νλ€. */\n instanceName = instanceName || scenarioName + '-' + String(Date.now())\n\n try {\n return await ScenarioEngine.run(instanceName, scenario, { domain, user, lng, variables })\n } catch (err) {\n console.error(err)\n\n throw new Error(\n context.t('error.scenario run error', {\n scenario: scenarioName\n })\n )\n }\n}\n\nexport async function startScenario(\n instanceName: string,\n scenarioName: string,\n variables: any,\n context: ResolverContext\n): Promise<ScenarioInstanceStartResult> {\n const { domain, user, lng } = context.state\n\n debug('startScenario', instanceName, scenarioName, variables)\n\n var scenario = await findScenario(scenarioName, domain)\n\n if (!scenario) {\n throw new Error(\n context.t('error.scenario not found', {\n scenario: scenarioName\n })\n )\n }\n\n await checkHasRole(scenario, context)\n\n instanceName = instanceName || scenarioName\n return await ScenarioEngine.loadIteration(instanceName, scenario, { domain, user, lng, variables })\n}\n\nexport async function stopScenario(\n instanceName: string,\n context: ResolverContext\n): Promise<ScenarioInstance | undefined> {\n const { domain, user, unsafeIP, prohibitedPrivileges } = context.state\n\n debug('stopScenario', instanceName)\n\n var scenarioInstance = ScenarioEngine.getScenarioInstance(domain, instanceName)\n\n if (!scenarioInstance) {\n debug('stopScenario', `ScenarioInstance(${instanceName}) Not Found.`)\n throw new Error(\n context.t('error.scenario instance not found', {\n instance: instanceName\n })\n )\n }\n\n var scenario = await findScenario(scenarioInstance.scenarioName, domain)\n\n await checkHasRole(scenario, context)\n\n await ScenarioEngine.unload(domain, instanceName)\n\n return scenarioInstance\n}\n"]}
|
|
@@ -5,6 +5,12 @@ export declare class ConnectionManager {
|
|
|
5
5
|
private static connectors;
|
|
6
6
|
private static connections;
|
|
7
7
|
private static entities;
|
|
8
|
+
/**
|
|
9
|
+
* Session μ§λ ¬ν mutex β connection name λ¨μ (λλ©μΈ λ¬΄κ΄ κΈλ‘λ²).
|
|
10
|
+
* sessionExclusive connector μ acquireSessionPage λμ νΈμΆμ΄ μΈλΆ μΈμ
μ μλ‘
|
|
11
|
+
* invalidate νμ§ μλλ‘ νμ. release νΈμΆ μ λ€μ λκΈ°μκ° μ§ν.
|
|
12
|
+
*/
|
|
13
|
+
private static sessionLocks;
|
|
8
14
|
private static logFormat;
|
|
9
15
|
static logger: import("winston").Logger;
|
|
10
16
|
static ready(): Promise<void>;
|
|
@@ -21,6 +27,19 @@ export declare class ConnectionManager {
|
|
|
21
27
|
};
|
|
22
28
|
static getEntities(): {};
|
|
23
29
|
static getConnectionInstance(connection: Connection): any;
|
|
30
|
+
/**
|
|
31
|
+
* μΈμ
μ¬μ© ν¨ν΄ (RAII).
|
|
32
|
+
*
|
|
33
|
+
* connector κ° sessionExclusive=true λ‘ μ μΈν κ²½μ° connection.name λ¨μ mutex λ‘
|
|
34
|
+
* μ§λ ¬ν. νΈμΆμλ acquireSessionPage / releasePage μ lifecycle μ μ κ²½ μΈ νμ μμ΄
|
|
35
|
+
* `withSession(connection, async page => { ... })` ννλ‘ μ¬μ©νλ©΄ λ¨.
|
|
36
|
+
*
|
|
37
|
+
* stateless connector (sessionExclusive=false) λ mutex μμ΄ μ¦μ μ§ν.
|
|
38
|
+
*
|
|
39
|
+
* @param connection λλ©μΈ instance (connection.type μμ connector μ‘°ν)
|
|
40
|
+
* @param fn page λ₯Ό λ°μ λ°μ΄ν° μμ
νλ async ν¨μ
|
|
41
|
+
*/
|
|
42
|
+
static withSession<T>(connection: any, fn: (page: any) => Promise<T>): Promise<T>;
|
|
24
43
|
static getConnectionInstanceByName(domain: Domain, name: string): Promise<any>;
|
|
25
44
|
static getConnectionEntityByName(domain: Domain, name: string): Promise<Connection | null>;
|
|
26
45
|
static getConnectionInstanceEntityByName(domain: Domain, name: string): any;
|
|
@@ -6,6 +6,7 @@ const moment_timezone_1 = tslib_1.__importDefault(require("moment-timezone"));
|
|
|
6
6
|
const winston_1 = require("winston");
|
|
7
7
|
const shell_1 = require("@things-factory/shell");
|
|
8
8
|
const service_1 = require("../service");
|
|
9
|
+
const domain_inheritance_1 = require("../utils/domain-inheritance");
|
|
9
10
|
const proxy_connector_1 = require("./connector/proxy-connector");
|
|
10
11
|
const { combine, splat, printf, errors } = winston_1.format;
|
|
11
12
|
const debug = require('debug')('things-factory:integration-base:connections');
|
|
@@ -32,6 +33,12 @@ class ConnectionManager {
|
|
|
32
33
|
static { this.connectors = {}; }
|
|
33
34
|
static { this.connections = {}; }
|
|
34
35
|
static { this.entities = {}; }
|
|
36
|
+
/**
|
|
37
|
+
* Session μ§λ ¬ν mutex β connection name λ¨μ (λλ©μΈ λ¬΄κ΄ κΈλ‘λ²).
|
|
38
|
+
* sessionExclusive connector μ acquireSessionPage λμ νΈμΆμ΄ μΈλΆ μΈμ
μ μλ‘
|
|
39
|
+
* invalidate νμ§ μλλ‘ νμ. release νΈμΆ μ λ€μ λκΈ°μκ° μ§ν.
|
|
40
|
+
*/
|
|
41
|
+
static { this.sessionLocks = new Map(); }
|
|
35
42
|
static { this.logFormat = printf(({ level, message, timestamp, stack }) => {
|
|
36
43
|
return `${timestamp} ${level}: ${stack || message}`;
|
|
37
44
|
}); }
|
|
@@ -114,20 +121,106 @@ class ConnectionManager {
|
|
|
114
121
|
const { domain, name } = connection;
|
|
115
122
|
return ConnectionManager.connections[domain.id]?.[name];
|
|
116
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* μΈμ
μ¬μ© ν¨ν΄ (RAII).
|
|
126
|
+
*
|
|
127
|
+
* connector κ° sessionExclusive=true λ‘ μ μΈν κ²½μ° connection.name λ¨μ mutex λ‘
|
|
128
|
+
* μ§λ ¬ν. νΈμΆμλ acquireSessionPage / releasePage μ lifecycle μ μ κ²½ μΈ νμ μμ΄
|
|
129
|
+
* `withSession(connection, async page => { ... })` ννλ‘ μ¬μ©νλ©΄ λ¨.
|
|
130
|
+
*
|
|
131
|
+
* stateless connector (sessionExclusive=false) λ mutex μμ΄ μ¦μ μ§ν.
|
|
132
|
+
*
|
|
133
|
+
* @param connection λλ©μΈ instance (connection.type μμ connector μ‘°ν)
|
|
134
|
+
* @param fn page λ₯Ό λ°μ λ°μ΄ν° μμ
νλ async ν¨μ
|
|
135
|
+
*/
|
|
136
|
+
static async withSession(connection, fn) {
|
|
137
|
+
const connector = ConnectionManager.getConnector(connection.type);
|
|
138
|
+
const exclusive = !!connector?.sessionExclusive;
|
|
139
|
+
const run = async () => {
|
|
140
|
+
const page = await connection.acquireSessionPage();
|
|
141
|
+
try {
|
|
142
|
+
return await fn(page);
|
|
143
|
+
}
|
|
144
|
+
finally {
|
|
145
|
+
// releasePage κ° page μΈμλ₯Ό λ°μ β λλ½ μ λ΄λΆμ page.close() μ
|
|
146
|
+
// browser ν λ°νμ΄ μ€ν΅λμ΄ λΈλΌμ°μ κ° leak. ν κ³ κ° β μ μ μ’
λ£ hang μΌλ‘ μ΄μ΄μ§.
|
|
147
|
+
try {
|
|
148
|
+
await connection.releasePage?.(page);
|
|
149
|
+
}
|
|
150
|
+
catch (e) {
|
|
151
|
+
ConnectionManager.logger.warn(`releasePage failed for '${connection.name}':`, e);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
if (!exclusive)
|
|
156
|
+
return await run();
|
|
157
|
+
// mutex: connection name λ¨μλ‘ μ§λ ¬ν (λλ©μΈ 무κ΄, κ°μ μΈλΆ κ³μ μ€λ³΅ λ‘κ·ΈμΈ λ°©μ§)
|
|
158
|
+
const lockKey = connection.name;
|
|
159
|
+
const wasQueued = ConnectionManager.sessionLocks.has(lockKey);
|
|
160
|
+
const prev = ConnectionManager.sessionLocks.get(lockKey) || Promise.resolve();
|
|
161
|
+
let release;
|
|
162
|
+
const next = new Promise(r => (release = r));
|
|
163
|
+
// chain: μ΄μ μμ
μ΄ λλ λ€ next κ° λλ λκΉμ§ pending β λ€μ λκΈ°μκ° μ΄ chain μΌλ‘ await
|
|
164
|
+
const chain = prev.then(() => next);
|
|
165
|
+
ConnectionManager.sessionLocks.set(lockKey, chain);
|
|
166
|
+
// ν λκΈ° μ§λ¨ β μ΄μ μ€ "μ μμ
μ΄ stall λλκ°" μΆμ μ©
|
|
167
|
+
const waitStartedAt = wasQueued ? Date.now() : 0;
|
|
168
|
+
if (wasQueued) {
|
|
169
|
+
ConnectionManager.logger.info(`[withSession] '${lockKey}' queued behind existing lock β waiting (domain='${connection.domain?.subdomain || connection.domainId}')`);
|
|
170
|
+
}
|
|
171
|
+
await prev;
|
|
172
|
+
if (wasQueued) {
|
|
173
|
+
const waited = Date.now() - waitStartedAt;
|
|
174
|
+
ConnectionManager.logger.info(`[withSession] '${lockKey}' lock acquired after ${waited}ms wait`);
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
return await run();
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
release();
|
|
181
|
+
// λ΄κ° latest λ©΄ (μ΄ chain λ€λ‘ μλ‘ λ€μ΄μ¨ λκΈ°μ μμ) cleanup
|
|
182
|
+
if (ConnectionManager.sessionLocks.get(lockKey) === chain) {
|
|
183
|
+
ConnectionManager.sessionLocks.delete(lockKey);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
117
187
|
static async getConnectionInstanceByName(domain, name) {
|
|
118
188
|
const connections = ConnectionManager.connections[domain.id];
|
|
119
189
|
const connection = connections?.[name];
|
|
120
190
|
if (!connection) {
|
|
121
|
-
//
|
|
191
|
+
// μμ λλ©μΈμ instance κ° μμ λμ μΈ κ°μ§ μλ μ²λ¦¬ λΆκΈ°:
|
|
192
|
+
//
|
|
193
|
+
// (a) entity.__sharedFrom μμ β SHARE λͺ¨λ inheritance
|
|
194
|
+
// β λΆλͺ¨ λλ©μΈμ instance λ₯Ό κ·Έλλ‘ lookup ν΄μ λ°ν. μμ λλ©μΈμλ instance λ±λ‘ μ ν¨.
|
|
195
|
+
// κ°μ instance κ° λΆλͺ¨Β·μμ λͺ¨λμκ² μλΉμ€ λ¨.
|
|
196
|
+
//
|
|
197
|
+
// (b) entity.__inheritedFrom μμ β ISOLATE λͺ¨λ inheritance
|
|
198
|
+
// β μμ λλ©μΈ ν€ μλ μ instance μλ μμ±. cookies/μΈμ
격리.
|
|
199
|
+
//
|
|
200
|
+
// (c) entity.onDemand=true β λͺ
μμ lazy μμ± (μμ μ체 record μΈ κ²½μ°μλ μ μ©)
|
|
201
|
+
// β μμ λλ©μΈ ν€ μλ μ instance μμ±.
|
|
202
|
+
//
|
|
203
|
+
// λλ¨Έμ§: μμ record λ μκ³ inherit λ μ λλ κ²½μ° β throw.
|
|
122
204
|
try {
|
|
123
205
|
const connectionEntity = await ConnectionManager.getConnectionEntityByName(domain, name);
|
|
124
|
-
if (connectionEntity?.
|
|
125
|
-
//
|
|
126
|
-
const
|
|
127
|
-
|
|
206
|
+
if (connectionEntity?.__sharedFrom) {
|
|
207
|
+
// SHARE: λΆλͺ¨ instance μ§μ μ¬μ©
|
|
208
|
+
const parentInstance = ConnectionManager.connections[connectionEntity.__sharedFrom]?.[name];
|
|
209
|
+
if (parentInstance)
|
|
210
|
+
return parentInstance;
|
|
211
|
+
throw `SHARE mode: parent instance for '${name}' (domain id '${connectionEntity.__sharedFrom}') not registered yet β startup ready() may have failed for parent`;
|
|
212
|
+
}
|
|
213
|
+
if (connectionEntity?.onDemand || connectionEntity?.__inheritedFrom) {
|
|
214
|
+
const instance = await ConnectionManager.createOnDemandConnection(connectionEntity);
|
|
215
|
+
return instance;
|
|
216
|
+
}
|
|
217
|
+
else if (connectionEntity) {
|
|
218
|
+
// entity λ μ°Ύμλλ° instance μμ± trigger (onDemand/inherit) μμ β μ΄μμκ° record μ체 μ κ² νμ
|
|
219
|
+
throw `Connection '${name}' record exists but instance is not registered and no auto-create trigger (onDemand=false, no inheritance marker). Check whether parent record's active=true and ready() succeeded at startup.`;
|
|
128
220
|
}
|
|
129
221
|
else {
|
|
130
|
-
|
|
222
|
+
// entity μ체 λͺ» μ°Ύμ β λλ©μΈ νΈλ¦¬ μ΄λμλ record μμ
|
|
223
|
+
throw `Connection '${name}' not found in domain '${domain.subdomain || domain.id}' or any ancestor β verify the Connection record exists at the running domain or any of its ancestors.`;
|
|
131
224
|
}
|
|
132
225
|
}
|
|
133
226
|
catch (error) {
|
|
@@ -163,22 +256,61 @@ class ConnectionManager {
|
|
|
163
256
|
// return parentCachedEntity
|
|
164
257
|
// }
|
|
165
258
|
// }
|
|
166
|
-
// 4.
|
|
167
|
-
|
|
168
|
-
|
|
259
|
+
// 4. ancestor λλ©μΈ νΈλ¦¬ fallback (closest-first walk)
|
|
260
|
+
//
|
|
261
|
+
// EnvVar inheritance μ μΌκ΄λκ² λͺ¨λ μ‘°μ λλ©μΈμ closest-first λ‘ νμ.
|
|
262
|
+
// μ: SYSTEM β μκ³΅μ¬ β νλ‘μ νΈ νΈλ¦¬μμ μλ리μ€κ° νλ‘μ νΈ λλ©μΈμμ μ€νλ λ
|
|
263
|
+
// Connection record κ° SYSTEM λλ μκ³΅μ¬ μ΄λμ μμ΄λ μ°Ύμλ.
|
|
264
|
+
//
|
|
265
|
+
// λ§€μΉλ ancestor μ inheritanceMode μ λ°λΌ λ κ°λ:
|
|
266
|
+
// ISOLATE (default): μμ λλ©μΈμ© clone μμ±. cookies/μΈμ
격리, μμ 컨ν
μ€νΈμμ
|
|
267
|
+
// EnvVar override ν΄μ. __inheritedFrom marker λ‘ νμ μλ instance.
|
|
268
|
+
// SHARE: λΆλͺ¨ entity κ·Έλλ‘ λ°ν. paramsΒ·μΈμ
Β·μΈμ€ν΄μ€ λͺ¨λ λΆλͺ¨ κ² κ³΅μ .
|
|
269
|
+
// __sharedFrom marker λ‘ instance lookup μ΄ λΆλͺ¨ λλ©μΈμ κ°λ¦¬ν€κ² ν¨.
|
|
270
|
+
//
|
|
271
|
+
// νΈνμ±: inheritanceMode λ―Έμ§μ (NULL) β connector default β ν΄λ°± ISOLATE.
|
|
272
|
+
// κΈ°μ‘΄ λͺ¨λ Connection μ μ΄ column μΆκ° μ λ§λ€μ΄μ‘μΌλ―λ‘ NULL β ISOLATE = κΈ°μ‘΄ κ±°λ.
|
|
273
|
+
const ancestorIds = await (0, domain_inheritance_1.getDomainIdsWithAncestors)(domain);
|
|
274
|
+
// ancestorIds[0] = domain.id (μ΄λ―Έ μ λΆκΈ°μμ μλ), skip
|
|
275
|
+
const searchedAncestors = [];
|
|
276
|
+
for (let i = 1; i < ancestorIds.length; i++) {
|
|
277
|
+
const ancestorId = ancestorIds[i];
|
|
278
|
+
searchedAncestors.push(ancestorId);
|
|
279
|
+
const parentConn = await (0, shell_1.getRepository)(service_1.Connection).findOne({
|
|
169
280
|
where: {
|
|
170
|
-
domain: { id:
|
|
281
|
+
domain: { id: ancestorId },
|
|
171
282
|
name: name
|
|
172
283
|
},
|
|
173
284
|
relations: ['domain', 'edge', 'creator', 'updater']
|
|
174
285
|
});
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
286
|
+
if (!parentConn)
|
|
287
|
+
continue; // μ΄ ancestor μ μμΌλ©΄ λ€μ ancestor
|
|
288
|
+
ConnectionManager.logger.info(`[inheritance] '${name}' inherited by domain '${domain.subdomain || domain.id}' ` +
|
|
289
|
+
`from ancestor '${parentConn.domain?.subdomain || ancestorId}' ` +
|
|
290
|
+
`(walked ${i} ancestor(s))`);
|
|
291
|
+
const connectorDefault = ConnectionManager.connectors[parentConn.type]?.inheritanceMode;
|
|
292
|
+
const effectiveMode = parentConn.inheritanceMode || connectorDefault || service_1.ConnectionInheritanceMode.ISOLATE;
|
|
293
|
+
if (effectiveMode === service_1.ConnectionInheritanceMode.SHARE) {
|
|
294
|
+
// SHARE β λΆλͺ¨ entity κ·Έλλ‘ λ°ν (mutation μ΅μν).
|
|
295
|
+
const shared = parentConn;
|
|
296
|
+
shared.__sharedFrom = parentConn.domainId;
|
|
297
|
+
shared.params = await parentConn.getResolvedParameters();
|
|
298
|
+
return shared;
|
|
181
299
|
}
|
|
300
|
+
// ISOLATE (default) β clone + marker
|
|
301
|
+
const inherited = Object.assign(Object.create(Object.getPrototypeOf(parentConn)), parentConn, {
|
|
302
|
+
domain,
|
|
303
|
+
domainId: domain.id,
|
|
304
|
+
cookies: undefined,
|
|
305
|
+
__inheritedFrom: parentConn.domainId
|
|
306
|
+
});
|
|
307
|
+
inherited.params = await inherited.getResolvedParameters();
|
|
308
|
+
return inherited;
|
|
309
|
+
}
|
|
310
|
+
// μ΄λ ancestor μμλ λͺ» μ°Ύμ β μ΄μμκ° μ΄λκΉμ§ μ°Ύμλμ§ μ μ μλλ‘ μ§λ¨ λ‘κ·Έ
|
|
311
|
+
if (searchedAncestors.length > 0) {
|
|
312
|
+
ConnectionManager.logger.warn(`[inheritance] '${name}' not found at any ancestor of domain '${domain.subdomain || domain.id}' ` +
|
|
313
|
+
`β searched: [${searchedAncestors.join(', ')}]`);
|
|
182
314
|
}
|
|
183
315
|
return null;
|
|
184
316
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection-manager.js","sourceRoot":"","sources":["../../server/engine/connection-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import moment from 'moment-timezone'\nimport { createLogger, format, transports } from 'winston'\n\nimport { Domain, getRepository, pubsub, PubSubLogTransport } from '@things-factory/shell'\n\nimport { Connection, ConnectionStatus } from '../service'\nimport { Connector } from './types'\nimport { ProxyConnector } from './connector/proxy-connector'\n\nconst { combine, splat, printf, errors } = format\nconst debug = require('debug')('things-factory:integration-base:connections')\n\nfunction getSystemTimeZone() {\n try {\n const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone\n if (!timeZone) {\n throw new Error('Unable to resolve timeZone')\n }\n return timeZone\n } catch (e) {\n console.warn('Failed to get system timeZone, falling back to UTC.', e)\n return 'UTC'\n }\n}\n\nconst SYSTEM_TZ = getSystemTimeZone()\nconst systemTimestamp = format((info, opts: { tz?: string }) => {\n if (opts.tz) info.timestamp = moment().tz(opts.tz).format()\n return info\n})\n\nexport class ConnectionManager {\n private static connectors: { [propName: string]: Connector } = {}\n private static connections: { [domainId: string]: { [name: string]: any } } = {}\n private static entities = {}\n private static logFormat = printf(({ level, message, timestamp, stack }) => {\n return `${timestamp} ${level}: ${stack || message}`\n })\n\n public static logger = createLogger({\n format: combine(errors({ stack: true }), systemTimestamp({ tz: SYSTEM_TZ }), splat(), ConnectionManager.logFormat),\n transports: [\n new (transports as any).DailyRotateFile({\n filename: `logs/connections-%DATE%.log`,\n datePattern: 'YYYY-MM-DD-HH',\n zippedArchive: false,\n maxSize: '20m',\n maxFiles: '14d',\n level: 'info'\n }),\n new PubSubLogTransport({\n topic: 'connection-log'\n })\n ]\n })\n\n static async ready() {\n const CONNECTIONS = await Promise.all(\n (\n await getRepository(Connection).find({\n where: { active: true },\n relations: ['domain', 'edge', 'creator', 'updater']\n })\n ).map(async connection => {\n // π ν΄κ²°λ νλΌλ―Έν° μ¬μ©\n const resolvedParams = await connection.getResolvedParameters()\n\n return {\n ...connection,\n params: resolvedParams\n }\n })\n )\n\n ConnectionManager.logger.info('Initializing ConnectionManager...')\n\n return await Promise.all(\n [...Object.keys(ConnectionManager.connectors), 'proxy-connector'].map(type => {\n const connector = type == 'proxy-connector' ? ProxyConnector.instance : ConnectionManager.getConnector(type)\n\n ConnectionManager.logger.info(`Connector '${type}' started to ready`)\n\n return connector\n .ready(\n CONNECTIONS.filter(connection => {\n if (type == 'proxy-connector') {\n return !!connection.edge\n } else {\n return !connection.edge && connection.type == type\n }\n }) as any\n )\n .catch(error => {\n ConnectionManager.logger.error(error)\n })\n .then(() => {\n ConnectionManager.logger.info(`All connector for '${type}' ready`)\n })\n })\n ).then(() => {\n ConnectionManager.logger.info('ConnectionManager initialization done:')\n Object.keys(ConnectionManager.connections).forEach(key => {\n var connections = ConnectionManager.connections[key]\n ConnectionManager.logger.info('For domain(%s) : %s', key, JSON.stringify(Object.keys(connections)))\n })\n })\n }\n\n static registerConnector(type: string, connector: Connector) {\n ConnectionManager.connectors[type] = connector\n }\n\n static getConnector(type: string): Connector {\n return ConnectionManager.connectors[type]\n }\n\n static getConnectors(): { [connectorName: string]: Connector } {\n return {\n ...ConnectionManager.connectors\n }\n }\n\n static unregisterConnector(type: string) {\n delete ConnectionManager.connectors[type]\n }\n\n static getConnections() {\n return ConnectionManager.connections\n }\n\n static getEntities() {\n return ConnectionManager.entities\n }\n\n static getConnectionInstance(connection: Connection): any {\n const { domain, name } = connection\n return ConnectionManager.connections[domain.id]?.[name]\n }\n\n static async getConnectionInstanceByName(domain: Domain, name: string) {\n const connections = ConnectionManager.connections[domain.id]\n const connection = connections?.[name]\n\n if (!connection) {\n // on-demand 컀λ₯μ
μΈμ§ νμΈνκ³ μμ±\n try {\n const connectionEntity = await ConnectionManager.getConnectionEntityByName(domain, name)\n\n if (connectionEntity?.onDemand) {\n // on-demand 컀λ₯μ
μμ±\n const onDemandInstance = await ConnectionManager.createOnDemandConnection(connectionEntity)\n return onDemandInstance\n } else {\n throw `The connection with the given name(${name}) cannot be found`\n }\n } catch (error) {\n throw `The connection with the given name(${name}) cannot be found: ${error}`\n }\n }\n\n return connection\n }\n\n static async getConnectionEntityByName(domain: Domain, name: string): Promise<Connection | null> {\n // 1. νμ¬ λλ©μΈμμ λ©λͺ¨λ¦¬ μ‘°ν (μ°μ )\n const cachedEntity = ConnectionManager.entities[domain.id]?.[name]\n if (cachedEntity) {\n return cachedEntity\n }\n\n // 2. νμ¬ λλ©μΈμμ λ°μ΄ν°λ² μ΄μ€ μ‘°ν (μ°μ )\n try {\n let connection = await getRepository(Connection).findOne({\n where: {\n domain: { id: domain.id },\n name: name\n },\n relations: ['domain', 'edge', 'creator', 'updater']\n })\n\n if (connection) {\n const resolvedParams = await connection.getResolvedParameters()\n connection.params = resolvedParams\n return connection\n }\n\n // 3. νμ¬ λλ©μΈμμ λͺ» μ°ΎμΌλ©΄ λΆλͺ¨ λλ©μΈμμ λ©λͺ¨λ¦¬ μ‘°ν - μλλ€. connectionμ 보λ₯Ό μμ ν΄μΌ νλ―λ‘ μ¬μ©ν μ μλ€.\n // if (domain.parentId) {\n // const parentCachedEntity = ConnectionManager.entities[domain.parentId]?.[name]\n // if (parentCachedEntity) {\n // return parentCachedEntity\n // }\n // }\n\n // 4. λΆλͺ¨ λλ©μΈμμ λ°μ΄ν°λ² μ΄μ€ μ‘°ν (fallback)\n if (domain.parentId) {\n connection = await getRepository(Connection).findOne({\n where: {\n domain: { id: domain.parentId },\n name: name\n },\n relations: ['domain', 'edge', 'creator', 'updater']\n })\n\n if (connection) {\n const resolvedParams = await connection.getResolvedParameters()\n connection.params = resolvedParams\n connection.domain = domain\n connection.domainId = domain.id\n\n return connection\n }\n }\n\n return null\n } catch (error) {\n ConnectionManager.logger.error(`Failed to get connection entity '${name}' from database:`, error)\n return null\n }\n }\n\n static getConnectionInstanceEntityByName(domain: Domain, name: string): any {\n const connection = ConnectionManager.entities[domain.id]?.[name]\n if (connection) {\n return connection\n }\n\n if (domain.parentId) {\n return ConnectionManager.entities[domain.parentId]?.[name]\n }\n }\n\n /**\n * Creates a connection on-demand and returns the instance.\n * @param connection - The connection entity to create\n * @returns The connection instance\n */\n static async createOnDemandConnection(connection: Connection): Promise<any> {\n try {\n // 컀λ₯μ
μμ±\n await connection.connect()\n\n ConnectionManager.logger.info(`On-demand connection '${connection.name}' created successfully`)\n return ConnectionManager.getConnectionInstance(connection)\n } catch (error) {\n ConnectionManager.logger.error(`Failed to create on-demand connection '${connection.name}':`, error)\n throw error\n }\n }\n\n /**\n * Disconnects an on-demand connection.\n * @param connection - The connection entity to disconnect\n */\n static async disconnectOnDemandConnection(connection: Connection): Promise<void> {\n try {\n await connection.disconnect()\n // ConnectionManager.removeConnectionInstance(connection)\n ConnectionManager.logger.info(`On-demand connection '${connection.name}' disconnected successfully`)\n } catch (error) {\n ConnectionManager.logger.error(`Failed to disconnect on-demand connection '${connection.name}':`, error)\n }\n }\n\n static getConnectionInstances(domain: Domain): { [connectionName: string]: any } {\n const connections = ConnectionManager.connections[domain.id]\n const parentConnections = domain.parentId && ConnectionManager.connections[domain.parentId]\n\n return {\n ...parentConnections,\n ...connections\n }\n }\n\n static getConnectionInstanceEntities(domain: Domain): { [connectionName: string]: any } {\n const connections = ConnectionManager.entities[domain.id]\n\n return {\n ...connections\n }\n }\n\n static addConnectionInstance(connection: Connection, instance: any) {\n const { domain, name } = connection\n\n var connections = ConnectionManager.connections[domain.id]\n if (!connections) {\n connections = ConnectionManager.connections[domain.id] = {}\n }\n\n var entities = ConnectionManager.entities[domain.id]\n if (!entities) {\n entities = ConnectionManager.entities[domain.id] = {}\n }\n\n connections[name] = instance\n entities[name] = connection\n\n ConnectionManager.publishState(connection, ConnectionStatus.CONNECTED)\n debug('add-connection', domain.subdomain, name)\n }\n\n static removeConnectionInstance(connection: Connection): any {\n const { domain, name } = connection\n var connections = ConnectionManager.connections[domain.id]\n var entities = ConnectionManager.entities[domain.id]\n\n var instance = connections?.[name]\n\n if (!connections || !instance) {\n debug('remove-connection', `'${name}' connection not found in domain '${domain.subdomain}'`)\n return\n }\n\n delete connections[name]\n delete entities[name]\n\n ConnectionManager.publishState(connection, ConnectionStatus.DISCONNECTED)\n debug('remove-connection', `'${name}' connection is removed from domain '${domain.subdomain}'`)\n\n return instance\n }\n\n private static async publishState(connection: Connection, state) {\n const { domain, id, name, description, type, edge } = connection\n\n pubsub.publish('connection-state', {\n connectionState: {\n domain,\n id,\n name,\n description,\n type,\n edge,\n state,\n timestamp: new Date()\n }\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"connection-manager.js","sourceRoot":"","sources":["../../server/engine/connection-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import moment from 'moment-timezone'\nimport { createLogger, format, transports } from 'winston'\n\nimport { Domain, getRepository, pubsub, PubSubLogTransport } from '@things-factory/shell'\n\nimport { Connection, ConnectionInheritanceMode, ConnectionStatus } from '../service'\nimport { getDomainIdsWithAncestors } from '../utils/domain-inheritance'\nimport { Connector } from './types'\nimport { ProxyConnector } from './connector/proxy-connector'\n\nconst { combine, splat, printf, errors } = format\nconst debug = require('debug')('things-factory:integration-base:connections')\n\nfunction getSystemTimeZone() {\n try {\n const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone\n if (!timeZone) {\n throw new Error('Unable to resolve timeZone')\n }\n return timeZone\n } catch (e) {\n console.warn('Failed to get system timeZone, falling back to UTC.', e)\n return 'UTC'\n }\n}\n\nconst SYSTEM_TZ = getSystemTimeZone()\nconst systemTimestamp = format((info, opts: { tz?: string }) => {\n if (opts.tz) info.timestamp = moment().tz(opts.tz).format()\n return info\n})\n\nexport class ConnectionManager {\n private static connectors: { [propName: string]: Connector } = {}\n private static connections: { [domainId: string]: { [name: string]: any } } = {}\n private static entities = {}\n /**\n * Session μ§λ ¬ν mutex β connection name λ¨μ (λλ©μΈ λ¬΄κ΄ κΈλ‘λ²).\n * sessionExclusive connector μ acquireSessionPage λμ νΈμΆμ΄ μΈλΆ μΈμ
μ μλ‘\n * invalidate νμ§ μλλ‘ νμ. release νΈμΆ μ λ€μ λκΈ°μκ° μ§ν.\n */\n private static sessionLocks: Map<string, Promise<void>> = new Map()\n private static logFormat = printf(({ level, message, timestamp, stack }) => {\n return `${timestamp} ${level}: ${stack || message}`\n })\n\n public static logger = createLogger({\n format: combine(errors({ stack: true }), systemTimestamp({ tz: SYSTEM_TZ }), splat(), ConnectionManager.logFormat),\n transports: [\n new (transports as any).DailyRotateFile({\n filename: `logs/connections-%DATE%.log`,\n datePattern: 'YYYY-MM-DD-HH',\n zippedArchive: false,\n maxSize: '20m',\n maxFiles: '14d',\n level: 'info'\n }),\n new PubSubLogTransport({\n topic: 'connection-log'\n })\n ]\n })\n\n static async ready() {\n const CONNECTIONS = await Promise.all(\n (\n await getRepository(Connection).find({\n where: { active: true },\n relations: ['domain', 'edge', 'creator', 'updater']\n })\n ).map(async connection => {\n // π ν΄κ²°λ νλΌλ―Έν° μ¬μ©\n const resolvedParams = await connection.getResolvedParameters()\n\n return {\n ...connection,\n params: resolvedParams\n }\n })\n )\n\n ConnectionManager.logger.info('Initializing ConnectionManager...')\n\n return await Promise.all(\n [...Object.keys(ConnectionManager.connectors), 'proxy-connector'].map(type => {\n const connector = type == 'proxy-connector' ? ProxyConnector.instance : ConnectionManager.getConnector(type)\n\n ConnectionManager.logger.info(`Connector '${type}' started to ready`)\n\n return connector\n .ready(\n CONNECTIONS.filter(connection => {\n if (type == 'proxy-connector') {\n return !!connection.edge\n } else {\n return !connection.edge && connection.type == type\n }\n }) as any\n )\n .catch(error => {\n ConnectionManager.logger.error(error)\n })\n .then(() => {\n ConnectionManager.logger.info(`All connector for '${type}' ready`)\n })\n })\n ).then(() => {\n ConnectionManager.logger.info('ConnectionManager initialization done:')\n Object.keys(ConnectionManager.connections).forEach(key => {\n var connections = ConnectionManager.connections[key]\n ConnectionManager.logger.info('For domain(%s) : %s', key, JSON.stringify(Object.keys(connections)))\n })\n })\n }\n\n static registerConnector(type: string, connector: Connector) {\n ConnectionManager.connectors[type] = connector\n }\n\n static getConnector(type: string): Connector {\n return ConnectionManager.connectors[type]\n }\n\n static getConnectors(): { [connectorName: string]: Connector } {\n return {\n ...ConnectionManager.connectors\n }\n }\n\n static unregisterConnector(type: string) {\n delete ConnectionManager.connectors[type]\n }\n\n static getConnections() {\n return ConnectionManager.connections\n }\n\n static getEntities() {\n return ConnectionManager.entities\n }\n\n static getConnectionInstance(connection: Connection): any {\n const { domain, name } = connection\n return ConnectionManager.connections[domain.id]?.[name]\n }\n\n /**\n * μΈμ
μ¬μ© ν¨ν΄ (RAII).\n *\n * connector κ° sessionExclusive=true λ‘ μ μΈν κ²½μ° connection.name λ¨μ mutex λ‘\n * μ§λ ¬ν. νΈμΆμλ acquireSessionPage / releasePage μ lifecycle μ μ κ²½ μΈ νμ μμ΄\n * `withSession(connection, async page => { ... })` ννλ‘ μ¬μ©νλ©΄ λ¨.\n *\n * stateless connector (sessionExclusive=false) λ mutex μμ΄ μ¦μ μ§ν.\n *\n * @param connection λλ©μΈ instance (connection.type μμ connector μ‘°ν)\n * @param fn page λ₯Ό λ°μ λ°μ΄ν° μμ
νλ async ν¨μ\n */\n static async withSession<T>(connection: any, fn: (page: any) => Promise<T>): Promise<T> {\n const connector = ConnectionManager.getConnector(connection.type)\n const exclusive = !!connector?.sessionExclusive\n\n const run = async (): Promise<T> => {\n const page = await connection.acquireSessionPage()\n try {\n return await fn(page)\n } finally {\n // releasePage κ° page μΈμλ₯Ό λ°μ β λλ½ μ λ΄λΆμ page.close() μ\n // browser ν λ°νμ΄ μ€ν΅λμ΄ λΈλΌμ°μ κ° leak. ν κ³ κ° β μ μ μ’
λ£ hang μΌλ‘ μ΄μ΄μ§.\n try {\n await connection.releasePage?.(page)\n } catch (e) {\n ConnectionManager.logger.warn(`releasePage failed for '${connection.name}':`, e as any)\n }\n }\n }\n\n if (!exclusive) return await run()\n\n // mutex: connection name λ¨μλ‘ μ§λ ¬ν (λλ©μΈ 무κ΄, κ°μ μΈλΆ κ³μ μ€λ³΅ λ‘κ·ΈμΈ λ°©μ§)\n const lockKey = connection.name\n const wasQueued = ConnectionManager.sessionLocks.has(lockKey)\n const prev = ConnectionManager.sessionLocks.get(lockKey) || Promise.resolve()\n let release!: () => void\n const next = new Promise<void>(r => (release = r))\n // chain: μ΄μ μμ
μ΄ λλ λ€ next κ° λλ λκΉμ§ pending β λ€μ λκΈ°μκ° μ΄ chain μΌλ‘ await\n const chain = prev.then(() => next)\n ConnectionManager.sessionLocks.set(lockKey, chain)\n\n // ν λκΈ° μ§λ¨ β μ΄μ μ€ \"μ μμ
μ΄ stall λλκ°\" μΆμ μ©\n const waitStartedAt = wasQueued ? Date.now() : 0\n if (wasQueued) {\n ConnectionManager.logger.info(\n `[withSession] '${lockKey}' queued behind existing lock β waiting (domain='${connection.domain?.subdomain || connection.domainId}')`\n )\n }\n await prev\n if (wasQueued) {\n const waited = Date.now() - waitStartedAt\n ConnectionManager.logger.info(\n `[withSession] '${lockKey}' lock acquired after ${waited}ms wait`\n )\n }\n\n try {\n return await run()\n } finally {\n release()\n // λ΄κ° latest λ©΄ (μ΄ chain λ€λ‘ μλ‘ λ€μ΄μ¨ λκΈ°μ μμ) cleanup\n if (ConnectionManager.sessionLocks.get(lockKey) === chain) {\n ConnectionManager.sessionLocks.delete(lockKey)\n }\n }\n }\n\n static async getConnectionInstanceByName(domain: Domain, name: string) {\n const connections = ConnectionManager.connections[domain.id]\n const connection = connections?.[name]\n\n if (!connection) {\n // μμ λλ©μΈμ instance κ° μμ λμ μΈ κ°μ§ μλ μ²λ¦¬ λΆκΈ°:\n //\n // (a) entity.__sharedFrom μμ β SHARE λͺ¨λ inheritance\n // β λΆλͺ¨ λλ©μΈμ instance λ₯Ό κ·Έλλ‘ lookup ν΄μ λ°ν. μμ λλ©μΈμλ instance λ±λ‘ μ ν¨.\n // κ°μ instance κ° λΆλͺ¨Β·μμ λͺ¨λμκ² μλΉμ€ λ¨.\n //\n // (b) entity.__inheritedFrom μμ β ISOLATE λͺ¨λ inheritance\n // β μμ λλ©μΈ ν€ μλ μ instance μλ μμ±. cookies/μΈμ
격리.\n //\n // (c) entity.onDemand=true β λͺ
μμ lazy μμ± (μμ μ체 record μΈ κ²½μ°μλ μ μ©)\n // β μμ λλ©μΈ ν€ μλ μ instance μμ±.\n //\n // λλ¨Έμ§: μμ record λ μκ³ inherit λ μ λλ κ²½μ° β throw.\n try {\n const connectionEntity = await ConnectionManager.getConnectionEntityByName(domain, name)\n\n if (connectionEntity?.__sharedFrom) {\n // SHARE: λΆλͺ¨ instance μ§μ μ¬μ©\n const parentInstance = ConnectionManager.connections[connectionEntity.__sharedFrom]?.[name]\n if (parentInstance) return parentInstance\n throw `SHARE mode: parent instance for '${name}' (domain id '${connectionEntity.__sharedFrom}') not registered yet β startup ready() may have failed for parent`\n }\n\n if (connectionEntity?.onDemand || connectionEntity?.__inheritedFrom) {\n const instance = await ConnectionManager.createOnDemandConnection(connectionEntity!)\n return instance\n } else if (connectionEntity) {\n // entity λ μ°Ύμλλ° instance μμ± trigger (onDemand/inherit) μμ β μ΄μμκ° record μ체 μ κ² νμ\n throw `Connection '${name}' record exists but instance is not registered and no auto-create trigger (onDemand=false, no inheritance marker). Check whether parent record's active=true and ready() succeeded at startup.`\n } else {\n // entity μ체 λͺ» μ°Ύμ β λλ©μΈ νΈλ¦¬ μ΄λμλ record μμ\n throw `Connection '${name}' not found in domain '${domain.subdomain || domain.id}' or any ancestor β verify the Connection record exists at the running domain or any of its ancestors.`\n }\n } catch (error) {\n throw `The connection with the given name(${name}) cannot be found: ${error}`\n }\n }\n\n return connection\n }\n\n static async getConnectionEntityByName(domain: Domain, name: string): Promise<Connection | null> {\n // 1. νμ¬ λλ©μΈμμ λ©λͺ¨λ¦¬ μ‘°ν (μ°μ )\n const cachedEntity = ConnectionManager.entities[domain.id]?.[name]\n if (cachedEntity) {\n return cachedEntity\n }\n\n // 2. νμ¬ λλ©μΈμμ λ°μ΄ν°λ² μ΄μ€ μ‘°ν (μ°μ )\n try {\n let connection = await getRepository(Connection).findOne({\n where: {\n domain: { id: domain.id },\n name: name\n },\n relations: ['domain', 'edge', 'creator', 'updater']\n })\n\n if (connection) {\n const resolvedParams = await connection.getResolvedParameters()\n connection.params = resolvedParams\n return connection\n }\n\n // 3. νμ¬ λλ©μΈμμ λͺ» μ°ΎμΌλ©΄ λΆλͺ¨ λλ©μΈμμ λ©λͺ¨λ¦¬ μ‘°ν - μλλ€. connectionμ 보λ₯Ό μμ ν΄μΌ νλ―λ‘ μ¬μ©ν μ μλ€.\n // if (domain.parentId) {\n // const parentCachedEntity = ConnectionManager.entities[domain.parentId]?.[name]\n // if (parentCachedEntity) {\n // return parentCachedEntity\n // }\n // }\n\n // 4. ancestor λλ©μΈ νΈλ¦¬ fallback (closest-first walk)\n //\n // EnvVar inheritance μ μΌκ΄λκ² λͺ¨λ μ‘°μ λλ©μΈμ closest-first λ‘ νμ.\n // μ: SYSTEM β μκ³΅μ¬ β νλ‘μ νΈ νΈλ¦¬μμ μλ리μ€κ° νλ‘μ νΈ λλ©μΈμμ μ€νλ λ\n // Connection record κ° SYSTEM λλ μκ³΅μ¬ μ΄λμ μμ΄λ μ°Ύμλ.\n //\n // λ§€μΉλ ancestor μ inheritanceMode μ λ°λΌ λ κ°λ:\n // ISOLATE (default): μμ λλ©μΈμ© clone μμ±. cookies/μΈμ
격리, μμ 컨ν
μ€νΈμμ\n // EnvVar override ν΄μ. __inheritedFrom marker λ‘ νμ μλ instance.\n // SHARE: λΆλͺ¨ entity κ·Έλλ‘ λ°ν. paramsΒ·μΈμ
Β·μΈμ€ν΄μ€ λͺ¨λ λΆλͺ¨ κ² κ³΅μ .\n // __sharedFrom marker λ‘ instance lookup μ΄ λΆλͺ¨ λλ©μΈμ κ°λ¦¬ν€κ² ν¨.\n //\n // νΈνμ±: inheritanceMode λ―Έμ§μ (NULL) β connector default β ν΄λ°± ISOLATE.\n // κΈ°μ‘΄ λͺ¨λ Connection μ μ΄ column μΆκ° μ λ§λ€μ΄μ‘μΌλ―λ‘ NULL β ISOLATE = κΈ°μ‘΄ κ±°λ.\n const ancestorIds = await getDomainIdsWithAncestors(domain)\n // ancestorIds[0] = domain.id (μ΄λ―Έ μ λΆκΈ°μμ μλ), skip\n const searchedAncestors: string[] = []\n for (let i = 1; i < ancestorIds.length; i++) {\n const ancestorId = ancestorIds[i]\n searchedAncestors.push(ancestorId)\n const parentConn = await getRepository(Connection).findOne({\n where: {\n domain: { id: ancestorId },\n name: name\n },\n relations: ['domain', 'edge', 'creator', 'updater']\n })\n\n if (!parentConn) continue // μ΄ ancestor μ μμΌλ©΄ λ€μ ancestor\n\n ConnectionManager.logger.info(\n `[inheritance] '${name}' inherited by domain '${domain.subdomain || domain.id}' ` +\n `from ancestor '${parentConn.domain?.subdomain || ancestorId}' ` +\n `(walked ${i} ancestor(s))`\n )\n\n const connectorDefault = ConnectionManager.connectors[parentConn.type]?.inheritanceMode\n const effectiveMode =\n parentConn.inheritanceMode || connectorDefault || ConnectionInheritanceMode.ISOLATE\n\n if (effectiveMode === ConnectionInheritanceMode.SHARE) {\n // SHARE β λΆλͺ¨ entity κ·Έλλ‘ λ°ν (mutation μ΅μν).\n const shared: any = parentConn\n shared.__sharedFrom = parentConn.domainId\n shared.params = await parentConn.getResolvedParameters()\n return shared\n }\n\n // ISOLATE (default) β clone + marker\n const inherited: any = Object.assign(\n Object.create(Object.getPrototypeOf(parentConn)),\n parentConn,\n {\n domain,\n domainId: domain.id,\n cookies: undefined,\n __inheritedFrom: parentConn.domainId\n }\n )\n inherited.params = await inherited.getResolvedParameters()\n return inherited\n }\n\n // μ΄λ ancestor μμλ λͺ» μ°Ύμ β μ΄μμκ° μ΄λκΉμ§ μ°Ύμλμ§ μ μ μλλ‘ μ§λ¨ λ‘κ·Έ\n if (searchedAncestors.length > 0) {\n ConnectionManager.logger.warn(\n `[inheritance] '${name}' not found at any ancestor of domain '${domain.subdomain || domain.id}' ` +\n `β searched: [${searchedAncestors.join(', ')}]`\n )\n }\n return null\n } catch (error) {\n ConnectionManager.logger.error(`Failed to get connection entity '${name}' from database:`, error)\n return null\n }\n }\n\n static getConnectionInstanceEntityByName(domain: Domain, name: string): any {\n const connection = ConnectionManager.entities[domain.id]?.[name]\n if (connection) {\n return connection\n }\n\n if (domain.parentId) {\n return ConnectionManager.entities[domain.parentId]?.[name]\n }\n }\n\n /**\n * Creates a connection on-demand and returns the instance.\n * @param connection - The connection entity to create\n * @returns The connection instance\n */\n static async createOnDemandConnection(connection: Connection): Promise<any> {\n try {\n // 컀λ₯μ
μμ±\n await connection.connect()\n\n ConnectionManager.logger.info(`On-demand connection '${connection.name}' created successfully`)\n return ConnectionManager.getConnectionInstance(connection)\n } catch (error) {\n ConnectionManager.logger.error(`Failed to create on-demand connection '${connection.name}':`, error)\n throw error\n }\n }\n\n /**\n * Disconnects an on-demand connection.\n * @param connection - The connection entity to disconnect\n */\n static async disconnectOnDemandConnection(connection: Connection): Promise<void> {\n try {\n await connection.disconnect()\n // ConnectionManager.removeConnectionInstance(connection)\n ConnectionManager.logger.info(`On-demand connection '${connection.name}' disconnected successfully`)\n } catch (error) {\n ConnectionManager.logger.error(`Failed to disconnect on-demand connection '${connection.name}':`, error)\n }\n }\n\n static getConnectionInstances(domain: Domain): { [connectionName: string]: any } {\n const connections = ConnectionManager.connections[domain.id]\n const parentConnections = domain.parentId && ConnectionManager.connections[domain.parentId]\n\n return {\n ...parentConnections,\n ...connections\n }\n }\n\n static getConnectionInstanceEntities(domain: Domain): { [connectionName: string]: any } {\n const connections = ConnectionManager.entities[domain.id]\n\n return {\n ...connections\n }\n }\n\n static addConnectionInstance(connection: Connection, instance: any) {\n const { domain, name } = connection\n\n var connections = ConnectionManager.connections[domain.id]\n if (!connections) {\n connections = ConnectionManager.connections[domain.id] = {}\n }\n\n var entities = ConnectionManager.entities[domain.id]\n if (!entities) {\n entities = ConnectionManager.entities[domain.id] = {}\n }\n\n connections[name] = instance\n entities[name] = connection\n\n ConnectionManager.publishState(connection, ConnectionStatus.CONNECTED)\n debug('add-connection', domain.subdomain, name)\n }\n\n static removeConnectionInstance(connection: Connection): any {\n const { domain, name } = connection\n var connections = ConnectionManager.connections[domain.id]\n var entities = ConnectionManager.entities[domain.id]\n\n var instance = connections?.[name]\n\n if (!connections || !instance) {\n debug('remove-connection', `'${name}' connection not found in domain '${domain.subdomain}'`)\n return\n }\n\n delete connections[name]\n delete entities[name]\n\n ConnectionManager.publishState(connection, ConnectionStatus.DISCONNECTED)\n debug('remove-connection', `'${name}' connection is removed from domain '${domain.subdomain}'`)\n\n return instance\n }\n\n private static async publishState(connection: Connection, state) {\n const { domain, id, name, description, type, edge } = connection\n\n pubsub.publish('connection-state', {\n connectionState: {\n domain,\n id,\n name,\n description,\n type,\n edge,\n state,\n timestamp: new Date()\n }\n })\n }\n}\n"]}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { Connector } from '../types';
|
|
2
2
|
export declare class HeadlessConnector implements Connector {
|
|
3
|
+
/**
|
|
4
|
+
* μΈλΆ μ¬μ΄νΈ λ‘κ·ΈμΈ μΈμ
보μ β κ°μ connection name μ λμ acquireSessionPage
|
|
5
|
+
* νΈμΆμ΄ κ°μ μΈλΆ κ³μ μΈμ
μ μλ‘ invalidate νμ§ μλλ‘ ConnectionManager κ°
|
|
6
|
+
* mutex μ§λ ¬ν. μμ connector (allbaro, kiscon λ±) μλ μ μ©.
|
|
7
|
+
*/
|
|
8
|
+
sessionExclusive: boolean;
|
|
9
|
+
/**
|
|
10
|
+
* μμ λλ©μΈμ΄ λΆλͺ¨μ Connection μ μλ₯Ό inherit ν λ μμλ³ μ μΈμ€ν΄μ€ μμ±.
|
|
11
|
+
* cookies/μΈμ
Β·μ격μ¦λͺ
격리. ν€λλ¦¬μ€ μ¬μ΄νΈ connector λ μΈλΆ μ격μ¦λͺ
μ΄
|
|
12
|
+
* μμ (ν
λνΈ) λ§λ€ λ€λ₯Ό μ μμΌλ―λ‘ ISOLATE κ° μμ° default.
|
|
13
|
+
*/
|
|
14
|
+
inheritanceMode: "isolate";
|
|
3
15
|
ready(connectionConfigs: any): Promise<void>;
|
|
4
16
|
connect(connection: any): Promise<void>;
|
|
5
17
|
setupPage(page: any, uri: any, timeout: any): Promise<void>;
|