github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/sdk/javascript/processor/index.js (about) 1 /** 2 * Copyright 2016 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * ------------------------------------------------------------------------------ 16 */ 17 18 'use strict' 19 20 const { 21 TpRegisterRequest, 22 TpRegisterResponse, 23 TpUnregisterRequest, 24 TpProcessRequest, 25 TpProcessResponse, 26 PingResponse, 27 Message 28 } = require('../protobuf') 29 30 const { 31 InternalError, 32 AuthorizationException, 33 InvalidTransaction, 34 ValidatorConnectionError 35 } = require('./exceptions') 36 37 const Context = require('./context') 38 39 const { Stream } = require('../messaging/stream') 40 41 /** 42 * TransactionProcessor is a generic class for communicating with a 43 * validator and routing transaction processing requests to a 44 * registered handler. It uses ZMQ and channels to handle requests 45 * concurrently. 46 * 47 * @param {string} url - the URL of the validator 48 */ 49 class TransactionProcessor { 50 constructor (url) { 51 this._stream = new Stream(url) 52 this._handlers = [] 53 } 54 55 /** 56 * addHandler adds the given handler to the transaction processor so 57 * it can receive transaction processing requests. All handlers must 58 * be added prior to starting the processor. 59 * 60 * @param {TransactionHandler} handler - a handler to be added 61 */ 62 addHandler (handler) { 63 this._handlers.push(handler) 64 } 65 66 /** 67 * start connects the transaction processor to a validator and 68 * starts listening for requests and routing them to an appropriate 69 * handler. 70 */ 71 start () { 72 this._stream.connect(() => { 73 this._stream.onReceive(message => { 74 if (message.messageType !== Message.MessageType.TP_PROCESS_REQUEST) { 75 if (message.messageType === Message.MessageType.PING_REQUEST) { 76 console.log(`Received Ping`) 77 let pingResponse = PingResponse.create() 78 this._stream.sendBack( 79 Message.MessageType.PING_RESPONSE, 80 message.correlationId, 81 PingResponse.encode(pingResponse).finish() 82 ) 83 return 84 } 85 console.log( 86 `Ignoring ${Message.MessageType.stringValue(message.messageType)}` 87 ) 88 return 89 } 90 91 const request = TpProcessRequest.toObject( 92 TpProcessRequest.decode(message.content), 93 { defaults: false } 94 ) 95 const context = new Context(this._stream, request.contextId) 96 97 if (this._handlers.length > 0) { 98 let txnHeader = request.header 99 100 let handler = this._handlers.find( 101 (candidate) => 102 candidate.transactionFamilyName === txnHeader.familyName && 103 candidate.versions.includes(txnHeader.familyVersion)) 104 105 if (handler) { 106 let applyPromise 107 try { 108 applyPromise = Promise.resolve(handler.apply(request, context)) 109 } catch(err) { 110 applyPromise = Promise.reject(err) 111 } 112 applyPromise 113 .then(() => 114 TpProcessResponse.create({ 115 status: TpProcessResponse.Status.OK 116 }) 117 ) 118 .catch(e => { 119 if (e instanceof InvalidTransaction) { 120 console.log(e) 121 return TpProcessResponse.create({ 122 status: TpProcessResponse.Status.INVALID_TRANSACTION, 123 message: e.message, 124 extendedData: e.extendedData 125 }) 126 } else if (e instanceof InternalError) { 127 console.log('Internal Error Occurred', e) 128 return TpProcessResponse.create({ 129 status: TpProcessResponse.Status.INTERNAL_ERROR, 130 message: e.message, 131 extendedData: e.extendedData 132 }) 133 } else if (e instanceof ValidatorConnectionError) { 134 console.log('Validator disconnected. Ignoring.') 135 } else if (e instanceof AuthorizationException) { 136 console.log(e) 137 return TpProcessResponse.create({ 138 status: TpProcessResponse.Status.INVALID_TRANSACTION, 139 message: e.message, 140 extendedData: e.extendedData 141 }) 142 } else { 143 console.log('Unhandled exception, returning INTERNAL_ERROR', e) 144 return TpProcessResponse.create({ 145 status: TpProcessResponse.Status.INTERNAL_ERROR, 146 message: `Unhandled exception in ${txnHeader.familyName} ${txnHeader.familyVersion}` 147 }) 148 } 149 }) 150 .then((response) => { 151 if (response) { 152 this._stream.sendBack( 153 Message.MessageType.TP_PROCESS_RESPONSE, 154 message.correlationId, 155 TpProcessResponse.encode(response).finish() 156 ) 157 } 158 }) 159 .catch(e => console.log('Unhandled error on sendBack', e)) 160 } 161 } 162 }) 163 164 this._handlers.forEach(handler => { 165 handler.versions.forEach(version => { 166 this._stream.send( 167 Message.MessageType.TP_REGISTER_REQUEST, 168 TpRegisterRequest.encode({ 169 family: handler.transactionFamilyName, 170 version: version, 171 namespaces: handler.namespaces 172 }).finish()) 173 .then(content => TpRegisterResponse.decode(content)) 174 .then(ack => { 175 let { transactionFamilyName: familyName } = handler 176 let status = 177 ack.status === TpRegisterResponse.Status.OK 178 ? 'succeeded' 179 : 'failed' 180 console.log( 181 `Registration of [${familyName} ${version}] ${status}` 182 ) 183 }) 184 .catch(e => { 185 let { transactionFamilyName: familyName } = handler 186 console.log( 187 `Registration of [${familyName} ${version}] Failed!`, 188 e 189 ) 190 }) 191 }) 192 }) 193 }) 194 195 process.on('SIGINT', () => this._handleShutdown()) 196 process.on('SIGTERM', () => this._handleShutdown()) 197 } 198 199 _handleShutdown () { 200 console.log('Unregistering transaction processor') 201 this._stream.send( 202 Message.MessageType.TP_UNREGISTER_REQUEST, 203 TpUnregisterRequest.encode().finish() 204 ) 205 process.exit() 206 } 207 } 208 209 module.exports = { 210 TransactionProcessor 211 }