account-lookup-service 17.7.1 → 17.8.0-snapshot.7

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +0 -7
  2. package/package.json +8 -5
  3. package/src/constants.js +34 -2
  4. package/src/domain/parties/deps.js +11 -4
  5. package/src/domain/parties/getPartiesByTypeAndID.js +9 -13
  6. package/src/domain/parties/partiesUtils.js +4 -34
  7. package/src/domain/parties/putParties.js +26 -71
  8. package/src/domain/parties/services/BasePartiesService.js +143 -15
  9. package/src/domain/parties/services/GetPartiesService.js +194 -164
  10. package/src/domain/parties/services/PutPartiesErrorService.js +51 -27
  11. package/src/domain/parties/services/PutPartiesService.js +51 -33
  12. package/src/domain/parties/services/TimeoutPartiesService.js +84 -0
  13. package/src/domain/parties/services/index.js +3 -1
  14. package/src/domain/timeout/createSpan.js +55 -0
  15. package/src/domain/timeout/index.js +27 -36
  16. package/src/handlers/TimeoutHandler.js +2 -2
  17. package/src/lib/util.js +11 -3
  18. package/test/fixtures/index.js +46 -0
  19. package/test/integration/domain/timeout/index.test.js +83 -28
  20. package/test/unit/domain/parties/parties.test.js +26 -18
  21. package/test/unit/domain/parties/partiesUtils.test.js +51 -0
  22. package/test/unit/domain/parties/services/BasePartiesService.test.js +71 -0
  23. package/test/unit/domain/parties/services/GetPartiesService.test.js +245 -0
  24. package/test/unit/domain/parties/services/PutPartiesErrorService.test.js +50 -0
  25. package/test/unit/domain/parties/services/TimeoutPartiesService.test.js +72 -0
  26. package/test/unit/domain/parties/services/deps.js +51 -0
  27. package/test/unit/domain/timeout/index.test.js +17 -12
  28. package/test/util/apiClients/BasicApiClient.js +33 -6
  29. package/test/util/apiClients/ProxyApiClient.js +46 -1
  30. package/test/util/index.js +5 -6
  31. package/test/util/mockDeps.js +72 -0
  32. package/src/domain/timeout/dto.js +0 -54
  33. package/test/unit/domain/parties/utils.test.js +0 -60
  34. package/test/unit/domain/timeout/dto.test.js +0 -24
@@ -25,207 +25,135 @@
25
25
  --------------
26
26
  ******/
27
27
 
28
- const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
28
  const { ERROR_MESSAGES } = require('../../../constants')
30
- const { createCallbackHeaders } = require('../../../lib/headers')
31
29
  const BasePartiesService = require('./BasePartiesService')
32
30
 
33
- const {
34
- FspEndpointTypes, FspEndpointTemplates,
35
- Headers, RestMethods
36
- } = BasePartiesService.enums()
37
-
31
+ const { FspEndpointTypes, RestMethods } = BasePartiesService.enums()
38
32
  const proxyCacheTtlSec = 40 // todo: make configurable
39
33
 
40
34
  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]
35
+ async handleRequest () {
36
+ const { destination, source, proxy } = this.state
45
37
  // see https://github.com/mojaloop/design-authority/issues/79
46
38
  // the requester has specified a destination routing header. We should respect that and forward the request directly to the destination
47
39
  // 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
40
+ this.log.info('handling getParties request...', { source, destination, proxy })
41
+ this.state.requester = await this.validateRequester()
52
42
 
53
43
  if (destination) {
54
- await this.forwardRequestToDestination({ destination, headers, params })
44
+ await this.forwardRequestToDestination()
55
45
  return
56
46
  }
57
- const response = await this.sendOracleDiscoveryRequest({ headers, params, query })
58
47
 
48
+ const response = await this.sendOracleDiscoveryRequest()
59
49
  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
50
+ const isDone = await this.processOraclePartyListResponse(response)
51
+ if (isDone) return
63
52
  }
64
53
 
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
54
+ this.log.info('no forwarded requests for oracle partyList')
55
+ const fspiopError = await this.triggerInterSchemeDiscoveryFlow(this.inputs.headers)
56
+ if (fspiopError) {
57
+ this.state.fspiopError = fspiopError // todo: think, if we need this
71
58
  }
72
-
73
- results.fspiopError = await this.sendPartyNotFoundErrorCallback({ requester, headers, params })
74
59
  }
75
60
 
76
- async validateRequester ({ source, proxy }) {
77
- this.deps.stepState.inProgress('validateRequester-0')
61
+ async validateRequester () {
62
+ const { source, proxy, proxyEnabled } = this.state
78
63
  const log = this.log.child({ source, proxy, method: 'validateRequester' })
64
+ this.stepInProgress('validateRequester-0')
79
65
 
80
- const sourceParticipant = await this.validateParticipant(source)
81
- if (sourceParticipant) {
82
- log.debug('source is in scheme')
66
+ const schemeSource = await this.validateParticipant(source)
67
+ if (schemeSource) {
68
+ log.debug('source participant is in scheme')
83
69
  return source
84
70
  }
85
71
 
86
- if (!this.proxyEnabled || !proxy) {
87
- const errMessage = ERROR_MESSAGES.sourceFspNotFound
88
- log.warn(errMessage)
89
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
72
+ if (!proxyEnabled || !proxy) {
73
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.sourceFspNotFound, log)
90
74
  }
91
75
 
92
- const proxyParticipant = await this.validateParticipant(proxy)
93
- if (!proxyParticipant) {
94
- const errMessage = ERROR_MESSAGES.partyProxyNotFound
95
- log.warn(errMessage)
96
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
76
+ const schemeProxy = await this.validateParticipant(proxy)
77
+ if (!schemeProxy) {
78
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.partyProxyNotFound, log)
97
79
  }
98
80
 
99
81
  const isCached = await this.deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
100
82
  if (!isCached) {
101
- const errMessage = 'failed to addDfspIdToProxyMapping'
102
- log.warn(errMessage)
103
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
83
+ throw super.createFspiopIdNotFoundError('failed to addDfspIdToProxyMapping', log)
104
84
  }
105
85
 
106
- log.info('source is added to proxyMapping cache:', { proxy, isCached })
86
+ log.info('source is added to proxyMapping cache')
107
87
  return proxy
108
88
  }
109
89
 
110
- async forwardRequestToDestination ({ destination, headers, params }) {
111
- this.deps.stepState.inProgress('validateDestination-1')
90
+ async forwardRequestToDestination () {
91
+ const { headers, params } = this.inputs
92
+ const { destination } = this.state
112
93
  const log = this.log.child({ method: 'forwardRequestToDestination' })
113
94
  let sendTo = destination
114
95
 
115
- const destParticipantModel = await this.validateParticipant(destination)
116
- if (!destParticipantModel) {
117
- this.deps.stepState.inProgress('lookupProxyDestination-2')
118
- const proxyId = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
96
+ const schemeParticipant = await this.validateParticipant(destination)
97
+ if (!schemeParticipant) {
98
+ this.stepInProgress('lookupProxyDestination-2')
99
+ const proxyId = this.state.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
119
100
 
120
101
  if (!proxyId) {
121
- log.warn('no destination participant, and no dfsp-to-proxy mapping', { destination })
122
- const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
123
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
102
+ log.warn('destination participant is not in scheme, and no dfsp-to-proxy mapping', { destination })
103
+ await super.sendDeleteOracleRequest(headers, params)
104
+ await this.triggerInterSchemeDiscoveryFlow(GetPartiesService.headersWithoutDestination(headers))
105
+ return
124
106
  }
125
107
  sendTo = proxyId
126
108
  }
127
- // all ok, go ahead and forward the request
109
+
128
110
  await this.#forwardGetPartiesRequest({ sendTo, headers, params })
129
111
  log.info('discovery getPartiesByTypeAndID request was sent', { sendTo })
130
112
  }
131
113
 
132
- filterOraclePartyList ({ response, params }) {
133
- // 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:
134
- this.deps.stepState.inProgress('filterOraclePartyList-5')
135
- const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
136
- let filteredResponsePartyList
137
-
138
- switch (callbackEndpointType) {
139
- case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_GET:
140
- filteredResponsePartyList = response.data.partyList.filter(party => party.partySubIdOrType == null) // Filter records that DON'T contain a partySubIdOrType
141
- break
142
- case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET:
143
- filteredResponsePartyList = response.data.partyList.filter(party => party.partySubIdOrType === params.SubId) // Filter records that match partySubIdOrType
144
- break
145
- default:
146
- filteredResponsePartyList = response // Fallback to providing the standard list
147
- }
148
-
149
- if (!Array.isArray(filteredResponsePartyList) || !filteredResponsePartyList.length) {
150
- const errMessage = 'Requested FSP/Party not found'
151
- this.log.warn(errMessage)
152
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
153
- }
154
-
155
- return filteredResponsePartyList
114
+ async sendOracleDiscoveryRequest () {
115
+ this.stepInProgress('#sendOracleDiscoveryRequest')
116
+ const { headers, params, query } = this.inputs
117
+ return this.deps.oracle.oracleRequest(headers, RestMethods.GET, params, query, undefined, this.deps.cache)
156
118
  }
157
119
 
158
- async processOraclePartyList ({ partyList, headers, params, destination }) {
159
- const log = this.log.child({ method: 'processOraclePartyList' })
120
+ async processOraclePartyListResponse (response) {
121
+ this.stepInProgress('processOraclePartyList')
122
+ const partyList = this.#filterOraclePartyList(response)
160
123
 
161
- let sentCount = 0 // if sentCount === 0 after sending, should we restart the whole process?
162
- const sending = partyList.map(async party => {
163
- const { fspId } = party
164
- const clonedHeaders = { ...headers }
165
- if (!destination) {
166
- clonedHeaders[Headers.FSPIOP.DESTINATION] = fspId
167
- }
168
- this.deps.stepState.inProgress('validateParticipant-6')
169
- const schemeParticipant = await this.validateParticipant(fspId)
170
- if (schemeParticipant) {
171
- sentCount++
172
- log.info('participant is in scheme', { fspId })
173
- return this.#forwardGetPartiesRequest({
174
- sendTo: fspId,
175
- headers: clonedHeaders,
176
- params
177
- })
178
- }
124
+ let sentCount = 0
125
+ await Promise.all(partyList.map(async party => {
126
+ const isSent = await this.#processSingleOracleParty(party)
127
+ if (isSent) sentCount++
128
+ }))
179
129
 
180
- // If the participant is not in the scheme and proxy routing is enabled,
181
- // we should check if there is a proxy for it and send the request to the proxy
182
- if (this.proxyEnabled) {
183
- this.deps.stepState.inProgress('lookupProxyByDfspId-7')
184
- const proxyName = await this.deps.proxyCache.lookupProxyByDfspId(fspId)
185
- if (!proxyName) {
186
- log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
187
- // todo: delete reference in oracle
188
- } else {
189
- sentCount++
190
- log.info('participant is NOT in scheme, use proxy name', { fspId, proxyName })
191
- return this.#forwardGetPartiesRequest({
192
- sendTo: proxyName,
193
- headers: clonedHeaders,
194
- params
195
- })
196
- }
197
- }
198
- })
199
- await Promise.all(sending)
200
- log.verbose('processOraclePartyList is done', { sentCount })
201
- // todo: think what if sentCount === 0 here
130
+ const isDone = sentCount > 0
131
+ this.log.verbose('processOraclePartyList is done', { isDone, sentCount })
132
+ // if NOT isDone, need to trigger interScheme discovery flow
133
+ return isDone
202
134
  }
203
135
 
204
- async getFilteredProxyList (proxy) {
205
- this.deps.stepState.inProgress('getAllProxies-8')
206
- if (!this.proxyEnabled) {
207
- this.log.warn('proxyCache is not enabled')
208
- return []
209
- }
136
+ async triggerInterSchemeDiscoveryFlow (headers) {
137
+ const { params } = this.inputs
138
+ const { proxy, source } = this.state
139
+ const log = this.log.child({ method: 'triggerInterSchemeDiscoveryFlow' })
140
+ log.verbose('triggerInterSchemeDiscoveryFlow start...', { proxy, source })
210
141
 
211
- const proxyNames = await this.deps.proxies.getAllProxiesNames(this.deps.config.SWITCH_ENDPOINT)
212
- this.log.debug('getAllProxiesNames is done', { proxyNames })
213
- return proxyNames.filter(name => name !== proxy)
214
- }
142
+ const proxyNames = await this.#getFilteredProxyList(proxy)
143
+ if (!proxyNames.length) {
144
+ return this.#sendPartyNotFoundErrorCallback(headers)
145
+ }
215
146
 
216
- async triggerSendToProxiesFlow ({ proxyNames, headers, params, source }) {
217
- const log = this.log.child({ method: 'triggerSendToProxiesFlow' })
218
- this.deps.stepState.inProgress('setSendToProxiesList-10')
147
+ this.stepInProgress('setSendToProxiesList-10')
219
148
  const alsReq = this.deps.partiesUtils.alsRequestDto(source, params)
220
- log.info('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
149
+ log.verbose('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
221
150
 
222
151
  const isCached = await this.deps.proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
223
152
  if (!isCached) {
224
- log.warn('failed to setSendToProxiesList')
225
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
153
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.failedToCacheSendToProxiesList, log)
226
154
  }
227
155
 
228
- this.deps.stepState.inProgress('sendingProxyRequests-11')
156
+ this.stepInProgress('sendingProxyRequests')
229
157
  const sending = proxyNames.map(
230
158
  sendTo => this.#forwardGetPartiesRequest({ sendTo, headers, params })
231
159
  .then(({ status, data } = {}) => ({ status, data }))
@@ -234,48 +162,150 @@ class GetPartiesService extends BasePartiesService {
234
162
  const isOk = results.some(result => result.status === 'fulfilled')
235
163
  // If, at least, one request is sent to proxy, we treat the whole flow as successful.
236
164
  // Failed requests should be handled by TTL expired/timeout handler
237
- // todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
238
- log.info('triggerSendToProxiesFlow is done:', { isOk, results, proxyNames, alsReq })
239
- this.deps.stepState.inProgress('allSent-12')
165
+ // todo: If forwarding request to proxy failed, remove the proxy from setSendToProxiesList
166
+ log.info('triggerInterSchemeDiscoveryFlow is done:', { isOk, results, proxyNames, alsReq })
167
+ this.stepInProgress('allSent-12')
168
+
240
169
  if (!isOk) {
241
- log.warn('no successful requests sent to proxies')
242
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
170
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.proxyConnectionError, log)
243
171
  }
244
172
  }
245
173
 
246
- async sendPartyNotFoundErrorCallback ({ requester, headers, params }) {
247
- this.deps.stepState.inProgress('sendErrorCallback-9')
248
- const callbackHeaders = createCallbackHeaders({
249
- requestHeaders: headers,
250
- partyIdType: params.Type,
251
- partyIdentifier: params.ID,
252
- endpointTemplate: params.SubId
253
- ? FspEndpointTemplates.PARTIES_SUB_ID_PUT_ERROR
254
- : FspEndpointTemplates.PARTIES_PUT_ERROR
255
- })
256
- const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND)
174
+ isLocalSource () {
175
+ const isLocal = this.state.source === this.state.requester
176
+ this.log.debug(`isLocalSource: ${isLocal}`)
177
+ return isLocal
178
+ }
179
+
180
+ #filterOraclePartyList (response) {
181
+ // Oracle's API is a standard rest-style end-point Thus a GET /party on the oracle will return all participant-party records.
182
+ // 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:
183
+ this.stepInProgress('filterOraclePartyList')
184
+ const { params } = this.inputs
185
+ const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
186
+ let filteredPartyList
187
+
188
+ switch (callbackEndpointType) {
189
+ case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_GET:
190
+ filteredPartyList = response.data.partyList.filter(party => party.partySubIdOrType == null) // Filter records that DON'T contain a partySubIdOrType
191
+ break
192
+ case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET:
193
+ filteredPartyList = response.data.partyList.filter(party => party.partySubIdOrType === params.SubId) // Filter records that match partySubIdOrType
194
+ break
195
+ default:
196
+ filteredPartyList = response // Fallback to providing the standard list
197
+ }
198
+
199
+ if (!Array.isArray(filteredPartyList) || !filteredPartyList.length) {
200
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.emptyFilteredPartyList)
201
+ }
202
+
203
+ return filteredPartyList
204
+ }
205
+
206
+ /** @returns {Promise<boolean>} - is request forwarded to participant */
207
+ async #processSingleOracleParty (party) {
208
+ const { headers, params } = this.inputs
209
+ const { fspId } = party
210
+
211
+ const schemeParticipant = await this.validateParticipant(fspId)
212
+ if (schemeParticipant) {
213
+ this.log.info('participant is in scheme, so forwarding to it...', { fspId })
214
+ await this.#forwardGetPartiesRequest({
215
+ sendTo: fspId,
216
+ headers: GetPartiesService.overrideDestinationHeader(headers, fspId),
217
+ params
218
+ })
219
+ return true
220
+ }
221
+
222
+ if (this.state.proxyEnabled) {
223
+ const proxyName = await this.deps.proxyCache.lookupProxyByDfspId(fspId)
224
+ if (!proxyName) {
225
+ this.log.warn('no proxyMapping for external DFSP! Deleting reference in oracle...', { fspId })
226
+ await super.sendDeleteOracleRequest(headers, params)
227
+ // todo: check if it won't delete all parties
228
+ return false
229
+ }
230
+
231
+ // Coz there's no destination header, it means we're inside initial inter-scheme discovery phase.
232
+ // So we should proceed only if source is in scheme (local participant)
233
+ const isLocalSource = this.isLocalSource()
234
+ if (isLocalSource) {
235
+ this.log.info('participant is NOT in scheme, but source is. So forwarding to proxy...', { fspId, proxyName })
236
+ await this.#forwardGetPartiesRequest({ // todo: add timeout if sendTo is proxy
237
+ sendTo: proxyName,
238
+ headers: GetPartiesService.overrideDestinationHeader(headers, fspId),
239
+ params
240
+ })
241
+ return true
242
+ }
243
+ }
244
+ return false
245
+ }
246
+
247
+ async #sendPartyNotFoundErrorCallback (headers) {
248
+ const { params } = this.inputs
249
+ const callbackHeaders = GetPartiesService.createErrorCallbackHeaders(headers, params)
250
+ const fspiopError = super.createFspiopIdNotFoundError('No proxy found to start inter-scheme discovery flow')
251
+ const errorInfo = await this.deps.partiesUtils.makePutPartiesErrorPayload(
252
+ this.deps.config, fspiopError, callbackHeaders, params
253
+ )
257
254
 
258
255
  await this.sendErrorCallback({
259
- sendTo: requester,
260
- errorInfo: fspiopError.toApiErrorObject(this.deps.config.ERROR_HANDLING),
256
+ errorInfo,
261
257
  headers: callbackHeaders,
262
258
  params
263
259
  })
264
260
  return fspiopError
265
261
  }
266
262
 
267
- async sendOracleDiscoveryRequest ({ headers, params, query }) {
268
- this.deps.stepState.inProgress('oracleRequest-4')
269
- return this.deps.oracle.oracleRequest(headers, RestMethods.GET, params, query, undefined, this.deps.cache)
270
- }
271
-
272
263
  async #forwardGetPartiesRequest ({ sendTo, headers, params }) {
273
- this.deps.stepState.inProgress('forwardRequest-3')
264
+ this.stepInProgress('#forwardGetPartiesRequest')
274
265
  const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
275
266
  const options = this.deps.partiesUtils.partiesRequestOptionsDto(params)
276
267
 
277
- return this.deps.participant.sendRequest(headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, this.deps.childSpan)
268
+ const sentResult = await this.deps.participant.sendRequest(
269
+ headers, sendTo, callbackEndpointType, RestMethods.GET, undefined, options, this.deps.childSpan
270
+ )
271
+ await this.#setProxyGetPartiesTimeout(sendTo)
272
+ return sentResult
273
+ }
274
+
275
+ async #getFilteredProxyList (proxy) {
276
+ this.stepInProgress('#getFilteredProxyList')
277
+ if (!this.state.proxyEnabled) {
278
+ this.log.warn('proxyCache is not enabled')
279
+ return []
280
+ }
281
+
282
+ const proxyNames = await this.deps.proxies.getAllProxiesNames(this.deps.config.SWITCH_ENDPOINT)
283
+ this.log.debug('getAllProxiesNames is done', { proxyNames })
284
+ return proxyNames.filter(name => name !== proxy)
285
+ }
286
+
287
+ async #setProxyGetPartiesTimeout (sendTo) {
288
+ const isLocalSource = this.isLocalSource()
289
+ const isSentToProxy = this.state.destination !== sendTo
290
+ this.log.verbose('isLocalSource and isSentToProxy: ', { isLocalSource, isSentToProxy, sendTo })
291
+
292
+ if (isSentToProxy && isLocalSource) {
293
+ this.stepInProgress('#setProxyGetPartiesTimeout')
294
+ const alsReq = this.deps.partiesUtils.alsRequestDto(this.state.source, this.inputs.params)
295
+ const isSet = await this.deps.proxyCache.setProxyGetPartiesTimeout(alsReq, sendTo)
296
+ this.log.info('#setProxyGetPartiesTimeout is done', { isSet })
297
+ return isSet
298
+ }
278
299
  }
279
300
  }
280
301
 
281
302
  module.exports = GetPartiesService
303
+
304
+ // As Payee DFSP Scheme Oracle identifies direct participant.
305
+ // As Payer DFSP Scheme oracle identifies interscheme participant.
306
+
307
+ // zm-dfsp --> ZM
308
+ // region-dfsp --> Region
309
+ // mw-dfsp --> MW (mw-party-123)
310
+
311
+ // 1. region-dfsp gets info about mw-party-123
@@ -30,49 +30,73 @@ const { ERROR_MESSAGES } = require('../../../constants')
30
30
  const BasePartiesService = require('./BasePartiesService')
31
31
 
32
32
  class PutPartiesErrorService extends BasePartiesService {
33
- // async handleRequest () {
34
- // // todo: add impl.
35
- // }
36
-
37
- async checkPayee ({ headers, params, payload, proxy }) {
38
- const notValid = this.deps.partiesUtils.isNotValidPayeeCase(payload)
39
- if (notValid) {
40
- this.deps.stepState.inProgress('notValidPayeeCase-1')
41
- this.log.warn('notValidPayee case - deleting Participants and run getPartiesByTypeAndID', { proxy, payload })
42
- const swappedHeaders = this.deps.partiesUtils.swapSourceDestinationHeaders(headers)
43
- await super.sendDeleteOracleRequest(swappedHeaders, params)
33
+ /** @returns {Promise<true | undefined>} - If true, need to trigger inter-scheme discovery. */
34
+ async handleRequest () {
35
+ if (this.state.proxyEnabled && this.state.proxy) {
36
+ const alsReq = this.deps.partiesUtils.alsRequestDto(this.state.destination, this.inputs.params) // or source?
37
+ const isPending = await this.deps.proxyCache.isPendingCallback(alsReq)
38
+
39
+ if (!isPending) {
40
+ // not initial inter-scheme discovery case. Cleanup oracle and trigger inter-scheme discovery
41
+ this.log.warn('Need to cleanup oracle and trigger new inter-scheme discovery flow')
42
+ await this.cleanupOracle()
43
+ await this.removeProxyGetPartiesTimeoutCache(alsReq)
44
+ return true // need to trigger inter-scheme discovery
45
+ }
46
+
47
+ const isLast = await this.checkLastProxyCallback(alsReq)
48
+ if (!isLast) {
49
+ this.log.verbose('putPartiesErrorByTypeAndID proxy callback was processed')
50
+ return
51
+ }
44
52
  }
45
- return notValid
53
+
54
+ await this.identifyDestinationForErrorCallback()
55
+ await this.sendErrorCallbackToParticipant()
56
+ this.log.info('putPartiesByTypeAndID is done')
46
57
  }
47
58
 
48
- async checkLastProxyCallback ({ destination, proxy, params }) {
49
- this.deps.stepState.inProgress('checkLastProxyCallback-2')
50
- const alsReq = this.deps.partiesUtils.alsRequestDto(destination, params) // or source?
59
+ async cleanupOracle () {
60
+ this.stepInProgress('cleanupOracle')
61
+ const { headers, params, payload } = this.inputs
62
+ this.log.info('cleanupOracle due to error callback...', { payload })
63
+ const swappedHeaders = this.deps.partiesUtils.swapSourceDestinationHeaders(headers)
64
+ await super.sendDeleteOracleRequest(swappedHeaders, params)
65
+ }
66
+
67
+ async checkLastProxyCallback (alsReq) {
68
+ this.stepInProgress('checkLastProxyCallback')
69
+ const { proxy } = this.state
51
70
  const isLast = await this.deps.proxyCache.receivedErrorResponse(alsReq, proxy)
52
71
  this.log.info(`got${isLast ? '' : 'NOT'} last error callback from proxy`, { proxy, alsReq, isLast })
53
72
  return isLast
54
73
  }
55
74
 
56
- async identifyDestinationForErrorCallback (destination) {
57
- this.deps.stepState.inProgress('validateParticipant-3')
58
- const destinationParticipant = await super.validateParticipant(destination)
59
- if (destinationParticipant) return destination
75
+ async identifyDestinationForErrorCallback () {
76
+ this.stepInProgress('identifyDestinationForErrorCallback')
77
+ const { destination } = this.state
78
+ const schemeParticipant = await super.validateParticipant(destination)
79
+ if (schemeParticipant) {
80
+ this.state.requester = destination
81
+ return
82
+ }
60
83
 
61
- this.deps.stepState.inProgress('lookupProxyDestination-4')
62
- const proxyName = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
63
- if (proxyName) return proxyName
84
+ this.stepInProgress('lookupProxyDestination-4')
85
+ const proxyName = this.state.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
86
+ if (proxyName) {
87
+ this.state.requester = proxyName
88
+ return
89
+ }
64
90
 
65
91
  const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
66
92
  this.log.warn(errMessage, { destination })
67
93
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
68
94
  }
69
95
 
70
- async sendErrorCallbackToParticipant ({ sendTo, headers, params, dataUri }) {
71
- this.deps.stepState.inProgress('sendErrorToParticipant-5')
96
+ async sendErrorCallbackToParticipant () {
97
+ const { headers, params, dataUri } = this.inputs
72
98
  const errorInfo = PutPartiesErrorService.decodeDataUriPayload(dataUri)
73
- return super.sendErrorCallback({
74
- sendTo, errorInfo, headers, params
75
- })
99
+ return super.sendErrorCallback({ errorInfo, headers, params })
76
100
  }
77
101
  }
78
102