javonet-nodejs-sdk 2.6.9 → 2.6.10
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/core/handler/CreateClassInstanceHandler.cjs +1 -35
- package/dist/core/handler/Handler.cjs +26 -12
- package/dist/core/handler/InvokeInstanceMethodHandler.cjs +1 -1
- package/dist/core/handler/InvokeStaticMethodHandler.cjs +1 -1
- package/dist/core/handler/RegisterForUpdateHandler.cjs +60 -0
- package/dist/core/handler/ValueForUpdateHandler.cjs +36 -0
- package/dist/sdk/InvocationContext.cjs +92 -60
- package/dist/sdk/RuntimeContext.cjs +1 -1
- package/dist/types/core/handler/CreateClassInstanceHandler.d.ts +0 -8
- package/dist/types/core/handler/Handler.d.ts +7 -0
- package/dist/types/core/handler/RegisterForUpdateHandler.d.ts +17 -0
- package/dist/types/core/handler/ValueForUpdateHandler.d.ts +7 -0
- package/dist/types/sdk/InvocationContext.d.ts +1 -5
- package/dist/types/utils/CommandType.d.ts +2 -1
- package/dist/utils/CommandType.cjs +2 -1
- package/lib/core/handler/CreateClassInstanceHandler.js +1 -46
- package/lib/core/handler/Handler.js +31 -15
- package/lib/core/handler/InvokeInstanceMethodHandler.js +1 -1
- package/lib/core/handler/InvokeStaticMethodHandler.js +1 -1
- package/lib/core/handler/RegisterForUpdateHandler.js +40 -0
- package/lib/core/handler/ValueForUpdateHandler.js +11 -0
- package/lib/sdk/InvocationContext.js +111 -75
- package/lib/sdk/RuntimeContext.js +1 -1
- package/lib/utils/CommandType.js +2 -1
- package/package.json +1 -1
|
@@ -24,23 +24,9 @@ module.exports = __toCommonJS(CreateClassInstanceHandler_exports);
|
|
|
24
24
|
var import_AbstractHandler = require("./AbstractHandler.cjs");
|
|
25
25
|
class CreateClassInstanceHandler extends import_AbstractHandler.AbstractHandler {
|
|
26
26
|
requiredParametersCount = 1;
|
|
27
|
-
// Add a simple invocation contexts store (Map GUID -> object)
|
|
28
|
-
static _invocationContexts = /* @__PURE__ */ new Map();
|
|
29
|
-
static getOrCreateContextDictionary() {
|
|
30
|
-
return CreateClassInstanceHandler._invocationContexts;
|
|
31
|
-
}
|
|
32
27
|
constructor() {
|
|
33
28
|
super();
|
|
34
29
|
}
|
|
35
|
-
// Helper to detect GUID in payload (standard format)
|
|
36
|
-
/**
|
|
37
|
-
* @param {{ toString: () => any; } | null} value
|
|
38
|
-
*/
|
|
39
|
-
static isGuid(value) {
|
|
40
|
-
if (value == null) return false;
|
|
41
|
-
const s = value.toString();
|
|
42
|
-
return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(s);
|
|
43
|
-
}
|
|
44
30
|
/**
|
|
45
31
|
* @param {Command} command
|
|
46
32
|
*/
|
|
@@ -50,23 +36,7 @@ class CreateClassInstanceHandler extends import_AbstractHandler.AbstractHandler
|
|
|
50
36
|
throw new Error("Create Class Instance parameters mismatch");
|
|
51
37
|
}
|
|
52
38
|
let clazz = command.payload[0];
|
|
53
|
-
let
|
|
54
|
-
let contextGuid = null;
|
|
55
|
-
let constructorArguments = [];
|
|
56
|
-
if (payloadLength > 1 && CreateClassInstanceHandler.isGuid(command.payload[1])) {
|
|
57
|
-
contextGuid = command.payload[1].toString();
|
|
58
|
-
if (payloadLength > 2) {
|
|
59
|
-
constructorArguments = command.payload.slice(2);
|
|
60
|
-
} else {
|
|
61
|
-
constructorArguments = [];
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
if (payloadLength > 1) {
|
|
65
|
-
constructorArguments = command.payload.slice(1);
|
|
66
|
-
} else {
|
|
67
|
-
constructorArguments = [];
|
|
68
|
-
}
|
|
69
|
-
}
|
|
39
|
+
let constructorArguments = command.payload.slice(1);
|
|
70
40
|
let instance = new clazz(...constructorArguments);
|
|
71
41
|
if (typeof instance === "undefined") {
|
|
72
42
|
let methods = Object.getOwnPropertyNames(clazz).filter(function(property) {
|
|
@@ -80,10 +50,6 @@ class CreateClassInstanceHandler extends import_AbstractHandler.AbstractHandler
|
|
|
80
50
|
});
|
|
81
51
|
throw new Error(message);
|
|
82
52
|
} else {
|
|
83
|
-
if (contextGuid) {
|
|
84
|
-
const contextDict = CreateClassInstanceHandler.getOrCreateContextDictionary();
|
|
85
|
-
contextDict.set(contextGuid, instance);
|
|
86
|
-
}
|
|
87
53
|
return instance;
|
|
88
54
|
}
|
|
89
55
|
} catch (error) {
|
|
@@ -22,6 +22,11 @@ __export(Handler_exports, {
|
|
|
22
22
|
handlers: () => handlers
|
|
23
23
|
});
|
|
24
24
|
module.exports = __toCommonJS(Handler_exports);
|
|
25
|
+
var import_CommandType = require("../../utils/CommandType.cjs");
|
|
26
|
+
var import_Command = require("../../utils/Command.cjs");
|
|
27
|
+
var import_TypesHandler = require("../../utils/TypesHandler.cjs");
|
|
28
|
+
var import_ExceptionSerializer = require("../../utils/exception/ExceptionSerializer.cjs");
|
|
29
|
+
var import_AbstractHandler = require("./AbstractHandler.cjs");
|
|
25
30
|
var import_ReferencesCache = require("../referenceCache/ReferencesCache.cjs");
|
|
26
31
|
var import_ValueHandler = require("./ValueHandler.cjs");
|
|
27
32
|
var import_LoadLibraryHandler = require("./LoadLibraryHandler.cjs");
|
|
@@ -71,11 +76,8 @@ var import_GetAsyncOperationResultHandler = require("./GetAsyncOperationResultHa
|
|
|
71
76
|
var import_AsKwargsHandler = require("./AsKwargsHandler.cjs");
|
|
72
77
|
var import_GetResultTypeHandler = require("./GetResultTypeHandler.cjs");
|
|
73
78
|
var import_GetGlobalFieldHandler = require("./GetGlobalFieldHandler.cjs");
|
|
74
|
-
var
|
|
75
|
-
var
|
|
76
|
-
var import_TypesHandler = require("../../utils/TypesHandler.cjs");
|
|
77
|
-
var import_ExceptionSerializer = require("../../utils/exception/ExceptionSerializer.cjs");
|
|
78
|
-
var import_AbstractHandler = require("./AbstractHandler.cjs");
|
|
79
|
+
var import_RegisterForUpdateHandler = require("./RegisterForUpdateHandler.cjs");
|
|
80
|
+
var import_ValueForUpdateHandler = require("./ValueForUpdateHandler.cjs");
|
|
79
81
|
const handlers = {
|
|
80
82
|
[import_CommandType.CommandType.Value]: new import_ValueHandler.ValueHandler(),
|
|
81
83
|
[import_CommandType.CommandType.LoadLibrary]: new import_LoadLibraryHandler.LoadLibraryHandler(),
|
|
@@ -124,7 +126,9 @@ const handlers = {
|
|
|
124
126
|
[import_CommandType.CommandType.GetAsyncOperationResult]: new import_GetAsyncOperationResultHandler.GetAsyncOperationResultHandler(),
|
|
125
127
|
[import_CommandType.CommandType.AsKwargs]: new import_AsKwargsHandler.AsKwargsHandler(),
|
|
126
128
|
[import_CommandType.CommandType.GetResultType]: new import_GetResultTypeHandler.GetResultTypeHandler(),
|
|
127
|
-
[import_CommandType.CommandType.GetGlobalField]: new import_GetGlobalFieldHandler.GetGlobalFieldHandler()
|
|
129
|
+
[import_CommandType.CommandType.GetGlobalField]: new import_GetGlobalFieldHandler.GetGlobalFieldHandler(),
|
|
130
|
+
[import_CommandType.CommandType.RegisterForUpdate]: new import_RegisterForUpdateHandler.RegisterForUpdateHandler(),
|
|
131
|
+
[import_CommandType.CommandType.ValueForUpdate]: new import_ValueForUpdateHandler.ValueForUpdateHandler()
|
|
128
132
|
};
|
|
129
133
|
class Handler {
|
|
130
134
|
/**
|
|
@@ -153,9 +157,19 @@ class Handler {
|
|
|
153
157
|
const response = handlers[command.commandType].handleCommand(command);
|
|
154
158
|
return this.parseCommand(response, command.runtimeName);
|
|
155
159
|
} catch (e) {
|
|
156
|
-
return
|
|
160
|
+
return Handler.resolveException(e, command);
|
|
157
161
|
}
|
|
158
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Prefer innerException (or cause) when available.
|
|
165
|
+
* @param {any} error
|
|
166
|
+
* @param {Command} command
|
|
167
|
+
* @returns {Command}
|
|
168
|
+
*/
|
|
169
|
+
static resolveException(error, command) {
|
|
170
|
+
const inner = error?.cause;
|
|
171
|
+
return import_ExceptionSerializer.ExceptionSerializer.serializeException(inner ?? error, command);
|
|
172
|
+
}
|
|
159
173
|
/**
|
|
160
174
|
* @param {any} response
|
|
161
175
|
* @param {RuntimeName} runtimeName
|
|
@@ -171,18 +185,18 @@ class Handler {
|
|
|
171
185
|
if (import_TypesHandler.TypesHandler.isPrimitiveOrNullOrUndefined(response)) {
|
|
172
186
|
responseCommand = import_Command.Command.createResponse(response, runtimeName);
|
|
173
187
|
} else {
|
|
174
|
-
|
|
175
|
-
|
|
188
|
+
const refCache = import_ReferencesCache.ReferencesCache.getInstance();
|
|
189
|
+
const uuid = refCache.cacheReference(response);
|
|
176
190
|
responseCommand = import_Command.Command.createReference(uuid, runtimeName);
|
|
177
191
|
}
|
|
178
|
-
const invocationContexts =
|
|
179
|
-
if (invocationContexts &&
|
|
192
|
+
const invocationContexts = import_RegisterForUpdateHandler.RegisterForUpdateHandler._invocationContexts.Value;
|
|
193
|
+
if (invocationContexts && invocationContexts.size > 0) {
|
|
180
194
|
const refCache = import_ReferencesCache.ReferencesCache.getInstance();
|
|
181
195
|
for (const [contextKey, instance] of invocationContexts.entries()) {
|
|
182
196
|
const instanceGuid = refCache.cacheReference(instance);
|
|
183
197
|
const updateContextCommand = new import_Command.Command(
|
|
184
198
|
runtimeName,
|
|
185
|
-
import_CommandType.CommandType.
|
|
199
|
+
import_CommandType.CommandType.ValueForUpdate,
|
|
186
200
|
[
|
|
187
201
|
contextKey.toString(),
|
|
188
202
|
instanceGuid
|
|
@@ -44,7 +44,7 @@ class InvokeInstanceMethodHandler extends import_AbstractHandler.AbstractHandler
|
|
|
44
44
|
let methods = Object.getOwnPropertyNames(instance.__proto__).filter(function(property) {
|
|
45
45
|
return typeof instance.__proto__[property] === "function";
|
|
46
46
|
});
|
|
47
|
-
let message = `Method ${methodName} not found in object. Available methods:
|
|
47
|
+
let message = `Method ${methodName} not found in object ${instance.constructor.name}. Available methods:
|
|
48
48
|
`;
|
|
49
49
|
methods.forEach((methodIter) => {
|
|
50
50
|
message += `${methodIter}
|
|
@@ -44,7 +44,7 @@ class InvokeStaticMethodHandler extends import_AbstractHandler.AbstractHandler {
|
|
|
44
44
|
let methods = Object.getOwnPropertyNames(type).filter(function(property) {
|
|
45
45
|
return typeof type[property] === "function";
|
|
46
46
|
});
|
|
47
|
-
let message = `Method ${methodName} not found in class. Available methods:
|
|
47
|
+
let message = `Method ${methodName} not found in class ${type.name}. Available methods:
|
|
48
48
|
`;
|
|
49
49
|
methods.forEach((methodIter) => {
|
|
50
50
|
message += `${methodIter}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var RegisterForUpdateHandler_exports = {};
|
|
20
|
+
__export(RegisterForUpdateHandler_exports, {
|
|
21
|
+
RegisterForUpdateHandler: () => RegisterForUpdateHandler
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(RegisterForUpdateHandler_exports);
|
|
24
|
+
var import_AbstractHandler = require("./AbstractHandler.cjs");
|
|
25
|
+
class RegisterForUpdateHandler extends import_AbstractHandler.AbstractHandler {
|
|
26
|
+
requiredParametersCount = 2;
|
|
27
|
+
/* type {Map<string, any>} */
|
|
28
|
+
static _invocationContexts = { Value: /* @__PURE__ */ new Map() };
|
|
29
|
+
/**
|
|
30
|
+
* Ensure context map exists and return it.
|
|
31
|
+
* @returns {Map<string, any>}
|
|
32
|
+
*/
|
|
33
|
+
static getOrCreateContextMap() {
|
|
34
|
+
const container = RegisterForUpdateHandler._invocationContexts;
|
|
35
|
+
if (!container.Value) {
|
|
36
|
+
container.Value = /* @__PURE__ */ new Map();
|
|
37
|
+
}
|
|
38
|
+
return container.Value;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @param {any} command
|
|
42
|
+
* @returns {any}
|
|
43
|
+
*/
|
|
44
|
+
process(command) {
|
|
45
|
+
if (command.payload.length < this.requiredParametersCount) {
|
|
46
|
+
throw new Error("RegisterForUpdateHandler parameters mismatch");
|
|
47
|
+
}
|
|
48
|
+
const objectToRegister = command.payload[0];
|
|
49
|
+
const guidToRegister = command.payload.length > 1 && typeof command.payload[1] === "string" ? command.payload[1] : "";
|
|
50
|
+
const contextMap = RegisterForUpdateHandler.getOrCreateContextMap();
|
|
51
|
+
if (!contextMap.has(guidToRegister)) {
|
|
52
|
+
contextMap.set(guidToRegister, objectToRegister);
|
|
53
|
+
}
|
|
54
|
+
return objectToRegister;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
58
|
+
0 && (module.exports = {
|
|
59
|
+
RegisterForUpdateHandler
|
|
60
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var ValueForUpdateHandler_exports = {};
|
|
20
|
+
__export(ValueForUpdateHandler_exports, {
|
|
21
|
+
ValueForUpdateHandler: () => ValueForUpdateHandler
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(ValueForUpdateHandler_exports);
|
|
24
|
+
var import_AbstractHandler = require("./AbstractHandler.cjs");
|
|
25
|
+
class ValueForUpdateHandler extends import_AbstractHandler.AbstractHandler {
|
|
26
|
+
/**
|
|
27
|
+
* @param {any} command
|
|
28
|
+
*/
|
|
29
|
+
process(command) {
|
|
30
|
+
throw new Error(`${this.constructor.name} is not implemented in Node.js`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
34
|
+
0 && (module.exports = {
|
|
35
|
+
ValueForUpdateHandler
|
|
36
|
+
});
|
|
@@ -29,6 +29,18 @@ var import_ExceptionThrower = require("../utils/exception/ExceptionThrower.cjs")
|
|
|
29
29
|
var import_RuntimeName = require("../utils/RuntimeName.cjs");
|
|
30
30
|
var import_TypesHandler = require("../utils/TypesHandler.cjs");
|
|
31
31
|
var import_uuid = require("uuid");
|
|
32
|
+
class AsyncLock {
|
|
33
|
+
constructor() {
|
|
34
|
+
this._tail = Promise.resolve();
|
|
35
|
+
}
|
|
36
|
+
async lock() {
|
|
37
|
+
let release;
|
|
38
|
+
const prev = this._tail;
|
|
39
|
+
this._tail = new Promise((res) => release = res);
|
|
40
|
+
await prev;
|
|
41
|
+
return () => release(void 0);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
32
44
|
class InvocationContext {
|
|
33
45
|
/** @type {RuntimeNameType} */
|
|
34
46
|
#runtimeName;
|
|
@@ -44,6 +56,8 @@ class InvocationContext {
|
|
|
44
56
|
#interpreter = null;
|
|
45
57
|
/** @type {string | null} */
|
|
46
58
|
#guid = null;
|
|
59
|
+
/** @type {AsyncLock} */
|
|
60
|
+
#materializationLock = new AsyncLock();
|
|
47
61
|
// Static map holding contexts waiting for materialization (guid -> InvocationContext)
|
|
48
62
|
static _invocationContexts = /* @__PURE__ */ new Map();
|
|
49
63
|
/**
|
|
@@ -82,7 +96,7 @@ class InvocationContext {
|
|
|
82
96
|
/**
|
|
83
97
|
* @returns {Command|null}
|
|
84
98
|
*/
|
|
85
|
-
|
|
99
|
+
getCurrentCommand() {
|
|
86
100
|
return this.#currentCommand;
|
|
87
101
|
}
|
|
88
102
|
//destructor() {
|
|
@@ -123,20 +137,73 @@ class InvocationContext {
|
|
|
123
137
|
if (!this.#interpreter) {
|
|
124
138
|
this.#interpreter = new import_Interpreter.Interpreter();
|
|
125
139
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
140
|
+
const entries = Array.from(InvocationContext._invocationContexts.entries());
|
|
141
|
+
entries.sort((a, b) => String(a[0]).localeCompare(String(b[0])));
|
|
142
|
+
const releases = [];
|
|
143
|
+
for (const [, ic] of entries) {
|
|
144
|
+
const release = await ic.#materializationLock.lock();
|
|
145
|
+
releases.push(release);
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
this.#responseCommand = await this.#interpreter.execute(this.#currentCommand, this.#connectionData);
|
|
149
|
+
if (!this.#responseCommand) {
|
|
150
|
+
throw new Error("responseCommand is undefined in Invocation Context execute method");
|
|
151
|
+
}
|
|
152
|
+
if (this.#responseCommand.commandType === import_CommandType.CommandType.Exception) {
|
|
153
|
+
throw import_ExceptionThrower.ExceptionThrower.throwException(this.#responseCommand);
|
|
154
|
+
}
|
|
155
|
+
this.#responseCommand = this.#processUpdateInvocationContextCommands(this.#responseCommand);
|
|
156
|
+
if (this.#responseCommand.commandType === import_CommandType.CommandType.CreateClassInstance) {
|
|
157
|
+
this.#currentCommand = this.#responseCommand;
|
|
158
|
+
this.#isExecuted = true;
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
return new InvocationContext(this.#runtimeName, this.#connectionData, this.#responseCommand, true);
|
|
162
|
+
} finally {
|
|
163
|
+
for (let i = releases.length - 1; i >= 0; i--) {
|
|
164
|
+
try {
|
|
165
|
+
releases[i]();
|
|
166
|
+
} catch {
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Process UpdateInvocationContext commands in the provided responseCommand payload.
|
|
173
|
+
* For each ValueForUpdate command, set the referenced InvocationContext's currentCommand to a Reference command,
|
|
174
|
+
* remove that InvocationContext from the static map and remove ValueForUpdate items from response payload.
|
|
175
|
+
* @param {Command} responseCommand
|
|
176
|
+
* @returns {Command}
|
|
177
|
+
*/
|
|
178
|
+
#processUpdateInvocationContextCommands(responseCommand) {
|
|
179
|
+
if (!responseCommand?.payload || responseCommand.payload.length === 0) {
|
|
180
|
+
return responseCommand;
|
|
181
|
+
}
|
|
182
|
+
const commandsToUpdate = [];
|
|
183
|
+
for (const item of responseCommand.payload) {
|
|
184
|
+
if (item instanceof import_Command.Command && item.commandType === import_CommandType.CommandType.ValueForUpdate) {
|
|
185
|
+
commandsToUpdate.push(item);
|
|
186
|
+
}
|
|
129
187
|
}
|
|
130
|
-
if (
|
|
131
|
-
|
|
188
|
+
if (commandsToUpdate.length === 0) {
|
|
189
|
+
return responseCommand;
|
|
132
190
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
191
|
+
const updatedPayload = Array.from(responseCommand.payload);
|
|
192
|
+
for (const cmd of commandsToUpdate) {
|
|
193
|
+
const cmdPayload = cmd.payload;
|
|
194
|
+
if (cmdPayload && cmdPayload.length >= 2) {
|
|
195
|
+
const contextGuid = String(cmdPayload[0]);
|
|
196
|
+
const instanceGuid = String(cmdPayload[1]);
|
|
197
|
+
const invCtx = InvocationContext._invocationContexts.get(contextGuid);
|
|
198
|
+
if (invCtx) {
|
|
199
|
+
invCtx.#currentCommand = new import_Command.Command(invCtx.#runtimeName, import_CommandType.CommandType.Reference, [instanceGuid]);
|
|
200
|
+
InvocationContext._invocationContexts.delete(contextGuid);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const idx = updatedPayload.indexOf(cmd);
|
|
204
|
+
if (idx >= 0) updatedPayload.splice(idx, 1);
|
|
138
205
|
}
|
|
139
|
-
return new
|
|
206
|
+
return new import_Command.Command(responseCommand.runtimeName, responseCommand.commandType, updatedPayload);
|
|
140
207
|
}
|
|
141
208
|
/**
|
|
142
209
|
* Invokes a static method on the target runtime.
|
|
@@ -185,17 +252,18 @@ class InvocationContext {
|
|
|
185
252
|
* @method
|
|
186
253
|
*/
|
|
187
254
|
createInstance(...args) {
|
|
188
|
-
const
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
255
|
+
const localCommand = new import_Command.Command(this.#runtimeName, import_CommandType.CommandType.CreateClassInstance, [...args]);
|
|
256
|
+
const createInstanceInvCtx = this.#createInstanceContext(localCommand);
|
|
257
|
+
return createInstanceInvCtx.#registerForUpdate();
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Registers the current InvocationContext for updates.
|
|
261
|
+
* @returns {InvocationContext}
|
|
262
|
+
*/
|
|
263
|
+
#registerForUpdate() {
|
|
264
|
+
this.#currentCommand = this.#buildCommand(new import_Command.Command(this.#runtimeName, import_CommandType.CommandType.RegisterForUpdate, [this.getGuid()]));
|
|
265
|
+
InvocationContext._invocationContexts.set(this.getGuid(), this);
|
|
266
|
+
return this;
|
|
199
267
|
}
|
|
200
268
|
/**
|
|
201
269
|
* Retrieves the value of an instance field from the target runtime.
|
|
@@ -467,7 +535,7 @@ class InvocationContext {
|
|
|
467
535
|
}
|
|
468
536
|
return payloadItem;
|
|
469
537
|
} else if (payloadItem instanceof InvocationContext) {
|
|
470
|
-
return payloadItem.
|
|
538
|
+
return payloadItem.getCurrentCommand();
|
|
471
539
|
} else if (payloadItem instanceof Array) {
|
|
472
540
|
const copiedArray = payloadItem.map((item) => this.#encapsulatePayloadItem(item));
|
|
473
541
|
return new import_Command.Command(this.#runtimeName, import_CommandType.CommandType.Array, copiedArray);
|
|
@@ -487,42 +555,6 @@ class InvocationContext {
|
|
|
487
555
|
);
|
|
488
556
|
}
|
|
489
557
|
}
|
|
490
|
-
/**
|
|
491
|
-
* Process UpdateInvocationContext commands in the provided responseCommand payload.
|
|
492
|
-
* For each UpdateInvocationContext command, set the referenced InvocationContext's currentCommand to a Reference command,
|
|
493
|
-
* remove that InvocationContext from the static map and remove UpdateInvocationContext items from response payload.
|
|
494
|
-
* @param {Command} responseCommand
|
|
495
|
-
* @returns {Command}
|
|
496
|
-
*/
|
|
497
|
-
#processUpdateInvocationContextCommands(responseCommand) {
|
|
498
|
-
if (!responseCommand?.payload?.length) {
|
|
499
|
-
return responseCommand;
|
|
500
|
-
}
|
|
501
|
-
const commandsToUpdate = responseCommand.payload.filter(
|
|
502
|
-
(item) => item instanceof import_Command.Command && item.commandType === import_CommandType.CommandType.UpdateInvocationContext
|
|
503
|
-
);
|
|
504
|
-
if (commandsToUpdate.length === 0) {
|
|
505
|
-
return responseCommand;
|
|
506
|
-
}
|
|
507
|
-
const updatedPayload = new Set(responseCommand.payload);
|
|
508
|
-
for (const cmd of commandsToUpdate) {
|
|
509
|
-
if (cmd.payload?.length >= 2) {
|
|
510
|
-
const contextGuid = String(cmd.payload[0]);
|
|
511
|
-
const instanceGuid = cmd.payload[1];
|
|
512
|
-
const invCtx = InvocationContext._invocationContexts.get(contextGuid);
|
|
513
|
-
if (invCtx) {
|
|
514
|
-
invCtx.#currentCommand = new import_Command.Command(invCtx.#runtimeName, import_CommandType.CommandType.Reference, [instanceGuid]);
|
|
515
|
-
InvocationContext._invocationContexts.delete(contextGuid);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
updatedPayload.delete(cmd);
|
|
519
|
-
}
|
|
520
|
-
return new import_Command.Command(
|
|
521
|
-
responseCommand.runtimeName,
|
|
522
|
-
responseCommand.commandType,
|
|
523
|
-
Array.from(updatedPayload)
|
|
524
|
-
);
|
|
525
|
-
}
|
|
526
558
|
}
|
|
527
559
|
// Annotate the CommonJS export names for ESM import in node:
|
|
528
560
|
0 && (module.exports = {
|
|
@@ -284,7 +284,7 @@ class RuntimeContext {
|
|
|
284
284
|
}
|
|
285
285
|
return payloadItem;
|
|
286
286
|
} else if (payloadItem instanceof import_InvocationContext.InvocationContext) {
|
|
287
|
-
const command = payloadItem?.
|
|
287
|
+
const command = payloadItem?.getCurrentCommand();
|
|
288
288
|
if (!command) {
|
|
289
289
|
throw new Error("Command not found");
|
|
290
290
|
}
|
|
@@ -3,14 +3,6 @@ export type Command = import("../../utils/Command.js").Command;
|
|
|
3
3
|
* @typedef {import('../../utils/Command.js').Command} Command
|
|
4
4
|
*/
|
|
5
5
|
export class CreateClassInstanceHandler extends AbstractHandler {
|
|
6
|
-
static _invocationContexts: Map<any, any>;
|
|
7
|
-
static getOrCreateContextDictionary(): Map<any, any>;
|
|
8
|
-
/**
|
|
9
|
-
* @param {{ toString: () => any; } | null} value
|
|
10
|
-
*/
|
|
11
|
-
static isGuid(value: {
|
|
12
|
-
toString: () => any;
|
|
13
|
-
} | null): boolean;
|
|
14
6
|
requiredParametersCount: number;
|
|
15
7
|
/**
|
|
16
8
|
* @param {Command} command
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
export type RuntimeName = import("../../types.d.ts").RuntimeName;
|
|
2
2
|
export class Handler {
|
|
3
|
+
/**
|
|
4
|
+
* Prefer innerException (or cause) when available.
|
|
5
|
+
* @param {any} error
|
|
6
|
+
* @param {Command} command
|
|
7
|
+
* @returns {Command}
|
|
8
|
+
*/
|
|
9
|
+
static resolveException(error: any, command: Command): Command;
|
|
3
10
|
/**
|
|
4
11
|
* @param {import('../interpreter/Interpreter.js').Interpreter} interpreter
|
|
5
12
|
*/
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class RegisterForUpdateHandler extends AbstractHandler {
|
|
2
|
+
static _invocationContexts: {
|
|
3
|
+
Value: Map<any, any>;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Ensure context map exists and return it.
|
|
7
|
+
* @returns {Map<string, any>}
|
|
8
|
+
*/
|
|
9
|
+
static getOrCreateContextMap(): Map<string, any>;
|
|
10
|
+
requiredParametersCount: number;
|
|
11
|
+
/**
|
|
12
|
+
* @param {any} command
|
|
13
|
+
* @returns {any}
|
|
14
|
+
*/
|
|
15
|
+
process(command: any): any;
|
|
16
|
+
}
|
|
17
|
+
import { AbstractHandler } from './AbstractHandler.js';
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export type RuntimeNameType = import("../types.d.ts").RuntimeName;
|
|
2
2
|
export type IConnectionData = import("../utils/connectionData/IConnectionData.js").IConnectionData;
|
|
3
|
-
/**
|
|
4
|
-
* @typedef {import('../types.d.ts').RuntimeName} RuntimeNameType
|
|
5
|
-
* @typedef {import('../utils/connectionData/IConnectionData.js').IConnectionData} IConnectionData
|
|
6
|
-
*/
|
|
7
3
|
/**
|
|
8
4
|
* InvocationContext is a class that represents a context for invoking commands.
|
|
9
5
|
* It implements several interfaces for different types of interactions.
|
|
@@ -28,7 +24,7 @@ export class InvocationContext {
|
|
|
28
24
|
/**
|
|
29
25
|
* @returns {Command|null}
|
|
30
26
|
*/
|
|
31
|
-
|
|
27
|
+
getCurrentCommand(): Command | null;
|
|
32
28
|
/**
|
|
33
29
|
* Executes the current command.
|
|
34
30
|
* Returns the InvocationContext after executing the command.
|
|
@@ -8,28 +8,10 @@ import { AbstractHandler } from './AbstractHandler.js'
|
|
|
8
8
|
class CreateClassInstanceHandler extends AbstractHandler {
|
|
9
9
|
requiredParametersCount = 1
|
|
10
10
|
|
|
11
|
-
// Add a simple invocation contexts store (Map GUID -> object)
|
|
12
|
-
static _invocationContexts = new Map()
|
|
13
|
-
|
|
14
|
-
static getOrCreateContextDictionary() {
|
|
15
|
-
// In a simple approach we keep a single map for the process.
|
|
16
|
-
return CreateClassInstanceHandler._invocationContexts
|
|
17
|
-
}
|
|
18
|
-
|
|
19
11
|
constructor() {
|
|
20
12
|
super()
|
|
21
13
|
}
|
|
22
14
|
|
|
23
|
-
// Helper to detect GUID in payload (standard format)
|
|
24
|
-
/**
|
|
25
|
-
* @param {{ toString: () => any; } | null} value
|
|
26
|
-
*/
|
|
27
|
-
static isGuid(value) {
|
|
28
|
-
if (value == null) return false
|
|
29
|
-
const s = value.toString()
|
|
30
|
-
return /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(s)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
15
|
/**
|
|
34
16
|
* @param {Command} command
|
|
35
17
|
*/
|
|
@@ -38,29 +20,8 @@ class CreateClassInstanceHandler extends AbstractHandler {
|
|
|
38
20
|
if (command.payload.length < this.requiredParametersCount) {
|
|
39
21
|
throw new Error('Create Class Instance parameters mismatch')
|
|
40
22
|
}
|
|
41
|
-
|
|
42
23
|
let clazz = command.payload[0]
|
|
43
|
-
|
|
44
|
-
// Extract optional GUID and constructor arguments
|
|
45
|
-
let payloadLength = command.payload.length
|
|
46
|
-
let contextGuid = null
|
|
47
|
-
let constructorArguments = []
|
|
48
|
-
|
|
49
|
-
if (payloadLength > 1 && CreateClassInstanceHandler.isGuid(command.payload[1])) {
|
|
50
|
-
contextGuid = command.payload[1].toString()
|
|
51
|
-
if (payloadLength > 2) {
|
|
52
|
-
constructorArguments = command.payload.slice(2)
|
|
53
|
-
} else {
|
|
54
|
-
constructorArguments = []
|
|
55
|
-
}
|
|
56
|
-
} else {
|
|
57
|
-
if (payloadLength > 1) {
|
|
58
|
-
constructorArguments = command.payload.slice(1)
|
|
59
|
-
} else {
|
|
60
|
-
constructorArguments = []
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
24
|
+
let constructorArguments = command.payload.slice(1)
|
|
64
25
|
let instance = new clazz(...constructorArguments)
|
|
65
26
|
if (typeof instance === 'undefined') {
|
|
66
27
|
let methods = Object.getOwnPropertyNames(clazz).filter(function (property) {
|
|
@@ -72,12 +33,6 @@ class CreateClassInstanceHandler extends AbstractHandler {
|
|
|
72
33
|
})
|
|
73
34
|
throw new Error(message)
|
|
74
35
|
} else {
|
|
75
|
-
// If GUID provided, store instance in context dictionary
|
|
76
|
-
if (contextGuid) {
|
|
77
|
-
const contextDict = CreateClassInstanceHandler.getOrCreateContextDictionary()
|
|
78
|
-
// Overwrite or add entry
|
|
79
|
-
contextDict.set(contextGuid, instance)
|
|
80
|
-
}
|
|
81
36
|
return instance
|
|
82
37
|
}
|
|
83
38
|
} catch (error) {
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
//@ts-check
|
|
2
|
+
|
|
3
|
+
import { CommandType } from '../../utils/CommandType.js'
|
|
4
|
+
import { Command } from '../../utils/Command.js'
|
|
5
|
+
import { TypesHandler } from '../../utils/TypesHandler.js'
|
|
6
|
+
import { ExceptionSerializer } from '../../utils/exception/ExceptionSerializer.js'
|
|
7
|
+
import { AbstractHandler } from './AbstractHandler.js'
|
|
8
|
+
|
|
2
9
|
import { ReferencesCache } from '../referenceCache/ReferencesCache.js'
|
|
3
10
|
import { ValueHandler } from './ValueHandler.js'
|
|
4
11
|
import { LoadLibraryHandler } from './LoadLibraryHandler.js'
|
|
@@ -48,11 +55,8 @@ import { GetAsyncOperationResultHandler } from './GetAsyncOperationResultHandler
|
|
|
48
55
|
import { AsKwargsHandler } from './AsKwargsHandler.js'
|
|
49
56
|
import { GetResultTypeHandler } from './GetResultTypeHandler.js'
|
|
50
57
|
import { GetGlobalFieldHandler } from './GetGlobalFieldHandler.js'
|
|
51
|
-
import {
|
|
52
|
-
import {
|
|
53
|
-
import { TypesHandler } from '../../utils/TypesHandler.js'
|
|
54
|
-
import { ExceptionSerializer } from '../../utils/exception/ExceptionSerializer.js'
|
|
55
|
-
import { AbstractHandler } from './AbstractHandler.js'
|
|
58
|
+
import { RegisterForUpdateHandler } from './RegisterForUpdateHandler.js'
|
|
59
|
+
import { ValueForUpdateHandler } from './ValueForUpdateHandler.js'
|
|
56
60
|
|
|
57
61
|
/**
|
|
58
62
|
* @typedef {import('../../types.d.ts').RuntimeName} RuntimeName
|
|
@@ -110,6 +114,8 @@ const handlers = {
|
|
|
110
114
|
[CommandType.AsKwargs]: new AsKwargsHandler(),
|
|
111
115
|
[CommandType.GetResultType]: new GetResultTypeHandler(),
|
|
112
116
|
[CommandType.GetGlobalField]: new GetGlobalFieldHandler(),
|
|
117
|
+
[CommandType.RegisterForUpdate]: new RegisterForUpdateHandler(),
|
|
118
|
+
[CommandType.ValueForUpdate]: new ValueForUpdateHandler(),
|
|
113
119
|
}
|
|
114
120
|
|
|
115
121
|
class Handler {
|
|
@@ -144,14 +150,26 @@ class Handler {
|
|
|
144
150
|
const responseArray = handlers[CommandType.Reference].handleCommand(command.payload[0])
|
|
145
151
|
return Command.createArrayResponse(responseArray, command.runtimeName)
|
|
146
152
|
}
|
|
153
|
+
|
|
147
154
|
/** @type {any} */
|
|
148
155
|
const response = handlers[command.commandType].handleCommand(command)
|
|
149
156
|
return this.parseCommand(response, command.runtimeName)
|
|
150
157
|
} catch (e) {
|
|
151
|
-
return
|
|
158
|
+
return Handler.resolveException(e, command)
|
|
152
159
|
}
|
|
153
160
|
}
|
|
154
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Prefer innerException (or cause) when available.
|
|
164
|
+
* @param {any} error
|
|
165
|
+
* @param {Command} command
|
|
166
|
+
* @returns {Command}
|
|
167
|
+
*/
|
|
168
|
+
static resolveException(error, command) {
|
|
169
|
+
const inner = error?.cause
|
|
170
|
+
return ExceptionSerializer.serializeException(inner ?? error, command)
|
|
171
|
+
}
|
|
172
|
+
|
|
155
173
|
/**
|
|
156
174
|
* @param {any} response
|
|
157
175
|
* @param {RuntimeName} runtimeName
|
|
@@ -164,30 +182,28 @@ class Handler {
|
|
|
164
182
|
})
|
|
165
183
|
}
|
|
166
184
|
|
|
167
|
-
// Create base responseCommand (either primitive response or a reference)
|
|
168
185
|
let responseCommand
|
|
169
186
|
if (TypesHandler.isPrimitiveOrNullOrUndefined(response)) {
|
|
170
187
|
responseCommand = Command.createResponse(response, runtimeName)
|
|
171
188
|
} else {
|
|
172
|
-
|
|
173
|
-
|
|
189
|
+
const refCache = ReferencesCache.getInstance()
|
|
190
|
+
const uuid = refCache.cacheReference(response)
|
|
174
191
|
responseCommand = Command.createReference(uuid, runtimeName)
|
|
175
192
|
}
|
|
176
193
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (invocationContexts && typeof invocationContexts.size === 'number' && invocationContexts.size > 0) {
|
|
194
|
+
const invocationContexts = RegisterForUpdateHandler._invocationContexts.Value
|
|
195
|
+
if (invocationContexts && invocationContexts.size > 0) {
|
|
180
196
|
const refCache = ReferencesCache.getInstance()
|
|
181
197
|
for (const [contextKey, instance] of invocationContexts.entries()) {
|
|
182
198
|
const instanceGuid = refCache.cacheReference(instance)
|
|
199
|
+
|
|
183
200
|
const updateContextCommand = new Command(
|
|
184
201
|
runtimeName,
|
|
185
|
-
CommandType.
|
|
202
|
+
CommandType.ValueForUpdate,
|
|
186
203
|
[contextKey.toString(),
|
|
187
204
|
instanceGuid]
|
|
188
205
|
)
|
|
189
206
|
|
|
190
|
-
// Prefer using addArgToPayload if available, otherwise push into payload array
|
|
191
207
|
if (typeof responseCommand.addArgToPayload === 'function') {
|
|
192
208
|
responseCommand = responseCommand.addArgToPayload(updateContextCommand)
|
|
193
209
|
} else {
|
|
@@ -196,7 +212,7 @@ class Handler {
|
|
|
196
212
|
}
|
|
197
213
|
}
|
|
198
214
|
|
|
199
|
-
// Clear
|
|
215
|
+
// Clear all entries after processing this request
|
|
200
216
|
invocationContexts.clear()
|
|
201
217
|
}
|
|
202
218
|
|
|
@@ -29,7 +29,7 @@ class InvokeInstanceMethodHandler extends AbstractHandler {
|
|
|
29
29
|
let methods = Object.getOwnPropertyNames(instance.__proto__).filter(function (property) {
|
|
30
30
|
return typeof instance.__proto__[property] === 'function'
|
|
31
31
|
})
|
|
32
|
-
let message = `Method ${methodName} not found in object. Available methods:\n`
|
|
32
|
+
let message = `Method ${methodName} not found in object ${instance.constructor.name}. Available methods:\n`
|
|
33
33
|
methods.forEach((methodIter) => {
|
|
34
34
|
message += `${methodIter}\n`
|
|
35
35
|
})
|
|
@@ -29,7 +29,7 @@ class InvokeStaticMethodHandler extends AbstractHandler {
|
|
|
29
29
|
let methods = Object.getOwnPropertyNames(type).filter(function (property) {
|
|
30
30
|
return typeof type[property] === 'function'
|
|
31
31
|
})
|
|
32
|
-
let message = `Method ${methodName} not found in class. Available methods:\n`
|
|
32
|
+
let message = `Method ${methodName} not found in class ${type.name}. Available methods:\n`
|
|
33
33
|
methods.forEach((methodIter) => {
|
|
34
34
|
message += `${methodIter}\n`
|
|
35
35
|
})
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { AbstractHandler } from './AbstractHandler.js'
|
|
3
|
+
|
|
4
|
+
export class RegisterForUpdateHandler extends AbstractHandler {
|
|
5
|
+
requiredParametersCount = 2
|
|
6
|
+
/* type {Map<string, any>} */
|
|
7
|
+
static _invocationContexts = { Value: new Map() }
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Ensure context map exists and return it.
|
|
11
|
+
* @returns {Map<string, any>}
|
|
12
|
+
*/
|
|
13
|
+
static getOrCreateContextMap() {
|
|
14
|
+
const container = RegisterForUpdateHandler._invocationContexts
|
|
15
|
+
if (!container.Value) {
|
|
16
|
+
container.Value = new Map()
|
|
17
|
+
}
|
|
18
|
+
return container.Value
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {any} command
|
|
23
|
+
* @returns {any}
|
|
24
|
+
*/
|
|
25
|
+
process(command) {
|
|
26
|
+
if (command.payload.length < this.requiredParametersCount) {
|
|
27
|
+
throw new Error('RegisterForUpdateHandler parameters mismatch')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const objectToRegister = command.payload[0]
|
|
31
|
+
const guidToRegister = command.payload.length > 1 && typeof command.payload[1] === 'string' ? command.payload[1] : '' // Guid.Empty -> empty string
|
|
32
|
+
|
|
33
|
+
const contextMap = RegisterForUpdateHandler.getOrCreateContextMap()
|
|
34
|
+
if (!contextMap.has(guidToRegister)) {
|
|
35
|
+
contextMap.set(guidToRegister, objectToRegister)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return objectToRegister
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { AbstractHandler } from './AbstractHandler.js'
|
|
3
|
+
|
|
4
|
+
export class ValueForUpdateHandler extends AbstractHandler {
|
|
5
|
+
/**
|
|
6
|
+
* @param {any} command
|
|
7
|
+
*/
|
|
8
|
+
process(command) {
|
|
9
|
+
throw new Error(`${this.constructor.name} is not implemented in Node.js`)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -13,6 +13,25 @@ import { v4 as uuidv4 } from 'uuid' // add lightweight uuid generation
|
|
|
13
13
|
* @typedef {import('../utils/connectionData/IConnectionData.js').IConnectionData} IConnectionData
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Simple async lock implementation to ensure sequential execution of critical sections.
|
|
18
|
+
*/
|
|
19
|
+
class AsyncLock {
|
|
20
|
+
constructor() {
|
|
21
|
+
this._tail = Promise.resolve()
|
|
22
|
+
}
|
|
23
|
+
async lock() {
|
|
24
|
+
/**
|
|
25
|
+
* @type {(value?: any) => void}
|
|
26
|
+
*/
|
|
27
|
+
let release
|
|
28
|
+
const prev = this._tail
|
|
29
|
+
this._tail = new Promise((res) => (release = res))
|
|
30
|
+
await prev
|
|
31
|
+
return () => release(undefined)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
16
35
|
/**
|
|
17
36
|
* InvocationContext is a class that represents a context for invoking commands.
|
|
18
37
|
* It implements several interfaces for different types of interactions.
|
|
@@ -35,6 +54,8 @@ class InvocationContext {
|
|
|
35
54
|
#interpreter = null
|
|
36
55
|
/** @type {string | null} */
|
|
37
56
|
#guid = null
|
|
57
|
+
/** @type {AsyncLock} */
|
|
58
|
+
#materializationLock = new AsyncLock()
|
|
38
59
|
|
|
39
60
|
// Static map holding contexts waiting for materialization (guid -> InvocationContext)
|
|
40
61
|
static _invocationContexts = new Map()
|
|
@@ -79,7 +100,7 @@ class InvocationContext {
|
|
|
79
100
|
/**
|
|
80
101
|
* @returns {Command|null}
|
|
81
102
|
*/
|
|
82
|
-
|
|
103
|
+
getCurrentCommand() {
|
|
83
104
|
return this.#currentCommand
|
|
84
105
|
}
|
|
85
106
|
|
|
@@ -121,30 +142,92 @@ class InvocationContext {
|
|
|
121
142
|
if (this.#currentCommand === null) {
|
|
122
143
|
throw new Error('currentCommand is undefined in Invocation Context execute method')
|
|
123
144
|
}
|
|
124
|
-
|
|
125
145
|
if (!this.#interpreter) {
|
|
126
146
|
this.#interpreter = new Interpreter()
|
|
127
147
|
}
|
|
128
148
|
|
|
129
|
-
//
|
|
130
|
-
|
|
149
|
+
// Zablokuj wszystkie konteksty do materializacji w deterministycznej kolejności (po GUID)
|
|
150
|
+
const entries = Array.from(InvocationContext._invocationContexts.entries())
|
|
151
|
+
entries.sort((a, b) => String(a[0]).localeCompare(String(b[0])))
|
|
152
|
+
const releases = []
|
|
153
|
+
for (const [, ic] of entries) {
|
|
154
|
+
// eslint-disable-next-line no-await-in-loop
|
|
155
|
+
const release = await ic.#materializationLock.lock()
|
|
156
|
+
releases.push(release)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
// Execute command on interpreter
|
|
161
|
+
this.#responseCommand = await this.#interpreter.execute(this.#currentCommand, this.#connectionData)
|
|
162
|
+
|
|
163
|
+
if (!this.#responseCommand) {
|
|
164
|
+
throw new Error('responseCommand is undefined in Invocation Context execute method')
|
|
165
|
+
}
|
|
166
|
+
if (this.#responseCommand.commandType === CommandType.Exception) {
|
|
167
|
+
throw ExceptionThrower.throwException(this.#responseCommand)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Process ValueForUpdate commands (jeśli są) przychodzące z runtime
|
|
171
|
+
this.#responseCommand = this.#processUpdateInvocationContextCommands(this.#responseCommand)
|
|
172
|
+
|
|
173
|
+
if (this.#responseCommand.commandType === CommandType.CreateClassInstance) {
|
|
174
|
+
this.#currentCommand = this.#responseCommand
|
|
175
|
+
this.#isExecuted = true
|
|
176
|
+
return this
|
|
177
|
+
}
|
|
178
|
+
return new InvocationContext(this.#runtimeName, this.#connectionData, this.#responseCommand, true)
|
|
179
|
+
} finally {
|
|
180
|
+
// Zwolnij locki w odwrotnej kolejności
|
|
181
|
+
for (let i = releases.length - 1; i >= 0; i--) {
|
|
182
|
+
try { releases[i]() } catch { /* ignore */ }
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Process UpdateInvocationContext commands in the provided responseCommand payload.
|
|
189
|
+
* For each ValueForUpdate command, set the referenced InvocationContext's currentCommand to a Reference command,
|
|
190
|
+
* remove that InvocationContext from the static map and remove ValueForUpdate items from response payload.
|
|
191
|
+
* @param {Command} responseCommand
|
|
192
|
+
* @returns {Command}
|
|
193
|
+
*/
|
|
194
|
+
#processUpdateInvocationContextCommands(responseCommand) {
|
|
195
|
+
if (!responseCommand?.payload || responseCommand.payload.length === 0) {
|
|
196
|
+
return responseCommand
|
|
197
|
+
}
|
|
131
198
|
|
|
132
|
-
|
|
133
|
-
|
|
199
|
+
/** @type {Command[]} */
|
|
200
|
+
const commandsToUpdate = []
|
|
201
|
+
for (const item of responseCommand.payload) {
|
|
202
|
+
if (item instanceof Command && item.commandType === CommandType.ValueForUpdate) {
|
|
203
|
+
commandsToUpdate.push(item)
|
|
204
|
+
}
|
|
134
205
|
}
|
|
135
|
-
if (
|
|
136
|
-
|
|
206
|
+
if (commandsToUpdate.length === 0) {
|
|
207
|
+
return responseCommand
|
|
137
208
|
}
|
|
138
209
|
|
|
139
|
-
//
|
|
140
|
-
|
|
210
|
+
// create a copy of the payload to modify
|
|
211
|
+
const updatedPayload = Array.from(responseCommand.payload)
|
|
141
212
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
213
|
+
// update each InvocationContext referenced in ValueForUpdate commands
|
|
214
|
+
for (const cmd of commandsToUpdate) {
|
|
215
|
+
const cmdPayload = cmd.payload
|
|
216
|
+
if (cmdPayload && cmdPayload.length >= 2) {
|
|
217
|
+
const contextGuid = String(cmdPayload[0])
|
|
218
|
+
const instanceGuid = String(cmdPayload[1])
|
|
219
|
+
const invCtx = InvocationContext._invocationContexts.get(contextGuid)
|
|
220
|
+
if (invCtx) {
|
|
221
|
+
invCtx.#currentCommand = new Command(invCtx.#runtimeName, CommandType.Reference, [instanceGuid])
|
|
222
|
+
InvocationContext._invocationContexts.delete(contextGuid)
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// remove ValueForUpdate command from payload
|
|
226
|
+
const idx = updatedPayload.indexOf(cmd)
|
|
227
|
+
if (idx >= 0) updatedPayload.splice(idx, 1)
|
|
146
228
|
}
|
|
147
|
-
|
|
229
|
+
|
|
230
|
+
return new Command(responseCommand.runtimeName, responseCommand.commandType, updatedPayload)
|
|
148
231
|
}
|
|
149
232
|
|
|
150
233
|
/**
|
|
@@ -197,23 +280,19 @@ class InvocationContext {
|
|
|
197
280
|
* @method
|
|
198
281
|
*/
|
|
199
282
|
createInstance(...args) {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
// include guid as first payload element followed by constructor args
|
|
205
|
-
let localCommand = new Command(this.#runtimeName, CommandType.CreateClassInstance, [
|
|
206
|
-
createInstanceContext.getGuid(),
|
|
207
|
-
...args,
|
|
208
|
-
])
|
|
209
|
-
|
|
210
|
-
// set current command for the new context
|
|
211
|
-
createInstanceContext.#currentCommand = this.#buildCommand(localCommand)
|
|
212
|
-
|
|
213
|
-
// register context for materialization
|
|
214
|
-
InvocationContext._invocationContexts.set(createInstanceContext.getGuid(), createInstanceContext)
|
|
283
|
+
const localCommand = new Command(this.#runtimeName, CommandType.CreateClassInstance, [...args])
|
|
284
|
+
const createInstanceInvCtx = this.#createInstanceContext(localCommand)
|
|
285
|
+
return createInstanceInvCtx.#registerForUpdate()
|
|
286
|
+
}
|
|
215
287
|
|
|
216
|
-
|
|
288
|
+
/**
|
|
289
|
+
* Registers the current InvocationContext for updates.
|
|
290
|
+
* @returns {InvocationContext}
|
|
291
|
+
*/
|
|
292
|
+
#registerForUpdate() {
|
|
293
|
+
this.#currentCommand = this.#buildCommand(new Command(this.#runtimeName, CommandType.RegisterForUpdate, [this.getGuid()]))
|
|
294
|
+
InvocationContext._invocationContexts.set(this.getGuid(), this)
|
|
295
|
+
return this
|
|
217
296
|
}
|
|
218
297
|
|
|
219
298
|
/**
|
|
@@ -514,7 +593,7 @@ class InvocationContext {
|
|
|
514
593
|
return payloadItem
|
|
515
594
|
// eslint-disable-next-line valid-typeof
|
|
516
595
|
} else if (payloadItem instanceof InvocationContext) {
|
|
517
|
-
return payloadItem.
|
|
596
|
+
return payloadItem.getCurrentCommand()
|
|
518
597
|
} else if (payloadItem instanceof Array) {
|
|
519
598
|
const copiedArray = payloadItem.map((item) => this.#encapsulatePayloadItem(item))
|
|
520
599
|
return new Command(this.#runtimeName, CommandType.Array, copiedArray)
|
|
@@ -537,49 +616,6 @@ class InvocationContext {
|
|
|
537
616
|
)
|
|
538
617
|
}
|
|
539
618
|
}
|
|
540
|
-
|
|
541
|
-
/**
|
|
542
|
-
* Process UpdateInvocationContext commands in the provided responseCommand payload.
|
|
543
|
-
* For each UpdateInvocationContext command, set the referenced InvocationContext's currentCommand to a Reference command,
|
|
544
|
-
* remove that InvocationContext from the static map and remove UpdateInvocationContext items from response payload.
|
|
545
|
-
* @param {Command} responseCommand
|
|
546
|
-
* @returns {Command}
|
|
547
|
-
*/
|
|
548
|
-
#processUpdateInvocationContextCommands(responseCommand) {
|
|
549
|
-
if (!responseCommand?.payload?.length) {
|
|
550
|
-
return responseCommand
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
const commandsToUpdate = responseCommand.payload.filter(
|
|
554
|
-
(/** @type {unknown} */ item) => item instanceof Command && item.commandType === CommandType.UpdateInvocationContext
|
|
555
|
-
)
|
|
556
|
-
|
|
557
|
-
if (commandsToUpdate.length === 0) {
|
|
558
|
-
return responseCommand
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
const updatedPayload = new Set(responseCommand.payload)
|
|
562
|
-
|
|
563
|
-
for (const cmd of commandsToUpdate) {
|
|
564
|
-
if (cmd.payload?.length >= 2) {
|
|
565
|
-
const contextGuid = String(cmd.payload[0])
|
|
566
|
-
const instanceGuid = cmd.payload[1]
|
|
567
|
-
const invCtx = InvocationContext._invocationContexts.get(contextGuid)
|
|
568
|
-
|
|
569
|
-
if (invCtx) {
|
|
570
|
-
invCtx.#currentCommand = new Command(invCtx.#runtimeName, CommandType.Reference, [instanceGuid])
|
|
571
|
-
InvocationContext._invocationContexts.delete(contextGuid)
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
updatedPayload.delete(cmd)
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
return new Command(
|
|
578
|
-
responseCommand.runtimeName,
|
|
579
|
-
responseCommand.commandType,
|
|
580
|
-
Array.from(updatedPayload)
|
|
581
|
-
)
|
|
582
|
-
}
|
|
583
619
|
}
|
|
584
620
|
|
|
585
621
|
export { InvocationContext }
|
|
@@ -303,7 +303,7 @@ class RuntimeContext {
|
|
|
303
303
|
}
|
|
304
304
|
return payloadItem
|
|
305
305
|
} else if (payloadItem instanceof InvocationContext) {
|
|
306
|
-
const command = payloadItem?.
|
|
306
|
+
const command = payloadItem?.getCurrentCommand()
|
|
307
307
|
if (!command) {
|
|
308
308
|
throw new Error('Command not found')
|
|
309
309
|
}
|
package/lib/utils/CommandType.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "javonet-nodejs-sdk",
|
|
3
|
-
"version": "2.6.
|
|
3
|
+
"version": "2.6.10",
|
|
4
4
|
"description": "Javonet allows you to reference and use modules or packages written in (Java/Kotlin/Groovy/Clojure, C#/VB.NET, Ruby, Perl, Python, JavaScript/TypeScript) like they were created in your technology. It works on Linux/Windows and MacOS for applications created in JVM, CLR/Netcore, Perl, Python, Ruby, NodeJS, C++ or GoLang and gives you unparalleled freedom and flexibility with native performance in building your mixed-technologies products. Let it be accessing best AI or cryptography libraries, devices SDKs, legacy client modules, internal custom packages or anything from public repositories available on NPM, Nuget, PyPI, Maven/Gradle, RubyGems or GitHub. Get free from programming languages barriers today! For more information check out our guides at https://www.javonet.com/guides/v2/",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "SdNCenter Sp. z o. o.",
|