javonet-nodejs-sdk 2.6.8 → 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/Handler.cjs +49 -11
- 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 +108 -23
- package/dist/sdk/RuntimeContext.cjs +1 -1
- 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 +10 -13
- package/dist/types/utils/CommandType.d.ts +2 -0
- package/dist/utils/CommandType.cjs +3 -1
- package/lib/core/handler/Handler.js +56 -10
- 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 +136 -27
- package/lib/sdk/RuntimeContext.js +1 -1
- package/lib/utils/CommandType.js +2 -0
- package/package.json +4 -3
|
@@ -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
|
|
@@ -167,13 +181,37 @@ class Handler {
|
|
|
167
181
|
return this.parseCommand(resolvedResponse, runtimeName);
|
|
168
182
|
});
|
|
169
183
|
}
|
|
184
|
+
let responseCommand;
|
|
170
185
|
if (import_TypesHandler.TypesHandler.isPrimitiveOrNullOrUndefined(response)) {
|
|
171
|
-
|
|
186
|
+
responseCommand = import_Command.Command.createResponse(response, runtimeName);
|
|
172
187
|
} else {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
188
|
+
const refCache = import_ReferencesCache.ReferencesCache.getInstance();
|
|
189
|
+
const uuid = refCache.cacheReference(response);
|
|
190
|
+
responseCommand = import_Command.Command.createReference(uuid, runtimeName);
|
|
191
|
+
}
|
|
192
|
+
const invocationContexts = import_RegisterForUpdateHandler.RegisterForUpdateHandler._invocationContexts.Value;
|
|
193
|
+
if (invocationContexts && invocationContexts.size > 0) {
|
|
194
|
+
const refCache = import_ReferencesCache.ReferencesCache.getInstance();
|
|
195
|
+
for (const [contextKey, instance] of invocationContexts.entries()) {
|
|
196
|
+
const instanceGuid = refCache.cacheReference(instance);
|
|
197
|
+
const updateContextCommand = new import_Command.Command(
|
|
198
|
+
runtimeName,
|
|
199
|
+
import_CommandType.CommandType.ValueForUpdate,
|
|
200
|
+
[
|
|
201
|
+
contextKey.toString(),
|
|
202
|
+
instanceGuid
|
|
203
|
+
]
|
|
204
|
+
);
|
|
205
|
+
if (typeof responseCommand.addArgToPayload === "function") {
|
|
206
|
+
responseCommand = responseCommand.addArgToPayload(updateContextCommand);
|
|
207
|
+
} else {
|
|
208
|
+
responseCommand.payload = responseCommand.payload || [];
|
|
209
|
+
responseCommand.payload.push(updateContextCommand);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
invocationContexts.clear();
|
|
176
213
|
}
|
|
214
|
+
return responseCommand;
|
|
177
215
|
}
|
|
178
216
|
}
|
|
179
217
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -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
|
+
});
|
|
@@ -25,10 +25,22 @@ var import_DelegatesCache = require("../core/delegatesCache/DelegatesCache.cjs")
|
|
|
25
25
|
var import_Interpreter = require("../core/interpreter/Interpreter.cjs");
|
|
26
26
|
var import_Command = require("../utils/Command.cjs");
|
|
27
27
|
var import_CommandType = require("../utils/CommandType.cjs");
|
|
28
|
-
var import_ConnectionType = require("../utils/ConnectionType.cjs");
|
|
29
28
|
var import_ExceptionThrower = require("../utils/exception/ExceptionThrower.cjs");
|
|
30
29
|
var import_RuntimeName = require("../utils/RuntimeName.cjs");
|
|
31
30
|
var import_TypesHandler = require("../utils/TypesHandler.cjs");
|
|
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;
|
|
@@ -42,6 +54,12 @@ class InvocationContext {
|
|
|
42
54
|
#isExecuted = false;
|
|
43
55
|
/** @type {Interpreter | null} */
|
|
44
56
|
#interpreter = null;
|
|
57
|
+
/** @type {string | null} */
|
|
58
|
+
#guid = null;
|
|
59
|
+
/** @type {AsyncLock} */
|
|
60
|
+
#materializationLock = new AsyncLock();
|
|
61
|
+
// Static map holding contexts waiting for materialization (guid -> InvocationContext)
|
|
62
|
+
static _invocationContexts = /* @__PURE__ */ new Map();
|
|
45
63
|
/**
|
|
46
64
|
*
|
|
47
65
|
* @param {RuntimeNameType} runtimeName
|
|
@@ -56,6 +74,13 @@ class InvocationContext {
|
|
|
56
74
|
this.#responseCommand = null;
|
|
57
75
|
this.#isExecuted = isExecuted;
|
|
58
76
|
this.#interpreter = null;
|
|
77
|
+
this.#guid = (0, import_uuid.v4)();
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* @returns {string} guid of this InvocationContext
|
|
81
|
+
*/
|
|
82
|
+
getGuid() {
|
|
83
|
+
return this.#guid;
|
|
59
84
|
}
|
|
60
85
|
/**
|
|
61
86
|
* @param {Command} localCommand
|
|
@@ -71,7 +96,7 @@ class InvocationContext {
|
|
|
71
96
|
/**
|
|
72
97
|
* @returns {Command|null}
|
|
73
98
|
*/
|
|
74
|
-
|
|
99
|
+
getCurrentCommand() {
|
|
75
100
|
return this.#currentCommand;
|
|
76
101
|
}
|
|
77
102
|
//destructor() {
|
|
@@ -101,13 +126,8 @@ class InvocationContext {
|
|
|
101
126
|
}
|
|
102
127
|
/**
|
|
103
128
|
* Executes the current command.
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
* Commands are becoming nested through each invocation of methods on Invocation Context.
|
|
107
|
-
* Each invocation triggers the creation of new Invocation Context instance wrapping the current command with new parent command valid for invoked method.
|
|
108
|
-
* Developer can decide on any moment of the materialization for the context taking full control of the chunks of the expression being transferred and processed on target runtime.
|
|
109
|
-
* @returns {Promise<InvocationContext>} the InvocationContext after executing the command.
|
|
110
|
-
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/foundations/execute-method)
|
|
129
|
+
* Returns the InvocationContext after executing the command.
|
|
130
|
+
* @returns {Promise<InvocationContext>}
|
|
111
131
|
* @method
|
|
112
132
|
*/
|
|
113
133
|
async execute() {
|
|
@@ -117,19 +137,73 @@ class InvocationContext {
|
|
|
117
137
|
if (!this.#interpreter) {
|
|
118
138
|
this.#interpreter = new import_Interpreter.Interpreter();
|
|
119
139
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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);
|
|
123
146
|
}
|
|
124
|
-
|
|
125
|
-
|
|
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
|
+
}
|
|
126
169
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (commandsToUpdate.length === 0) {
|
|
189
|
+
return responseCommand;
|
|
190
|
+
}
|
|
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);
|
|
131
205
|
}
|
|
132
|
-
return new
|
|
206
|
+
return new import_Command.Command(responseCommand.runtimeName, responseCommand.commandType, updatedPayload);
|
|
133
207
|
}
|
|
134
208
|
/**
|
|
135
209
|
* Invokes a static method on the target runtime.
|
|
@@ -171,14 +245,25 @@ class InvocationContext {
|
|
|
171
245
|
}
|
|
172
246
|
/**
|
|
173
247
|
* Creates a new instance of a class in the target runtime.
|
|
248
|
+
* Adds the newly created context to the static invocation contexts map and
|
|
249
|
+
* includes the context GUID as the first argument of CreateClassInstance command payload.
|
|
174
250
|
* @param {...any} args - The arguments to pass to the class constructor
|
|
175
251
|
* @returns {InvocationContext} A new InvocationContext instance that wraps the command to create the instance.
|
|
176
|
-
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/calling-methods/creating-instance-and-calling-instance-methods)
|
|
177
252
|
* @method
|
|
178
253
|
*/
|
|
179
254
|
createInstance(...args) {
|
|
180
|
-
|
|
181
|
-
|
|
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;
|
|
182
267
|
}
|
|
183
268
|
/**
|
|
184
269
|
* Retrieves the value of an instance field from the target runtime.
|
|
@@ -450,7 +535,7 @@ class InvocationContext {
|
|
|
450
535
|
}
|
|
451
536
|
return payloadItem;
|
|
452
537
|
} else if (payloadItem instanceof InvocationContext) {
|
|
453
|
-
return payloadItem.
|
|
538
|
+
return payloadItem.getCurrentCommand();
|
|
454
539
|
} else if (payloadItem instanceof Array) {
|
|
455
540
|
const copiedArray = payloadItem.map((item) => this.#encapsulatePayloadItem(item));
|
|
456
541
|
return new import_Command.Command(this.#runtimeName, import_CommandType.CommandType.Array, copiedArray);
|
|
@@ -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
|
}
|
|
@@ -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.
|
|
@@ -12,6 +8,7 @@ export type IConnectionData = import("../utils/connectionData/IConnectionData.js
|
|
|
12
8
|
* @class
|
|
13
9
|
*/
|
|
14
10
|
export class InvocationContext {
|
|
11
|
+
static _invocationContexts: Map<any, any>;
|
|
15
12
|
/**
|
|
16
13
|
*
|
|
17
14
|
* @param {RuntimeNameType} runtimeName
|
|
@@ -20,19 +17,18 @@ export class InvocationContext {
|
|
|
20
17
|
* @param {boolean} isExecuted
|
|
21
18
|
*/
|
|
22
19
|
constructor(runtimeName: RuntimeNameType, connectionData: IConnectionData, command: Command, isExecuted?: boolean);
|
|
20
|
+
/**
|
|
21
|
+
* @returns {string} guid of this InvocationContext
|
|
22
|
+
*/
|
|
23
|
+
getGuid(): string;
|
|
23
24
|
/**
|
|
24
25
|
* @returns {Command|null}
|
|
25
26
|
*/
|
|
26
|
-
|
|
27
|
+
getCurrentCommand(): Command | null;
|
|
27
28
|
/**
|
|
28
29
|
* Executes the current command.
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* Commands are becoming nested through each invocation of methods on Invocation Context.
|
|
32
|
-
* Each invocation triggers the creation of new Invocation Context instance wrapping the current command with new parent command valid for invoked method.
|
|
33
|
-
* Developer can decide on any moment of the materialization for the context taking full control of the chunks of the expression being transferred and processed on target runtime.
|
|
34
|
-
* @returns {Promise<InvocationContext>} the InvocationContext after executing the command.
|
|
35
|
-
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/foundations/execute-method)
|
|
30
|
+
* Returns the InvocationContext after executing the command.
|
|
31
|
+
* @returns {Promise<InvocationContext>}
|
|
36
32
|
* @method
|
|
37
33
|
*/
|
|
38
34
|
execute(): Promise<InvocationContext>;
|
|
@@ -64,9 +60,10 @@ export class InvocationContext {
|
|
|
64
60
|
setStaticField(fieldName: string, value: any): InvocationContext;
|
|
65
61
|
/**
|
|
66
62
|
* Creates a new instance of a class in the target runtime.
|
|
63
|
+
* Adds the newly created context to the static invocation contexts map and
|
|
64
|
+
* includes the context GUID as the first argument of CreateClassInstance command payload.
|
|
67
65
|
* @param {...any} args - The arguments to pass to the class constructor
|
|
68
66
|
* @returns {InvocationContext} A new InvocationContext instance that wraps the command to create the instance.
|
|
69
|
-
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/calling-methods/creating-instance-and-calling-instance-methods)
|
|
70
67
|
* @method
|
|
71
68
|
*/
|
|
72
69
|
createInstance(...args: any[]): InvocationContext;
|
|
@@ -71,7 +71,9 @@ const CommandType = (
|
|
|
71
71
|
GetAsyncOperationResult: 44,
|
|
72
72
|
AsKwargs: 45,
|
|
73
73
|
GetResultType: 46,
|
|
74
|
-
GetGlobalField: 47
|
|
74
|
+
GetGlobalField: 47,
|
|
75
|
+
RegisterForUpdate: 48,
|
|
76
|
+
ValueForUpdate: 49
|
|
75
77
|
}
|
|
76
78
|
);
|
|
77
79
|
// Annotate the CommonJS export names for ESM import in node:
|
|
@@ -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,13 +182,41 @@ class Handler {
|
|
|
164
182
|
})
|
|
165
183
|
}
|
|
166
184
|
|
|
185
|
+
let responseCommand
|
|
167
186
|
if (TypesHandler.isPrimitiveOrNullOrUndefined(response)) {
|
|
168
|
-
|
|
187
|
+
responseCommand = Command.createResponse(response, runtimeName)
|
|
169
188
|
} else {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
189
|
+
const refCache = ReferencesCache.getInstance()
|
|
190
|
+
const uuid = refCache.cacheReference(response)
|
|
191
|
+
responseCommand = Command.createReference(uuid, runtimeName)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const invocationContexts = RegisterForUpdateHandler._invocationContexts.Value
|
|
195
|
+
if (invocationContexts && invocationContexts.size > 0) {
|
|
196
|
+
const refCache = ReferencesCache.getInstance()
|
|
197
|
+
for (const [contextKey, instance] of invocationContexts.entries()) {
|
|
198
|
+
const instanceGuid = refCache.cacheReference(instance)
|
|
199
|
+
|
|
200
|
+
const updateContextCommand = new Command(
|
|
201
|
+
runtimeName,
|
|
202
|
+
CommandType.ValueForUpdate,
|
|
203
|
+
[contextKey.toString(),
|
|
204
|
+
instanceGuid]
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
if (typeof responseCommand.addArgToPayload === 'function') {
|
|
208
|
+
responseCommand = responseCommand.addArgToPayload(updateContextCommand)
|
|
209
|
+
} else {
|
|
210
|
+
responseCommand.payload = responseCommand.payload || []
|
|
211
|
+
responseCommand.payload.push(updateContextCommand)
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Clear all entries after processing this request
|
|
216
|
+
invocationContexts.clear()
|
|
173
217
|
}
|
|
218
|
+
|
|
219
|
+
return responseCommand
|
|
174
220
|
}
|
|
175
221
|
}
|
|
176
222
|
|
|
@@ -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
|
+
}
|
|
@@ -3,16 +3,35 @@ import { delegatesCacheInstance } from '../core/delegatesCache/DelegatesCache.js
|
|
|
3
3
|
import { Interpreter } from '../core/interpreter/Interpreter.js'
|
|
4
4
|
import { Command } from '../utils/Command.js'
|
|
5
5
|
import { CommandType } from '../utils/CommandType.js'
|
|
6
|
-
import { ConnectionType } from '../utils/ConnectionType.js'
|
|
7
6
|
import { ExceptionThrower } from '../utils/exception/ExceptionThrower.js'
|
|
8
7
|
import { RuntimeName } from '../utils/RuntimeName.js'
|
|
9
8
|
import { TypesHandler } from '../utils/TypesHandler.js'
|
|
9
|
+
import { v4 as uuidv4 } from 'uuid' // add lightweight uuid generation
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* @typedef {import('../types.d.ts').RuntimeName} RuntimeNameType
|
|
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.
|
|
@@ -33,6 +52,13 @@ class InvocationContext {
|
|
|
33
52
|
#isExecuted = false
|
|
34
53
|
/** @type {Interpreter | null} */
|
|
35
54
|
#interpreter = null
|
|
55
|
+
/** @type {string | null} */
|
|
56
|
+
#guid = null
|
|
57
|
+
/** @type {AsyncLock} */
|
|
58
|
+
#materializationLock = new AsyncLock()
|
|
59
|
+
|
|
60
|
+
// Static map holding contexts waiting for materialization (guid -> InvocationContext)
|
|
61
|
+
static _invocationContexts = new Map()
|
|
36
62
|
|
|
37
63
|
/**
|
|
38
64
|
*
|
|
@@ -48,6 +74,15 @@ class InvocationContext {
|
|
|
48
74
|
this.#responseCommand = null
|
|
49
75
|
this.#isExecuted = isExecuted
|
|
50
76
|
this.#interpreter = null
|
|
77
|
+
this.#guid = uuidv4()
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @returns {string} guid of this InvocationContext
|
|
82
|
+
*/
|
|
83
|
+
getGuid() {
|
|
84
|
+
// @ts-ignore
|
|
85
|
+
return this.#guid
|
|
51
86
|
}
|
|
52
87
|
|
|
53
88
|
/**
|
|
@@ -65,7 +100,7 @@ class InvocationContext {
|
|
|
65
100
|
/**
|
|
66
101
|
* @returns {Command|null}
|
|
67
102
|
*/
|
|
68
|
-
|
|
103
|
+
getCurrentCommand() {
|
|
69
104
|
return this.#currentCommand
|
|
70
105
|
}
|
|
71
106
|
|
|
@@ -99,38 +134,100 @@ class InvocationContext {
|
|
|
99
134
|
|
|
100
135
|
/**
|
|
101
136
|
* Executes the current command.
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
* Commands are becoming nested through each invocation of methods on Invocation Context.
|
|
105
|
-
* Each invocation triggers the creation of new Invocation Context instance wrapping the current command with new parent command valid for invoked method.
|
|
106
|
-
* Developer can decide on any moment of the materialization for the context taking full control of the chunks of the expression being transferred and processed on target runtime.
|
|
107
|
-
* @returns {Promise<InvocationContext>} the InvocationContext after executing the command.
|
|
108
|
-
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/foundations/execute-method)
|
|
137
|
+
* Returns the InvocationContext after executing the command.
|
|
138
|
+
* @returns {Promise<InvocationContext>}
|
|
109
139
|
* @method
|
|
110
140
|
*/
|
|
111
141
|
async execute() {
|
|
112
142
|
if (this.#currentCommand === null) {
|
|
113
143
|
throw new Error('currentCommand is undefined in Invocation Context execute method')
|
|
114
144
|
}
|
|
115
|
-
|
|
116
145
|
if (!this.#interpreter) {
|
|
117
146
|
this.#interpreter = new Interpreter()
|
|
118
147
|
}
|
|
119
148
|
|
|
120
|
-
|
|
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)
|
|
121
172
|
|
|
122
|
-
|
|
123
|
-
|
|
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
|
+
}
|
|
124
184
|
}
|
|
125
|
-
|
|
126
|
-
|
|
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
|
|
127
197
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
198
|
+
|
|
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
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (commandsToUpdate.length === 0) {
|
|
207
|
+
return responseCommand
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// create a copy of the payload to modify
|
|
211
|
+
const updatedPayload = Array.from(responseCommand.payload)
|
|
212
|
+
|
|
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)
|
|
132
228
|
}
|
|
133
|
-
|
|
229
|
+
|
|
230
|
+
return new Command(responseCommand.runtimeName, responseCommand.commandType, updatedPayload)
|
|
134
231
|
}
|
|
135
232
|
|
|
136
233
|
/**
|
|
@@ -176,14 +273,26 @@ class InvocationContext {
|
|
|
176
273
|
|
|
177
274
|
/**
|
|
178
275
|
* Creates a new instance of a class in the target runtime.
|
|
276
|
+
* Adds the newly created context to the static invocation contexts map and
|
|
277
|
+
* includes the context GUID as the first argument of CreateClassInstance command payload.
|
|
179
278
|
* @param {...any} args - The arguments to pass to the class constructor
|
|
180
279
|
* @returns {InvocationContext} A new InvocationContext instance that wraps the command to create the instance.
|
|
181
|
-
* @see [Javonet Guides](https://www.javonet.com/guides/v2/javascript/calling-methods/creating-instance-and-calling-instance-methods)
|
|
182
280
|
* @method
|
|
183
281
|
*/
|
|
184
282
|
createInstance(...args) {
|
|
185
|
-
|
|
186
|
-
|
|
283
|
+
const localCommand = new Command(this.#runtimeName, CommandType.CreateClassInstance, [...args])
|
|
284
|
+
const createInstanceInvCtx = this.#createInstanceContext(localCommand)
|
|
285
|
+
return createInstanceInvCtx.#registerForUpdate()
|
|
286
|
+
}
|
|
287
|
+
|
|
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
|
|
187
296
|
}
|
|
188
297
|
|
|
189
298
|
/**
|
|
@@ -429,7 +538,7 @@ class InvocationContext {
|
|
|
429
538
|
await localInvCtx.execute()
|
|
430
539
|
|
|
431
540
|
const resolve = (/** @type {any} */ item) => {
|
|
432
|
-
return item?.commandType === CommandType.Reference ?
|
|
541
|
+
return item?.commandType === CommandType.Reference ?
|
|
433
542
|
new InvocationContext(
|
|
434
543
|
this.#runtimeName,
|
|
435
544
|
this.#connectionData,
|
|
@@ -441,11 +550,11 @@ class InvocationContext {
|
|
|
441
550
|
if (!respCommand) {
|
|
442
551
|
return []
|
|
443
552
|
}
|
|
444
|
-
|
|
553
|
+
|
|
445
554
|
if (respCommand.payload) {
|
|
446
555
|
return respCommand.payload.map((/** @type {any} */ item) => resolve(item))
|
|
447
556
|
}
|
|
448
|
-
|
|
557
|
+
|
|
449
558
|
return respCommand.payload || []
|
|
450
559
|
}
|
|
451
560
|
|
|
@@ -484,7 +593,7 @@ class InvocationContext {
|
|
|
484
593
|
return payloadItem
|
|
485
594
|
// eslint-disable-next-line valid-typeof
|
|
486
595
|
} else if (payloadItem instanceof InvocationContext) {
|
|
487
|
-
return payloadItem.
|
|
596
|
+
return payloadItem.getCurrentCommand()
|
|
488
597
|
} else if (payloadItem instanceof Array) {
|
|
489
598
|
const copiedArray = payloadItem.map((item) => this.#encapsulatePayloadItem(item))
|
|
490
599
|
return new Command(this.#runtimeName, CommandType.Array, copiedArray)
|
|
@@ -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.",
|
|
@@ -40,12 +40,13 @@
|
|
|
40
40
|
"format": "prettier --write ."
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"@types/uuid": "^10.0.0",
|
|
43
44
|
"@types/ws": "^8.18.1",
|
|
44
45
|
"buffer": "^6.0.3",
|
|
45
46
|
"glob": "^10.4.5",
|
|
46
47
|
"js-yaml": "^4.1.0",
|
|
47
48
|
"uuid": "^10.0.0",
|
|
48
|
-
"ws": "^8.
|
|
49
|
+
"ws": "^8.18.1"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@babel/cli": "^7.25.9",
|
|
@@ -58,7 +59,7 @@
|
|
|
58
59
|
"@types/js-yaml": "^4.0.9",
|
|
59
60
|
"babel-loader": "^9.2.1",
|
|
60
61
|
"cross-env": "^7.0.3",
|
|
61
|
-
"esbuild": "^0.
|
|
62
|
+
"esbuild": "^0.27.0",
|
|
62
63
|
"eslint": "^9.15.0",
|
|
63
64
|
"eslint-config-prettier": "^9.1.0",
|
|
64
65
|
"eslint-plugin-jest": "^28.9.0",
|