account-lookup-service 17.4.1-csi-1300.0 → 17.4.1-csi-1300.2
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/package.json +2 -2
- package/src/domain/parties/deps.js +49 -0
- package/src/domain/parties/getPartiesByTypeAndID.js +13 -273
- package/src/domain/parties/partiesUtils.js +8 -1
- package/src/domain/parties/putParties.js +31 -77
- package/src/domain/parties/services/BasePartiesService.js +88 -0
- package/src/domain/parties/services/GetPartiesService.js +82 -64
- package/src/domain/parties/services/PutPartiesErrorService.js +81 -0
- package/src/domain/parties/services/index.js +3 -1
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "account-lookup-service",
|
3
3
|
"description": "Account Lookup Service is used to validate Party and Participant lookups.",
|
4
|
-
"version": "17.4.1-csi-1300.
|
4
|
+
"version": "17.4.1-csi-1300.2",
|
5
5
|
"license": "Apache-2.0",
|
6
6
|
"author": "ModusBox",
|
7
7
|
"contributors": [
|
@@ -97,7 +97,7 @@
|
|
97
97
|
"@mojaloop/central-services-metrics": "12.4.5",
|
98
98
|
"@mojaloop/central-services-shared": "18.22.4-snapshot.0",
|
99
99
|
"@mojaloop/central-services-stream": "11.5.1",
|
100
|
-
"@mojaloop/database-lib": "11.1.
|
100
|
+
"@mojaloop/database-lib": "11.1.4",
|
101
101
|
"@mojaloop/event-sdk": "14.3.2",
|
102
102
|
"@mojaloop/inter-scheme-proxy-cache-lib": "2.3.7",
|
103
103
|
"@mojaloop/ml-schema-transformer-lib": "2.5.8",
|
@@ -0,0 +1,49 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
10
|
+
|
11
|
+
Contributors
|
12
|
+
--------------
|
13
|
+
This is the official list of the Mojaloop project contributors for this file.
|
14
|
+
Names of the original copyright holders (individuals or organizations)
|
15
|
+
should be listed with a '*' in the first column. People who have
|
16
|
+
contributed from an organization can be listed under the organization
|
17
|
+
that actually holds the copyright for their contributions (see the
|
18
|
+
Mojaloop Foundation for an example). Those individuals should have
|
19
|
+
their names indented and be marked with a '-'. Email address can be added
|
20
|
+
optionally within square brackets <email>.
|
21
|
+
|
22
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const { proxies } = require('@mojaloop/central-services-shared').Util
|
29
|
+
const oracle = require('../../models/oracle/facade')
|
30
|
+
const participant = require('../../models/participantEndpoint/facade')
|
31
|
+
const config = require('../../lib/config')
|
32
|
+
const partiesUtils = require('./partiesUtils')
|
33
|
+
|
34
|
+
const createDeps = ({ cache, proxyCache, childSpan, log, stepState }) => Object.freeze({
|
35
|
+
cache,
|
36
|
+
proxyCache,
|
37
|
+
childSpan,
|
38
|
+
log,
|
39
|
+
stepState,
|
40
|
+
config,
|
41
|
+
oracle,
|
42
|
+
participant,
|
43
|
+
proxies,
|
44
|
+
partiesUtils
|
45
|
+
})
|
46
|
+
|
47
|
+
module.exports = {
|
48
|
+
createDeps
|
49
|
+
}
|
@@ -23,38 +23,11 @@
|
|
23
23
|
--------------
|
24
24
|
**********/
|
25
25
|
|
26
|
-
const { Enum, Util } = require('@mojaloop/central-services-shared')
|
27
|
-
// const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
28
26
|
const Metrics = require('@mojaloop/central-services-metrics')
|
29
|
-
|
30
|
-
const oracle = require('../../models/oracle/facade')
|
31
|
-
const participant = require('../../models/participantEndpoint/facade')
|
32
|
-
const config = require('../../lib/config')
|
33
27
|
const libUtil = require('../../lib/util')
|
34
28
|
const { logger } = require('../../lib')
|
35
|
-
// const { createCallbackHeaders } = require('../../lib/headers')
|
36
|
-
// const { ERROR_MESSAGES } = require('../../constants')
|
37
29
|
const { GetPartiesService } = require('./services')
|
38
|
-
const
|
39
|
-
|
40
|
-
// const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
|
41
|
-
// const { Headers, RestMethods } = Enum.Http
|
42
|
-
const { Headers } = Enum.Http
|
43
|
-
|
44
|
-
// const proxyCacheTtlSec = 40 // todo: make configurable
|
45
|
-
|
46
|
-
const createDeps = ({ cache, proxyCache, childSpan, log, stepState }) => Object.freeze({
|
47
|
-
cache,
|
48
|
-
proxyCache,
|
49
|
-
childSpan,
|
50
|
-
log,
|
51
|
-
stepState,
|
52
|
-
config,
|
53
|
-
oracle,
|
54
|
-
participant,
|
55
|
-
proxies: Util.proxies,
|
56
|
-
partiesUtils
|
57
|
-
})
|
30
|
+
const { createDeps } = require('./deps')
|
58
31
|
|
59
32
|
/**
|
60
33
|
* @function getPartiesByTypeAndID
|
@@ -76,261 +49,28 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
76
49
|
'Get party by Type and Id',
|
77
50
|
['success']
|
78
51
|
).startTimer()
|
52
|
+
const childSpan = span ? span.getChild(component) : undefined
|
79
53
|
const log = logger.child({ component, params })
|
80
54
|
const stepState = libUtil.initStepState()
|
81
|
-
const childSpan = span ? span.getChild(component) : undefined
|
82
55
|
|
83
|
-
const
|
84
|
-
|
85
|
-
}
|
86
|
-
|
87
|
-
const proxyEnabled = !!(config.PROXY_CACHE_CONFIG.enabled && proxyCache)
|
88
|
-
const source = headers[Headers.FSPIOP.SOURCE]
|
89
|
-
const proxy = proxyEnabled && headers[Headers.FSPIOP.PROXY]
|
90
|
-
const destination = headers[Headers.FSPIOP.DESTINATION]
|
91
|
-
// see https://github.com/mojaloop/design-authority/issues/79
|
92
|
-
// the requester has specified a destination routing header. We should respect that and forward the request directly to the destination
|
93
|
-
// without consulting any oracles.
|
94
|
-
|
95
|
-
log.info('parties::getPartiesByTypeAndID start', { source, destination, proxy })
|
96
|
-
|
97
|
-
let requester
|
98
|
-
let fspiopError
|
56
|
+
const deps = createDeps({ cache, proxyCache, childSpan, log, stepState })
|
57
|
+
const service = new GetPartiesService(deps)
|
58
|
+
const results = {}
|
99
59
|
|
100
60
|
try {
|
101
|
-
|
102
|
-
|
103
|
-
if (destination) {
|
104
|
-
await service.forwardRequestToDestination({ destination, headers, params })
|
105
|
-
// await forwardRequestToDestination({
|
106
|
-
// destination, headers, options, callbackEndpointType, childSpan, proxyEnabled, proxyCache, log, stepState
|
107
|
-
// })
|
108
|
-
histTimerEnd({ success: true })
|
109
|
-
return
|
110
|
-
}
|
111
|
-
|
112
|
-
const response = await service.sendOracleDiscoveryRequest({ headers, params, query })
|
113
|
-
|
114
|
-
if (Array.isArray(response?.data?.partyList) && response.data.partyList.length > 0) {
|
115
|
-
const partyList = service.filterOraclePartyList({ response, params })
|
116
|
-
await service.processOraclePartyList({ partyList, headers, params, destination })
|
117
|
-
// const partyList = filterOraclePartyList({ response, params, log, stepState })
|
118
|
-
// await processOraclePartyList({
|
119
|
-
// partyList, headers, params, destination, childSpan, proxyEnabled, proxyCache, log, stepState
|
120
|
-
// })
|
121
|
-
} else {
|
122
|
-
log.info('empty partyList form oracle, getting proxies list...', { proxyEnabled, params })
|
123
|
-
const proxyNames = await service.getFilteredProxyList(proxy)
|
124
|
-
// getFilteredProxyList({ config, proxy, proxyEnabled, stepState })
|
125
|
-
|
126
|
-
if (!proxyNames.length) {
|
127
|
-
fspiopError = await service.sendErrorCallback({ requester, headers, params })
|
128
|
-
// sendErrorCallback({
|
129
|
-
// headers, params, requester, childSpan, stepState
|
130
|
-
// })
|
131
|
-
} else {
|
132
|
-
await service.triggerSendToProxiesFlow({ proxyNames, headers, params, source })
|
133
|
-
// await triggerSendToProxiesFlow({
|
134
|
-
// proxyNames, headers, params, source, childSpan, proxyCache, log, stepState
|
135
|
-
// })
|
136
|
-
}
|
137
|
-
}
|
138
|
-
log.info('parties::getPartiesByTypeAndID is done')
|
61
|
+
await service.handleRequest({ headers, params, query, results })
|
62
|
+
log.info('getPartiesByTypeAndID is done')
|
139
63
|
histTimerEnd({ success: true })
|
140
|
-
} catch (
|
141
|
-
|
64
|
+
} catch (error) {
|
65
|
+
const { requester } = results
|
66
|
+
results.fspiopError = await service.handleError({ error, requester, headers, params })
|
142
67
|
histTimerEnd({ success: false })
|
143
|
-
if (fspiopError) {
|
144
|
-
libUtil.countFspiopError(fspiopError, { operation: component, step: stepState.step })
|
68
|
+
if (results.fspiopError) {
|
69
|
+
libUtil.countFspiopError(results.fspiopError, { operation: component, step: stepState.step })
|
145
70
|
}
|
146
71
|
} finally {
|
147
|
-
await libUtil.finishSpanWithError(childSpan, fspiopError)
|
72
|
+
await libUtil.finishSpanWithError(childSpan, results.fspiopError)
|
148
73
|
}
|
149
74
|
}
|
150
75
|
|
151
|
-
// const validateRequester = async ({ source, proxy, proxyCache, stepState }) => {
|
152
|
-
// stepState.inProgress('validateRequester-0')
|
153
|
-
// const log = logger.child({ source, method: 'validateRequester' })
|
154
|
-
// const sourceParticipant = await participant.validateParticipant(source)
|
155
|
-
// if (sourceParticipant) {
|
156
|
-
// log.debug('source is in scheme')
|
157
|
-
// return source
|
158
|
-
// }
|
159
|
-
//
|
160
|
-
// if (!proxy) {
|
161
|
-
// const errMessage = ERROR_MESSAGES.sourceFspNotFound
|
162
|
-
// log.warn(errMessage)
|
163
|
-
// throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
|
164
|
-
// }
|
165
|
-
//
|
166
|
-
// const proxyParticipant = await participant.validateParticipant(proxy)
|
167
|
-
// if (!proxyParticipant) {
|
168
|
-
// const errMessage = ERROR_MESSAGES.partyProxyNotFound
|
169
|
-
// log.warn(errMessage, { proxy })
|
170
|
-
// throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
|
171
|
-
// }
|
172
|
-
//
|
173
|
-
// const isCached = await proxyCache.addDfspIdToProxyMapping(source, proxy)
|
174
|
-
// // think, what if isCached !== true?
|
175
|
-
// log.info('source is added to proxyMapping cache:', { proxy, isCached })
|
176
|
-
// return proxy
|
177
|
-
// }
|
178
|
-
|
179
|
-
// const forwardRequestToDestination = async ({
|
180
|
-
// destination, headers, options, callbackEndpointType, childSpan, proxyEnabled, proxyCache, log, stepState
|
181
|
-
// }) => {
|
182
|
-
// let sendTo = destination
|
183
|
-
// stepState.inProgress('validateDestination-1')
|
184
|
-
//
|
185
|
-
// const destParticipantModel = await participant.validateParticipant(destination)
|
186
|
-
// if (!destParticipantModel) {
|
187
|
-
// stepState.inProgress('lookupProxyDestination-2')
|
188
|
-
// const proxyId = proxyEnabled && await proxyCache.lookupProxyByDfspId(destination)
|
189
|
-
//
|
190
|
-
// if (!proxyId) {
|
191
|
-
// log.warn('no destination participant, and no dfsp-to-proxy mapping', { destination })
|
192
|
-
// const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
|
193
|
-
// throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
|
194
|
-
// }
|
195
|
-
// sendTo = proxyId
|
196
|
-
// }
|
197
|
-
// // all ok, go ahead and forward the request
|
198
|
-
// stepState.inProgress('forwardRequest-3')
|
199
|
-
// await participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
|
200
|
-
// log.info('discovery getPartiesByTypeAndID request was sent', { sendTo })
|
201
|
-
// }
|
202
|
-
|
203
|
-
// const filterOraclePartyList = ({ response, params, log, stepState }) => {
|
204
|
-
// // Oracle's API is a standard rest-style end-point Thus a GET /party on the oracle will return all participant-party records. We must filter the results based on the callbackEndpointType to make sure we remove records containing partySubIdOrType when we are in FSPIOP_CALLBACK_URL_PARTIES_GET mode:
|
205
|
-
// stepState.inProgress('filterOraclePartyList-5')
|
206
|
-
// const callbackEndpointType = partiesUtils.getPartyCbType(params.SubId)
|
207
|
-
// let filteredResponsePartyList
|
208
|
-
//
|
209
|
-
// switch (callbackEndpointType) {
|
210
|
-
// case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_GET:
|
211
|
-
// filteredResponsePartyList = response.data.partyList.filter(party => party.partySubIdOrType == null) // Filter records that DON'T contain a partySubIdOrType
|
212
|
-
// break
|
213
|
-
// case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET:
|
214
|
-
// filteredResponsePartyList = response.data.partyList.filter(party => party.partySubIdOrType === params.SubId) // Filter records that match partySubIdOrType
|
215
|
-
// break
|
216
|
-
// default:
|
217
|
-
// filteredResponsePartyList = response // Fallback to providing the standard list
|
218
|
-
// }
|
219
|
-
//
|
220
|
-
// if (!Array.isArray(filteredResponsePartyList) || !filteredResponsePartyList.length) {
|
221
|
-
// const errMessage = 'Requested FSP/Party not found'
|
222
|
-
// log.warn(errMessage)
|
223
|
-
// throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
|
224
|
-
// }
|
225
|
-
//
|
226
|
-
// return filteredResponsePartyList
|
227
|
-
// }
|
228
|
-
|
229
|
-
// const processOraclePartyList = async ({
|
230
|
-
// partyList, headers, params, destination, childSpan, proxyEnabled, proxyCache, log, stepState
|
231
|
-
// }) => {
|
232
|
-
// const callbackEndpointType = partiesUtils.getPartyCbType(params.SubId)
|
233
|
-
// const options = partiesUtils.partiesRequestOptionsDto(params)
|
234
|
-
//
|
235
|
-
// let sentCount = 0 // if sentCount === 0 after sending, should we restart the whole process?
|
236
|
-
// const sending = partyList.map(async party => {
|
237
|
-
// const { fspId } = party
|
238
|
-
// const clonedHeaders = { ...headers }
|
239
|
-
// if (!destination) {
|
240
|
-
// clonedHeaders[Headers.FSPIOP.DESTINATION] = fspId
|
241
|
-
// }
|
242
|
-
// stepState.inProgress('validateParticipant-6')
|
243
|
-
// const schemeParticipant = await participant.validateParticipant(fspId)
|
244
|
-
// if (schemeParticipant) {
|
245
|
-
// sentCount++
|
246
|
-
// log.info('participant is in scheme', { fspId })
|
247
|
-
// return participant.sendRequest(clonedHeaders, fspId, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
|
248
|
-
// }
|
249
|
-
//
|
250
|
-
// // If the participant is not in the scheme and proxy routing is enabled,
|
251
|
-
// // we should check if there is a proxy for it and send the request to the proxy
|
252
|
-
// if (proxyEnabled) {
|
253
|
-
// stepState.inProgress('lookupProxyByDfspId-7')
|
254
|
-
// const proxyName = await proxyCache.lookupProxyByDfspId(fspId)
|
255
|
-
// if (!proxyName) {
|
256
|
-
// log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
|
257
|
-
// // todo: delete reference in oracle
|
258
|
-
// } else {
|
259
|
-
// sentCount++
|
260
|
-
// log.info('participant is NOT in scheme, use proxy name', { fspId, proxyName })
|
261
|
-
// return participant.sendRequest(clonedHeaders, proxyName, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
|
262
|
-
// }
|
263
|
-
// }
|
264
|
-
// })
|
265
|
-
// await Promise.all(sending)
|
266
|
-
// log.verbose('processOraclePartyList is done', { sentCount })
|
267
|
-
// // todo: think what if sentCount === 0 here
|
268
|
-
// }
|
269
|
-
|
270
|
-
// const getFilteredProxyList = async ({ config, proxy, proxyEnabled, stepState }) => {
|
271
|
-
// stepState.inProgress('getAllProxies-8')
|
272
|
-
// if (!proxyEnabled) return []
|
273
|
-
//
|
274
|
-
// const proxyNames = await Util.proxies.getAllProxiesNames(config.SWITCH_ENDPOINT)
|
275
|
-
// return proxyNames.filter(name => name !== proxy)
|
276
|
-
// }
|
277
|
-
|
278
|
-
// const sendErrorCallback = async ({
|
279
|
-
// headers, params, requester, childSpan, stepState
|
280
|
-
// }) => {
|
281
|
-
// stepState.inProgress('sendErrorToParticipant-9')
|
282
|
-
// const callbackHeaders = createCallbackHeaders({
|
283
|
-
// requestHeaders: headers,
|
284
|
-
// partyIdType: params.Type,
|
285
|
-
// partyIdentifier: params.ID,
|
286
|
-
// endpointTemplate: params.SubId
|
287
|
-
// ? FspEndpointTemplates.PARTIES_SUB_ID_PUT_ERROR
|
288
|
-
// : FspEndpointTemplates.PARTIES_PUT_ERROR
|
289
|
-
// })
|
290
|
-
// const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND)
|
291
|
-
//
|
292
|
-
// await participant.sendErrorToParticipant(
|
293
|
-
// requester,
|
294
|
-
// partiesUtils.errorPartyCbType(params.SubId),
|
295
|
-
// fspiopError.toApiErrorObject(config.ERROR_HANDLING),
|
296
|
-
// callbackHeaders,
|
297
|
-
// params,
|
298
|
-
// childSpan
|
299
|
-
// )
|
300
|
-
// return fspiopError
|
301
|
-
// }
|
302
|
-
|
303
|
-
// const triggerSendToProxiesFlow = async ({
|
304
|
-
// proxyNames, headers, params, source, childSpan, proxyCache, log, stepState
|
305
|
-
// }) => {
|
306
|
-
// stepState.inProgress('setSendToProxiesList-10')
|
307
|
-
// const alsReq = partiesUtils.alsRequestDto(source, params)
|
308
|
-
// log.info('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
|
309
|
-
//
|
310
|
-
// const isCached = await proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
|
311
|
-
// if (!isCached) {
|
312
|
-
// log.warn('failed to setSendToProxiesList')
|
313
|
-
// throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
|
314
|
-
// }
|
315
|
-
//
|
316
|
-
// const callbackEndpointType = partiesUtils.getPartyCbType(params.SubId)
|
317
|
-
// const options = partiesUtils.partiesRequestOptionsDto(params)
|
318
|
-
// stepState.inProgress('sendingProxyRequests-11')
|
319
|
-
// const sending = proxyNames.map(
|
320
|
-
// proxyName => participant.sendRequest(headers, proxyName, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
|
321
|
-
// .then(({ status, data } = {}) => ({ status, data }))
|
322
|
-
// )
|
323
|
-
// const results = await Promise.allSettled(sending)
|
324
|
-
// const isOk = results.some(result => result.status === 'fulfilled')
|
325
|
-
// // If, at least, one request is sent to proxy, we treat the whole flow as successful.
|
326
|
-
// // Failed requests should be handled by TTL expired/timeout handler
|
327
|
-
// // todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
|
328
|
-
// log.info('triggerSendToProxiesFlow is done:', { isOk, results, proxyNames, alsReq })
|
329
|
-
// stepState.inProgress('allSent-12')
|
330
|
-
// if (!isOk) {
|
331
|
-
// log.warn('no successful requests sent to proxies')
|
332
|
-
// throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
|
333
|
-
// }
|
334
|
-
// }
|
335
|
-
|
336
76
|
module.exports = getPartiesByTypeAndID
|
@@ -26,6 +26,8 @@
|
|
26
26
|
******/
|
27
27
|
|
28
28
|
const { Enum, Util: { Hapi } } = require('@mojaloop/central-services-shared')
|
29
|
+
const { MojaloopApiErrorCodes } = require('@mojaloop/sdk-standard-components').Errors
|
30
|
+
// todo: check why do we need sdk-standard-components deps here !!!
|
29
31
|
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
30
32
|
|
31
33
|
const participant = require('../../models/participantEndpoint/facade')
|
@@ -99,6 +101,10 @@ const createErrorHandlerOnSendingCallback = (config, logger) => async (err, head
|
|
99
101
|
}
|
100
102
|
}
|
101
103
|
|
104
|
+
function isNotValidPayeeCase (payload) {
|
105
|
+
return payload?.errorInformation?.errorCode === MojaloopApiErrorCodes.PAYEE_IDENTIFIER_NOT_VALID.code
|
106
|
+
}
|
107
|
+
|
102
108
|
module.exports = {
|
103
109
|
getPartyCbType,
|
104
110
|
putPartyCbType,
|
@@ -107,5 +113,6 @@ module.exports = {
|
|
107
113
|
createErrorHandlerOnSendingCallback,
|
108
114
|
alsRequestDto,
|
109
115
|
partiesRequestOptionsDto,
|
110
|
-
swapSourceDestinationHeaders
|
116
|
+
swapSourceDestinationHeaders,
|
117
|
+
isNotValidPayeeCase
|
111
118
|
}
|
@@ -31,7 +31,6 @@
|
|
31
31
|
|
32
32
|
const { Headers, RestMethods } = require('@mojaloop/central-services-shared').Enum.Http
|
33
33
|
const { decodePayload } = require('@mojaloop/central-services-shared').Util.StreamingProtocol
|
34
|
-
const { MojaloopApiErrorCodes } = require('@mojaloop/sdk-standard-components').Errors
|
35
34
|
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
36
35
|
const Metrics = require('@mojaloop/central-services-metrics')
|
37
36
|
|
@@ -43,7 +42,8 @@ const { logger } = require('../../lib')
|
|
43
42
|
const { ERROR_MESSAGES } = require('../../constants')
|
44
43
|
|
45
44
|
const partiesUtils = require('./partiesUtils')
|
46
|
-
const
|
45
|
+
const services = require('./services')
|
46
|
+
const { createDeps } = require('./deps')
|
47
47
|
|
48
48
|
/**
|
49
49
|
* @function putPartiesByTypeAndID
|
@@ -158,103 +158,57 @@ const putPartiesErrorByTypeAndID = async (headers, params, payload, dataUri, spa
|
|
158
158
|
'Put parties error by type and id',
|
159
159
|
['success']
|
160
160
|
).startTimer()
|
161
|
-
const
|
161
|
+
const childSpan = span ? span.getChild(component) : undefined
|
162
|
+
const log = logger.child({ component, params })
|
163
|
+
const stepState = libUtil.initStepState()
|
164
|
+
|
165
|
+
const deps = createDeps({ cache, proxyCache, childSpan, log, stepState })
|
166
|
+
const service = new services.PutPartiesErrorService(deps)
|
167
|
+
const results = {}
|
168
|
+
|
162
169
|
const destination = headers[Headers.FSPIOP.DESTINATION]
|
163
170
|
const proxyEnabled = !!(Config.PROXY_CACHE_CONFIG.enabled && proxyCache)
|
164
171
|
const proxy = proxyEnabled && headers[Headers.FSPIOP.PROXY]
|
165
|
-
|
166
|
-
const childSpan = span ? span.getChild(component) : undefined
|
167
|
-
const stepState = libUtil.initStepState()
|
168
172
|
log.info('parties::putPartiesErrorByTypeAndID start', { destination, proxy })
|
169
173
|
|
170
|
-
let sendTo
|
171
|
-
let fspiopError
|
172
|
-
|
173
174
|
try {
|
174
175
|
if (proxy) {
|
175
|
-
const
|
176
|
-
|
177
|
-
|
178
|
-
|
176
|
+
const notValid = await service.checkPayee({ headers, params, payload, proxy })
|
177
|
+
if (notValid) {
|
178
|
+
const getPartiesService = new services.GetPartiesService(deps)
|
179
|
+
// todo: think, if we need to remove destination header before starting new discovery
|
180
|
+
await getPartiesService.handleRequest({ headers, params, results })
|
181
|
+
log.info('putPartiesErrorByTypeAndID triggered new discovery flow')
|
182
|
+
histTimerEnd({ success: true })
|
183
|
+
return
|
184
|
+
}
|
185
|
+
|
186
|
+
const isLast = await service.checkLastProxyCallback({ destination, proxy, params })
|
187
|
+
if (!isLast) {
|
179
188
|
log.info('putPartiesErrorByTypeAndID proxy callback was processed', { proxy })
|
180
189
|
histTimerEnd({ success: true })
|
181
190
|
return
|
182
191
|
}
|
183
192
|
}
|
184
193
|
|
185
|
-
sendTo = await identifyDestinationForErrorCallback(
|
186
|
-
|
187
|
-
})
|
188
|
-
|
189
|
-
await sendErrorCallbackToParticipant({
|
190
|
-
sendTo, headers, params, dataUri, childSpan, stepState
|
191
|
-
})
|
194
|
+
const sendTo = await service.identifyDestinationForErrorCallback(destination)
|
195
|
+
results.requester = sendTo
|
196
|
+
await service.sendErrorCallbackToParticipant({ sendTo, headers, params, dataUri })
|
192
197
|
|
193
198
|
log.info('putPartiesErrorByTypeAndID callback was sent', { sendTo })
|
194
199
|
histTimerEnd({ success: true })
|
195
|
-
} catch (
|
196
|
-
|
197
|
-
|
198
|
-
|
200
|
+
} catch (error) {
|
201
|
+
const { requester } = results
|
202
|
+
results.fspiopError = await service.handleError({ error, requester, headers, params })
|
203
|
+
if (results.fspiopError) {
|
204
|
+
libUtil.countFspiopError(results.fspiopError, { operation: component, step: stepState.step })
|
199
205
|
}
|
200
206
|
histTimerEnd({ success: false })
|
201
207
|
} finally {
|
202
|
-
await libUtil.finishSpanWithError(childSpan, fspiopError)
|
208
|
+
await libUtil.finishSpanWithError(childSpan, results.fspiopError)
|
203
209
|
}
|
204
210
|
}
|
205
211
|
|
206
|
-
const processProxyErrorCallback = async ({
|
207
|
-
headers, params, payload, childSpan, cache, proxyCache, log, proxy, destination, stepState
|
208
|
-
}) => {
|
209
|
-
log.verbose('processProxyErrorCallback...')
|
210
|
-
let isDone // whether or not to continue putPartiesErrorByTypeAndID
|
211
|
-
|
212
|
-
if (isNotValidPayeeCase(payload)) {
|
213
|
-
stepState.inProgress('notValidPayeeCase-1')
|
214
|
-
log.info('notValidPayee case - deleted Participants and run getPartiesByTypeAndID', { proxy, payload })
|
215
|
-
const swappedHeaders = partiesUtils.swapSourceDestinationHeaders(headers)
|
216
|
-
await oracle.oracleRequest(swappedHeaders, RestMethods.DELETE, params, null, null, cache)
|
217
|
-
getPartiesByTypeAndID(swappedHeaders, params, RestMethods.GET, {}, childSpan, cache, proxyCache)
|
218
|
-
isDone = true
|
219
|
-
} else {
|
220
|
-
stepState.inProgress('receivedErrorResponse-2')
|
221
|
-
const alsReq = partiesUtils.alsRequestDto(destination, params) // or source?
|
222
|
-
const isLast = await proxyCache.receivedErrorResponse(alsReq, proxy)
|
223
|
-
log.info(`got${isLast ? '' : 'NOT'} last error callback from proxy`, { proxy, alsReq, isLast })
|
224
|
-
isDone = !isLast
|
225
|
-
}
|
226
|
-
return isDone
|
227
|
-
}
|
228
|
-
|
229
|
-
const identifyDestinationForErrorCallback = async ({
|
230
|
-
destination, proxyCache, proxyEnabled, log, stepState
|
231
|
-
}) => {
|
232
|
-
stepState.inProgress('validateParticipant-3')
|
233
|
-
const destinationParticipant = await participant.validateParticipant(destination)
|
234
|
-
if (destinationParticipant) return destination
|
235
|
-
|
236
|
-
stepState.inProgress('lookupProxyDestination-4')
|
237
|
-
const proxyName = proxyEnabled && await proxyCache.lookupProxyByDfspId(destination)
|
238
|
-
if (proxyName) return proxyName
|
239
|
-
|
240
|
-
const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
|
241
|
-
log.warn(errMessage)
|
242
|
-
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
|
243
|
-
}
|
244
|
-
|
245
|
-
const sendErrorCallbackToParticipant = async ({
|
246
|
-
sendTo, headers, params, dataUri, childSpan, stepState
|
247
|
-
}) => {
|
248
|
-
stepState.inProgress('sendErrorToParticipant-5')
|
249
|
-
const decodedPayload = decodePayload(dataUri, { asParsed: false })
|
250
|
-
const callbackEndpointType = partiesUtils.errorPartyCbType(params.SubId)
|
251
|
-
await participant.sendErrorToParticipant(sendTo, callbackEndpointType, decodedPayload.body.toString(), headers, params, childSpan)
|
252
|
-
}
|
253
|
-
|
254
|
-
function isNotValidPayeeCase (payload) {
|
255
|
-
return payload?.errorInformation?.errorCode === MojaloopApiErrorCodes.PAYEE_IDENTIFIER_NOT_VALID.code
|
256
|
-
}
|
257
|
-
|
258
212
|
module.exports = {
|
259
213
|
putPartiesByTypeAndID,
|
260
214
|
putPartiesErrorByTypeAndID
|
@@ -0,0 +1,88 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
10
|
+
|
11
|
+
Contributors
|
12
|
+
--------------
|
13
|
+
This is the official list of the Mojaloop project contributors for this file.
|
14
|
+
Names of the original copyright holders (individuals or organizations)
|
15
|
+
should be listed with a '*' in the first column. People who have
|
16
|
+
contributed from an organization can be listed under the organization
|
17
|
+
that actually holds the copyright for their contributions (see the
|
18
|
+
Mojaloop Foundation for an example). Those individuals should have
|
19
|
+
their names indented and be marked with a '-'. Email address can be added
|
20
|
+
optionally within square brackets <email>.
|
21
|
+
|
22
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
29
|
+
const { Enum } = require('@mojaloop/central-services-shared')
|
30
|
+
|
31
|
+
const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
|
32
|
+
const { Headers, RestMethods } = Enum.Http
|
33
|
+
|
34
|
+
class BasePartiesService {
|
35
|
+
constructor (deps) {
|
36
|
+
this.deps = deps
|
37
|
+
this.log = this.deps.log.child({ component: this.constructor.name })
|
38
|
+
this.proxyEnabled = !!(deps.config.PROXY_CACHE_CONFIG?.enabled && deps.proxyCache)
|
39
|
+
}
|
40
|
+
|
41
|
+
async handleRequest () {
|
42
|
+
throw new Error('handleRequest must be implemented by subclass')
|
43
|
+
}
|
44
|
+
|
45
|
+
async handleError ({ error, requester, headers, params }) {
|
46
|
+
const log = this.log.child({ method: 'handleError' })
|
47
|
+
try {
|
48
|
+
log.error('error in processing parties request: ', error)
|
49
|
+
const sendTo = requester || headers[Headers.FSPIOP.SOURCE]
|
50
|
+
const fspiopError = ErrorHandler.Factory.reformatFSPIOPError(error)
|
51
|
+
const errorInfo = await this.deps.partiesUtils.makePutPartiesErrorPayload(this.deps.config, fspiopError, headers, params)
|
52
|
+
|
53
|
+
await this.sendErrorCallback({ sendTo, errorInfo, headers, params })
|
54
|
+
log.info('handleError in done', { sendTo, errorInfo })
|
55
|
+
return fspiopError
|
56
|
+
} catch (exc) {
|
57
|
+
// We can't do anything else here- we _must_ handle all errors _within_ this function because
|
58
|
+
// we've already sent a sync response- we cannot throw.
|
59
|
+
log.error('failed to handleError. No further processing! ', exc)
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
async validateParticipant (participantId) {
|
64
|
+
return this.deps.participant.validateParticipant(participantId)
|
65
|
+
}
|
66
|
+
|
67
|
+
async sendErrorCallback ({ sendTo, errorInfo, headers, params, payload = undefined }) {
|
68
|
+
const endpointType = this.deps.partiesUtils.errorPartyCbType(params.SubId)
|
69
|
+
return this.deps.participant.sendErrorToParticipant(
|
70
|
+
sendTo, endpointType, errorInfo, headers, params, payload, this.deps.childSpan
|
71
|
+
)
|
72
|
+
}
|
73
|
+
|
74
|
+
async sendDeleteOracleRequest (headers, params) {
|
75
|
+
return this.deps.oracle.oracleRequest(headers, RestMethods.DELETE, params, null, null, this.deps.cache)
|
76
|
+
}
|
77
|
+
|
78
|
+
static enums () {
|
79
|
+
return {
|
80
|
+
FspEndpointTypes,
|
81
|
+
FspEndpointTemplates,
|
82
|
+
Headers,
|
83
|
+
RestMethods
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
module.exports = BasePartiesService
|
@@ -26,66 +26,91 @@
|
|
26
26
|
******/
|
27
27
|
|
28
28
|
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
29
|
-
const { Enum } = require('@mojaloop/central-services-shared')
|
30
29
|
const { ERROR_MESSAGES } = require('../../../constants')
|
31
30
|
const { createCallbackHeaders } = require('../../../lib/headers')
|
31
|
+
const BasePartiesService = require('./BasePartiesService')
|
32
32
|
|
33
|
-
const {
|
34
|
-
|
33
|
+
const {
|
34
|
+
FspEndpointTypes, FspEndpointTemplates,
|
35
|
+
Headers, RestMethods
|
36
|
+
} = BasePartiesService.enums()
|
35
37
|
|
36
38
|
const proxyCacheTtlSec = 40 // todo: make configurable
|
37
39
|
|
38
|
-
class GetPartiesService {
|
39
|
-
|
40
|
+
class GetPartiesService extends BasePartiesService {
|
41
|
+
async handleRequest ({ headers, params, query, results }) {
|
42
|
+
const source = headers[Headers.FSPIOP.SOURCE]
|
43
|
+
const proxy = headers[Headers.FSPIOP.PROXY]
|
44
|
+
const destination = headers[Headers.FSPIOP.DESTINATION]
|
45
|
+
// see https://github.com/mojaloop/design-authority/issues/79
|
46
|
+
// the requester has specified a destination routing header. We should respect that and forward the request directly to the destination
|
47
|
+
// without consulting any oracles.
|
48
|
+
this.log.info('handling getParties request', { source, destination, proxy })
|
49
|
+
|
50
|
+
const requester = await this.validateRequester({ source, proxy })
|
51
|
+
results.requester = requester
|
52
|
+
|
53
|
+
if (destination) {
|
54
|
+
await this.forwardRequestToDestination({ destination, headers, params })
|
55
|
+
return
|
56
|
+
}
|
57
|
+
const response = await this.sendOracleDiscoveryRequest({ headers, params, query })
|
40
58
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
59
|
+
if (Array.isArray(response?.data?.partyList) && response.data.partyList.length > 0) {
|
60
|
+
const partyList = this.filterOraclePartyList({ response, params })
|
61
|
+
await this.processOraclePartyList({ partyList, headers, params, destination })
|
62
|
+
return
|
63
|
+
}
|
64
|
+
|
65
|
+
this.log.info('empty partyList form oracle, getting proxyList...', { params })
|
66
|
+
const proxyNames = await this.getFilteredProxyList(proxy)
|
67
|
+
|
68
|
+
if (proxyNames.length) {
|
69
|
+
await this.triggerSendToProxiesFlow({ proxyNames, headers, params, source })
|
70
|
+
return
|
71
|
+
}
|
46
72
|
|
47
|
-
|
48
|
-
// todo: add logic
|
73
|
+
results.fspiopError = await this.sendPartyNotFoundErrorCallback({ requester, headers, params })
|
49
74
|
}
|
50
75
|
|
51
76
|
async validateRequester ({ source, proxy }) {
|
52
|
-
this
|
77
|
+
this.deps.stepState.inProgress('validateRequester-0')
|
53
78
|
const log = this.log.child({ source, method: 'validateRequester' })
|
54
79
|
|
55
|
-
const sourceParticipant = await this
|
80
|
+
const sourceParticipant = await this.validateParticipant(source)
|
56
81
|
if (sourceParticipant) {
|
57
82
|
log.debug('source is in scheme')
|
58
83
|
return source
|
59
84
|
}
|
60
85
|
|
61
|
-
if (!proxy) {
|
86
|
+
if (!this.proxyEnabled || !proxy) {
|
62
87
|
const errMessage = ERROR_MESSAGES.sourceFspNotFound
|
63
88
|
log.warn(errMessage)
|
64
89
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
|
65
90
|
}
|
66
91
|
|
67
|
-
const proxyParticipant = await this
|
92
|
+
const proxyParticipant = await this.validateParticipant(proxy)
|
68
93
|
if (!proxyParticipant) {
|
69
94
|
const errMessage = ERROR_MESSAGES.partyProxyNotFound
|
70
95
|
log.warn(errMessage, { proxy })
|
71
96
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
|
72
97
|
}
|
73
98
|
|
74
|
-
const isCached = await this
|
99
|
+
const isCached = await this.deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
|
75
100
|
// think, what if isCached !== true?
|
76
101
|
log.info('source is added to proxyMapping cache:', { proxy, isCached })
|
77
102
|
return proxy
|
78
103
|
}
|
79
104
|
|
80
105
|
async forwardRequestToDestination ({ destination, headers, params }) {
|
81
|
-
this
|
106
|
+
this.deps.stepState.inProgress('validateDestination-1')
|
82
107
|
const log = this.log.child({ method: 'forwardRequestToDestination' })
|
83
108
|
let sendTo = destination
|
84
109
|
|
85
|
-
const destParticipantModel = await this
|
110
|
+
const destParticipantModel = await this.validateParticipant(destination)
|
86
111
|
if (!destParticipantModel) {
|
87
|
-
this
|
88
|
-
const proxyId = this.proxyEnabled && await this
|
112
|
+
this.deps.stepState.inProgress('lookupProxyDestination-2')
|
113
|
+
const proxyId = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
|
89
114
|
|
90
115
|
if (!proxyId) {
|
91
116
|
log.warn('no destination participant, and no dfsp-to-proxy mapping', { destination })
|
@@ -101,8 +126,8 @@ class GetPartiesService {
|
|
101
126
|
|
102
127
|
filterOraclePartyList ({ response, params }) {
|
103
128
|
// Oracle's API is a standard rest-style end-point Thus a GET /party on the oracle will return all participant-party records. We must filter the results based on the callbackEndpointType to make sure we remove records containing partySubIdOrType when we are in FSPIOP_CALLBACK_URL_PARTIES_GET mode:
|
104
|
-
this
|
105
|
-
const callbackEndpointType = this
|
129
|
+
this.deps.stepState.inProgress('filterOraclePartyList-5')
|
130
|
+
const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
|
106
131
|
let filteredResponsePartyList
|
107
132
|
|
108
133
|
switch (callbackEndpointType) {
|
@@ -118,7 +143,7 @@ class GetPartiesService {
|
|
118
143
|
|
119
144
|
if (!Array.isArray(filteredResponsePartyList) || !filteredResponsePartyList.length) {
|
120
145
|
const errMessage = 'Requested FSP/Party not found'
|
121
|
-
this
|
146
|
+
this.log.warn(errMessage)
|
122
147
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
|
123
148
|
}
|
124
149
|
|
@@ -135,8 +160,8 @@ class GetPartiesService {
|
|
135
160
|
if (!destination) {
|
136
161
|
clonedHeaders[Headers.FSPIOP.DESTINATION] = fspId
|
137
162
|
}
|
138
|
-
this
|
139
|
-
const schemeParticipant = await this
|
163
|
+
this.deps.stepState.inProgress('validateParticipant-6')
|
164
|
+
const schemeParticipant = await this.validateParticipant(fspId)
|
140
165
|
if (schemeParticipant) {
|
141
166
|
sentCount++
|
142
167
|
log.info('participant is in scheme', { fspId })
|
@@ -150,8 +175,8 @@ class GetPartiesService {
|
|
150
175
|
// If the participant is not in the scheme and proxy routing is enabled,
|
151
176
|
// we should check if there is a proxy for it and send the request to the proxy
|
152
177
|
if (this.proxyEnabled) {
|
153
|
-
this
|
154
|
-
const proxyName = await this
|
178
|
+
this.deps.stepState.inProgress('lookupProxyByDfspId-7')
|
179
|
+
const proxyName = await this.deps.proxyCache.lookupProxyByDfspId(fspId)
|
155
180
|
if (!proxyName) {
|
156
181
|
log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
|
157
182
|
// todo: delete reference in oracle
|
@@ -172,27 +197,30 @@ class GetPartiesService {
|
|
172
197
|
}
|
173
198
|
|
174
199
|
async getFilteredProxyList (proxy) {
|
175
|
-
this
|
176
|
-
if (!this.proxyEnabled)
|
200
|
+
this.deps.stepState.inProgress('getAllProxies-8')
|
201
|
+
if (!this.proxyEnabled) {
|
202
|
+
this.log.warn('proxyCache is not enabled')
|
203
|
+
return []
|
204
|
+
}
|
177
205
|
|
178
|
-
const proxyNames = await this
|
206
|
+
const proxyNames = await this.deps.proxies.getAllProxiesNames(this.deps.config.SWITCH_ENDPOINT)
|
179
207
|
this.log.debug('getAllProxiesNames is done', { proxyNames })
|
180
208
|
return proxyNames.filter(name => name !== proxy)
|
181
209
|
}
|
182
210
|
|
183
211
|
async triggerSendToProxiesFlow ({ proxyNames, headers, params, source }) {
|
184
212
|
const log = this.log.child({ method: 'triggerSendToProxiesFlow' })
|
185
|
-
this
|
186
|
-
const alsReq = this
|
213
|
+
this.deps.stepState.inProgress('setSendToProxiesList-10')
|
214
|
+
const alsReq = this.deps.partiesUtils.alsRequestDto(source, params)
|
187
215
|
log.info('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
|
188
216
|
|
189
|
-
const isCached = await this
|
217
|
+
const isCached = await this.deps.proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
|
190
218
|
if (!isCached) {
|
191
219
|
log.warn('failed to setSendToProxiesList')
|
192
220
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
|
193
221
|
}
|
194
222
|
|
195
|
-
this
|
223
|
+
this.deps.stepState.inProgress('sendingProxyRequests-11')
|
196
224
|
const sending = proxyNames.map(
|
197
225
|
sendTo => this.#forwardGetPartiesRequest({ sendTo, headers, params })
|
198
226
|
.then(({ status, data } = {}) => ({ status, data }))
|
@@ -203,31 +231,15 @@ class GetPartiesService {
|
|
203
231
|
// Failed requests should be handled by TTL expired/timeout handler
|
204
232
|
// todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
|
205
233
|
log.info('triggerSendToProxiesFlow is done:', { isOk, results, proxyNames, alsReq })
|
206
|
-
this
|
234
|
+
this.deps.stepState.inProgress('allSent-12')
|
207
235
|
if (!isOk) {
|
208
236
|
log.warn('no successful requests sent to proxies')
|
209
237
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
|
210
238
|
}
|
211
239
|
}
|
212
240
|
|
213
|
-
async
|
214
|
-
|
215
|
-
}
|
216
|
-
|
217
|
-
async #forwardGetPartiesRequest ({ sendTo, headers, params }) {
|
218
|
-
this.#deps.stepState.inProgress('forwardRequest-3')
|
219
|
-
const callbackEndpointType = this.#deps.partiesUtils.getPartyCbType(params.SubId)
|
220
|
-
const options = this.#deps.partiesUtils.partiesRequestOptionsDto(params)
|
221
|
-
|
222
|
-
return this.#deps.participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, this.#deps.childSpan)
|
223
|
-
}
|
224
|
-
|
225
|
-
// async sendSuccessCallback ({ headers, sendTo }) {
|
226
|
-
// return this.#deps.participant.sendRequest(headers, sendTo,)
|
227
|
-
// }
|
228
|
-
|
229
|
-
async sendErrorCallback ({ requester, headers, params }) {
|
230
|
-
this.#deps.stepState.inProgress('sendErrorCallback-9')
|
241
|
+
async sendPartyNotFoundErrorCallback ({ requester, headers, params }) {
|
242
|
+
this.deps.stepState.inProgress('sendErrorCallback-9')
|
231
243
|
const callbackHeaders = createCallbackHeaders({
|
232
244
|
requestHeaders: headers,
|
233
245
|
partyIdType: params.Type,
|
@@ -238,20 +250,26 @@ class GetPartiesService {
|
|
238
250
|
})
|
239
251
|
const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND)
|
240
252
|
|
241
|
-
await this
|
242
|
-
requester,
|
243
|
-
this
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
this.#deps.childSpan
|
248
|
-
)
|
253
|
+
await this.sendErrorCallback({
|
254
|
+
sendTo: requester,
|
255
|
+
errorInfo: fspiopError.toApiErrorObject(this.deps.config.ERROR_HANDLING),
|
256
|
+
headers: callbackHeaders,
|
257
|
+
params
|
258
|
+
})
|
249
259
|
return fspiopError
|
250
260
|
}
|
251
261
|
|
252
262
|
async sendOracleDiscoveryRequest ({ headers, params, query }) {
|
253
|
-
this
|
254
|
-
return this
|
263
|
+
this.deps.stepState.inProgress('oracleRequest-4')
|
264
|
+
return this.deps.oracle.oracleRequest(headers, RestMethods.GET, params, query, undefined, this.deps.cache)
|
265
|
+
}
|
266
|
+
|
267
|
+
async #forwardGetPartiesRequest ({ sendTo, headers, params }) {
|
268
|
+
this.deps.stepState.inProgress('forwardRequest-3')
|
269
|
+
const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
|
270
|
+
const options = this.deps.partiesUtils.partiesRequestOptionsDto(params)
|
271
|
+
|
272
|
+
return this.deps.participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, this.deps.childSpan)
|
255
273
|
}
|
256
274
|
}
|
257
275
|
|
@@ -0,0 +1,81 @@
|
|
1
|
+
/*****
|
2
|
+
License
|
3
|
+
--------------
|
4
|
+
Copyright © 2020-2025 Mojaloop Foundation
|
5
|
+
The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
10
|
+
|
11
|
+
Contributors
|
12
|
+
--------------
|
13
|
+
This is the official list of the Mojaloop project contributors for this file.
|
14
|
+
Names of the original copyright holders (individuals or organizations)
|
15
|
+
should be listed with a '*' in the first column. People who have
|
16
|
+
contributed from an organization can be listed under the organization
|
17
|
+
that actually holds the copyright for their contributions (see the
|
18
|
+
Mojaloop Foundation for an example). Those individuals should have
|
19
|
+
their names indented and be marked with a '-'. Email address can be added
|
20
|
+
optionally within square brackets <email>.
|
21
|
+
|
22
|
+
* Mojaloop Foundation
|
23
|
+
* Eugen Klymniuk <eugen.klymniuk@infitx.com>
|
24
|
+
|
25
|
+
--------------
|
26
|
+
******/
|
27
|
+
|
28
|
+
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
29
|
+
const { decodePayload } = require('@mojaloop/central-services-shared').Util.StreamingProtocol
|
30
|
+
const { ERROR_MESSAGES } = require('../../../constants')
|
31
|
+
const BasePartiesService = require('./BasePartiesService')
|
32
|
+
|
33
|
+
class PutPartiesErrorService extends BasePartiesService {
|
34
|
+
async handleRequest () {
|
35
|
+
// todo: add impl.
|
36
|
+
}
|
37
|
+
|
38
|
+
async checkPayee ({ headers, params, payload, proxy }) {
|
39
|
+
const notValid = this.deps.partiesUtils.isNotValidPayeeCase(payload)
|
40
|
+
if (notValid) {
|
41
|
+
this.deps.stepState.inProgress('notValidPayeeCase-1')
|
42
|
+
this.log.warn('notValidPayee case - deleting Participants and run getPartiesByTypeAndID', { proxy, payload })
|
43
|
+
const swappedHeaders = this.deps.partiesUtils.swapSourceDestinationHeaders(headers)
|
44
|
+
await super.sendDeleteOracleRequest(swappedHeaders, params)
|
45
|
+
}
|
46
|
+
return notValid
|
47
|
+
}
|
48
|
+
|
49
|
+
async checkLastProxyCallback ({ destination, proxy, params }) {
|
50
|
+
this.deps.stepState.inProgress('checkLastProxyCallback-2')
|
51
|
+
const alsReq = this.deps.partiesUtils.alsRequestDto(destination, params) // or source?
|
52
|
+
const isLast = await this.deps.proxyCache.receivedErrorResponse(alsReq, proxy)
|
53
|
+
this.log.info(`got${isLast ? '' : 'NOT'} last error callback from proxy`, { proxy, alsReq, isLast })
|
54
|
+
return isLast
|
55
|
+
}
|
56
|
+
|
57
|
+
async identifyDestinationForErrorCallback (destination) {
|
58
|
+
this.deps.stepState.inProgress('validateParticipant-3')
|
59
|
+
const destinationParticipant = await super.validateParticipant(destination)
|
60
|
+
if (destinationParticipant) return destination
|
61
|
+
|
62
|
+
this.deps.stepState.inProgress('lookupProxyDestination-4')
|
63
|
+
const proxyName = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
|
64
|
+
if (proxyName) return proxyName
|
65
|
+
|
66
|
+
const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
|
67
|
+
this.log.warn(errMessage, { destination })
|
68
|
+
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
|
69
|
+
}
|
70
|
+
|
71
|
+
async sendErrorCallbackToParticipant ({ sendTo, headers, params, dataUri }) {
|
72
|
+
this.deps.stepState.inProgress('sendErrorToParticipant-5')
|
73
|
+
const decodedPayload = decodePayload(dataUri, { asParsed: false })
|
74
|
+
const errorInfo = decodedPayload.body.toString()
|
75
|
+
return super.sendErrorCallback({
|
76
|
+
sendTo, errorInfo, headers, params
|
77
|
+
})
|
78
|
+
}
|
79
|
+
}
|
80
|
+
|
81
|
+
module.exports = PutPartiesErrorService
|