Invoke different contract in a single Chaincode - hyperledger-fabric

I am using hyperledger-fabric 1.4 for developing a simple chaincode that saves the project information.
I am working on a existing code repository that contains chain code function calls using, facing many difficulties already in running the network. I managed to get the chaincode installed on 2 peers.
Now i am on invoking the chain code part. I know that in fabric-client two types there are bootstrap identities and then enrollment strategies for users and admins.
What I am trying to achieve is to write separate contract files say Project and Folder, install these contract files as single chaincode and then invoke these contract functions using client.
Originally the repository contain only one contract that was built using shim:
const util = require('util');
var Chaincode = class {
async Init(stub) {
return shim.success();
}
async Invoke(stub) {
let ret = stub.getFunctionAndParameters();
console.info(ret);
let method = this[ret.fcn];
if (!method) {
return shim.success();
}
try {
let payload = await method(stub, ret.params, this);
return shim.success(payload);
} catch (err) {
return shim.error(err);
}
}
async save(stub, args, thisClass) {
if (args.length != 1) {
return Buffer.from(JSON.stringify({result: 400, message: "Invalid arguments"}));
}
let transactionHash = stub.getTxID();
let timeStamp = stub
.getTxTimestamp()
.seconds
.low;
try {
let order = JSON.parse(args[0]);
order.updateLogs = [
{
transactionHash: transactionHash,
createdAt: timeStamp,
completedMilestone: order.completedMilestone
}
]
let orderAsByte = await stub.getState(order.orderId);
if (orderAsByte && orderAsByte.length > 0) {
return Buffer.from(
JSON.stringify({result: 409, message: "order already exist"})
);
}
await stub.putState(order.orderId, Buffer.from(JSON.stringify(order)));
return Buffer.from(
JSON.stringify({result: 200, message: 'successfully Save', transactionHash})
);
} catch (err) {
return Buffer.from(
JSON.stringify({result: 400, message: err.message, transactionHash})
);
}
}
//Change modified of PO
async update(stub, args, thisClass) {
// args[0] = order id, args[1] = completedMilestone
if (args.length != 2) { //
return Buffer.from(JSON.stringify({result: 400, message: "Invalid arguments"}));
}
let timeStamp = stub
.getTxTimestamp()
.seconds
.low;
let orderAsByte = await stub.getState(args[0]);
if (!orderAsByte || orderAsByte.length === 0) {
return Buffer.from(
JSON.stringify({result: 404, message: "order does not exist"})
);
}
let transactionHash = stub.getTxID();
let order = JSON.parse(orderAsByte);
order.completedMilestone = args[1];
order
.updateLogs
.push(
{completedMilestone: order.completedMilestone, transactionHash: transactionHash, createdAt: timeStamp}
)
try {
await stub.putState(args[0], Buffer.from(JSON.stringify(order)));
return Buffer.from(
JSON.stringify({result: 200, message: 'successfully update', transactionHash})
);
} catch (err) {
return Buffer.from(JSON.stringify({result: 400, message: err.message}));
}
}
async queryOrder(stub, args, thisClass) {
if (args.length < 1) {
return Buffer.from(JSON.stringify({result: 400, message: "Invalid arguments"}));
}
let queryString = args[0];
let method = thisClass['getQueryResultForQueryString'];
let queryResults = await method(stub, queryString, thisClass);
return queryResults;
}
async getQueryResultForQueryString(stub, queryString, thisClass) {
let resultsIterator = await stub.getQueryResult(queryString);
let method = thisClass['getAllResults'];
let results = await method(resultsIterator, false);
return Buffer.from(JSON.stringify(results));
}
async getAllResults(iterator) {
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {};
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
jsonRes.Record = res
.value
.value
.toString('utf8');
}
allResults.push(jsonRes);
}
if (res.done) {
await iterator.close();
console.info(allResults);
return allResults;
}
}
}
async get(stub, args, thisClass) {
if (args.length != 1) { //
return Buffer.from(JSON.stringify({result: 400, message: "Invalid arguments"}));
}
try {
let orderAsByte = await stub.getState(args[0]);
let order = JSON.parse(orderAsByte);
console.info('GET <--> ', order);
return Buffer.from(JSON.stringify({result: 200, order: JSON.stringify(order)}));
} catch (err) {
return Buffer.from(JSON.stringify({result: 404, message: 'Order Not Found'}));
}
}
};
shim.start(new Chaincode());
and it was working flawlessly with following snippet.
async function loadAdmin() {
const adminKeystorePath = path.join(
process.cwd(),
"../",
"network",
"crypto-config",
"peerOrganizations",
"blockchain.kwiktrust.com",
"users",
"Admin#blockchain.kwiktrust.com",
"msp",
"keystore",
"509c6e0476760a3eb9a6b37b7788f2178bb708e651e7f3f89a05d10eefc48522_sk");
const keystore = fs.readFileSync(adminKeystorePath);
const adminCertPath = path.join(
process.cwd(),
"../",
"network",
"crypto-config",
"peerOrganizations",
"blockchain.kwiktrust.com",
"users",
"Admin#blockchain.kwiktrust.com",
"msp",
"signcerts",
"Admin#blockchain.kwiktrust.com-cert.pem"
);
const signCert = fs.readFileSync(adminCertPath)
console.log('fabricHelper.js.loadAdmin().adminKeystorePath => ',adminKeystorePath);
console.log('fabricHelper.js.loadAdmin().adminCertPath => ', adminCertPath);
const state_store = await Fabric_Client.newDefaultKeyValueStore(
{path: store_path}
)
fabric_client.setStateStore(state_store)
const crypto_suite = Fabric_Client.newCryptoSuite()
const crypto_store = Fabric_Client.newCryptoKeyStore({path: store_path})
crypto_suite.setCryptoKeyStore(crypto_store)
fabric_client.setCryptoSuite(crypto_suite)
let admin = await fabric_client.getUserContext("admin", true)
if (!admin) {
admin = await fabric_client.createUser({
username: "admin",
mspid: process.env.MSP,
cryptoContent: {
privateKeyPEM: keystore.toString(),
signedCertPEM: signCert.toString()
}
})
console.log('fabricHelper.js.loadAdmin.createUser =>', admin.getIdentity().toString())
fabric_client.setUserContext(admin, true)
}
else{
console.log('fabricHelper.js.loadAdmin.alreadyCreated =>', admin.getIdentity().toString())
}
}
Above loads the user context in fabric client SDK and then the saveOrder to execute contract and submit transaction
function saveOrder(orderObj) {
return new Promise(async (resolve, reject) => {
await loadAdmin()
const tx_id = fabric_client.newTransactionID()
let request = {
chaincodeId: process.env.CHAIN_CODE_ID,
fcn: "save",
args: [JSON.stringify(orderObj)],
chainId: process.env.CHANNEL,
txId: tx_id
}
const results = await channel.sendTransactionProposal(request)
const [proposalResponses,proposal] = results
if (proposalResponses && proposalResponses[0].response && proposalResponses[0].response.status === 200) {
const payload = JSON.parse(proposalResponses[0].response.payload.toString())
console.log("channel.sendTransactionProposal:proposalResponses[0].response.status =>", proposalResponses[0].response.status)
console.log("channel.sendTransactionProposal:proposalResponses[0].response.payload =>", payload.result)
if (payload.result == 200) {
request = {
proposalResponses,
proposal
}
const sendRequest = await channel.sendTransaction(request)
console.log('sendRequest.Status =>', sendRequest);
if (sendRequest && sendRequest.status === "SUCCESS") {
resolve(true)
} else {
reject(false)
}
} else {
console.log("Unable to get payload success in porposal response")
reject(false)
}
} else {
console.log("Unable to get payload success in porposal response")
reject(false)
}
})
}
Now I have changed shim to fabric-contract-api:-1.4.0 and exporting two contracts Project and Folder.
As i stated I want more then one contract files, but I have no idea how to execute the transaction the same way that I did for one contract, as channel.getContract is not any function. I tried another way that uses FileSystemWallet in fabric-sample 1.4 fabcar which required enrollAdmin and registerUser options but there i get authentication failure when I even try to enroll admin and probably because of my lack of knowledge on how to setup connections.json.
// Create a new file system based wallet for managing identities.
const walletPath = path.join(process.cwd(), 'http','utils','hfc-key-store');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
// Check to see if we've already enrolled the user.
const userExists = await wallet.exists('user1');
if (!userExists) {
console.log('An identity for the user "admin" does not exist in the wallet');
console.log('Run the registerUser.js application before retrying');
return;
}
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: 'user1', discovery: { enabled: false } });
// Get the network (channel) our contract is deployed to.
const network = await gateway.getNetwork('mychannel');
// Get the contract from the network.
const contract = network.getContract('Project');
This way i get to submit transaction on contract but when i run enrollAdmin.js before running registerUser.js script it gives me unable to enroll Authentication Failure.
Its been only four days since i started working on hyper-ledger so any help is appriciated..

Related

TypeError: Cannot read properties of undefined (reading 'send')

I am getting the following error using discord.js V14 :
TypeError: Cannot read properties of undefined (reading 'send')
Thank you to anyone who can help me.
const { Client, Message, MessageEmbed } = require("discord.js");
const {SlashCommandBuilder} = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('test')
.setDescription('this is a test thing'),
/**
* #parom {Client} client
* #parom {Message} message
* #parom {String[]} args
*/
async execute(client, message, args, interaction) {
const questions = [
"test",
"test1?"
];
let collectCounter = 0;
let endCounter = 0;
const filter = (m) => m.author.id === message.author.id;
const author = message.author;
const appStart = await author.send(questions[collectCounter++]);
const channel = appStart.channel;
const collector = channel.createMessageCollector(filter);
message.delete({timeout: 100})
collector.on("collect", () => {
if (collectCounter < questions.length) {
channel.send(questions[collectCounter++]);
} else {
channel.send("submited!");
collector.stop("fulfilled");
}
});
const appsChannel = client.channels.cache.get("976110575547482152");
collector.on("end", (collected, reason) =>{
if (reason === "fulfilled") {
let index = 1;
const mappedResponses = collected
.map((msg) => {
return `${index++}) ${questions[endCounter++]}\n-> ${msg.content}`;
})
.join("\n\n");
appsChannel.send(
new MessageEmbed()
.setAuthor(message.author.tag, message.author.displayAvatarURL({ dynamic: true}))
.setTitle("!New Report!")
.setDescription(mappedResponses)
.setColor(`RANDOM`)
.setTimestamp()
);
appsChannel.send(`<#1057374161846145076>`);
}
});
},
};
Note I was using this before and once I updated to V14 I started getting this error.
it should message the user the set questions then post the answers in a channel.
EDIT: I am getting the error on this line
const appStart = await author.send(questions[collectCounter++]);
My interactions.js file
module.exports = {
name: "interactionCreate",
async execute(interaction, client) {
if (interaction.isChatInputCommand()) {
const {commands} = client;
const {commandName} = interaction;
const command = commands.get(commandName);
if (!command) return;
try {
await command.execute(interaction, client);
} catch (error) {
console.error(error);
await interaction.reply({
content: `Something went wrong while executing this command...`,
ephemeral: true,
});
}
} else if (interaction.isButton()) {
const {buttons} = client;
const {customId} = interaction;
const button = buttons.get(customId);
if (!button) return new Error('This Button Does not exist');
try{
await button.execute(interaction, client);
} catch (err) {
console.error(err);
}
}
},
};
You're calling the execute method of your /test command file with (interaction, client) but the method expects (client, message, args, interaction).
A possible solution would be to change the /test command file to
// Optimized imports
const { Client, MessageEmbed, BaseInteraction,
SlashCommandBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName('test')
.setDescription('this is a test thing'),
// Fixed typo in #param
/**
* #param {Client} client
* #param {BaseInteraction} interaction
*/
async execute(interaction, client) {
const questions = [
"test",
"test1?"
];
let collectCounter = 0;
let endCounter = 0;
// Get "Author" from interaction
const author = interaction.user;
const filter = (m) => m.author.id === author.id;
const appStart = await author.send(questions[collectCounter++]);
const channel = appStart.channel;
const collector = channel.createMessageCollector(filter);
// Removed message.delete() because interactions aren't messages and cant be deleted.
collector.on("collect", () => {
if (collectCounter < questions.length) {
channel.send(questions[collectCounter++]);
} else {
channel.send("submited!");
collector.stop("fulfilled");
}
});
const appsChannel = client.channels.cache.get("976110575547482152");
collector.on("end", (collected, reason) => {
if (reason === "fulfilled") {
let index = 1;
const mappedResponses = collected
.map((msg) => {
return `${index++}) ${questions[endCounter++]}\n-> ${msg.content}`;
})
.join("\n\n");
appsChannel.send(
new MessageEmbed()
.setAuthor(message.author.tag, message.author.displayAvatarURL({ dynamic: true }))
.setTitle("!New Report!")
.setDescription(mappedResponses)
.setColor(`RANDOM`)
.setTimestamp()
);
appsChannel.send(`<#1057374161846145076>`);
}
});
},
};

How to properly make a promise.all function with a .map?

I attempted to ask a simplified version of this here but I realized that it probably doesn't contain enough information. So unfortunately I'm just going to post the whole thing and hope that it doesn't offend anyone.
Basically I have 4 functions, with their stated purposes below:
1.InitializeDrive() takes a user email and uses Google's JWT user impersonation method to return the appropriate authorization for that user.
2.listfiles() calls on InitializeDrive() for authorization and retrieves a list of the documents associated with the associated user auth.
3.singleUserData() expects a list of the files such as that from listfiles() and refines them.
4.all_user_data() is intended to be the Promise.all async function that combines all of the aforementioned functions, and maps to an array of users getListUsers(), creating a master array containing all of the refined file data for each user.
Basically my poorly formed and ignorant question is 'how can make the all_user_data() in such a way that it will return the aforementioned master array?'. I am relatively new to async programming, and have a persistent problem getting confused with nested functions.
// loads credentials from .env file
require('dotenv').config();
const util = require('util');
const { google } = require('googleapis');
const { logger } = require('handlebars');
const { getListUsers } = require('./get_users');
const target_users = getListUsers();
function initializeDrive(version, user) {
return new Promise((resolve, reject) => {
const client_email = process.env.GOOGLE_CLIENT_EMAIL;
console.log(client_email);
// add some necessary escaping so to avoid errors when parsing the private key.
const private_key = process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n');
// impersonate an account with rights to create team drives
const emailToImpersonate = user;
const jwtClient = new google.auth.JWT(
client_email,
null,
private_key,
['https://www.googleapis.com/auth/drive'],
emailToImpersonate,
);
return google.drive({
version: version,
auth: jwtClient,
});
});
}
const listfiles = async (pagetokenObj, user) => {
let pageToken = '';
let version = 'v3';
if (pagetokenObj !== undefined) {
pageToken = pagetokenObj.pageToken;
}
const drive = await initializeDrive(version, user);
//const drive = initializeDrive(version,user);
return new Promise((resolve, reject) => {
drive.files.list(
{
pageSize: 100,
fields:
'nextPageToken, files(id, name, owners(emailAddress),
sharingUser(emailAddress), permissions)',
...(pageToken ? { pageToken } : {}),
},
function (err, { data: { nextPageToken = '', files = [] } = {} }) {
if (err) {
return reject(err);
}
if (!nextPageToken) {
return resolve(files);
}
// if page token is present we'll recursively call ourselves until
// we have a complete file list.
return listfiles({ pageToken: nextPageToken }).then((otherfiles) => {
resolve(files.concat(otherfiles));
});
},
);
});
};
//Function returns formatted
const singleUserData = async (files) => {
return new Promise((resolve, reject) => {
const single_user_json = await listfiles();
const res = single_user_json
.filter((doc) => Boolean(doc.permissions))
.map((doc) => {
return {
id: doc.id,
sharedWith: doc.permissions
.filter((permission) => permission.type === 'user')
.map((permission) => {
return {
emailAddress: permission.emailAddress,
role: permission.role || null,
};
}), // convert the perm object into a string (email address)
};
});
// this is how you get nicer console.logs instead of just [Object] and [Array] BS
// https://stackoverflow.com/a/10729284/9200245
console.log(util.inspect(res, { showHidden: false, depth: null, colors: true }));
if (err) {
return reject(err);
}
if (!nextPageToken) {
return resolve(files);
};
})
};
const all_user_data = async() => {
const users = await getListUsers();
const pagetokenObj = "{ pageToken = '' } = {}";
Promise.all(
users.map(async (pagetokenObj,user) => {
const files = await listfiles(pagetokenObj, user);
console.log(files);
const singleUserData = await singleUserData(files)
console.log(singleUserData);
}),
);
console.log(users)
}
//returnJSON();
//getListUsers();
//singleUserData();
all_user_data();
I finally figured it out. Basically needed to await a lot more and properly declare async.
// loads credentials from .env file
require('dotenv').config();
const util = require('util');
const { google } = require('googleapis');
const { logger } = require('handlebars');
const { getListUsers } = require('./get_users');
const target_users = getListUsers();
async function initializeDrive(user) {
// return new Promise((resolve, reject) => {
const client_email = process.env.GOOGLE_CLIENT_EMAIL;
console.log(user + ': ' + client_email);
// add some necessary escaping so to avoid errors when parsing the private key.
const private_key = process.env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n');
// impersonate an account with rights to create team drives
const emailToImpersonate = await user;
const jwtClient = new google.auth.JWT(
client_email,
null,
private_key,
['https://www.googleapis.com/auth/drive'],
emailToImpersonate,
);
return google.drive({
version: "v3",
auth: jwtClient,
});
//});
}
//
async function listfiles(pagetokenObj, user) {
let pageToken = '';
if (pagetokenObj !== undefined) {
pageToken = pagetokenObj.pageToken;
}
const drive = await initializeDrive(user);
//console.log(drive)
return new Promise((resolve, reject) => {
drive.files.list(
{
pageSize: 100,
fields:
'nextPageToken, files(parents, id, name, properties, owners(emailAddress), sharingUser(emailAddress), permissions)',
...(pageToken ? { pageToken } : {}),
},
function (err, { data: { nextPageToken = '', files = [] } = {} }) {
if (err) {
return reject(err);
}
if (!nextPageToken) {
return resolve(files);
}
// if page token is present we'll recursively call ourselves until
// we have a complete file list.
return listfiles({ pageToken: nextPageToken }).then((otherfiles) => {
resolve(files.concat(otherfiles));
});
},
);
});
};
async function singleUserData(user) {
const pagetokenObj = "{ pageToken = '' } = {}"
const single_user_json = await listfiles(pagetokenObj, user);
// return new Promise ((resolve, reject) => {
console.log(user+ ":" + JSON.stringify(single_user_json));
const res = await single_user_json
.filter((doc) => Boolean(doc.permissions))
.map((doc) => {
return {
id: doc.id,
sharedWith: doc.permissions
.filter((permission) => permission.type === 'user')
.map((permission) => {
return {
emailAddress: permission.emailAddress,
role: permission.role || null,
};
}) // convert the perm object into a string (email address)
};
});
return JSON.stringify(res);
//})
}
async function getAllUserData() {
try {
const users = await getListUsers();
// const userString = JSON.parse(users);
console.log("test22222222222222: " + users)
const usersData = await Promise.all(
users.map((user) => {
return singleUserData(user);
})
);
console.log("[" + usersData + "]");
return usersData;
} catch (error) {
console.log(error);
}
}
getAllUserData();
You're almost there.
Remove listfiles call in all_user_data
Pass user to singleUserData
Remove pagetokenObj in all_user_data
Remove async and await inside users.map and return promise directly
Await Promise.all, assign it to a variable and return that variable
Remove unnecessary Promise wrapping in singleUserData
Change function signature of singleUserData to take in a user
Pass user to listfiles in singleUserData
Return res instead of files in singleUserData
Here are the changes I made to all_user_data and singleUserData:
// Function returns formatted
async function singleUserData(user) {
const single_user_json = await listfiles(user);
const res = single_user_json
.filter((doc) => Boolean(doc.permissions))
.map((doc) => {
return {
id: doc.id,
sharedWith: doc.permissions
.filter((permission) => permission.type === "user")
.map((permission) => {
return {
emailAddress: permission.emailAddress,
role: permission.role || null,
};
}), // convert the perm object into a string (email address)
};
});
return res;
};
async function getAllUserData() {
const users = await getListUsers();
const usersData = await Promise.all(
users.map((user) => {
return singleUserData(user);
})
);
return usersData;
};
const usersData = await getAllUserData();

Payment Options View Controller (for Stripe) Not Showing Up

I am fairly new to this. I have used cloud functions and firebase to integrate stripe into my iOS project. Here is my code for the payment options (in node.js).
exports.addPaymentMethodDetails = functions.firestore
.document('/stripe_customers/{userId}/payment_methods/{pushId}')
.onCreate(async (snap, context) => {
try {
const paymentMethodId = snap.data().id;
const paymentMethod = await stripe.paymentMethods.retrieve(
paymentMethodId
);
await snap.ref.set(paymentMethod);
// Create a new SetupIntent so the customer can add a new method next time.
const intent = await stripe.setupIntents.create({
customer: paymentMethod.customer,
});
await snap.ref.parent.parent.set(
{
setup_secret: intent.client_secret,
},
{ merge: true }
);
return;
} catch (error) {
await snap.ref.set({ error: userFacingMessage(error) }, { merge: true });
await reportError(error, { user: context.params.userId });
}
})
Here is my code in Xcode:
``let customerContext = STPCustomerContext(keyProvider: StripeApi)
var paymentContext: STPPaymentContext!
init() {
self.paymentContext = STPPaymentContext(customerContext: customerContext)
super.init(nibName: nil, bundle: nil)
self.paymentContext.delegate = self
self.paymentContext.hostViewController = self
self.paymentContext.paymentAmount = 5000 // This is in cents, i.e. $50 USD
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
#IBAction func paymentMethodClicked(_ sender: Any) {
paymentContext.pushPaymentOptionsViewController()
}
func setupStripeConfig() {
let config = STPPaymentConfiguration.shared()
config.additionalPaymentOptions = .default
config.requiredBillingAddressFields = .none
let customerContext = STPCustomerContext(keyProvider: StripeApi)
paymentContext = STPPaymentContext(customerContext: customerContext, configuration: config, theme: .default())
paymentContext.delegate = self
paymentContext.hostViewController = self
When I run the simulator of this and click the button to pull up payment options, nothing happens and my console (in Xcode) reads "INTERNAL". Can someone please show me how to bring up the Payment Options View Controller, or if there is something I need to or add/fix in order to do so? Also here is my node.js code for getting an ephemeral key:
exports.createEphemeralKey = functions.https.onCall(async (data, context) => {
const customerID = data.customer_id;
const stripeVersion = data.stripe_version;
const uid = context.auth.uid;
if (uid === null) {
console.log('Illegal access attempt due to unauthenticated user');
throw new functions.https.HtppsError('permission-denied', 'Illegal access attempt')
}
let key = await stripe.ephemeralKeys.create(
{customer: '{{CUSTOMER_ID}}'},
{stripe_version: '{{API_VERSION}}'}
);
return stripe.ephemeralKeys.create(
{customer: customerID},
{stripe_version: stripeVersion}).then((key) => {
return key
}).catch((err) => {
console.log(err)
throw new functions.https.HttpsError9('internal', 'Unable to create ephemeral key.')
});
});

use async - await with socket.io nodejs

I'm developing a web application using nodejs socket.io and angular 9. In my backend code I have written sockets in socket.connect.service.
Follows is a socket I'm using
socket.on('request-to-sit-on-the-table', async function (data, callback) { //Previously Register
let table = persistence.getTable(tableToken);
if (typeof table === 'undefined') {
let errMsg = 'This table does not exists or already closed.'
callback(prepareResponse({}, errMsg, new Error(errMsg)));
return;
}
//TODO: Get the displayName from the token.
let guest = await guestUserService.getGuestUserByPlayerToken(JSON.parse(data.userToken));***//Here is the issue***
// let displayName = 'DisplayName-' + guest;
let displayName = 'DisplayName-' + Math.random();
//TODO: Check whether the seat is available
// If the new screen name is not an empty string
let isPlayerInCurrentTable = persistence.isPlayerInCurrentTable(tableToken, userToken);
if (displayName && !isPlayerInCurrentTable) {
var nameExists = false;
let currentPlayersTokenArr = persistence.getTableObjectPlayersToken(table)
for (var token in currentPlayersTokenArr) {
let gamePlayer = persistence.getPlayerPlayer(currentPlayersTokenArr[token])
if (typeof gamePlayer !== "undefined" && gamePlayer.public.name === displayName) {
nameExists = true;
break;
}
}
if (!nameExists) {
//Emit event to inform the admin for requesting to sit on the table.
let ownerToken = persistence.getTableObjectOwnerToken(table);
let ownerSocket = persistence.getPlayerSocket(ownerToken);
ownerSocket.emit('requested-to-sit', {
seat: data.seat,
secondaryUserToken: userToken,
displayName,
numberOfChips: envConfig.defaultNumberOfChips
});
callback(prepareResponse({userToken}, 'Player connected successfully.'));
} else {
callback(prepareResponse({}, 'This name is already taken'));
}
} else {
callback(prepareResponse({}, 'This user has already joined to a game. Try clear caching'));
}
});
In my code I'm getting data from another code in guest.user.service. But I get undefined to the value of "guest"
Follows are the methods I have used in guest.user.service
exports.findById = (id) => {
return new Promise(function(resolve, reject) {
guestUserModel.findById(id, (err, data) =>{
if(err){
reject(err);
} else {
resolve(data);
}
});
});
};
exports.getGuestUserByPlayerToken = (playerToken) => {
var player = playerService.findOne({ token: playerToken })
.then(function (data) {
return self.findById(data.guestUser._id.toString());
})
.then(function (guestUser) {
return guestUser.displayName;
})
.catch(function (err) {
throw new Error(err);
})
};
Although I get my displayName for the return value It is not passed to the "guest" in my socket.Is there any syntax issue to get data as I'm using promises.please help
exports.getGuestUserByPlayerToken = async playerToken => {
try {
let player = await playerService.findOne({token:playerToken});
return playerService.findById(player.guestUser._id)
} catch(error) {
console.log(error);
return null;
}
};
This is just handle error on awaited promise not returned one. You need to handle that in caller side.

Session expiring in Dialogflow

I came to know that context expires in 15 minutes but is there any way to solve it manually i.e by storing the previous conversation in dB so can we handle that session expiring issue or else the whole conversation(output context) under that session ID will get clear and need to start from the first.
exports.fulfillmenttext = functions.https.onRequest((req,res) =>{
const answer1 = req.body.Text;
console.log("Text said by the user",answer1);
const uid = answer1.substring(0,28);
console.log("uid1 is",uid);
const answer = answer1.substring(28);
console.log("answer is",answer);
const sessionId = uid;
var count,questvalue;
runSample();
async function runSample(projectId = 'xxxxxxx') {
const languageCode = 'en-US';
const credentials = {
client_email: 'xxxxxxxxxx',
private_key: 'xxxxxxxxx'
};
//Instantiate a DialogFlow client.
const dialogflow = require('dialogflow');
const sessionClient = new dialogflow.SessionsClient({
projectId,
credentials,
});
// Define session path
const sessionPath = sessionClient.sessionPath(projectId, sessionId);
// The text query request.
const request = {
session: sessionPath,
queryInput: {
text: {
text: answer,
languageCode,
},
},
};
const responses = await sessionClient.detectIntent(request);
console.log('Detected intent');
const result = responses[0].queryResult;
let action = result.action;
console.log("action is"+action);
console.log(` Query: ${result.queryText}`);
console.log(` Response: ${result.fulfillmentText}`);
if (result.intent) {
const question = result.fulfillmentText;
console.log("question is",question);
const actionHandlers = {
'early': () => {
console.log('earlyaction1', action);
let name1 = JSON.stringify(result.parameters.fields.Name.stringValue);
name1 = name1.toString().replace(/"/g,"");
var data1 = {
Name: name1
};
var setDoc1 = admin.firestore().collection('User').doc(uid).collection("Popop").doc(uid).collection('Answers').doc('Earlyyears').update(data1);
},
'family': () => {
console.log('familyaction1', action);
let mname1 = JSON.stringify(result.parameters.fields.M_Name.stringValue);
let mname_string = mname1.toString().replace(/"/g,"");
var data20 = {
MName: mname_string
};
var setDoc20 = admin.firestore().collection('User').doc(uid).collection("Popop").doc(uid).collection('Answers').doc('Family').update(data20);
}
};
if (action === 'early') {
console.log('1');
actionHandlers[action]();
}
else if (action === 'family') {
console.log('2');
actionHandlers[action]();
}
res.status(200).send({"question":result.fulfillmentText,"action":action});
} else {
console.log(` No intent matched.`);
res.status(400).send({"action":"empty"});
}
}
});
I stumbled upon this problem as well. My solution was to save the userID and save the contexts to Firestore.
UPDATE:
This is how I stored Dialogflow's contexts in Firestore:
function saveContexts(userId, contexts) {
let UID = userId;
//get all contexts + parameters
if (contexts === undefined) {
console.log("contexts are undefined! returning");
return false;
}
db.collection("user-contexts-prod").doc(UID).set({
dateCreated: new Date(),
contexts: JSON.stringify(contexts)
})
.then(function () {
console.log("success!");
return true;
})
.catch(function (error) {
console.log("error writing document..", error);
return false;
});
}
Retrieving user contexts:
async function getContexts(userId) {
let UID = userId;
let docRef = db.collection("user-contexts-prod").doc(UID);
return docRef.get()
.then(res => {
if (res.exists) {
let contexts = JSON.parse(res.data().contexts);
console.log("<><> parsed contexts <><>: ");
console.log(contexts);
return contexts;
} else {
console.log(" UID DOES NOT EXIST!");
return false;
}
})
}
You can set the contexts again by looping over them and using the contextClient to create new contexts. Or use this method to loop through the contexts and find the one you need:
contexts.forEach(function(context) {
if (context.name === 'projects/{DIALOGFLOWPROJECTID}/agent/sessions/' + senderId + '/contexts/{CONTEXTNAME}') {
sessionData = context.parameters;
// all data that you saved in CONTEXTNAME is now available in the sessionData variable
}
});
Original answer:
Whenever a user started talking that didn't have any active contexts I check if I had the userID stored in my Database. If this user existed in my DB I retrieved the user information with all his data like this:
knownUser = await db.isKnownUser(senderId);
if (knownUser) {
//knownUser
console.log("Known user");
let userData = db.getUserDataById(senderId)
//initialize contexts with data you need
payload = returningUser_useSameData();
messenger.send(payload, senderId);
dashbot.logBotMessage(payload.toString, sessionId, intentName);
break;
} else {
//newUser
console.log("new user");
createContext('await_fillInTogether', '', sessionPath, sessionId, 1);
createContext('session', '', sessionPath, sessionId, 500);
payload = fillInTogetherNewUser();
messenger.send(payload, senderId);
dashbot.logBotMessage(payload.toString, sessionId, intentName);
break;
}

Resources