1 | //
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | const JsonPathReplacer = require('./JsonPathReplacer');
|
8 |
|
9 | /**
|
10 | * @classdesc
|
11 | * Handles all the sequential and parallel requests.
|
12 | *
|
13 | * @class SubrequestsManager
|
14 | */
|
15 | module.exports = class SubrequestsManager {
|
16 | /**
|
17 | * Take a request tree and issue the subrequests with the requestor.
|
18 | *
|
19 | * @param {SubrequestsTree} tree
|
20 | * The tree of subrequests.
|
21 | * @param {RequestorInterface} requestor
|
22 | * The wrapper to resolve the requests.
|
23 | *
|
24 | * @return {Promise.<Response[]>}
|
25 | * The responses for the requests.
|
26 | */
|
27 | static request(tree , requestor ) {
|
28 | // Loop through all sequential requests and merge them.
|
29 | return this._processBatchesSequence(tree, requestor);
|
30 | }
|
31 |
|
32 | /**
|
33 | * Takes a batch sequence and replaces everything that needs replacing.
|
34 | *
|
35 | * @param {SubrequestsTree} tree
|
36 | * The request tree that contains the requesting structure.
|
37 | * @param {RequestorInterface} requestor
|
38 | * The wrapper around the request library to use.
|
39 | * @param {int} _sequence
|
40 | * (internal) The current index in the sequential chain.
|
41 | * @param {Response[]} _responses
|
42 | * (internal) The list of responses accumulated so far.
|
43 | *
|
44 | * @return {Promise.<Response[]>}
|
45 | * A promise of an array of responses when everything has been resolved.
|
46 | *
|
47 | * @private
|
48 | */
|
49 | static _processBatchesSequence(
|
50 | tree ,
|
51 | requestor ,
|
52 | _sequence = 0,
|
53 | _responses = []
|
54 | ) {
|
55 | let batch = tree[_sequence];
|
56 | // Perform all the necessary replacements for the elements in the batch.
|
57 | batch = JsonPathReplacer.replaceBatch(batch, _responses);
|
58 | return Promise.all(requestor.requestInParallel(batch))
|
59 | // Turn all the responses from whatever shape the HTTP library uses to the
|
60 | // shape in the Response type.
|
61 | .then(results => this._translateResponsesFromLibFormat(results, requestor))
|
62 | // Link each response with the request that initiated it.
|
63 | .then(this._setRequestIdInResponses.bind(this))
|
64 | // Now that the promise has resolved, issue the new request.
|
65 | .then((results) => {
|
66 | _responses = [..._responses, ...results];
|
67 | // If the last batch was processed then resolve the output. If not
|
68 | // then continue processing batches.
|
69 | _sequence += 1;
|
70 | return _sequence === tree.length
|
71 | ? Promise.resolve(_responses)
|
72 | : this._processBatchesSequence(tree, requestor, _sequence, _responses);
|
73 | });
|
74 | }
|
75 |
|
76 | /**
|
77 | * Takes a list of responses in the lib format and turns them into Response.
|
78 | * @param {Array} responses
|
79 | * An array of responses in whatever format the requestor library expects
|
80 | * them.
|
81 | * @param {RequestorInterface} requestor
|
82 | * The requestor that resolved the request.
|
83 | *
|
84 | * @returns {Response[]}
|
85 | * The list of responses in the canonical form.
|
86 | *
|
87 | * @private
|
88 | */
|
89 | static _translateResponsesFromLibFormat(
|
90 | responses ,
|
91 | requestor
|
92 | ) {
|
93 | return responses.map(response => requestor.translateResponseFromLibFormat(response));
|
94 | }
|
95 |
|
96 | /**
|
97 | * Sets the ID of the request that originated the response in Content-ID.
|
98 | *
|
99 | * @param {Response[]} responses
|
100 | * The responses to alter.
|
101 | *
|
102 | * @returns {Response[]}
|
103 | * The altered responses.
|
104 | *
|
105 | * @private
|
106 | */
|
107 | static _setRequestIdInResponses(responses ) {
|
108 | return responses.map((response) => {
|
109 | this._setRequestIdInResponse(response.headers.get('x-subrequest-id'), response);
|
110 | return response;
|
111 | });
|
112 | }
|
113 |
|
114 | /**
|
115 | * Puts the request ID in the response so a consumer.
|
116 | *
|
117 | * This way a consumer can know what part of the subrequest was initiated by
|
118 | * what request.
|
119 | *
|
120 | * @param {string} requestId
|
121 | * The content id.
|
122 | * @param {Response} response
|
123 | * The response object we are dealing with.
|
124 | *
|
125 | * @return {void}
|
126 | *
|
127 | * @private
|
128 | */
|
129 | static _setRequestIdInResponse(requestId , response ) {
|
130 | if (!requestId) {
|
131 | throw new Error(`Unable to find the requestId for response "${JSON.stringify(response)}".`);
|
132 | }
|
133 | response.headers.set('Content-ID', `<${requestId}>`);
|
134 | }
|
135 | };
|