I'm trying to emit an event when other transaction has been called. But I can't execute my intentions.
I have the following piece of code:
event TransactionAssetEvent {
o BlastAsset eventAsset
o String eventCalledFromTransaction
}
In the logic.js file I have a function that works fine:
async function Transfer(transfer) {
//Some logic with a asset object
TransactionAssetEvent(asset, 'Transfer');
return updateAsset(asset);
}
/**
* Emit a notification that a transaction has occurred
* #param {Object} asset
* #param {String} eventCalledFromTransaction
* #transaction
*/
async function TransactionAssetEvent(asset, eventCalledFromTransaction) {
const factory = getFactory();
let event = factory.newEvent(org.test', 'TransactionAssetEvent');
event.eventAsset = asset;
event.eventCalledFromTransaction = eventCalledFromTransaction;
emit(event);
}
But I have the following error:
Error: t: Transaction processing function TransactionAssetEvent must have 1 function argument of type transaction.
How can emit an event successfully?
I'm implementing a great flow with the events? Or I'm using in a bad way the events?
I look for other post's but I can't implemented the commented flow
let event = factory.newEvent(org.test', 'TransactionAssetEvent');
should be
let event = factory.newEvent('namespace*', 'TransactionAssetEvent');
namespace is basically the namespace of the file where event TransactionAssetEvent is saved
so for example your line will be
let event = factory.newEvent('org.test.eventModelFile', 'TransactionAssetEvent');
Also you missed a ' in factory.newEvent(org.test', 'TransactionAssetEvent');
it should be factory.newEvent('org.test', 'TransactionAssetEvent');
Related
I set up a simple Backendless API Service and am running it through CodeRunner. As a test, I'm simply getting a record from the database and returning it. I've tried every combination of return type definition in the class annotations that I can think of, and I've assured that the correct record exists and is being returned to the service, but I've never successfully had the record returned using the console, or via a SDK invocation. In every case, the body returned to the invocation is null. My current test uses "Object" as the return type for the getSchedule call - are database objects not objects?
Here is the entire service:
'use strict';
const { DateTime } = require("luxon");
const util = require("util");
class Scheduling {
/**
*
* #param {String} day
* #returns {Object}
*/
getSchedule( day ) {
let t = DateTime.fromISO(day).toMillis();
let q = Backendless.DataQueryBuilder.create().setWhereClause(`day = ${t}`);
Backendless.Data.of("schedules").find(q)
.then(rec => {
console.log(util.inspect(rec,3))
if (rec.length === 1) {
return rec[0]
}
else {
return {error: 404, msg: 'not found'}
}
})
}
}
Backendless.ServerCode.addService( Scheduling )
The "inspect" call indicates I am retrieving the correct record. No errors, the return status of the invocation is always 200. Obviously, I'm missing something about API service return types, please point me in the correct direction.
The problem is the response for the find method is returned after the invocation of getSchedule is complete (because the API invocation is asynchronous).
How about declaring the getSchedule with async and then await for the API invocation?
'use strict';
const { DateTime } = require("luxon");
const util = require("util");
class Scheduling {
/**
*
* #param {String} day
* #returns {Object}
*/
async getSchedule( day ) {
let t = DateTime.fromISO(day).toMillis();
let q = Backendless.DataQueryBuilder.create().setWhereClause(`day = ${t}`);
var rec = await Backendless.Data.of("schedules").find(q);
console.log(util.inspect(rec,3))
if (rec.length === 1) {
return rec[0]
}
else {
return {error: 404, msg: 'not found'}
}
}
}
Backendless.ServerCode.addService( Scheduling )
In my electron application I create Diffie-Hellman keys via the following method:
const crypto = require('crypto');
/**
* Generate the keys and the diffie hellman key agreement object.
* #param {Integer} p The prime for Diffie Hellman Key Generation
* #param {Integer} g The generator for Diffie Hellman Key Exchange
*/
async function createSelfKey(p, g, callback) {
let returnVal = null;
if (p && g) {
returnVal = { dh: await crypto.createDiffieHellman(p, g) };
} else {
returnVal = { dh: await crypto.createDiffieHellman(2048) };
}
returnVal.keys = await returnVal.dh.generateKeys();
return callback(returnVal);
};
But the key generation is a slightly computation-heavy process thus it makes my application to freeze. An example of usage is when I try to implement this method generateCreatorKeys from the following function:
function ChatRoomStatus() {
/**
* #var {Object}
*/
const chatrooms = {};
// Some other logic
/**
* This Method fetched the creator of the Chatroom and executes a callback on it.
* #param {String} chatroom The chatroom to fetch the creator
* #param {Function} callback The callback of the chatroom.
*/
this.processCreator = (chatroom, callback) => {
const index = _.findIndex(chatrooms[chatroom].friends, (friend) => friend.creator);
return callback(chatrooms[chatroom].friends[index], index , chatrooms[chatroom] );
};
/**
* Generate keys for the Chatroom Creator:
* #param {String} chatroom The chatroom to fetch the creator
* #param {Function} callback The callback of the chatroom.
*/
this.generateCreatorKeys = (chatroom, callback) => {
return this.processCreator(chatroom, (friend, index, chatroom) => {
return createSelfKey(null, null, (cryptoValues) => {
friend.encryption = cryptoValues;
return callback(friend, index, chatroom);
});
});
};
};
An example that this method is called is:
const { xml, jid } = require('#xmpp/client');
/**
* Handling the message Exchange for group Key agreement
* #param {Function} sendMessageCallback
* #param {ChatRoomStatus} ChatroomWithParticipants
*/
function GroupKeyAgreement(sendMessageCallback, ChatroomWithParticipants) {
const self = this;
/**
* Send the Owner participant Keys into the Chatroom
*/
self.sendSelfKeys = (chatroomJid, chatroomName) => {
ChatroomWithParticipants.generateCreatorKeys(chatroomName, (creator) => {
const message = xml('message', { to: jid(chatroomJid).bare().toString()+"/"+creator.nick });
const extention = xml('x', { xmlns: 'http://pcmagas.tk/gkePlusp#intiator_key' });
extention.append(xml('p', {}, creator.encryption.dh.getPrime().toString('hex')));
extention.append(xml('g', {}, creator.encryption.dh.getGenerator().toString('hex')));
extention.append(xml('pubKey', {}, creator.encryption.keys.toString('hex')));
message.append(extention);
sendMessageCallback(message);
});
};
};
module.exports = GroupKeyAgreement;
Do you know how I can "run" the function createSelfKey in parallel/seperate thread and serve its contents via a callback? Also the code above runs on Electron's main process thus a freeze on it causes the whole application to stall for a while.
I'd take a look at https://electronjs.org/docs/tutorial/multithreading.
Electron has basically everything from the DOM and node.js plus more in it, so you have a few options. In general, they are:
Web workers (renderer process only). If you're doing this in a renderer process, you can just use plain DOM web workers. Those are run in a separate process or thread (not sure which, that's a chromium implementation detail, but it definitely won't block your UI).
It looks like node.js worker_threads (renderer process only?) are also available now in Electron. That might work as well, never used these personally.
You can always create another renderer process and use that as your separate "thread" and communicate with it via IPC. When the work is done, you just close that. You do this by creating a new, hidden BrowserWindow.
Use node.js' cluster/child_process module to spin up a new node process, and use it's built-in IPC (not Electron's) to communicate with it.
Because you're running this code in the main process and assuming you can't move it out, your only option (to my knowledge) is #3. If you're okay with adding a library, electron-remote (https://github.com/electron-userland/electron-remote#the-renderer-taskpool) has some cool functionality that let's you spin up a renderer process (or several) in the background, get the results as a promise, and then closes them for you.
The best solution I tried to your problem is the following code based upon answer:
const crypto = require('crypto');
const spawn = require('threads').spawn;
/**
* Generate the keys and the diffie hellman key agreement object.
* #param {Integer} p The prime for Diffie Hellman Key Generation
* #param {Integer} g The generator for Diffie Hellman Key Exchange
* #param {Function} callback The callback in order to provide the keys and the diffie-hellman Object.
*/
const createSelfKey = (p, g, callback) => {
const thread = spawn(function(input, done) {
const cryptot = require('crypto');
console.log(input);
const pVal = input.p;
const gVal = input.g;
let dh = null;
if (pVal && gVal) {
dh = cryptot.createDiffieHellman(pVal, gVal);
} else {
dh = cryptot.createDiffieHellman(2048);
}
const pubKey = dh.generateKeys();
const signaturePubKey = dh.generateKeys();
done({ prime: dh.getPrime().toString('hex'), generator: dh.getGenerator().toString('hex'), pubKey, signaturePubKey});
});
return thread.send({p,g}).on('message', (response) => {
callback( crypto.createDiffieHellman(response.prime, response.generator), response.pubKey, response.signaturePubKey);
thread.kill();
}).on('error', (err)=>{
console.error(err);
}).on('exit', function() {
console.log('Worker has been terminated.');
});
};
As you can see using the threads library from npm will provide you what you need. The only negative on this approach is that you cannot pass the in-thread generated objects outside the thread's scope. Also the code that is inside the function executing the thread is an some sort of an isolated one thus you may need to re-include any library you need as you can see above.
I want to call/trigger a transaction inside from another transaction. how that will be possible.
async function updateOrder(uo) { // eslint-disable-line no-unused-vars
// Get the asset registry for the asset.
assetRegistry = await getAssetRegistry('org.example.basic.OrderList');
for(var i=0;i< uo.asset.orderDtls.length;i++)
{
if(uo.asset.orderDtls[i].orderID==uo.orderID){
uo.asset.orderDtls[i].orderStatus="Accepted";
}
}
await assetRegistry.update(uo.asset);
Please provide any sample code/example to trigger another transaction whenever this transaction happen.
Please view the github issue here:
https://github.com/hyperledger/composer/issues/4375
It should answer your question. A quote from the issue:
/**
* TransactionOne
* #param {org.example.TransactionOne} The transaction one object
* #transaction
*/
async function transactionOne(tx) {
const factory = getFactory();
tx.subTransactions.forEach(async (subTransactionData, idx) => {
const subTx = factory.newResource(namespace, "TransactionTwo", tx.transactionId + ":" + idx);
subTx.subTransactionData= subTransactiondata;
await transactionTwo(subTx);
});
}
I have just moved from V0.13.2 to V0.14.2 and am now getting following error in event processing. The error appears to be in the composer-client code, not mine. Any ideas on resolving? Events are still being posted and processed by my app, so my code still appears to work, but the presence of these error messages is troubling and their volume is overwhelming my console window.
error: [EventHub.js]: on.data - Error unmarshalling transaction= TypeError: Cannot read property 'getSerializer' of null
at events.forEach (<path>Z2B_Master/Chapter12/node_modules/composer-client/lib/businessnetworkconnection.js:483:73)
at Array.forEach (native)
at HLFConnection.connection.on (<path>Z2B_Master/Chapter12/node_modules/composer-client/lib/businessnetworkconnection.js:482:29)
at emitOne (events.js:96:13)
at HLFConnection.emit (events.js:188:7)
at ChainCodeCBE.ccEvent.eventHubs.(anonymous function).registerChaincodeEvent [as onEvent] (<path>Z2B_Master/Chapter12/node_modules/composer-connector-hlfv1/lib/hlfconnection.js:231:22)
at <path>Z2B_Master/Chapter12/node_modules/fabric-client/lib/EventHub.js:810:12
at Set.forEach (native)
at EventHub._processChainCodeOnEvents (<path>Z2B_Master/Chapter12/node_modules/fabric-client/lib/EventHub.js:808:14)
at ClientDuplexStream.<anonymous> (<path>Z2B_Master/Chapter12/node_modules/fabric-client/lib/EventHub.js:311:10)
This error is not present using identical code in V0.13.
All events are emitted via a single function in the sample.js file. A transaction calls the function as in the following example:
/**
* create an order to purchase
* #param {org.acme.Z2BTestNetwork.CreateOrder} purchase - the order to be processed
* #transaction
*/
function CreateOrder(purchase) {
purchase.order.buyer = purchase.buyer;
purchase.order.amount = purchase.amount;
purchase.order.financeCo = purchase.financeCo;
purchase.order.created = new Date().toISOString();
purchase.order.status = JSON.stringify(orderStatus.Created);
return getAssetRegistry('org.acme.Z2BTestNetwork.Order')
.then(function (assetRegistry) {
return assetRegistry.update(purchase.order)
.then (function (_res)
{
z2bEmit('Created', purchase.order);
return (_res);
}).catch(function(error){return(error);});
});
}
Each transaction calls the z2bEmit function with a unique _event string.
function z2bEmit(_event, _order)
{
var method = 'z2bEmit';
var factory = getFactory();
var z2bEvent = factory.newEvent(ns, _event);
z2bEvent.orderID = _order.$identifier;
z2bEvent.buyerID = _order.buyer.$identifier;
emit(z2bEvent);
return
}
_order is a defined asset in the cto file, _event is a defined event in the cto file.
The client side code has a single routine, executed once, to set up monitoring:
/**
* Register for all of the available Z2BEvents
* #param {express.req} req - the inbound request object from the client
* #param {express.res} res - the outbound response object for communicating back to client
* #param {express.next} next - an express service to enable post processing prior to responding to the client
*/
exports.init_z2bEvents = function (req, res, next)
{
var method = 'init_z2bEvents';
if (bRegistered) {res.send('Already Registered');}
else{
bRegistered = true;
let _conn = svc.createAlertSocket();
let businessNetworkConnection;
businessNetworkConnection = new BusinessNetworkConnection();
// following line added to deal with eventListener error message that more eventListeners needed to be added
businessNetworkConnection.setMaxListeners(50);
return businessNetworkConnection.connect(config.composer.connectionProfile, config.composer.network, config.composer.adminID, config.composer.adminPW)
.then(() => {
businessNetworkConnection.on('event', (event) => {_monitor(svc.al_connection, svc.f_connection, event); });
res.send('event registration complete');
}).catch((error) => {
console.log(method+' business network connection failed'+error.message);
res.send(method+' business network connection failed'+error.message);
});
}
}
The connectionProfile is 'hlfv1'
and a single monitor routine, which figures out what kind of event has been posted and then uses a web socket to send that info to a browser so that an alert icon can be posted or updated. A shortened version of that function follows. _conn _f_conn continue to work correctly. The _event information is being passed in and continues to parse correctly. The eventhub.js messages appear on every alert, irrespective of how long the program runs.
/**
* _monitor
* #param {web.socket} _conn - web socket connection for general alerts
* #param {web.socket} _f_conn - web socket for finance alerts
* #param {org.acme.z2bNetwork.Event} _event - the event just emitted
*
*/
function _monitor(_conn, _f_conn, _event)
{
var method = '_monitor';
console.log(method+ ' _event received: '+_event.$type+' for Order: '+_event.orderID);
var event = {};
event.type = _event.$type;
event.orderID = _event.orderID;
event.ID = _event.buyerID;
_conn.sendUTF(JSON.stringify(event));
switch (_event.$type)
{
case 'Created':
break;
case 'Bought':
case 'PaymentRequested':
event.ID = _event.sellerID;
_conn.sendUTF(JSON.stringify(event));
event.ID = _event.financeCoID;
_f_conn.sendUTF(JSON.stringify(event));
break;
case 'Ordered':
case 'Cancelled':
case 'Backordered':
event.ID = _event.sellerID;
_conn.sendUTF(JSON.stringify(event));
event.ID = _event.providerID;
_conn.sendUTF(JSON.stringify(event));
break;
default:
break;
}
}
While unable to determine the root cause of this problem, it has gone away with the release of (and upgrade to) hyperledger-composer V0.15.2.
I'm running a relatively simple AWS Function to add a subscription to Stripe.
It runs fine unless I hit it shortly after I just hit it. Just trying to run it in PostMan one after the other fails and returns:
{"errorMessage": "Process exited before completing request"}
The requests are delivered via API Gateway.
Function is configured with 30s timeout and is take ~1300ms to run on the base 128M RAM (issue reproducible # 256M).
I thought this was exactly what Lambda was designed to avoid... I'm second guessing my decision to use Lambda for a (synchronous) mission critical component.
EDIT: As requested, here's the function code:
var stripe = require('stripe');
exports.handler = function (event, context, callback) {
var self = this;
stripe = stripe(getKey(event.stage, 'STRIPE_SECRET_KEY'));
self.createSubscription = createSubscription;
self.validPayload = validPayload;
console.log('event: ', event);
if (self.validPayload(event, context)) {
self.createSubscription(event, stripe, callback, context);
}
/**
* checks that the necessary payload has been received
* if YES: returns true and allows process to continue
* if NO: throws context.fail with useful error message(s)
* operating under custom error code naming convention of
* http code + 3 digit ULM error code
* #param event - from Lambda
* #param context - from Lambda
* #returns {boolean} - whether the payload contains the required data
*/
function validPayload (event, context) {
var errorResponse = {
status: 400,
errors: []
};
if (!event.billing_email) {
errorResponse.errors.push({
code: 400001,
message: "No billing email provided."
})
}
if (!event.plan) {
errorResponse.errors.push({
code: 400002,
message: "No plan was selected."
})
}
if (!event.token) {
errorResponse.errors.push({
code: 400003,
message: "A valid credit card was not provided."
})
}
if (!!errorResponse.errors.length) {
context.fail(JSON.stringify(errorResponse));
return false;
} else {
return true;
}
}
/**
* Creates a new customer & subscription using stripe package method
* if success, executes callback with response data
* if fail, throws context.fail with useful error message(s)
* #param event - from Lambda
* #param stripe - probably not necessary...
* #param callback - from Lambda
* #param context - probably not necessary...
*/
function createSubscription (event, stripe, callback, context) {
stripe.customers.create({
source: event.token,
plan: event.plan,
email: event.billing_email
}, function (err, customer) {
if (err) {
var errorResponse = {
status: 400,
errors: []
};
errorResponse.errors.push({
code: 400004,
message: err.message
});
console.error('Customer/Plan Creation Failed');
callback(JSON.stringify(errorResponse));
} else {
callback(null, {
status: 200,
customer: customer
});
}
});
}
function getKey (stage, keyId) {
var keys = {
STRIPE_SECRET_KEY: {
staging: 'sk_test_123456',
prod: 'sk_live_123456'
}
};
if (stage === 'prod') {
return keys[keyId][stage];
} else {
return keys[keyId]['staging'];
}
}
};
EDIT 2: Dug into CloudWatch and found this error log: TypeError: stripe is not a function at exports.handler (/var/task/exports.js:5:14)
#rowanu is correct, your problem is on this line stripe = stripe(getKey(event.stage, 'STRIPE_SECRET_KEY'));. Since the Lambda stays hot to handle subsequent requests any variables declared outside of the handler function will be seen by each new request that comes in. This should be a simple fix, don't redefine the stripe variable. Something like this would do the trick:
var stripe = require('stripe');
var stripeInstance; // undefined on startup
exports.handler = function (event, context, callback) {
// now define stripeInstance if its not already defined
if(!stripeInstance) {
stripeInstance = stripe(getKey(event.stage, 'STRIPE_SECRET_KEY'));
}
// now all functions will be able to use the same instance of stripe.
// This assumes the event.stage is always the same, if you need a new instance for every request then remove the if statement
// rename all references of stripe to stripeInstance
...
"Process exited before completing request" indicates that your function exited without calling the callback. It is not related to timeouts or throttling.
Usually this indicates that an exception is thrown from a code path that doesn't have adequate error handling.
You will simply need to handle or fix "stripe is not a function at exports.handler (/var/task/exports.js:5:14)" and call the appropriate callback.