@twin.org/dataspace-control-plane-service 0.0.3-next.33 → 0.0.3-next.35
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/es/dataspaceControlPlaneService.js +301 -6
- package/dist/es/dataspaceControlPlaneService.js.map +1 -1
- package/dist/es/models/IDataspaceControlPlaneServiceConstructorOptions.js.map +1 -1
- package/dist/types/dataspaceControlPlaneService.d.ts +41 -1
- package/dist/types/models/IDataspaceControlPlaneServiceConstructorOptions.d.ts +6 -0
- package/docs/changelog.md +28 -0
- package/docs/reference/classes/DataspaceControlPlaneService.md +114 -0
- package/docs/reference/interfaces/IDataspaceControlPlaneServiceConstructorOptions.md +15 -0
- package/locales/en.json +7 -1
- package/package.json +2 -2
|
@@ -120,6 +120,22 @@ export class DataspaceControlPlaneService {
|
|
|
120
120
|
* @internal
|
|
121
121
|
*/
|
|
122
122
|
_negotiationCallbacks;
|
|
123
|
+
/**
|
|
124
|
+
* Registered transfer callbacks from upstream callers, keyed by registration key.
|
|
125
|
+
* @internal
|
|
126
|
+
*/
|
|
127
|
+
_transferCallbacks;
|
|
128
|
+
/**
|
|
129
|
+
* Internal transfer callback that fans out to all registered transfer callbacks.
|
|
130
|
+
* @internal
|
|
131
|
+
*/
|
|
132
|
+
_internalTransferCallback;
|
|
133
|
+
/**
|
|
134
|
+
* Factory key used to create remote control plane REST client instances for outbound
|
|
135
|
+
* DSP transfer requests. Resolved via ComponentFactory.create() at call time.
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
_remoteControlPlaneComponentType;
|
|
123
139
|
/**
|
|
124
140
|
* The component type name for the hosting component.
|
|
125
141
|
* @internal
|
|
@@ -159,6 +175,10 @@ export class DataspaceControlPlaneService {
|
|
|
159
175
|
options?.dataPlaneComponentType ?? "dataspace-data-plane-service";
|
|
160
176
|
this._urlTransformerComponent = ComponentFactory.get(options?.urlTransformerComponentType ?? "url-transformer");
|
|
161
177
|
this._negotiationCallbacks = new Map();
|
|
178
|
+
this._transferCallbacks = new Map();
|
|
179
|
+
this._internalTransferCallback = this.createInternalTransferCallback();
|
|
180
|
+
this._remoteControlPlaneComponentType =
|
|
181
|
+
options?.remoteControlPlaneComponentType ?? "dataspace-control-plane-rest-client";
|
|
162
182
|
const internalCallback = this.createInternalCallback();
|
|
163
183
|
this._policyRequester = new DataspaceControlPlanePolicyRequester(options?.loggingComponentType ?? "logging", internalCallback);
|
|
164
184
|
PolicyRequesterFactory.register(DataspaceControlPlaneService._REQUESTER_TYPE, () => this._policyRequester);
|
|
@@ -188,6 +208,24 @@ export class DataspaceControlPlaneService {
|
|
|
188
208
|
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "key", key);
|
|
189
209
|
this._negotiationCallbacks.delete(key);
|
|
190
210
|
}
|
|
211
|
+
/**
|
|
212
|
+
* Register a callback to receive transfer process state change notifications.
|
|
213
|
+
* @param key A unique key identifying this callback registration.
|
|
214
|
+
* @param callback The callback interface to register.
|
|
215
|
+
*/
|
|
216
|
+
registerTransferCallback(key, callback) {
|
|
217
|
+
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "key", key);
|
|
218
|
+
Guards.object(DataspaceControlPlaneService.CLASS_NAME, "callback", callback);
|
|
219
|
+
this._transferCallbacks.set(key, callback);
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Unregister a previously registered transfer callback.
|
|
223
|
+
* @param key The key used when registering the callback.
|
|
224
|
+
*/
|
|
225
|
+
unregisterTransferCallback(key) {
|
|
226
|
+
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "key", key);
|
|
227
|
+
this._transferCallbacks.delete(key);
|
|
228
|
+
}
|
|
191
229
|
/**
|
|
192
230
|
* The service needs to be started when the application is initialized.
|
|
193
231
|
* Populates the Federated Catalogue with datasets from registered apps
|
|
@@ -406,6 +444,142 @@ export class DataspaceControlPlaneService {
|
|
|
406
444
|
state: entity.state
|
|
407
445
|
};
|
|
408
446
|
}
|
|
447
|
+
/**
|
|
448
|
+
* Start a data transfer as a Consumer.
|
|
449
|
+
* Generates a consumerPid, POSTs a TransferRequestMessage to the provider's DSP endpoint,
|
|
450
|
+
* and (only if the provider accepts) persists a local TransferProcess in REQUESTED state.
|
|
451
|
+
* @param agreementId The finalized agreement ID from contract negotiation.
|
|
452
|
+
* @param providerEndpoint The provider's DSP control plane base URL.
|
|
453
|
+
* @param publicOrigin The public origin URL of this control plane (used as callbackAddress).
|
|
454
|
+
* @param format The transfer format (e.g. "HttpData-PULL", "HttpData-PUSH").
|
|
455
|
+
* @param trustPayload Trust payload for authenticating this call.
|
|
456
|
+
* @returns The consumerPid of the newly created TransferProcess.
|
|
457
|
+
*
|
|
458
|
+
* **Engine configuration requirement:** The outbound call to the provider uses
|
|
459
|
+
* `ComponentFactory.create(remoteControlPlaneComponentType, { endpoint, pathPrefix })`.
|
|
460
|
+
* For the runtime `providerEndpoint` to be forwarded correctly, the engine **must** register
|
|
461
|
+
* the component type (default: `dataspace-control-plane-rest-client`) as a
|
|
462
|
+
* **multi-instance** component (`isMultiInstance: true` in engine config). A singleton
|
|
463
|
+
* registration ignores the runtime `endpoint` arg and silently POSTs to its
|
|
464
|
+
* static endpoint instead.
|
|
465
|
+
*/
|
|
466
|
+
async startDataTransfer(agreementId, providerEndpoint, publicOrigin, format, trustPayload) {
|
|
467
|
+
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "agreementId", agreementId);
|
|
468
|
+
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "providerEndpoint", providerEndpoint);
|
|
469
|
+
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "publicOrigin", publicOrigin);
|
|
470
|
+
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "format", format);
|
|
471
|
+
if (!Object.values(DataspaceTransferFormat).includes(format)) {
|
|
472
|
+
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "unsupportedTransferFormat", {
|
|
473
|
+
format,
|
|
474
|
+
supported: Object.values(DataspaceTransferFormat)
|
|
475
|
+
});
|
|
476
|
+
}
|
|
477
|
+
const trustInfo = await TrustHelper.verifyTrust(this._trustComponent, trustPayload, "startDataTransfer");
|
|
478
|
+
await this._loggingComponent?.log({
|
|
479
|
+
level: "info",
|
|
480
|
+
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
481
|
+
ts: Date.now(),
|
|
482
|
+
message: "startingDataTransfer",
|
|
483
|
+
data: { agreementId, providerEndpoint, format, identity: trustInfo.identity }
|
|
484
|
+
});
|
|
485
|
+
const agreement = await this.lookupAgreement(agreementId);
|
|
486
|
+
const assigneeIdentity = OdrlPolicyHelper.extractAssigneeIdentity(agreement);
|
|
487
|
+
const assigneeIds = ArrayHelper.fromObjectOrArray(assigneeIdentity);
|
|
488
|
+
const callerComposite = this.buildCallerComposite(trustInfo);
|
|
489
|
+
if (!assigneeIds.includes(callerComposite)) {
|
|
490
|
+
throw new UnauthorizedError(DataspaceControlPlaneService.CLASS_NAME, "callerNotAuthorizedForAgreement");
|
|
491
|
+
}
|
|
492
|
+
const assignerIdentity = OdrlPolicyHelper.extractAssignerIdentity(agreement);
|
|
493
|
+
const assignerIds = ArrayHelper.fromObjectOrArray(assignerIdentity);
|
|
494
|
+
if (assignerIds.length > 1) {
|
|
495
|
+
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "multipleAssignersNotSupported");
|
|
496
|
+
}
|
|
497
|
+
const providerIdentity = assignerIds[0];
|
|
498
|
+
const datasetId = this.extractDatasetId(agreement);
|
|
499
|
+
const consumerPid = `urn:uuid:${RandomHelper.generateUuidV7()}`;
|
|
500
|
+
const callbackAddress = StringHelper.trimTrailingSlashes(publicOrigin);
|
|
501
|
+
// Fetch context once and reuse across the PUSH dataAddress, trust token, and storage entity.
|
|
502
|
+
const contextIds = await ContextIdStore.getContextIds();
|
|
503
|
+
const nodeIdentity = contextIds?.[ContextIdKeys.Node];
|
|
504
|
+
Guards.stringValue(DataspaceControlPlaneService.CLASS_NAME, "nodeIdentity", nodeIdentity);
|
|
505
|
+
const tenantId = contextIds?.[ContextIdKeys.Tenant];
|
|
506
|
+
const organizationIdentity = contextIds?.[ContextIdKeys.Organization];
|
|
507
|
+
const transferRequestMessage = {
|
|
508
|
+
"@context": [DataspaceProtocolContexts.Context],
|
|
509
|
+
"@type": DataspaceProtocolTransferProcessTypes.TransferRequestMessage,
|
|
510
|
+
consumerPid,
|
|
511
|
+
agreementId,
|
|
512
|
+
callbackAddress,
|
|
513
|
+
format
|
|
514
|
+
};
|
|
515
|
+
// For consumer-initiated PUSH transfers the consumer must supply its /inbox endpoint as
|
|
516
|
+
// dataAddress so the provider knows where to push ActivityStreams objects. Without it the
|
|
517
|
+
// provider silently falls through to PULL mode on startTransfer.
|
|
518
|
+
if (format === DataspaceTransferFormat.HttpDataPush) {
|
|
519
|
+
if (!Is.stringValue(this._dataPlanePath)) {
|
|
520
|
+
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "pushTransferDataPathNotConfigured", { consumerPid });
|
|
521
|
+
}
|
|
522
|
+
let inboxEndpoint = `${callbackAddress}/${this._dataPlanePath}/inbox`;
|
|
523
|
+
if (Is.stringValue(tenantId)) {
|
|
524
|
+
inboxEndpoint = await this._urlTransformerComponent.addEncryptedQueryParamToUrl(inboxEndpoint, "tenant", tenantId);
|
|
525
|
+
}
|
|
526
|
+
transferRequestMessage.dataAddress = {
|
|
527
|
+
"@type": DataspaceProtocolTransferProcessTypes.DataAddress,
|
|
528
|
+
endpointType: DataspaceProtocolEndpointType.HttpsActivityStreamEndpoint,
|
|
529
|
+
endpoint: inboxEndpoint
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
// Generate outbound trust token to authenticate this node to the provider.
|
|
533
|
+
const outboundToken = await this._trustComponent.generate(nodeIdentity, this._overrideTrustGeneratorType, { subject: { consumerPid, agreementId } }, Is.stringValue(tenantId) ? TrustHelper.hashTenantId(tenantId) : undefined, organizationIdentity);
|
|
534
|
+
// Create a remote REST client pointed at the provider endpoint and call requestTransfer.
|
|
535
|
+
const remoteControlPlane = ComponentFactory.create(this._remoteControlPlaneComponentType, { endpoint: providerEndpoint, pathPrefix: "" });
|
|
536
|
+
const result = await remoteControlPlane.requestTransfer(transferRequestMessage, outboundToken);
|
|
537
|
+
if (getJsonLdType(result) === DataspaceProtocolTransferProcessTypes.TransferError) {
|
|
538
|
+
const transferError = result;
|
|
539
|
+
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "transferRequestRejectedByProvider", {
|
|
540
|
+
agreementId,
|
|
541
|
+
providerEndpoint,
|
|
542
|
+
code: transferError.code
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
const transferProcess = result;
|
|
546
|
+
if (!Is.stringValue(transferProcess.providerPid)) {
|
|
547
|
+
throw new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "providerPidMissingInResponse", { consumerPid });
|
|
548
|
+
}
|
|
549
|
+
const now = new Date();
|
|
550
|
+
const storageEntity = {
|
|
551
|
+
id: Converter.bytesToHex(RandomHelper.generate(32)),
|
|
552
|
+
consumerPid,
|
|
553
|
+
providerPid: transferProcess.providerPid,
|
|
554
|
+
state: DataspaceProtocolTransferProcessStateType.REQUESTED,
|
|
555
|
+
agreementId,
|
|
556
|
+
datasetId,
|
|
557
|
+
consumerIdentity: callerComposite,
|
|
558
|
+
providerIdentity,
|
|
559
|
+
offerId: agreementId,
|
|
560
|
+
policies: [agreement],
|
|
561
|
+
callbackAddress,
|
|
562
|
+
format,
|
|
563
|
+
dataAddress: transferRequestMessage.dataAddress,
|
|
564
|
+
tenantId: Is.stringValue(tenantId) ? tenantId : undefined,
|
|
565
|
+
dateCreated: now.toISOString(),
|
|
566
|
+
dateModified: now.toISOString()
|
|
567
|
+
};
|
|
568
|
+
await this._transferProcessStorage.set(storageEntity);
|
|
569
|
+
await this._loggingComponent?.log({
|
|
570
|
+
level: "info",
|
|
571
|
+
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
572
|
+
ts: Date.now(),
|
|
573
|
+
message: "dataTransferStarted",
|
|
574
|
+
data: {
|
|
575
|
+
consumerPid,
|
|
576
|
+
providerPid: storageEntity.providerPid,
|
|
577
|
+
agreementId,
|
|
578
|
+
format
|
|
579
|
+
}
|
|
580
|
+
});
|
|
581
|
+
return { consumerPid };
|
|
582
|
+
}
|
|
409
583
|
// ----------------------------------------------------------------------------
|
|
410
584
|
// PROVIDER SIDE OPERATIONS
|
|
411
585
|
// ----------------------------------------------------------------------------
|
|
@@ -492,10 +666,10 @@ export class DataspaceControlPlaneService {
|
|
|
492
666
|
//
|
|
493
667
|
// See: https://eclipse-dataspace-protocol-base.github.io/DataspaceProtocol/2025-1-err1/#transfer-start-message
|
|
494
668
|
// ============================================================================
|
|
495
|
-
if (Is.empty(entity.dataAddress) && entity.format === DataspaceTransferFormat.
|
|
669
|
+
if (Is.empty(entity.dataAddress) && entity.format === DataspaceTransferFormat.HttpDataPost) {
|
|
496
670
|
// PROVIDER-INITIATED PUSH: Consumer requested push but did not supply an /inbox.
|
|
497
671
|
// Provider returns its own /inbox URL + a signed JWT so the consumer can verify
|
|
498
|
-
// the incoming activities (
|
|
672
|
+
// the incoming activities (HttpData-POST / DataspaceTransferFormat.HttpDataPost).
|
|
499
673
|
if (!Is.stringValue(this._dataPlanePath)) {
|
|
500
674
|
return transformToTransferError(new GeneralError(DataspaceControlPlaneService.CLASS_NAME, "pushTransferDataPathNotConfigured", { consumerPid: entity.consumerPid }), message);
|
|
501
675
|
}
|
|
@@ -549,7 +723,7 @@ export class DataspaceControlPlaneService {
|
|
|
549
723
|
consumerPid: entity.consumerPid,
|
|
550
724
|
providerPid: entity.providerPid,
|
|
551
725
|
endpoint: fullEndpoint,
|
|
552
|
-
transferMode: DataspaceTransferFormat.
|
|
726
|
+
transferMode: DataspaceTransferFormat.HttpDataPost
|
|
553
727
|
}
|
|
554
728
|
});
|
|
555
729
|
}
|
|
@@ -651,7 +825,7 @@ export class DataspaceControlPlaneService {
|
|
|
651
825
|
consumerPid: entity.consumerPid,
|
|
652
826
|
providerPid: entity.providerPid,
|
|
653
827
|
endpoint: fullEndpoint,
|
|
654
|
-
transferMode: DataspaceTransferFormat.
|
|
828
|
+
transferMode: DataspaceTransferFormat.HttpDataPush
|
|
655
829
|
}
|
|
656
830
|
});
|
|
657
831
|
try {
|
|
@@ -670,6 +844,10 @@ export class DataspaceControlPlaneService {
|
|
|
670
844
|
throw setupError;
|
|
671
845
|
}
|
|
672
846
|
}
|
|
847
|
+
if (role === TransferProcessRole.Consumer) {
|
|
848
|
+
await this._internalTransferCallback.onStateChanged(entity.consumerPid, DataspaceProtocolTransferProcessStateType.STARTED);
|
|
849
|
+
await this._internalTransferCallback.onStarted(entity.consumerPid, response);
|
|
850
|
+
}
|
|
673
851
|
return response;
|
|
674
852
|
}
|
|
675
853
|
catch (error) {
|
|
@@ -757,6 +935,10 @@ export class DataspaceControlPlaneService {
|
|
|
757
935
|
throw teardownError;
|
|
758
936
|
}
|
|
759
937
|
}
|
|
938
|
+
if (role === TransferProcessRole.Consumer) {
|
|
939
|
+
await this._internalTransferCallback.onStateChanged(entity.consumerPid, DataspaceProtocolTransferProcessStateType.COMPLETED);
|
|
940
|
+
await this._internalTransferCallback.onCompleted(entity.consumerPid);
|
|
941
|
+
}
|
|
760
942
|
return {
|
|
761
943
|
"@context": [DataspaceProtocolContexts.Context],
|
|
762
944
|
"@type": DataspaceProtocolTransferProcessTypes.TransferProcess,
|
|
@@ -846,6 +1028,15 @@ export class DataspaceControlPlaneService {
|
|
|
846
1028
|
throw suspendError;
|
|
847
1029
|
}
|
|
848
1030
|
}
|
|
1031
|
+
if (role === TransferProcessRole.Consumer) {
|
|
1032
|
+
await this._internalTransferCallback.onStateChanged(entity.consumerPid, DataspaceProtocolTransferProcessStateType.SUSPENDED);
|
|
1033
|
+
// DSP reason is typed any[] — forward only the first entry since the callback
|
|
1034
|
+
// contract is reason?: string. Additional entries are intentionally dropped.
|
|
1035
|
+
const suspendReason = Array.isArray(message.reason)
|
|
1036
|
+
? message.reason[0]
|
|
1037
|
+
: message.reason;
|
|
1038
|
+
await this._internalTransferCallback.onSuspended(entity.consumerPid, suspendReason);
|
|
1039
|
+
}
|
|
849
1040
|
return {
|
|
850
1041
|
"@context": [DataspaceProtocolContexts.Context],
|
|
851
1042
|
"@type": DataspaceProtocolTransferProcessTypes.TransferProcess,
|
|
@@ -929,6 +1120,15 @@ export class DataspaceControlPlaneService {
|
|
|
929
1120
|
throw teardownError;
|
|
930
1121
|
}
|
|
931
1122
|
}
|
|
1123
|
+
if (role === TransferProcessRole.Consumer) {
|
|
1124
|
+
await this._internalTransferCallback.onStateChanged(entity.consumerPid, DataspaceProtocolTransferProcessStateType.TERMINATED);
|
|
1125
|
+
// DSP reason is typed any[] — forward only the first entry since the callback
|
|
1126
|
+
// contract is reason?: string. Additional entries are intentionally dropped.
|
|
1127
|
+
const terminateReason = Array.isArray(message.reason)
|
|
1128
|
+
? message.reason[0]
|
|
1129
|
+
: message.reason;
|
|
1130
|
+
await this._internalTransferCallback.onTerminated(entity.consumerPid, terminateReason);
|
|
1131
|
+
}
|
|
932
1132
|
return {
|
|
933
1133
|
"@context": [DataspaceProtocolContexts.Context],
|
|
934
1134
|
"@type": DataspaceProtocolTransferProcessTypes.TransferProcess,
|
|
@@ -1632,8 +1832,8 @@ export class DataspaceControlPlaneService {
|
|
|
1632
1832
|
* @internal
|
|
1633
1833
|
*/
|
|
1634
1834
|
isPushFormat(format) {
|
|
1635
|
-
return (format === DataspaceTransferFormat.
|
|
1636
|
-
format === DataspaceTransferFormat.
|
|
1835
|
+
return (format === DataspaceTransferFormat.HttpDataPush ||
|
|
1836
|
+
format === DataspaceTransferFormat.HttpDataPost);
|
|
1637
1837
|
}
|
|
1638
1838
|
/**
|
|
1639
1839
|
* Extract the dataset ID from an ODRL agreement's target.
|
|
@@ -1996,6 +2196,101 @@ export class DataspaceControlPlaneService {
|
|
|
1996
2196
|
}
|
|
1997
2197
|
};
|
|
1998
2198
|
}
|
|
2199
|
+
/**
|
|
2200
|
+
* Creates the internal ITransferCallback that fans out to all registered transfer callbacks.
|
|
2201
|
+
* Errors thrown by individual callbacks are logged and swallowed so they cannot affect
|
|
2202
|
+
* the DSP protocol state machine or other registrants.
|
|
2203
|
+
* @returns The internal transfer callback.
|
|
2204
|
+
*/
|
|
2205
|
+
createInternalTransferCallback() {
|
|
2206
|
+
return {
|
|
2207
|
+
onStateChanged: async (consumerPid, state) => {
|
|
2208
|
+
for (const [key, cb] of this._transferCallbacks.entries()) {
|
|
2209
|
+
try {
|
|
2210
|
+
await cb.onStateChanged(consumerPid, state);
|
|
2211
|
+
}
|
|
2212
|
+
catch (error) {
|
|
2213
|
+
await this._loggingComponent?.log({
|
|
2214
|
+
level: "error",
|
|
2215
|
+
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
2216
|
+
ts: Date.now(),
|
|
2217
|
+
message: "transferCallbackError",
|
|
2218
|
+
error: BaseError.fromError(error),
|
|
2219
|
+
data: { key, consumerPid, state, method: "onStateChanged" }
|
|
2220
|
+
});
|
|
2221
|
+
}
|
|
2222
|
+
}
|
|
2223
|
+
},
|
|
2224
|
+
onStarted: async (consumerPid, message) => {
|
|
2225
|
+
for (const [key, cb] of this._transferCallbacks.entries()) {
|
|
2226
|
+
try {
|
|
2227
|
+
await cb.onStarted(consumerPid, message);
|
|
2228
|
+
}
|
|
2229
|
+
catch (error) {
|
|
2230
|
+
await this._loggingComponent?.log({
|
|
2231
|
+
level: "error",
|
|
2232
|
+
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
2233
|
+
ts: Date.now(),
|
|
2234
|
+
message: "transferCallbackError",
|
|
2235
|
+
error: BaseError.fromError(error),
|
|
2236
|
+
data: { key, consumerPid, method: "onStarted" }
|
|
2237
|
+
});
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
},
|
|
2241
|
+
onCompleted: async (consumerPid) => {
|
|
2242
|
+
for (const [key, cb] of this._transferCallbacks.entries()) {
|
|
2243
|
+
try {
|
|
2244
|
+
await cb.onCompleted(consumerPid);
|
|
2245
|
+
}
|
|
2246
|
+
catch (error) {
|
|
2247
|
+
await this._loggingComponent?.log({
|
|
2248
|
+
level: "error",
|
|
2249
|
+
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
2250
|
+
ts: Date.now(),
|
|
2251
|
+
message: "transferCallbackError",
|
|
2252
|
+
error: BaseError.fromError(error),
|
|
2253
|
+
data: { key, consumerPid, method: "onCompleted" }
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
onSuspended: async (consumerPid, reason) => {
|
|
2259
|
+
for (const [key, cb] of this._transferCallbacks.entries()) {
|
|
2260
|
+
try {
|
|
2261
|
+
await cb.onSuspended(consumerPid, reason);
|
|
2262
|
+
}
|
|
2263
|
+
catch (error) {
|
|
2264
|
+
await this._loggingComponent?.log({
|
|
2265
|
+
level: "error",
|
|
2266
|
+
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
2267
|
+
ts: Date.now(),
|
|
2268
|
+
message: "transferCallbackError",
|
|
2269
|
+
error: BaseError.fromError(error),
|
|
2270
|
+
data: { key, consumerPid, method: "onSuspended" }
|
|
2271
|
+
});
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
},
|
|
2275
|
+
onTerminated: async (consumerPid, reason) => {
|
|
2276
|
+
for (const [key, cb] of this._transferCallbacks.entries()) {
|
|
2277
|
+
try {
|
|
2278
|
+
await cb.onTerminated(consumerPid, reason);
|
|
2279
|
+
}
|
|
2280
|
+
catch (error) {
|
|
2281
|
+
await this._loggingComponent?.log({
|
|
2282
|
+
level: "error",
|
|
2283
|
+
source: DataspaceControlPlaneService.CLASS_NAME,
|
|
2284
|
+
ts: Date.now(),
|
|
2285
|
+
message: "transferCallbackError",
|
|
2286
|
+
error: BaseError.fromError(error),
|
|
2287
|
+
data: { key, consumerPid, method: "onTerminated" }
|
|
2288
|
+
});
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
};
|
|
2293
|
+
}
|
|
1999
2294
|
/**
|
|
2000
2295
|
* Re-stamp `@id` onto a stored payload blob using the entity primary key.
|
|
2001
2296
|
* @param payload The stored payload blob (without `@id`).
|