space-data-module-sdk 0.1.0 → 0.2.5
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/LICENSE +190 -0
- package/README.md +236 -73
- package/bin/space-data-module.js +24 -0
- package/package.json +16 -4
- package/schemas/ModuleBundle.fbs +108 -0
- package/schemas/PluginInvokeRequest.fbs +18 -0
- package/schemas/PluginInvokeResponse.fbs +30 -0
- package/schemas/PluginManifest.fbs +33 -1
- package/schemas/TypedArenaBuffer.fbs +23 -2
- package/src/bundle/codec.js +268 -0
- package/src/bundle/constants.js +8 -0
- package/src/bundle/index.js +3 -0
- package/src/bundle/wasm.js +447 -0
- package/src/compiler/compileModule.js +353 -37
- package/src/compiler/emceptionNode.js +217 -0
- package/src/compiler/flatcSupport.js +66 -0
- package/src/compiler/invokeGlue.js +884 -0
- package/src/compliance/pluginCompliance.js +575 -1
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts +51 -0
- package/src/generated/orbpro/invoke/plugin-invoke-request.d.ts.map +1 -0
- package/src/generated/orbpro/invoke/plugin-invoke-request.js +131 -0
- package/src/generated/orbpro/invoke/plugin-invoke-request.js.map +1 -0
- package/src/generated/orbpro/invoke/plugin-invoke-request.ts +173 -0
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts +76 -0
- package/src/generated/orbpro/invoke/plugin-invoke-response.d.ts.map +1 -0
- package/src/generated/orbpro/invoke/plugin-invoke-response.js +184 -0
- package/src/generated/orbpro/invoke/plugin-invoke-response.js.map +1 -0
- package/src/generated/orbpro/invoke/plugin-invoke-response.ts +243 -0
- package/src/generated/orbpro/invoke.d.ts +3 -0
- package/src/generated/orbpro/invoke.d.ts.map +1 -0
- package/src/generated/orbpro/invoke.js +5 -0
- package/src/generated/orbpro/invoke.js.map +1 -0
- package/src/generated/orbpro/invoke.ts +6 -0
- package/src/generated/orbpro/manifest/accepted-type-set.d.ts +4 -4
- package/src/generated/orbpro/manifest/accepted-type-set.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/accepted-type-set.js +18 -11
- package/src/generated/orbpro/manifest/accepted-type-set.js.map +1 -1
- package/src/generated/orbpro/manifest/build-artifact.d.ts +1 -1
- package/src/generated/orbpro/manifest/build-artifact.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/build-artifact.js +28 -15
- package/src/generated/orbpro/manifest/build-artifact.js.map +1 -1
- package/src/generated/orbpro/manifest/capability-kind.d.ts +26 -1
- package/src/generated/orbpro/manifest/capability-kind.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/capability-kind.js +25 -0
- package/src/generated/orbpro/manifest/capability-kind.js.map +1 -1
- package/src/generated/orbpro/manifest/capability-kind.ts +25 -0
- package/src/generated/orbpro/manifest/drain-policy.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/drain-policy.js.map +1 -1
- package/src/generated/orbpro/manifest/host-capability.d.ts +2 -2
- package/src/generated/orbpro/manifest/host-capability.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/host-capability.js +19 -11
- package/src/generated/orbpro/manifest/host-capability.js.map +1 -1
- package/src/generated/orbpro/manifest/invoke-surface.d.ts +8 -0
- package/src/generated/orbpro/manifest/invoke-surface.d.ts.map +1 -0
- package/src/generated/orbpro/manifest/invoke-surface.js +11 -0
- package/src/generated/orbpro/manifest/invoke-surface.js.map +1 -0
- package/src/generated/orbpro/manifest/invoke-surface.ts +11 -0
- package/src/generated/orbpro/manifest/method-manifest.d.ts +6 -6
- package/src/generated/orbpro/manifest/method-manifest.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/method-manifest.js +33 -16
- package/src/generated/orbpro/manifest/method-manifest.js.map +1 -1
- package/src/generated/orbpro/manifest/plugin-family.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/plugin-family.js.map +1 -1
- package/src/generated/orbpro/manifest/plugin-manifest.d.ts +10 -2
- package/src/generated/orbpro/manifest/plugin-manifest.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/plugin-manifest.js +48 -9
- package/src/generated/orbpro/manifest/plugin-manifest.js.map +1 -1
- package/src/generated/orbpro/manifest/plugin-manifest.ts +322 -491
- package/src/generated/orbpro/manifest/port-manifest.d.ts +4 -4
- package/src/generated/orbpro/manifest/port-manifest.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/port-manifest.js +26 -13
- package/src/generated/orbpro/manifest/port-manifest.js.map +1 -1
- package/src/generated/orbpro/manifest/protocol-spec.d.ts +1 -1
- package/src/generated/orbpro/manifest/protocol-spec.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/protocol-spec.js +28 -15
- package/src/generated/orbpro/manifest/protocol-spec.js.map +1 -1
- package/src/generated/orbpro/manifest/timer-spec.d.ts +1 -1
- package/src/generated/orbpro/manifest/timer-spec.d.ts.map +1 -1
- package/src/generated/orbpro/manifest/timer-spec.js +27 -16
- package/src/generated/orbpro/manifest/timer-spec.js.map +1 -1
- package/src/generated/orbpro/manifest.d.ts +13 -0
- package/src/generated/orbpro/manifest.d.ts.map +1 -0
- package/src/generated/orbpro/manifest.js +1 -0
- package/src/generated/orbpro/manifest.js.map +1 -0
- package/src/generated/orbpro/manifest.ts +16 -0
- package/src/generated/orbpro/module/canonicalization-rule.d.ts +48 -0
- package/src/generated/orbpro/module/canonicalization-rule.js +95 -0
- package/src/generated/orbpro/module/canonicalization-rule.ts +142 -0
- package/src/generated/orbpro/module/module-bundle-entry-role.d.ts +11 -0
- package/src/generated/orbpro/module/module-bundle-entry-role.js +14 -0
- package/src/generated/orbpro/module/module-bundle-entry-role.ts +15 -0
- package/src/generated/orbpro/module/module-bundle-entry.d.ts +97 -0
- package/src/generated/orbpro/module/module-bundle-entry.js +219 -0
- package/src/generated/orbpro/module/module-bundle-entry.ts +287 -0
- package/src/generated/orbpro/module/module-bundle.d.ts +86 -0
- package/src/generated/orbpro/module/module-bundle.js +213 -0
- package/src/generated/orbpro/module/module-bundle.ts +277 -0
- package/src/generated/orbpro/module/module-payload-encoding.d.ts +9 -0
- package/src/generated/orbpro/module/module-payload-encoding.js +12 -0
- package/src/generated/orbpro/module/module-payload-encoding.ts +13 -0
- package/src/generated/orbpro/module.d.ts +5 -0
- package/src/generated/orbpro/module.js +7 -0
- package/src/generated/orbpro/module.ts +9 -0
- package/src/generated/orbpro/stream/buffer-mutability.d.ts.map +1 -1
- package/src/generated/orbpro/stream/buffer-mutability.js.map +1 -1
- package/src/generated/orbpro/stream/buffer-ownership.d.ts.map +1 -1
- package/src/generated/orbpro/stream/buffer-ownership.js.map +1 -1
- package/src/generated/orbpro/stream/flat-buffer-type-ref.d.ts +22 -5
- package/src/generated/orbpro/stream/flat-buffer-type-ref.d.ts.map +1 -1
- package/src/generated/orbpro/stream/flat-buffer-type-ref.js +107 -17
- package/src/generated/orbpro/stream/flat-buffer-type-ref.js.map +1 -1
- package/src/generated/orbpro/stream/flat-buffer-type-ref.ts +126 -2
- package/src/generated/orbpro/stream/payload-wire-format.d.ts +8 -0
- package/src/generated/orbpro/stream/payload-wire-format.d.ts.map +1 -0
- package/src/generated/orbpro/stream/payload-wire-format.js +11 -0
- package/src/generated/orbpro/stream/payload-wire-format.js.map +1 -0
- package/src/generated/orbpro/stream/payload-wire-format.ts +11 -0
- package/src/generated/orbpro/stream/typed-arena-buffer.d.ts +4 -4
- package/src/generated/orbpro/stream/typed-arena-buffer.d.ts.map +1 -1
- package/src/generated/orbpro/stream/typed-arena-buffer.js +42 -24
- package/src/generated/orbpro/stream/typed-arena-buffer.js.map +1 -1
- package/src/host/abi.js +282 -0
- package/src/host/cron.js +247 -0
- package/src/host/index.js +3 -0
- package/src/host/nodeHost.js +2165 -0
- package/src/index.d.ts +958 -0
- package/src/index.js +12 -2
- package/src/invoke/codec.js +278 -0
- package/src/invoke/index.js +9 -0
- package/src/manifest/codec.js +10 -2
- package/src/manifest/index.js +5 -2
- package/src/manifest/normalize.js +90 -1
- package/src/runtime/constants.js +29 -0
- package/src/transport/pki.js +0 -5
- package/src/utils/encoding.js +9 -1
- package/src/utils/wasmCrypto.js +49 -1
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
import { InvokeSurface } from "../runtime/constants.js";
|
|
2
|
+
|
|
3
|
+
function quoteCString(value) {
|
|
4
|
+
return JSON.stringify(String(value ?? ""));
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function boolLiteral(value) {
|
|
8
|
+
return value ? "true" : "false";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function methodSymbol(method) {
|
|
12
|
+
return String(method?.methodId ?? "").trim();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function uniqueInputPorts(method) {
|
|
16
|
+
return Array.isArray(method?.inputPorts) ? method.inputPorts : [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function uniqueOutputPorts(method) {
|
|
20
|
+
return Array.isArray(method?.outputPorts) ? method.outputPorts : [];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function resolveInvokeSurfaces(manifest = {}) {
|
|
24
|
+
if (!Array.isArray(manifest.invokeSurfaces) || manifest.invokeSurfaces.length === 0) {
|
|
25
|
+
return [InvokeSurface.DIRECT, InvokeSurface.COMMAND];
|
|
26
|
+
}
|
|
27
|
+
const seen = new Set();
|
|
28
|
+
const surfaces = [];
|
|
29
|
+
for (const surface of manifest.invokeSurfaces) {
|
|
30
|
+
if (surface !== InvokeSurface.DIRECT && surface !== InvokeSurface.COMMAND) {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (seen.has(surface)) {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
seen.add(surface);
|
|
37
|
+
surfaces.push(surface);
|
|
38
|
+
}
|
|
39
|
+
return surfaces.length > 0
|
|
40
|
+
? surfaces
|
|
41
|
+
: [InvokeSurface.DIRECT, InvokeSurface.COMMAND];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function generateInvokeSupportHeader() {
|
|
45
|
+
return `#ifndef SPACE_DATA_MODULE_INVOKE_H
|
|
46
|
+
#define SPACE_DATA_MODULE_INVOKE_H
|
|
47
|
+
|
|
48
|
+
#include <stdint.h>
|
|
49
|
+
|
|
50
|
+
#ifdef __cplusplus
|
|
51
|
+
extern "C" {
|
|
52
|
+
#endif
|
|
53
|
+
|
|
54
|
+
enum plugin_payload_wire_format_t {
|
|
55
|
+
PLUGIN_PAYLOAD_WIRE_FORMAT_FLATBUFFER = 0,
|
|
56
|
+
PLUGIN_PAYLOAD_WIRE_FORMAT_ALIGNED_BINARY = 1,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
typedef struct plugin_input_frame_t {
|
|
60
|
+
const char *port_id;
|
|
61
|
+
const char *schema_name;
|
|
62
|
+
const char *file_identifier;
|
|
63
|
+
uint32_t wire_format;
|
|
64
|
+
const char *root_type_name;
|
|
65
|
+
uint16_t fixed_string_length;
|
|
66
|
+
uint32_t byte_length;
|
|
67
|
+
uint16_t required_alignment;
|
|
68
|
+
uint16_t alignment;
|
|
69
|
+
uint32_t size;
|
|
70
|
+
uint32_t generation;
|
|
71
|
+
uint64_t trace_id;
|
|
72
|
+
uint32_t stream_id;
|
|
73
|
+
uint64_t sequence;
|
|
74
|
+
int32_t end_of_stream;
|
|
75
|
+
const uint8_t *payload;
|
|
76
|
+
uint32_t payload_length;
|
|
77
|
+
} plugin_input_frame_t;
|
|
78
|
+
|
|
79
|
+
uint32_t plugin_get_input_count(void);
|
|
80
|
+
const plugin_input_frame_t *plugin_get_input_frame(uint32_t index);
|
|
81
|
+
int32_t plugin_find_input_index(const char *port_id, uint32_t ordinal);
|
|
82
|
+
|
|
83
|
+
void plugin_reset_output_state(void);
|
|
84
|
+
int32_t plugin_push_output(
|
|
85
|
+
const char *port_id,
|
|
86
|
+
const char *schema_name,
|
|
87
|
+
const char *file_identifier,
|
|
88
|
+
const uint8_t *payload_ptr,
|
|
89
|
+
uint32_t payload_length
|
|
90
|
+
);
|
|
91
|
+
int32_t plugin_push_output_typed(
|
|
92
|
+
const char *port_id,
|
|
93
|
+
const char *schema_name,
|
|
94
|
+
const char *file_identifier,
|
|
95
|
+
uint32_t wire_format,
|
|
96
|
+
const char *root_type_name,
|
|
97
|
+
uint16_t fixed_string_length,
|
|
98
|
+
uint32_t byte_length,
|
|
99
|
+
uint16_t required_alignment,
|
|
100
|
+
const uint8_t *payload_ptr,
|
|
101
|
+
uint32_t payload_length
|
|
102
|
+
);
|
|
103
|
+
int32_t plugin_push_output_ex(
|
|
104
|
+
const char *port_id,
|
|
105
|
+
const char *schema_name,
|
|
106
|
+
const char *file_identifier,
|
|
107
|
+
uint32_t wire_format,
|
|
108
|
+
const char *root_type_name,
|
|
109
|
+
uint16_t fixed_string_length,
|
|
110
|
+
uint16_t required_alignment,
|
|
111
|
+
const uint8_t *payload_ptr,
|
|
112
|
+
uint32_t payload_length
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
void plugin_set_yielded(int32_t yielded);
|
|
116
|
+
void plugin_set_backlog_remaining(uint32_t backlog_remaining);
|
|
117
|
+
void plugin_set_error(const char *error_code, const char *error_message);
|
|
118
|
+
|
|
119
|
+
uint32_t plugin_alloc(uint32_t size);
|
|
120
|
+
void plugin_free(uint32_t ptr, uint32_t size);
|
|
121
|
+
uint32_t plugin_invoke_stream(
|
|
122
|
+
uint32_t request_ptr,
|
|
123
|
+
uint32_t request_len,
|
|
124
|
+
uint32_t response_len_out_ptr
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
#ifdef __cplusplus
|
|
128
|
+
}
|
|
129
|
+
#endif
|
|
130
|
+
|
|
131
|
+
#endif
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function renderInputPortArrays(method) {
|
|
136
|
+
const inputPorts = uniqueInputPorts(method);
|
|
137
|
+
if (inputPorts.length === 0) {
|
|
138
|
+
return "";
|
|
139
|
+
}
|
|
140
|
+
return `static const PortRequirement kMethod_${methodSymbol(method)}_input_ports[] = {
|
|
141
|
+
${inputPorts
|
|
142
|
+
.map(
|
|
143
|
+
(port) =>
|
|
144
|
+
` { ${quoteCString(port.portId)}, ${boolLiteral(port.required !== false)} },`,
|
|
145
|
+
)
|
|
146
|
+
.join("\n")}
|
|
147
|
+
};
|
|
148
|
+
`;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function renderOutputPortArrays(method) {
|
|
152
|
+
const outputPorts = uniqueOutputPorts(method);
|
|
153
|
+
if (outputPorts.length === 0) {
|
|
154
|
+
return "";
|
|
155
|
+
}
|
|
156
|
+
return `static const char *kMethod_${methodSymbol(method)}_output_ports[] = {
|
|
157
|
+
${outputPorts.map((port) => ` ${quoteCString(port.portId)},`).join("\n")}
|
|
158
|
+
};
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function renderMethodDeclarations(methods) {
|
|
163
|
+
return methods
|
|
164
|
+
.map((method) => `extern "C" int ${methodSymbol(method)}(void);`)
|
|
165
|
+
.join("\n");
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function renderMethodTables(methods) {
|
|
169
|
+
return methods
|
|
170
|
+
.map((method) => `${renderInputPortArrays(method)}${renderOutputPortArrays(method)}`)
|
|
171
|
+
.join("\n");
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function renderMethodDescriptors(methods) {
|
|
175
|
+
return methods
|
|
176
|
+
.map((method) => {
|
|
177
|
+
const inputPorts = uniqueInputPorts(method);
|
|
178
|
+
const outputPorts = uniqueOutputPorts(method);
|
|
179
|
+
const rawShortcutAllowed = inputPorts.length === 1 && outputPorts.length <= 1;
|
|
180
|
+
return ` {
|
|
181
|
+
${quoteCString(method.methodId)},
|
|
182
|
+
&${methodSymbol(method)},
|
|
183
|
+
${inputPorts.length > 0 ? `kMethod_${methodSymbol(method)}_input_ports` : "nullptr"},
|
|
184
|
+
${inputPorts.length}u,
|
|
185
|
+
${outputPorts.length > 0 ? `kMethod_${methodSymbol(method)}_output_ports` : "nullptr"},
|
|
186
|
+
${outputPorts.length}u,
|
|
187
|
+
${boolLiteral(rawShortcutAllowed)},
|
|
188
|
+
${rawShortcutAllowed ? quoteCString(inputPorts[0].portId) : "nullptr"},
|
|
189
|
+
${
|
|
190
|
+
rawShortcutAllowed && outputPorts.length === 1
|
|
191
|
+
? quoteCString(outputPorts[0].portId)
|
|
192
|
+
: "nullptr"
|
|
193
|
+
}
|
|
194
|
+
},`;
|
|
195
|
+
})
|
|
196
|
+
.join("\n");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function generateInvokeSupportSource({ manifest = {}, includeCommandMain = true } = {}) {
|
|
200
|
+
const methods = Array.isArray(manifest.methods) ? manifest.methods : [];
|
|
201
|
+
return `#include <algorithm>
|
|
202
|
+
#include <cstdint>
|
|
203
|
+
#include <cstdio>
|
|
204
|
+
#include <cstdlib>
|
|
205
|
+
#include <cstring>
|
|
206
|
+
#include <memory>
|
|
207
|
+
#include <string>
|
|
208
|
+
#include <string_view>
|
|
209
|
+
#include <utility>
|
|
210
|
+
#include <vector>
|
|
211
|
+
|
|
212
|
+
#include <flatbuffers/flatbuffers.h>
|
|
213
|
+
|
|
214
|
+
#include "PluginInvokeRequest_generated.h"
|
|
215
|
+
#include "PluginInvokeResponse_generated.h"
|
|
216
|
+
#include "TypedArenaBuffer_generated.h"
|
|
217
|
+
#include "space_data_module_invoke.h"
|
|
218
|
+
|
|
219
|
+
${renderMethodDeclarations(methods)}
|
|
220
|
+
|
|
221
|
+
namespace {
|
|
222
|
+
|
|
223
|
+
struct PortRequirement {
|
|
224
|
+
const char *port_id;
|
|
225
|
+
bool required;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
struct MethodDescriptor {
|
|
229
|
+
const char *method_id;
|
|
230
|
+
int (*handler)(void);
|
|
231
|
+
const PortRequirement *input_ports;
|
|
232
|
+
size_t input_port_count;
|
|
233
|
+
const char *const *output_ports;
|
|
234
|
+
size_t output_port_count;
|
|
235
|
+
bool raw_shortcut_allowed;
|
|
236
|
+
const char *raw_input_port_id;
|
|
237
|
+
const char *raw_output_port_id;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
struct InputFrameOwned {
|
|
241
|
+
plugin_input_frame_t view{};
|
|
242
|
+
std::string port_id{};
|
|
243
|
+
std::string schema_name{};
|
|
244
|
+
std::string file_identifier{};
|
|
245
|
+
std::string root_type_name{};
|
|
246
|
+
std::vector<uint8_t> payload{};
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
struct OutputFrameOwned {
|
|
250
|
+
std::string port_id{};
|
|
251
|
+
std::string schema_name{};
|
|
252
|
+
std::string file_identifier{};
|
|
253
|
+
std::string root_type_name{};
|
|
254
|
+
uint32_t wire_format = 0;
|
|
255
|
+
uint16_t fixed_string_length = 0;
|
|
256
|
+
uint32_t byte_length = 0;
|
|
257
|
+
uint16_t required_alignment = 0;
|
|
258
|
+
uint16_t alignment = 8;
|
|
259
|
+
uint32_t generation = 0;
|
|
260
|
+
uint64_t trace_id = 0;
|
|
261
|
+
uint32_t stream_id = 0;
|
|
262
|
+
uint64_t sequence = 0;
|
|
263
|
+
bool end_of_stream = false;
|
|
264
|
+
std::vector<uint8_t> payload{};
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
struct InvokeContext {
|
|
268
|
+
const MethodDescriptor *method = nullptr;
|
|
269
|
+
std::vector<InputFrameOwned> inputs{};
|
|
270
|
+
std::vector<OutputFrameOwned> outputs{};
|
|
271
|
+
uint32_t backlog_remaining = 0;
|
|
272
|
+
bool yielded = false;
|
|
273
|
+
int32_t status_code = 0;
|
|
274
|
+
std::string error_code{};
|
|
275
|
+
std::string error_message{};
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
${renderMethodTables(methods)}
|
|
279
|
+
static const MethodDescriptor kMethodTable[] = {
|
|
280
|
+
${renderMethodDescriptors(methods)}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
static InvokeContext g_invoke_context;
|
|
284
|
+
|
|
285
|
+
static uintptr_t PtrFromU32(uint32_t value) {
|
|
286
|
+
return static_cast<uintptr_t>(value);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
static uint8_t *MutablePtr(uint32_t value) {
|
|
290
|
+
return reinterpret_cast<uint8_t *>(PtrFromU32(value));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
static const uint8_t *ConstPtr(uint32_t value) {
|
|
294
|
+
return reinterpret_cast<const uint8_t *>(PtrFromU32(value));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
static uint32_t *MutableU32Ptr(uint32_t value) {
|
|
298
|
+
return reinterpret_cast<uint32_t *>(PtrFromU32(value));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
static const MethodDescriptor *FindMethod(std::string_view method_id) {
|
|
302
|
+
for (const auto &method : kMethodTable) {
|
|
303
|
+
if (method_id == method.method_id) {
|
|
304
|
+
return &method;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return nullptr;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
static bool MethodDeclaresOutputPort(const MethodDescriptor *method, const char *port_id) {
|
|
311
|
+
if (!method || !port_id || !port_id[0]) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
for (size_t index = 0; index < method->output_port_count; index += 1) {
|
|
315
|
+
if (std::strcmp(method->output_ports[index], port_id) == 0) {
|
|
316
|
+
return true;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
static void ResetInvokeContext(const MethodDescriptor *method) {
|
|
323
|
+
g_invoke_context = InvokeContext{};
|
|
324
|
+
g_invoke_context.method = method;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
static void SetError(const char *code, const std::string &message) {
|
|
328
|
+
g_invoke_context.error_code = code ? code : "invoke-error";
|
|
329
|
+
g_invoke_context.error_message = message;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
static std::string ReadCString(const char *value) {
|
|
333
|
+
return value ? std::string(value) : std::string();
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
static uint32_t AlignOffset(uint32_t offset, uint32_t alignment) {
|
|
337
|
+
if (alignment <= 1u) {
|
|
338
|
+
return offset;
|
|
339
|
+
}
|
|
340
|
+
const uint32_t remainder = offset % alignment;
|
|
341
|
+
return remainder == 0u ? offset : offset + alignment - remainder;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
static bool LoadInputsFromRequest(const orbpro::invoke::PluginInvokeRequestT &request) {
|
|
345
|
+
g_invoke_context.inputs.clear();
|
|
346
|
+
g_invoke_context.inputs.reserve(request.input_frames.size());
|
|
347
|
+
|
|
348
|
+
for (const auto &frame_ptr : request.input_frames) {
|
|
349
|
+
if (!frame_ptr) {
|
|
350
|
+
continue;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const auto &frame = *frame_ptr;
|
|
354
|
+
const auto payload_offset = static_cast<size_t>(frame.offset);
|
|
355
|
+
const auto payload_size = static_cast<size_t>(frame.size);
|
|
356
|
+
if (payload_offset + payload_size > request.payload_arena.size()) {
|
|
357
|
+
SetError("invalid-request-frame", "Input frame payload range exceeds request payload arena.");
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
g_invoke_context.inputs.emplace_back();
|
|
362
|
+
auto &owned = g_invoke_context.inputs.back();
|
|
363
|
+
owned = InputFrameOwned{};
|
|
364
|
+
owned.port_id = frame.port_id;
|
|
365
|
+
if (frame.type_ref) {
|
|
366
|
+
owned.schema_name = frame.type_ref->schema_name;
|
|
367
|
+
owned.file_identifier = frame.type_ref->file_identifier;
|
|
368
|
+
owned.root_type_name = frame.type_ref->root_type_name;
|
|
369
|
+
}
|
|
370
|
+
owned.payload.insert(
|
|
371
|
+
owned.payload.end(),
|
|
372
|
+
request.payload_arena.begin() + static_cast<std::ptrdiff_t>(payload_offset),
|
|
373
|
+
request.payload_arena.begin() + static_cast<std::ptrdiff_t>(payload_offset + payload_size)
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
owned.view.port_id = owned.port_id.empty() ? nullptr : owned.port_id.c_str();
|
|
377
|
+
owned.view.schema_name = owned.schema_name.empty() ? nullptr : owned.schema_name.c_str();
|
|
378
|
+
owned.view.file_identifier = owned.file_identifier.empty() ? nullptr : owned.file_identifier.c_str();
|
|
379
|
+
owned.view.wire_format =
|
|
380
|
+
frame.type_ref
|
|
381
|
+
? static_cast<uint32_t>(frame.type_ref->wire_format)
|
|
382
|
+
: static_cast<uint32_t>(orbpro::stream::PayloadWireFormat_Flatbuffer);
|
|
383
|
+
owned.view.root_type_name = owned.root_type_name.empty() ? nullptr : owned.root_type_name.c_str();
|
|
384
|
+
owned.view.fixed_string_length = frame.type_ref ? frame.type_ref->fixed_string_length : 0;
|
|
385
|
+
owned.view.byte_length = frame.type_ref ? frame.type_ref->byte_length : static_cast<uint32_t>(payload_size);
|
|
386
|
+
owned.view.required_alignment = frame.type_ref ? frame.type_ref->required_alignment : 0;
|
|
387
|
+
owned.view.alignment = frame.alignment;
|
|
388
|
+
owned.view.size = frame.size;
|
|
389
|
+
owned.view.generation = frame.generation;
|
|
390
|
+
owned.view.trace_id = frame.trace_id;
|
|
391
|
+
owned.view.stream_id = frame.stream_id;
|
|
392
|
+
owned.view.sequence = frame.sequence;
|
|
393
|
+
owned.view.end_of_stream = frame.end_of_stream ? 1 : 0;
|
|
394
|
+
owned.view.payload = owned.payload.empty() ? nullptr : owned.payload.data();
|
|
395
|
+
owned.view.payload_length = static_cast<uint32_t>(owned.payload.size());
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
return true;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
static bool ValidateRequiredInputs(const MethodDescriptor *method) {
|
|
402
|
+
if (!method) {
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
for (size_t port_index = 0; port_index < method->input_port_count; port_index += 1) {
|
|
406
|
+
const auto &port = method->input_ports[port_index];
|
|
407
|
+
if (!port.required) {
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
bool present = false;
|
|
411
|
+
for (const auto &frame : g_invoke_context.inputs) {
|
|
412
|
+
if (frame.port_id == port.port_id) {
|
|
413
|
+
present = true;
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (!present) {
|
|
418
|
+
SetError(
|
|
419
|
+
"missing-required-input",
|
|
420
|
+
std::string("Missing required input port: ") + port.port_id
|
|
421
|
+
);
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
static orbpro::invoke::PluginInvokeResponseT BuildResponseObject() {
|
|
429
|
+
orbpro::invoke::PluginInvokeResponseT response{};
|
|
430
|
+
response.status_code = g_invoke_context.status_code;
|
|
431
|
+
response.yielded = g_invoke_context.yielded;
|
|
432
|
+
response.backlog_remaining = g_invoke_context.backlog_remaining;
|
|
433
|
+
response.error_code = g_invoke_context.error_code;
|
|
434
|
+
response.error_message = g_invoke_context.error_message;
|
|
435
|
+
|
|
436
|
+
uint32_t arena_offset = 0;
|
|
437
|
+
for (const auto &output : g_invoke_context.outputs) {
|
|
438
|
+
const uint32_t alignment = std::max<uint32_t>(
|
|
439
|
+
1u,
|
|
440
|
+
output.required_alignment > 0 ? output.required_alignment : output.alignment
|
|
441
|
+
);
|
|
442
|
+
const uint32_t aligned_offset = AlignOffset(arena_offset, alignment);
|
|
443
|
+
response.payload_arena.resize(aligned_offset, 0);
|
|
444
|
+
response.payload_arena.insert(
|
|
445
|
+
response.payload_arena.end(),
|
|
446
|
+
output.payload.begin(),
|
|
447
|
+
output.payload.end()
|
|
448
|
+
);
|
|
449
|
+
arena_offset = aligned_offset + static_cast<uint32_t>(output.payload.size());
|
|
450
|
+
|
|
451
|
+
auto type_ref = std::make_unique<orbpro::stream::FlatBufferTypeRefT>();
|
|
452
|
+
type_ref->schema_name = output.schema_name;
|
|
453
|
+
type_ref->file_identifier = output.file_identifier;
|
|
454
|
+
type_ref->wire_format =
|
|
455
|
+
static_cast<orbpro::stream::PayloadWireFormat>(output.wire_format);
|
|
456
|
+
type_ref->root_type_name = output.root_type_name;
|
|
457
|
+
type_ref->fixed_string_length = output.fixed_string_length;
|
|
458
|
+
type_ref->byte_length =
|
|
459
|
+
output.byte_length > 0 ? output.byte_length : static_cast<uint32_t>(output.payload.size());
|
|
460
|
+
type_ref->required_alignment = output.required_alignment;
|
|
461
|
+
|
|
462
|
+
auto frame = std::make_unique<orbpro::stream::TypedArenaBufferT>();
|
|
463
|
+
frame->type_ref = std::move(type_ref);
|
|
464
|
+
frame->port_id = output.port_id;
|
|
465
|
+
frame->alignment = static_cast<uint16_t>(alignment);
|
|
466
|
+
frame->offset = aligned_offset;
|
|
467
|
+
frame->size = static_cast<uint32_t>(output.payload.size());
|
|
468
|
+
frame->generation = output.generation;
|
|
469
|
+
frame->trace_id = output.trace_id;
|
|
470
|
+
frame->stream_id = output.stream_id;
|
|
471
|
+
frame->sequence = output.sequence;
|
|
472
|
+
frame->end_of_stream = output.end_of_stream;
|
|
473
|
+
response.output_frames.emplace_back(std::move(frame));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
return response;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
static std::vector<uint8_t> SerializeResponse(const orbpro::invoke::PluginInvokeResponseT &response) {
|
|
480
|
+
::flatbuffers::FlatBufferBuilder builder(1024);
|
|
481
|
+
const auto root = orbpro::invoke::CreatePluginInvokeResponse(builder, &response);
|
|
482
|
+
orbpro::invoke::FinishPluginInvokeResponseBuffer(builder, root);
|
|
483
|
+
return std::vector<uint8_t>(
|
|
484
|
+
builder.GetBufferPointer(),
|
|
485
|
+
builder.GetBufferPointer() + builder.GetSize()
|
|
486
|
+
);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
static std::vector<uint8_t> SerializeErrorResponse(
|
|
490
|
+
int32_t status_code,
|
|
491
|
+
const char *error_code,
|
|
492
|
+
const std::string &error_message
|
|
493
|
+
) {
|
|
494
|
+
orbpro::invoke::PluginInvokeResponseT response{};
|
|
495
|
+
response.status_code = status_code;
|
|
496
|
+
response.error_code = error_code ? error_code : "invoke-error";
|
|
497
|
+
response.error_message = error_message;
|
|
498
|
+
return SerializeResponse(response);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
static std::vector<uint8_t> DispatchRequestObject(
|
|
502
|
+
const orbpro::invoke::PluginInvokeRequestT &request,
|
|
503
|
+
bool *runtime_error
|
|
504
|
+
) {
|
|
505
|
+
const auto *method = FindMethod(request.method_id);
|
|
506
|
+
if (!method) {
|
|
507
|
+
if (runtime_error) {
|
|
508
|
+
*runtime_error = true;
|
|
509
|
+
}
|
|
510
|
+
return SerializeErrorResponse(
|
|
511
|
+
404,
|
|
512
|
+
"unknown-method",
|
|
513
|
+
std::string("Unknown method: ") + request.method_id
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
ResetInvokeContext(method);
|
|
518
|
+
if (!LoadInputsFromRequest(request) || !ValidateRequiredInputs(method)) {
|
|
519
|
+
if (runtime_error) {
|
|
520
|
+
*runtime_error = true;
|
|
521
|
+
}
|
|
522
|
+
if (g_invoke_context.status_code == 0) {
|
|
523
|
+
g_invoke_context.status_code = 400;
|
|
524
|
+
}
|
|
525
|
+
return SerializeResponse(BuildResponseObject());
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
g_invoke_context.status_code = method->handler ? method->handler() : -1;
|
|
529
|
+
return SerializeResponse(BuildResponseObject());
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
static std::vector<uint8_t> DispatchRequestBytes(
|
|
533
|
+
const uint8_t *request_bytes,
|
|
534
|
+
size_t request_len,
|
|
535
|
+
bool *runtime_error
|
|
536
|
+
) {
|
|
537
|
+
if (!request_bytes || request_len == 0u) {
|
|
538
|
+
if (runtime_error) {
|
|
539
|
+
*runtime_error = true;
|
|
540
|
+
}
|
|
541
|
+
return SerializeErrorResponse(400, "invalid-request", "Invoke request bytes are empty.");
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
::flatbuffers::Verifier verifier(request_bytes, request_len);
|
|
545
|
+
if (!orbpro::invoke::VerifyPluginInvokeRequestBuffer(verifier)) {
|
|
546
|
+
if (runtime_error) {
|
|
547
|
+
*runtime_error = true;
|
|
548
|
+
}
|
|
549
|
+
return SerializeErrorResponse(400, "invalid-request", "Invoke request FlatBuffer verification failed.");
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const auto *request = orbpro::invoke::GetPluginInvokeRequest(request_bytes);
|
|
553
|
+
auto request_object = std::unique_ptr<orbpro::invoke::PluginInvokeRequestT>(request->UnPack());
|
|
554
|
+
return DispatchRequestObject(*request_object, runtime_error);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
static bool ReadAllStdin(std::vector<uint8_t> *bytes_out) {
|
|
558
|
+
if (!bytes_out) {
|
|
559
|
+
return false;
|
|
560
|
+
}
|
|
561
|
+
bytes_out->clear();
|
|
562
|
+
|
|
563
|
+
uint8_t buffer[4096];
|
|
564
|
+
while (true) {
|
|
565
|
+
const size_t read_count = std::fread(buffer, 1, sizeof(buffer), stdin);
|
|
566
|
+
if (read_count > 0u) {
|
|
567
|
+
bytes_out->insert(bytes_out->end(), buffer, buffer + read_count);
|
|
568
|
+
}
|
|
569
|
+
if (read_count < sizeof(buffer)) {
|
|
570
|
+
if (std::ferror(stdin)) {
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
static bool WriteAllStdout(const uint8_t *bytes, size_t length) {
|
|
580
|
+
if (!bytes && length > 0u) {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
if (length == 0u) {
|
|
584
|
+
return std::fflush(stdout) == 0;
|
|
585
|
+
}
|
|
586
|
+
return std::fwrite(bytes, 1, length, stdout) == length && std::fflush(stdout) == 0;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
static bool BuildRawShortcutRequest(
|
|
590
|
+
const MethodDescriptor *method,
|
|
591
|
+
const std::vector<uint8_t> &stdin_bytes,
|
|
592
|
+
orbpro::invoke::PluginInvokeRequestT *request
|
|
593
|
+
) {
|
|
594
|
+
if (!method || !method->raw_shortcut_allowed || !request) {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
request->method_id = method->method_id;
|
|
598
|
+
request->payload_arena = stdin_bytes;
|
|
599
|
+
|
|
600
|
+
auto frame = std::make_unique<orbpro::stream::TypedArenaBufferT>();
|
|
601
|
+
frame->port_id = method->raw_input_port_id ? method->raw_input_port_id : "";
|
|
602
|
+
frame->alignment = 1;
|
|
603
|
+
frame->offset = 0;
|
|
604
|
+
frame->size = static_cast<uint32_t>(stdin_bytes.size());
|
|
605
|
+
request->input_frames.emplace_back(std::move(frame));
|
|
606
|
+
return true;
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
} // namespace
|
|
610
|
+
|
|
611
|
+
extern "C" uint32_t plugin_get_input_count(void) {
|
|
612
|
+
return static_cast<uint32_t>(g_invoke_context.inputs.size());
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
extern "C" const plugin_input_frame_t *plugin_get_input_frame(uint32_t index) {
|
|
616
|
+
if (index >= g_invoke_context.inputs.size()) {
|
|
617
|
+
return nullptr;
|
|
618
|
+
}
|
|
619
|
+
return &g_invoke_context.inputs[index].view;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
extern "C" int32_t plugin_find_input_index(const char *port_id, uint32_t ordinal) {
|
|
623
|
+
if (!port_id || !port_id[0]) {
|
|
624
|
+
return -1;
|
|
625
|
+
}
|
|
626
|
+
uint32_t seen = 0;
|
|
627
|
+
for (size_t index = 0; index < g_invoke_context.inputs.size(); index += 1) {
|
|
628
|
+
if (g_invoke_context.inputs[index].port_id != port_id) {
|
|
629
|
+
continue;
|
|
630
|
+
}
|
|
631
|
+
if (seen == ordinal) {
|
|
632
|
+
return static_cast<int32_t>(index);
|
|
633
|
+
}
|
|
634
|
+
seen += 1;
|
|
635
|
+
}
|
|
636
|
+
return -1;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
extern "C" void plugin_reset_output_state(void) {
|
|
640
|
+
g_invoke_context.outputs.clear();
|
|
641
|
+
g_invoke_context.backlog_remaining = 0;
|
|
642
|
+
g_invoke_context.yielded = false;
|
|
643
|
+
g_invoke_context.error_code.clear();
|
|
644
|
+
g_invoke_context.error_message.clear();
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
extern "C" int32_t plugin_push_output(
|
|
648
|
+
const char *port_id,
|
|
649
|
+
const char *schema_name,
|
|
650
|
+
const char *file_identifier,
|
|
651
|
+
const uint8_t *payload_ptr,
|
|
652
|
+
uint32_t payload_length
|
|
653
|
+
) {
|
|
654
|
+
return plugin_push_output_ex(
|
|
655
|
+
port_id,
|
|
656
|
+
schema_name,
|
|
657
|
+
file_identifier,
|
|
658
|
+
static_cast<uint32_t>(orbpro::stream::PayloadWireFormat_Flatbuffer),
|
|
659
|
+
nullptr,
|
|
660
|
+
0,
|
|
661
|
+
0,
|
|
662
|
+
payload_ptr,
|
|
663
|
+
payload_length
|
|
664
|
+
);
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
extern "C" int32_t plugin_push_output_typed(
|
|
668
|
+
const char *port_id,
|
|
669
|
+
const char *schema_name,
|
|
670
|
+
const char *file_identifier,
|
|
671
|
+
uint32_t wire_format,
|
|
672
|
+
const char *root_type_name,
|
|
673
|
+
uint16_t fixed_string_length,
|
|
674
|
+
uint32_t byte_length,
|
|
675
|
+
uint16_t required_alignment,
|
|
676
|
+
const uint8_t *payload_ptr,
|
|
677
|
+
uint32_t payload_length
|
|
678
|
+
) {
|
|
679
|
+
if (!port_id || !port_id[0]) {
|
|
680
|
+
SetError("invalid-output-port", "Output frames must declare a non-empty port id.");
|
|
681
|
+
return -1;
|
|
682
|
+
}
|
|
683
|
+
if (!MethodDeclaresOutputPort(g_invoke_context.method, port_id)) {
|
|
684
|
+
SetError(
|
|
685
|
+
"unknown-output-port",
|
|
686
|
+
std::string("Output port is not declared on the active method: ") + port_id
|
|
687
|
+
);
|
|
688
|
+
return -1;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
OutputFrameOwned frame{};
|
|
692
|
+
frame.port_id = ReadCString(port_id);
|
|
693
|
+
frame.schema_name = ReadCString(schema_name);
|
|
694
|
+
frame.file_identifier = ReadCString(file_identifier);
|
|
695
|
+
frame.root_type_name = ReadCString(root_type_name);
|
|
696
|
+
frame.wire_format = wire_format;
|
|
697
|
+
frame.fixed_string_length = fixed_string_length;
|
|
698
|
+
frame.byte_length = byte_length > 0u ? byte_length : payload_length;
|
|
699
|
+
frame.required_alignment = required_alignment;
|
|
700
|
+
frame.alignment = required_alignment > 0 ? required_alignment : 8;
|
|
701
|
+
if (payload_ptr && payload_length > 0u) {
|
|
702
|
+
frame.payload.insert(frame.payload.end(), payload_ptr, payload_ptr + payload_length);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
g_invoke_context.outputs.emplace_back(std::move(frame));
|
|
706
|
+
return static_cast<int32_t>(g_invoke_context.outputs.size() - 1u);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
extern "C" int32_t plugin_push_output_ex(
|
|
710
|
+
const char *port_id,
|
|
711
|
+
const char *schema_name,
|
|
712
|
+
const char *file_identifier,
|
|
713
|
+
uint32_t wire_format,
|
|
714
|
+
const char *root_type_name,
|
|
715
|
+
uint16_t fixed_string_length,
|
|
716
|
+
uint16_t required_alignment,
|
|
717
|
+
const uint8_t *payload_ptr,
|
|
718
|
+
uint32_t payload_length
|
|
719
|
+
) {
|
|
720
|
+
return plugin_push_output_typed(
|
|
721
|
+
port_id,
|
|
722
|
+
schema_name,
|
|
723
|
+
file_identifier,
|
|
724
|
+
wire_format,
|
|
725
|
+
root_type_name,
|
|
726
|
+
fixed_string_length,
|
|
727
|
+
payload_length,
|
|
728
|
+
required_alignment,
|
|
729
|
+
payload_ptr,
|
|
730
|
+
payload_length
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
extern "C" void plugin_set_yielded(int32_t yielded) {
|
|
735
|
+
g_invoke_context.yielded = yielded != 0;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
extern "C" void plugin_set_backlog_remaining(uint32_t backlog_remaining) {
|
|
739
|
+
g_invoke_context.backlog_remaining = backlog_remaining;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
extern "C" void plugin_set_error(const char *error_code, const char *error_message) {
|
|
743
|
+
g_invoke_context.error_code = error_code ? error_code : "";
|
|
744
|
+
g_invoke_context.error_message = error_message ? error_message : "";
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
extern "C" uint32_t plugin_alloc(uint32_t size) {
|
|
748
|
+
const auto allocation_size = size > 0u ? size : 1u;
|
|
749
|
+
void *ptr = std::malloc(allocation_size);
|
|
750
|
+
return ptr ? static_cast<uint32_t>(reinterpret_cast<uintptr_t>(ptr)) : 0u;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
extern "C" void plugin_free(uint32_t ptr, uint32_t size) {
|
|
754
|
+
(void)size;
|
|
755
|
+
if (ptr != 0u) {
|
|
756
|
+
std::free(reinterpret_cast<void *>(PtrFromU32(ptr)));
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
extern "C" uint32_t plugin_invoke_stream(
|
|
761
|
+
uint32_t request_ptr,
|
|
762
|
+
uint32_t request_len,
|
|
763
|
+
uint32_t response_len_out_ptr
|
|
764
|
+
) {
|
|
765
|
+
if (response_len_out_ptr != 0u) {
|
|
766
|
+
*MutableU32Ptr(response_len_out_ptr) = 0u;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
bool runtime_error = false;
|
|
770
|
+
const auto response_bytes = DispatchRequestBytes(
|
|
771
|
+
ConstPtr(request_ptr),
|
|
772
|
+
static_cast<size_t>(request_len),
|
|
773
|
+
&runtime_error
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
const uint32_t response_ptr = plugin_alloc(static_cast<uint32_t>(response_bytes.size()));
|
|
777
|
+
if (response_ptr == 0u) {
|
|
778
|
+
return 0u;
|
|
779
|
+
}
|
|
780
|
+
if (!response_bytes.empty()) {
|
|
781
|
+
std::memcpy(MutablePtr(response_ptr), response_bytes.data(), response_bytes.size());
|
|
782
|
+
}
|
|
783
|
+
if (response_len_out_ptr != 0u) {
|
|
784
|
+
*MutableU32Ptr(response_len_out_ptr) = static_cast<uint32_t>(response_bytes.size());
|
|
785
|
+
}
|
|
786
|
+
return response_ptr;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
${includeCommandMain
|
|
790
|
+
? `int main(int argc, char **argv) {
|
|
791
|
+
const char *shortcut_method = nullptr;
|
|
792
|
+
for (int index = 1; index < argc; index += 1) {
|
|
793
|
+
if (std::strcmp(argv[index], "--method") == 0) {
|
|
794
|
+
if (index + 1 >= argc) {
|
|
795
|
+
std::fprintf(stderr, "--method requires a method id argument.\\n");
|
|
796
|
+
return 64;
|
|
797
|
+
}
|
|
798
|
+
shortcut_method = argv[++index];
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
std::fprintf(stderr, "Unknown argument: %s\\n", argv[index]);
|
|
802
|
+
return 64;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
std::vector<uint8_t> stdin_bytes;
|
|
806
|
+
if (!ReadAllStdin(&stdin_bytes)) {
|
|
807
|
+
std::fprintf(stderr, "Failed to read stdin.\\n");
|
|
808
|
+
return 74;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
if (shortcut_method) {
|
|
812
|
+
const auto *method = FindMethod(shortcut_method);
|
|
813
|
+
if (!method || !method->raw_shortcut_allowed) {
|
|
814
|
+
std::fprintf(
|
|
815
|
+
stderr,
|
|
816
|
+
"Method %s does not support raw stdin/stdout shortcut mode.\\n",
|
|
817
|
+
shortcut_method
|
|
818
|
+
);
|
|
819
|
+
return 64;
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
orbpro::invoke::PluginInvokeRequestT shortcut_request{};
|
|
823
|
+
if (!BuildRawShortcutRequest(method, stdin_bytes, &shortcut_request)) {
|
|
824
|
+
std::fprintf(stderr, "Failed to construct raw shortcut request.\\n");
|
|
825
|
+
return 64;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
bool runtime_error = false;
|
|
829
|
+
const auto response_bytes = DispatchRequestObject(shortcut_request, &runtime_error);
|
|
830
|
+
::flatbuffers::Verifier verifier(response_bytes.data(), response_bytes.size());
|
|
831
|
+
if (!orbpro::invoke::VerifyPluginInvokeResponseBuffer(verifier)) {
|
|
832
|
+
std::fprintf(stderr, "Shortcut response verification failed.\\n");
|
|
833
|
+
return 70;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
auto response = std::unique_ptr<orbpro::invoke::PluginInvokeResponseT>(
|
|
837
|
+
orbpro::invoke::GetPluginInvokeResponse(response_bytes.data())->UnPack()
|
|
838
|
+
);
|
|
839
|
+
if (runtime_error || response->status_code != 0 || !response->error_code.empty()) {
|
|
840
|
+
if (!response->error_message.empty()) {
|
|
841
|
+
std::fprintf(stderr, "%s\\n", response->error_message.c_str());
|
|
842
|
+
}
|
|
843
|
+
return 1;
|
|
844
|
+
}
|
|
845
|
+
if (response->output_frames.size() > 1u) {
|
|
846
|
+
std::fprintf(stderr, "Raw shortcut mode produced more than one output frame.\\n");
|
|
847
|
+
return 65;
|
|
848
|
+
}
|
|
849
|
+
if (response->output_frames.empty()) {
|
|
850
|
+
return 0;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
const auto &frame = *response->output_frames[0];
|
|
854
|
+
const auto payload_offset = static_cast<size_t>(frame.offset);
|
|
855
|
+
const auto payload_size = static_cast<size_t>(frame.size);
|
|
856
|
+
if (payload_offset + payload_size > response->payload_arena.size()) {
|
|
857
|
+
std::fprintf(stderr, "Raw shortcut output frame exceeds response payload arena.\\n");
|
|
858
|
+
return 70;
|
|
859
|
+
}
|
|
860
|
+
if (!WriteAllStdout(response->payload_arena.data() + payload_offset, payload_size)) {
|
|
861
|
+
std::fprintf(stderr, "Failed to write stdout.\\n");
|
|
862
|
+
return 74;
|
|
863
|
+
}
|
|
864
|
+
return 0;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
bool runtime_error = false;
|
|
868
|
+
const auto response_bytes = DispatchRequestBytes(
|
|
869
|
+
stdin_bytes.empty() ? nullptr : stdin_bytes.data(),
|
|
870
|
+
stdin_bytes.size(),
|
|
871
|
+
&runtime_error
|
|
872
|
+
);
|
|
873
|
+
if (!WriteAllStdout(
|
|
874
|
+
response_bytes.empty() ? nullptr : response_bytes.data(),
|
|
875
|
+
response_bytes.size()
|
|
876
|
+
)) {
|
|
877
|
+
std::fprintf(stderr, "Failed to write stdout.\\n");
|
|
878
|
+
return 74;
|
|
879
|
+
}
|
|
880
|
+
return runtime_error ? 1 : 0;
|
|
881
|
+
}`
|
|
882
|
+
: ""}
|
|
883
|
+
`;
|
|
884
|
+
}
|