account-lookup-service 15.6.0-iso.2 → 15.6.0-iso.21
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/.circleci/config.yml +1 -1
- package/.ncurc.yaml +1 -2
- package/audit-ci.jsonc +3 -1
- package/jest.config.js +2 -0
- package/package.json +15 -17
- package/src/constants.js +2 -1
- package/src/domain/oracle/oracle.js +63 -4
- package/src/domain/participants/participants.js +259 -133
- package/src/domain/parties/getPartiesByTypeAndID.js +36 -15
- package/src/domain/parties/parties.js +44 -14
- package/src/domain/parties/utils.js +13 -6
- package/src/domain/timeout/dto.js +4 -10
- package/src/domain/timeout/index.js +12 -1
- package/src/handlers/index.js +4 -4
- package/src/handlers/monitoring/index.js +1 -1
- package/src/interface/api-swagger-iso20022-parties.yaml +7 -6
- package/src/interface/api-swagger.yaml +7 -6
- package/src/interface/fspiop-rest-v2.0-ISO20022_parties.yaml +2043 -1583
- package/src/lib/config.js +1 -1
- package/src/lib/index.js +1 -2
- package/src/models/currency/currency.js +10 -1
- package/src/models/endpointType/endpointType.js +10 -1
- package/src/models/oracle/facade.js +24 -3
- package/src/models/oracle/oracleEndpoint.js +64 -10
- package/src/models/oracle/oracleEndpointCached.js +22 -3
- package/src/models/participantEndpoint/facade.js +61 -23
- package/src/models/partyIdType/partyIdType.js +10 -1
- package/src/plugins.js +20 -9
- package/src/server.js +11 -19
- package/test/fixtures/index.js +30 -6
- package/test/fixtures/iso.js +1 -1
- package/test/unit/api/health.test.js +3 -0
- package/test/unit/api/participants/participants.test.js +5 -7
- package/test/unit/api/participants/{Type}/{ID}/{SubId}.test.js +0 -3
- package/test/unit/api/participants/{Type}/{ID}.test.js +0 -3
- package/test/unit/api/participants.test.js +36 -3
- package/test/unit/domain/oracle/oracle.test.js +8 -0
- package/test/unit/domain/participants/participants.test.js +83 -48
- package/test/unit/domain/parties/parties.test.js +11 -3
- package/test/unit/domain/parties/utils.test.js +60 -0
- package/test/unit/domain/timeout/dto.test.js +1 -2
- package/test/unit/domain/timeout/index.test.js +8 -0
- package/test/unit/lib/TransformFacades.test.js +2 -1
- package/test/unit/lib/config.test.js +7 -0
- package/test/unit/models/participantEndpoint/facade.test.js +25 -8
- package/test/unit/plugins.test.js +4 -2
- package/test/util/apiClients/BasicApiClient.js +2 -2
- package/src/handlers/monitoring/plugins/metrics.js +0 -48
- package/src/lib/requestLogger.js +0 -54
- package/src/metrics/handler.js +0 -33
- package/src/metrics/plugin.js +0 -52
- package/src/metrics/routes.js +0 -43
- package/test/unit/lib/requestLogger.test.js +0 -115
@@ -32,21 +32,22 @@ const oracle = require('../../models/oracle/facade')
|
|
32
32
|
const participant = require('../../models/participantEndpoint/facade')
|
33
33
|
const { createCallbackHeaders } = require('../../lib/headers')
|
34
34
|
const { ERROR_MESSAGES } = require('../../constants')
|
35
|
-
const {
|
35
|
+
const { logger } = require('../../lib')
|
36
36
|
const Config = require('../../lib/config')
|
37
37
|
const utils = require('./utils')
|
38
38
|
|
39
39
|
const { FspEndpointTypes, FspEndpointTemplates } = Enum.EndPoints
|
40
40
|
const { Headers, RestMethods } = Enum.Http
|
41
41
|
|
42
|
-
const
|
42
|
+
const log = logger.child('domain:get-parties')
|
43
|
+
const handleErrorOnSendingCallback = utils.createErrorHandlerOnSendingCallback(Config, log)
|
43
44
|
|
44
45
|
const proxyCacheTtlSec = 40 // todo: make configurable
|
45
46
|
|
46
47
|
const validateRequester = async ({ source, proxy, proxyCache }) => {
|
47
48
|
const sourceParticipant = await participant.validateParticipant(source)
|
48
49
|
if (sourceParticipant) {
|
49
|
-
|
50
|
+
log.debug('source is in scheme', { source })
|
50
51
|
return source
|
51
52
|
}
|
52
53
|
|
@@ -63,7 +64,7 @@ const validateRequester = async ({ source, proxy, proxyCache }) => {
|
|
63
64
|
|
64
65
|
const isCached = await proxyCache.addDfspIdToProxyMapping(source, proxy)
|
65
66
|
// think, what if isCached !== true?
|
66
|
-
|
67
|
+
log.info('source is added to proxyMapping cache:', { source, proxy, isCached })
|
67
68
|
return proxy
|
68
69
|
}
|
69
70
|
|
@@ -86,6 +87,7 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
86
87
|
'Get party by Type and Id',
|
87
88
|
['success']
|
88
89
|
).startTimer()
|
90
|
+
const errorCounter = Metrics.getCounter('errorCount')
|
89
91
|
const proxyEnabled = !!(Config.PROXY_CACHE_CONFIG.enabled && proxyCache)
|
90
92
|
const type = params.Type
|
91
93
|
const partySubId = params.SubId
|
@@ -94,11 +96,11 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
94
96
|
const callbackEndpointType = utils.getPartyCbType(partySubId)
|
95
97
|
|
96
98
|
const childSpan = span ? span.getChild('getPartiesByTypeAndID') : undefined
|
97
|
-
|
99
|
+
log.info('parties::getPartiesByTypeAndID::begin', { source, proxy, params })
|
98
100
|
|
99
101
|
let requester
|
100
102
|
let fspiopError
|
101
|
-
|
103
|
+
let step
|
102
104
|
try {
|
103
105
|
requester = await validateRequester({ source, proxy, proxyCache })
|
104
106
|
|
@@ -113,8 +115,10 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
113
115
|
// the requester has specified a destination routing header. We should respect that and forward the request directly to the destination
|
114
116
|
// without consulting any oracles.
|
115
117
|
if (destination) {
|
118
|
+
step = 'validateParticipant-1'
|
116
119
|
const destParticipantModel = await participant.validateParticipant(destination)
|
117
120
|
if (!destParticipantModel) {
|
121
|
+
step = 'lookupProxyByDfspId-2'
|
118
122
|
const proxyId = proxyEnabled && await proxyCache.lookupProxyByDfspId(destination)
|
119
123
|
|
120
124
|
if (!proxyId) {
|
@@ -124,13 +128,15 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
124
128
|
destination = proxyId
|
125
129
|
}
|
126
130
|
// all ok, go ahead and forward the request
|
131
|
+
step = 'sendRequest-3'
|
127
132
|
await participant.sendRequest(headers, destination, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
|
128
133
|
|
129
134
|
histTimerEnd({ success: true })
|
130
|
-
|
135
|
+
log.info('discovery getPartiesByTypeAndID request was sent to destination', { destination })
|
131
136
|
return
|
132
137
|
}
|
133
138
|
|
139
|
+
step = 'oracleRequest-4'
|
134
140
|
const response = await oracle.oracleRequest(headers, method, params, query, undefined, cache)
|
135
141
|
if (Array.isArray(response?.data?.partyList) && response.data.partyList.length > 0) {
|
136
142
|
// 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:
|
@@ -158,35 +164,39 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
158
164
|
if (!destination) {
|
159
165
|
clonedHeaders[Headers.FSPIOP.DESTINATION] = fspId
|
160
166
|
}
|
167
|
+
step = 'validateParticipant-5'
|
161
168
|
const schemeParticipant = await participant.validateParticipant(fspId)
|
162
169
|
if (schemeParticipant) {
|
163
170
|
sentCount++
|
164
|
-
|
171
|
+
log.debug('participant is in scheme', { fspId })
|
165
172
|
return participant.sendRequest(clonedHeaders, party.fspId, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
|
166
173
|
}
|
167
174
|
|
168
175
|
// If the participant is not in the scheme and proxy routing is enabled,
|
169
176
|
// we should check if there is a proxy for it and send the request to the proxy
|
170
177
|
if (proxyEnabled) {
|
178
|
+
step = 'lookupProxyByDfspId-6'
|
171
179
|
const proxyName = await proxyCache.lookupProxyByDfspId(fspId)
|
172
180
|
if (!proxyName) {
|
173
|
-
|
181
|
+
log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
|
174
182
|
// todo: delete reference in oracle
|
175
183
|
} else {
|
176
184
|
sentCount++
|
177
|
-
|
185
|
+
log.debug('participant NOT is in scheme, use proxy name', { fspId, proxyName })
|
178
186
|
return participant.sendRequest(clonedHeaders, proxyName, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
|
179
187
|
}
|
180
188
|
}
|
181
189
|
})
|
190
|
+
step = 'sendRequests-7'
|
182
191
|
await Promise.all(sending)
|
183
|
-
|
192
|
+
log.info('participant.sendRequests to filtered oracle partyList are done', { sentCount })
|
184
193
|
// todo: think what if sentCount === 0 here
|
185
194
|
} else {
|
186
|
-
|
195
|
+
log.info('empty partyList form oracle, getting proxies list...', { proxyEnabled, params })
|
187
196
|
let filteredProxyNames = []
|
188
197
|
|
189
198
|
if (proxyEnabled) {
|
199
|
+
step = 'getAllProxiesNames-8'
|
190
200
|
const proxyNames = await Util.proxies.getAllProxiesNames(Config.SWITCH_ENDPOINT)
|
191
201
|
filteredProxyNames = proxyNames.filter(name => name !== proxy)
|
192
202
|
}
|
@@ -202,16 +212,19 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
202
212
|
})
|
203
213
|
fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND)
|
204
214
|
const errorCallbackEndpointType = utils.errorPartyCbType(partySubId)
|
215
|
+
step = 'sendErrorToParticipant-9'
|
205
216
|
await participant.sendErrorToParticipant(requester, errorCallbackEndpointType,
|
206
217
|
fspiopError.toApiErrorObject(config.ERROR_HANDLING), callbackHeaders, params, childSpan)
|
207
218
|
} else {
|
208
219
|
const alsReq = utils.alsRequestDto(source, params)
|
209
|
-
|
220
|
+
log.info('starting setSendToProxiesList flow: ', { filteredProxyNames, alsReq, proxyCacheTtlSec })
|
221
|
+
step = 'setSendToProxiesList-10'
|
210
222
|
const isCached = await proxyCache.setSendToProxiesList(alsReq, filteredProxyNames, proxyCacheTtlSec)
|
211
223
|
if (!isCached) {
|
212
224
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
|
213
225
|
}
|
214
226
|
|
227
|
+
step = 'sending-11'
|
215
228
|
const sending = filteredProxyNames.map(
|
216
229
|
proxyName => participant.sendRequest(headers, proxyName, callbackEndpointType, RestMethods.GET, undefined, options, childSpan)
|
217
230
|
.then(({ status, data } = {}) => ({ status, data }))
|
@@ -221,7 +234,7 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
221
234
|
// If, at least, one request is sent to proxy, we treat the whole flow as successful.
|
222
235
|
// Failed requests should be handled by TTL expired/timeout handler
|
223
236
|
// todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
|
224
|
-
|
237
|
+
log.info('setSendToProxiesList flow is done:', { isOk, results, filteredProxyNames, alsReq })
|
225
238
|
if (!isOk) {
|
226
239
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
|
227
240
|
}
|
@@ -229,8 +242,16 @@ const getPartiesByTypeAndID = async (headers, params, method, query, span, cache
|
|
229
242
|
}
|
230
243
|
histTimerEnd({ success: true })
|
231
244
|
} catch (err) {
|
232
|
-
fspiopError = await
|
245
|
+
fspiopError = await handleErrorOnSendingCallback(err, headers, params, requester)
|
233
246
|
histTimerEnd({ success: false })
|
247
|
+
const extensions = err.extensions || []
|
248
|
+
const system = extensions.find((element) => element.key === 'system')?.value || ''
|
249
|
+
errorCounter.inc({
|
250
|
+
code: fspiopError?.apiErrorCode,
|
251
|
+
system,
|
252
|
+
operation: 'getPartiesByTypeAndID',
|
253
|
+
step
|
254
|
+
})
|
234
255
|
} finally {
|
235
256
|
await utils.finishSpanWithError(childSpan, fspiopError)
|
236
257
|
}
|
@@ -38,12 +38,13 @@ const Metrics = require('@mojaloop/central-services-metrics')
|
|
38
38
|
const oracle = require('../../models/oracle/facade')
|
39
39
|
const participant = require('../../models/participantEndpoint/facade')
|
40
40
|
const { ERROR_MESSAGES } = require('../../constants')
|
41
|
-
const {
|
41
|
+
const { logger } = require('../../lib')
|
42
42
|
const Config = require('../../lib/config')
|
43
43
|
const utils = require('./utils')
|
44
44
|
const getPartiesByTypeAndID = require('./getPartiesByTypeAndID')
|
45
45
|
|
46
|
-
const
|
46
|
+
const log = logger.child('domain:put-parties')
|
47
|
+
const handleErrorOnSendingCallback = utils.createErrorHandlerOnSendingCallback(Config, log)
|
47
48
|
|
48
49
|
/**
|
49
50
|
* @function putPartiesByTypeAndID
|
@@ -64,44 +65,51 @@ const putPartiesByTypeAndID = async (headers, params, method, payload, dataUri,
|
|
64
65
|
'Put parties by type and id',
|
65
66
|
['success']
|
66
67
|
).startTimer()
|
68
|
+
const errorCounter = Metrics.getCounter('errorCount')
|
67
69
|
const type = params.Type
|
68
70
|
const partySubId = params.SubId
|
69
71
|
const source = headers[Headers.FSPIOP.SOURCE]
|
70
72
|
const destination = headers[Headers.FSPIOP.DESTINATION]
|
71
73
|
const proxy = headers[Headers.FSPIOP.PROXY]
|
72
74
|
const proxyEnabled = !!(Config.PROXY_CACHE_CONFIG.enabled && proxyCache)
|
73
|
-
|
75
|
+
log.info('parties::putPartiesByTypeAndID::begin', { source, destination, proxy, params })
|
74
76
|
|
75
77
|
let sendTo
|
78
|
+
let step
|
76
79
|
try {
|
80
|
+
step = 'validateParticipant-1'
|
77
81
|
const requesterParticipant = await participant.validateParticipant(source)
|
78
82
|
if (!requesterParticipant) {
|
79
83
|
if (!proxyEnabled || !proxy) {
|
80
84
|
const errMessage = ERROR_MESSAGES.partySourceFspNotFound
|
81
85
|
throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
|
82
86
|
}
|
87
|
+
step = 'addDfspIdToProxyMapping-1'
|
83
88
|
const isCached = await proxyCache.addDfspIdToProxyMapping(source, proxy)
|
84
89
|
// think,if we should throw error if isCached === false?
|
85
|
-
|
90
|
+
log.info('addDfspIdToProxyMapping is done', { source, proxy, isCached })
|
86
91
|
}
|
87
92
|
|
88
93
|
if (proxyEnabled && proxy) {
|
89
94
|
const alsReq = utils.alsRequestDto(destination, params) // or source?
|
95
|
+
step = 'receivedSuccessResponse-2'
|
90
96
|
const isExists = await proxyCache.receivedSuccessResponse(alsReq)
|
91
97
|
if (!isExists) {
|
92
|
-
|
98
|
+
log.warn('destination is NOT in scheme, and no cached sendToProxiesList', { destination, alsReq })
|
93
99
|
// think, if we need to throw an error here
|
94
100
|
} else {
|
95
101
|
const mappingPayload = {
|
96
102
|
fspId: source
|
97
103
|
}
|
104
|
+
step = 'oracleRequest-3'
|
98
105
|
await oracle.oracleRequest(headers, RestMethods.POST, params, null, mappingPayload, cache)
|
99
|
-
|
106
|
+
log.info('oracle was updated with mappingPayload', { mappingPayload, params })
|
100
107
|
}
|
101
108
|
}
|
102
|
-
|
109
|
+
step = 'validateParticipant-4'
|
103
110
|
const destinationParticipant = await participant.validateParticipant(destination)
|
104
111
|
if (!destinationParticipant) {
|
112
|
+
step = 'lookupProxyByDfspId-5'
|
105
113
|
const proxyName = proxyEnabled && await proxyCache.lookupProxyByDfspId(destination)
|
106
114
|
if (!proxyName) {
|
107
115
|
const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
|
@@ -119,12 +127,21 @@ const putPartiesByTypeAndID = async (headers, params, method, payload, dataUri,
|
|
119
127
|
partyIdentifier: params.ID,
|
120
128
|
...(partySubId && { partySubIdOrType: partySubId })
|
121
129
|
}
|
130
|
+
step = 'sendRequest-6'
|
122
131
|
await participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.PUT, decodedPayload.body.toString(), options)
|
123
132
|
|
124
|
-
|
133
|
+
log.info('parties::putPartiesByTypeAndID::callback was sent', { sendTo, options })
|
125
134
|
histTimerEnd({ success: true })
|
126
135
|
} catch (err) {
|
127
|
-
await
|
136
|
+
const fspiopError = await handleErrorOnSendingCallback(err, headers, params, sendTo)
|
137
|
+
const extensions = err.extensions || []
|
138
|
+
const system = extensions.find((element) => element.key === 'system')?.value || ''
|
139
|
+
errorCounter.inc({
|
140
|
+
code: fspiopError?.apiErrorCode,
|
141
|
+
system,
|
142
|
+
operation: 'putPartiesByTypeAndID',
|
143
|
+
step
|
144
|
+
})
|
128
145
|
histTimerEnd({ success: false })
|
129
146
|
}
|
130
147
|
}
|
@@ -148,6 +165,7 @@ const putPartiesErrorByTypeAndID = async (headers, params, payload, dataUri, spa
|
|
148
165
|
'Put parties error by type and id',
|
149
166
|
['success']
|
150
167
|
).startTimer()
|
168
|
+
const errorCounter = Metrics.getCounter('errorCount')
|
151
169
|
const partySubId = params.SubId
|
152
170
|
const destination = headers[Headers.FSPIOP.DESTINATION]
|
153
171
|
const callbackEndpointType = utils.errorPartyCbType(partySubId)
|
@@ -157,33 +175,37 @@ const putPartiesErrorByTypeAndID = async (headers, params, payload, dataUri, spa
|
|
157
175
|
|
158
176
|
let sendTo
|
159
177
|
let fspiopError
|
178
|
+
let step
|
160
179
|
|
161
180
|
try {
|
162
181
|
const proxy = proxyEnabled && headers[Headers.FSPIOP.PROXY]
|
163
182
|
if (proxy) {
|
164
183
|
if (isNotValidPayeeCase(payload)) {
|
165
184
|
const swappedHeaders = utils.swapSourceDestinationHeaders(headers)
|
185
|
+
step = 'oracleRequest-1'
|
166
186
|
await oracle.oracleRequest(swappedHeaders, RestMethods.DELETE, params, null, null, cache)
|
167
187
|
getPartiesByTypeAndID(swappedHeaders, params, RestMethods.GET, {}, span, cache, proxyCache)
|
168
188
|
// todo: - think if we need to send errorCallback?
|
169
189
|
// - or sentCallback after getPartiesByTypeAndID is done
|
170
|
-
|
190
|
+
log.info('notValidPayee case - deleted Participants and run getPartiesByTypeAndID:', { proxy, params, payload })
|
171
191
|
return
|
172
192
|
}
|
173
193
|
|
174
194
|
const alsReq = utils.alsRequestDto(destination, params) // or source?
|
195
|
+
step = 'receivedErrorResponse-2'
|
175
196
|
const isLast = await proxyCache.receivedErrorResponse(alsReq, proxy)
|
176
197
|
if (!isLast) {
|
177
|
-
|
198
|
+
log.info('got NOT last error callback from proxy:', { proxy, alsReq })
|
178
199
|
return
|
179
200
|
}
|
180
201
|
}
|
181
|
-
|
202
|
+
step = 'validateParticipant-3'
|
182
203
|
const destinationParticipant = await participant.validateParticipant(destination)
|
183
204
|
|
184
205
|
if (destinationParticipant) {
|
185
206
|
sendTo = destination
|
186
207
|
} else {
|
208
|
+
step = 'lookupProxyByDfspId-4'
|
187
209
|
const proxyName = proxyEnabled && await proxyCache.lookupProxyByDfspId(destination)
|
188
210
|
if (!proxyName) {
|
189
211
|
const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
|
@@ -194,10 +216,18 @@ const putPartiesErrorByTypeAndID = async (headers, params, payload, dataUri, spa
|
|
194
216
|
const decodedPayload = decodePayload(dataUri, { asParsed: false })
|
195
217
|
await participant.sendErrorToParticipant(sendTo, callbackEndpointType, decodedPayload.body.toString(), headers, params, childSpan)
|
196
218
|
|
197
|
-
|
219
|
+
log.info('putPartiesErrorByTypeAndID callback was sent', { sendTo })
|
198
220
|
histTimerEnd({ success: true })
|
199
221
|
} catch (err) {
|
200
|
-
fspiopError = await
|
222
|
+
fspiopError = await handleErrorOnSendingCallback(err, headers, params, sendTo)
|
223
|
+
const extensions = err.extensions || []
|
224
|
+
const system = extensions.find((element) => element.key === 'system')?.value || ''
|
225
|
+
errorCounter.inc({
|
226
|
+
code: fspiopError?.apiErrorCode,
|
227
|
+
system,
|
228
|
+
operation: 'putPartiesErrorByTypeAndID',
|
229
|
+
step
|
230
|
+
})
|
201
231
|
histTimerEnd({ success: false })
|
202
232
|
} finally {
|
203
233
|
await utils.finishSpanWithError(childSpan, fspiopError)
|
@@ -1,10 +1,9 @@
|
|
1
|
-
const { Enum } = require('@mojaloop/central-services-shared')
|
1
|
+
const { Enum, Util: { Hapi } } = require('@mojaloop/central-services-shared')
|
2
2
|
const EventSdk = require('@mojaloop/event-sdk')
|
3
3
|
const ErrorHandler = require('@mojaloop/central-services-error-handling')
|
4
4
|
|
5
5
|
const participant = require('../../models/participantEndpoint/facade')
|
6
|
-
const
|
7
|
-
const { logger } = require('../../lib')
|
6
|
+
const { TransformFacades } = require('../../lib')
|
8
7
|
|
9
8
|
const { FspEndpointTypes } = Enum.EndPoints
|
10
9
|
const { Headers } = Enum.Http
|
@@ -33,6 +32,13 @@ const finishSpanWithError = async (childSpan, fspiopError) => {
|
|
33
32
|
}
|
34
33
|
}
|
35
34
|
|
35
|
+
const makePutPartiesErrorPayload = async (config, fspiopError, headers, params) => {
|
36
|
+
const body = fspiopError.toApiErrorObject(config.ERROR_HANDLING)
|
37
|
+
return config.API_TYPE === Hapi.API_TYPES.iso20022
|
38
|
+
? (await TransformFacades.FSPIOP.parties.putError({ body, headers, params })).body
|
39
|
+
: body
|
40
|
+
}
|
41
|
+
|
36
42
|
const alsRequestDto = (sourceId, params) => ({
|
37
43
|
sourceId,
|
38
44
|
type: params.Type,
|
@@ -54,13 +60,13 @@ const swapSourceDestinationHeaders = (headers) => {
|
|
54
60
|
}
|
55
61
|
|
56
62
|
// change signature to accept object
|
57
|
-
const
|
63
|
+
const createErrorHandlerOnSendingCallback = (config, logger) => async (err, headers, params, requester) => {
|
58
64
|
try {
|
59
65
|
logger.error('error in sending parties callback', err)
|
60
66
|
const sendTo = requester || headers[Headers.FSPIOP.SOURCE]
|
61
67
|
const errorCallbackEndpointType = errorPartyCbType(params.SubId)
|
62
68
|
const fspiopError = ErrorHandler.Factory.reformatFSPIOPError(err)
|
63
|
-
const errInfo = fspiopError
|
69
|
+
const errInfo = await makePutPartiesErrorPayload(config, fspiopError, headers, params)
|
64
70
|
|
65
71
|
await participant.sendErrorToParticipant(sendTo, errorCallbackEndpointType, errInfo, headers, params)
|
66
72
|
|
@@ -77,8 +83,9 @@ module.exports = {
|
|
77
83
|
getPartyCbType,
|
78
84
|
putPartyCbType,
|
79
85
|
errorPartyCbType,
|
86
|
+
makePutPartiesErrorPayload,
|
80
87
|
finishSpanWithError,
|
81
|
-
|
88
|
+
createErrorHandlerOnSendingCallback,
|
82
89
|
alsRequestDto,
|
83
90
|
swapSourceDestinationHeaders
|
84
91
|
}
|
@@ -8,18 +8,10 @@ const {
|
|
8
8
|
EndPoints: { FspEndpointTypes }
|
9
9
|
} = require('@mojaloop/central-services-shared').Enum
|
10
10
|
const { Tracer } = require('@mojaloop/event-sdk')
|
11
|
-
const { API_TYPES } = require('@mojaloop/central-services-shared').Util.Hapi
|
12
11
|
|
13
|
-
const { TransformFacades } = require('../../lib')
|
14
12
|
const LibUtil = require('../../lib/util')
|
15
13
|
const Config = require('../../lib/config')
|
16
|
-
|
17
|
-
const makeErrorPayload = async (headers, params) => {
|
18
|
-
const body = createFSPIOPError(FSPIOPErrorCodes.EXPIRED_ERROR).toApiErrorObject(Config.ERROR_HANDLING)
|
19
|
-
return Config.API_TYPE === API_TYPES.iso20022
|
20
|
-
? (await TransformFacades.FSPIOP.parties.putError({ body, headers, params })).body
|
21
|
-
: body
|
22
|
-
}
|
14
|
+
const partiesUtils = require('../parties/utils')
|
23
15
|
|
24
16
|
const timeoutCallbackDto = async ({ destination, partyId, partyType }) => {
|
25
17
|
const headers = {
|
@@ -30,8 +22,10 @@ const timeoutCallbackDto = async ({ destination, partyId, partyType }) => {
|
|
30
22
|
ID: partyId,
|
31
23
|
Type: partyType
|
32
24
|
}
|
25
|
+
const error = createFSPIOPError(FSPIOPErrorCodes.EXPIRED_ERROR)
|
26
|
+
|
33
27
|
const dto = {
|
34
|
-
errorInformation: await
|
28
|
+
errorInformation: await partiesUtils.makePutPartiesErrorPayload(Config, error, headers, params),
|
35
29
|
headers,
|
36
30
|
params,
|
37
31
|
endpointType: FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_PUT_ERROR
|
@@ -57,20 +57,31 @@ const sendTimeoutCallback = async (cacheKey) => {
|
|
57
57
|
'Egress - Interscheme parties lookup timeout callback',
|
58
58
|
['success']
|
59
59
|
).startTimer()
|
60
|
-
|
60
|
+
const errorCounter = Metrics.getCounter('errorCount')
|
61
|
+
let step
|
61
62
|
const [, destination, partyType, partyId] = cacheKey.split(':')
|
62
63
|
const { errorInformation, params, headers, endpointType, span } = await timeoutCallbackDto({ destination, partyId, partyType })
|
63
64
|
logger.debug('sendTimeoutCallback details:', { destination, partyType, partyId, cacheKey })
|
64
65
|
|
65
66
|
try {
|
67
|
+
step = 'validateParticipant-1'
|
66
68
|
await validateParticipant(destination)
|
67
69
|
await span.audit({ headers, errorInformation }, AuditEventAction.start)
|
70
|
+
step = 'sendErrorToParticipant-2'
|
68
71
|
await Participant.sendErrorToParticipant(destination, endpointType, errorInformation, headers, params, undefined, span)
|
69
72
|
histTimerEnd({ success: true })
|
70
73
|
} catch (err) {
|
71
74
|
logger.warn('error in sendTimeoutCallback: ', err)
|
72
75
|
histTimerEnd({ success: false })
|
73
76
|
const fspiopError = reformatFSPIOPError(err)
|
77
|
+
const extensions = err.extensions || []
|
78
|
+
const system = extensions.find((element) => element.key === 'system')?.value || ''
|
79
|
+
errorCounter.inc({
|
80
|
+
code: fspiopError?.apiErrorCode,
|
81
|
+
system,
|
82
|
+
operation: 'sendTimeoutCallback',
|
83
|
+
step
|
84
|
+
})
|
74
85
|
await finishSpan(span, fspiopError)
|
75
86
|
throw fspiopError
|
76
87
|
}
|
package/src/handlers/index.js
CHANGED
@@ -35,7 +35,7 @@ const Package = require('../../package.json')
|
|
35
35
|
const Server = require('../server')
|
36
36
|
const { HANDLER_TYPES } = require('../constants')
|
37
37
|
const Config = require('../lib/config')
|
38
|
-
const
|
38
|
+
const log = require('../lib').logger.child('ALS-timeout-handler')
|
39
39
|
|
40
40
|
const Program = new Command()
|
41
41
|
|
@@ -51,16 +51,16 @@ Program.command('handlers')
|
|
51
51
|
const handlers = []
|
52
52
|
|
53
53
|
if (args.timeout) {
|
54
|
-
|
54
|
+
log.debug('CLI: Executing --timeout')
|
55
55
|
handlers.push(HANDLER_TYPES.TIMEOUT)
|
56
56
|
}
|
57
57
|
|
58
58
|
if (handlers.length === 0) {
|
59
|
-
|
59
|
+
log.debug('CLI: No handlers specified')
|
60
60
|
return
|
61
61
|
}
|
62
62
|
|
63
|
-
module.exports = await Server.initializeHandlers(handlers, Config,
|
63
|
+
module.exports = await Server.initializeHandlers(handlers, Config, log)
|
64
64
|
})
|
65
65
|
|
66
66
|
if (Array.isArray(process.argv) && process.argv.length > 2) {
|
@@ -18,7 +18,7 @@
|
|
18
18
|
const Hapi = require('@hapi/hapi')
|
19
19
|
const Metrics = require('@mojaloop/central-services-metrics')
|
20
20
|
const { plugin: HealthPlugin } = require('./plugins/health')
|
21
|
-
const
|
21
|
+
const MetricsPlugin = require('@mojaloop/central-services-metrics').plugin
|
22
22
|
const { logger } = require('../../lib')
|
23
23
|
|
24
24
|
let server
|
@@ -890,13 +890,14 @@ components:
|
|
890
890
|
schemas:
|
891
891
|
CorrelationId:
|
892
892
|
title: CorrelationId
|
893
|
-
pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
|
894
893
|
type: string
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
894
|
+
pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$|^[0-9A-HJKMNP-TV-Z]{26}$
|
895
|
+
description: >-
|
896
|
+
Identifier that correlates all messages of the same sequence.
|
897
|
+
The supported identifiers formats are for
|
898
|
+
lowercase [UUID](https://datatracker.ietf.org/doc/html/rfc9562) and
|
899
|
+
uppercase [ULID](https://github.com/ulid/spec)
|
900
|
+
example: 'b51ec534-ee48-4575-b6a9-ead2955b8069'
|
900
901
|
Currency:
|
901
902
|
title: CurrencyEnum
|
902
903
|
maxLength: 3
|
@@ -889,13 +889,14 @@ components:
|
|
889
889
|
schemas:
|
890
890
|
CorrelationId:
|
891
891
|
title: CorrelationId
|
892
|
-
pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
|
893
892
|
type: string
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
893
|
+
pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[1-7][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$|^[0-9A-HJKMNP-TV-Z]{26}$
|
894
|
+
description: >-
|
895
|
+
Identifier that correlates all messages of the same sequence.
|
896
|
+
The supported identifiers formats are for
|
897
|
+
lowercase [UUID](https://datatracker.ietf.org/doc/html/rfc9562) and
|
898
|
+
uppercase [ULID](https://github.com/ulid/spec)
|
899
|
+
example: 'b51ec534-ee48-4575-b6a9-ead2955b8069'
|
899
900
|
Currency:
|
900
901
|
title: CurrencyEnum
|
901
902
|
maxLength: 3
|