Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Commit eafcbb5

Browse files
authored
[0.19.x] Experimental Pluggable Query Handler (#4534)
This is an experimental feature for composer and as such is not documented. Signed-off-by: Dave Kelsey <d_kelsey@uk.ibm.com>
1 parent 5953dad commit eafcbb5

File tree

5 files changed

+344
-300
lines changed

5 files changed

+344
-300
lines changed

packages/composer-connector-hlfv1/lib/hlfconnection.js

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ const fs = require('fs-extra');
1919
const HLFSecurityContext = require('./hlfsecuritycontext');
2020
const HLFUtil = require('./hlfutil');
2121
const HLFTxEventHandler = require('./hlftxeventhandler');
22-
const HLFQueryHandler = require('./hlfqueryhandler');
2322
const Logger = require('composer-common').Logger;
2423
const path = require('path');
2524
const temp = require('temp').track();
@@ -44,6 +43,7 @@ const installDependencies = {
4443

4544
const chaincodePathSection = 'businessnetwork';
4645

46+
let HLFQueryHandler;
4747
/**
4848
* Class representing a connection to a business network running on Hyperledger
4949
* Fabric, using the hfc module.
@@ -67,10 +67,18 @@ class HLFConnection extends Connection {
6767
/**
6868
* create a new Query Handler.
6969
* @param {HLFConnection} connection The connection to be used by the query handler.
70+
* @param {string} queryHandlerImpl The query handler to require
7071
* @return {HLFQueryManager} A new query manager.
7172
*/
72-
static createQueryHandler(connection) {
73-
return new HLFQueryHandler(connection);
73+
static createQueryHandler(connection, queryHandlerImpl) {
74+
const method = 'createQueryHandler';
75+
if (typeof queryHandlerImpl === 'string') {
76+
LOG.info(method, `attemping to load query handler module ${queryHandlerImpl}`);
77+
HLFQueryHandler = require(queryHandlerImpl);
78+
return new HLFQueryHandler(connection);
79+
} else {
80+
return new queryHandlerImpl(connection);
81+
}
7482
}
7583

7684
/**
@@ -128,7 +136,14 @@ class HLFConnection extends Connection {
128136
this.caClient = caClient;
129137
this.initialized = false;
130138
this.commitTimeout = connectOptions['x-commitTimeout'] ? connectOptions['x-commitTimeout'] * 1000 : 300 * 1000;
131-
this.queryHandler = HLFConnection.createQueryHandler(this);
139+
140+
let queryHandlerImpl = './hlfqueryhandler';
141+
if (process.env.COMPOSER_QUERY_HANDLER && process.env.COMPOSER_QUERY_HANDLER.length !== 0) {
142+
queryHandlerImpl = process.env.COMPOSER_QUERY_HANDLER;
143+
} else if (connectOptions.queryHandler && connectOptions.queryHandler.length !== 0) {
144+
queryHandlerImpl = connectOptions.queryHandler;
145+
}
146+
this.queryHandler = HLFConnection.createQueryHandler(this, queryHandlerImpl);
132147
LOG.debug(method, `commit timeout set to ${this.commitTimeout}`);
133148

134149
// We create promisified versions of these APIs.
@@ -1307,6 +1322,83 @@ class HLFConnection extends Connection {
13071322
return txId;
13081323
}
13091324

1325+
/**
1326+
* Send a query
1327+
* @param {Peer} peer The peer to query
1328+
* @param {TransactionID} txId the transaction id to use
1329+
* @param {string} functionName the function name of the query
1330+
* @param {array} args the arguments to ass
1331+
* @returns {Buffer} asynchronous response to query
1332+
*/
1333+
async querySinglePeer(peer, txId, functionName, args) {
1334+
const method = 'querySinglePeer';
1335+
LOG.entry(method, peer.getName(), txId, functionName, args);
1336+
const request = {
1337+
targets: [peer],
1338+
chaincodeId: this.businessNetworkIdentifier,
1339+
txId: txId,
1340+
fcn: functionName,
1341+
args: args
1342+
};
1343+
1344+
const t0 = Date.now();
1345+
let payloads = await this.queryByChaincode(request);
1346+
LOG.perf(method, `Total duration for queryByChaincode to ${functionName}: `, txId, t0);
1347+
LOG.debug(method, `Received ${payloads.length} payloads(s) from querying the composer runtime chaincode`);
1348+
if (!payloads.length) {
1349+
LOG.error(method, 'No payloads were returned from the query request:' + functionName);
1350+
throw new Error('No payloads were returned from the query request:' + functionName);
1351+
}
1352+
const payload = payloads[0];
1353+
1354+
// if it has a code value is 14, means unavailable, so throw that error
1355+
// code 2 looks like it is a chaincode response that was an error.
1356+
if (payload instanceof Error && payload.code && (payload.code === 14 || payload.code === 1 || payload.code === 4)) {
1357+
throw payload;
1358+
}
1359+
1360+
LOG.exit(method, payload);
1361+
return payload;
1362+
1363+
}
1364+
1365+
/**
1366+
* Perform a chaincode query and parse the responses.
1367+
* @param {object} request the proposal for a query
1368+
* @return {array} the responses
1369+
*/
1370+
async queryByChaincode(request) {
1371+
const method = 'queryByChaincode';
1372+
LOG.entry(method, request);
1373+
try {
1374+
const results = await this.channel.sendTransactionProposal(request);
1375+
const responses = results[0];
1376+
if (responses && Array.isArray(responses)) {
1377+
let results = [];
1378+
for (let i = 0; i < responses.length; i++) {
1379+
let response = responses[i];
1380+
if (response instanceof Error) {
1381+
results.push(response);
1382+
}
1383+
else if (response.response && response.response.payload) {
1384+
results.push(response.response.payload);
1385+
}
1386+
else {
1387+
results.push(new Error(response));
1388+
}
1389+
}
1390+
LOG.exit(method);
1391+
return results;
1392+
}
1393+
const err = new Error('Payload results are missing from the chaincode query');
1394+
LOG.error(method, err);
1395+
throw err;
1396+
} catch(err) {
1397+
LOG.error(method, err);
1398+
throw err;
1399+
}
1400+
}
1401+
13101402
}
13111403

13121404
module.exports = HLFConnection;

packages/composer-connector-hlfv1/lib/hlfqueryhandler.js

Lines changed: 2 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class HLFQueryHandler {
7373
if (this.queryPeerIndex !== -1) {
7474
let peer = this.allQueryPeers[this.queryPeerIndex];
7575
try {
76-
payload = await this.querySinglePeer(peer, txId, functionName, args);
76+
payload = await this.connection.querySinglePeer(peer, txId, functionName, args);
7777
success = true;
7878
} catch (error) {
7979
allErrors.push(error);
@@ -93,7 +93,7 @@ class HLFQueryHandler {
9393
}
9494
let peer = this.allQueryPeers[i];
9595
try {
96-
payload = await this.querySinglePeer(peer, txId, functionName, args);
96+
payload = await this.connection.querySinglePeer(peer, txId, functionName, args);
9797
this.queryPeerIndex = i;
9898
success = true;
9999
break;
@@ -119,83 +119,6 @@ class HLFQueryHandler {
119119
return payload;
120120

121121
}
122-
123-
/**
124-
* Send a query
125-
* @param {Peer} peer The peer to query
126-
* @param {TransactionID} txId the transaction id to use
127-
* @param {string} functionName the function name of the query
128-
* @param {array} args the arguments to ass
129-
* @returns {Buffer} asynchronous response to query
130-
*/
131-
async querySinglePeer(peer, txId, functionName, args) {
132-
const method = 'querySinglePeer';
133-
LOG.entry(method, peer.getName(), txId, functionName, args);
134-
const request = {
135-
targets: [peer],
136-
chaincodeId: this.connection.businessNetworkIdentifier,
137-
txId: txId,
138-
fcn: functionName,
139-
args: args
140-
};
141-
142-
const t0 = Date.now();
143-
let payloads = await this.queryByChaincode(request);
144-
LOG.perf(method, `Total duration for queryByChaincode to ${functionName}: `, txId, t0);
145-
LOG.debug(method, `Received ${payloads.length} payloads(s) from querying the composer runtime chaincode`);
146-
if (!payloads.length) {
147-
LOG.error(method, 'No payloads were returned from the query request:' + functionName);
148-
throw new Error('No payloads were returned from the query request:' + functionName);
149-
}
150-
const payload = payloads[0];
151-
152-
// if it has a code value is 14, means unavailable, so throw that error
153-
// code 2 looks like it is a chaincode response that was an error.
154-
if (payload instanceof Error && payload.code && (payload.code === 14 || payload.code === 1 || payload.code === 4)) {
155-
throw payload;
156-
}
157-
158-
LOG.exit(method, payload);
159-
return payload;
160-
161-
}
162-
163-
/**
164-
* Perform a chaincode query and parse the responses.
165-
* @param {object} request the proposal for a query
166-
* @return {array} the responses
167-
*/
168-
async queryByChaincode(request) {
169-
const method = 'queryByChaincode';
170-
LOG.entry(method, request);
171-
try {
172-
const results = await this.connection.channel.sendTransactionProposal(request);
173-
const responses = results[0];
174-
if (responses && Array.isArray(responses)) {
175-
let results = [];
176-
for (let i = 0; i < responses.length; i++) {
177-
let response = responses[i];
178-
if (response instanceof Error) {
179-
results.push(response);
180-
}
181-
else if (response.response && response.response.payload) {
182-
results.push(response.response.payload);
183-
}
184-
else {
185-
results.push(new Error(response));
186-
}
187-
}
188-
LOG.exit(method);
189-
return results;
190-
}
191-
const err = new Error('Payload results are missing from the chaincode query');
192-
LOG.error(method, err);
193-
throw err;
194-
} catch(err) {
195-
LOG.error(method, err);
196-
throw err;
197-
}
198-
}
199122
}
200123

201124
module.exports = HLFQueryHandler;

0 commit comments

Comments
 (0)