I have this code where I fetch a list of elements so I can make discordjs options with the mongoose data
const items = require(‘./schema.js’)
const items1 = await items.find()
module.exports = {
name: `buy`,
timeout:15000,
/**
* #param {Client} client
* #param {Message} message
* #param {String[]} args
*/
data: new SlashCommandBuilder()
.setName('buy')
.setDescription('buy an item!')
.addStringOption(option =>
option
.setName('itemid')
.setDescription('the item you want to buy')
.setRequired(true)
/** .addChoices(
items1.forEach(item => {
option.addChoice(`<:${item.EmojiName}:${item.EmojiID}>${item.ItemName} - <:bobux:809551218217058354>${item.Price} `,`${item.ItemID}` )
})
)
*/
),
When I do this, I get the error that you can’t use await outside of async. Does anyone have any solutions/alternatives to this code?
Thanks
The situation you're facing is more like a bad-design symptom than a limitation. What you are actually trying to do is "generating Discord commands — asynchronously — based on Mongoose data".
Well, just do that in the code. Don't try to mix and export synchronously an asynchronously generated thing. Rather simply make a function that generates it :
const Item = require('./schema.js')
const itemToChoice = item => `<:${item.EmojiName}:${item.EmojiID}>${item.ItemName} - <:bobux:809551218217058354>${item.Price} `
const addItemsChoices = (option, items) => (
items.reduce((option, item) => (
option.addChoice(itemToChoice(item),`${item.ItemID}`)
), option)
)
module.exports = async () => {
const items = await Item.find()
const command = {
name: `buy`,
timeout:15000,
/**
* #param {Client} client
* #param {Message} message
* #param {String[]} args
*/
data: new SlashCommandBuilder()
.setName('buy')
.setDescription('buy an item!')
.addStringOption(option => (
addItemsChoices(
option
.setName('itemid')
.setDescription('the item you want to buy')
.setRequired(true),
items
)
))
}
return command
}
PS: for god sake, format your code
PS2: for god sake, remove smart punctuation on your computer
Related
Firebase Realtime Database structure
freepacks contains 2 important elements:
current, that is the quizpack ID that I will download from the mobile app (retrieving it from quizpacks).
history, that is a node where I add all the quizpacks ID that I put in current over time with a scheduled function in Cloud Functions.
What I need to do EVERY TIME THE CLOUD FUNCTION EXECUTES
Step 1: Add value of current in history with the current timestamp.
Step 2: Substitute the current value with another quizpack ID that is not in history.
Done
How I tried to accomplish this target
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.scheduledFunction = functions.pubsub.schedule('* * * * *').onRun((context) => {
// Current timestamp
const dt = new Date();
const timestamp = `${
(dt.getMonth()+1).toString().padStart(2, '0')}/${
dt.getDate().toString().padStart(2, '0')}/${
dt.getFullYear().toString().padStart(4, '0')} ${
dt.getHours().toString().padStart(2, '0')}:${
dt.getMinutes().toString().padStart(2, '0')}:${
dt.getSeconds().toString().padStart(2, '0')}`
// Download the entire node 'freepacks'
return admin.database().ref('quiz/freepacks').once('value').then((currentSnap) => {
const currentPack = currentSnap.val().current;
// Add current to history
admin.database().ref('quiz/freepacks/history/' + currentPack).set(timestamp);
// Download entire history node
admin.database().ref('quiz/freepacks/history').once('value').then((historySnap) => {
const history = historySnap.val();
console.log('HISTORY: ' + history);
// Download entire quizpacks node
admin.database().ref('quiz/quizpacks').once('value').then((quizpacksSnap) => {
for(quizpack in Object.keys(quizpacksSnap.val())) {
console.log('ITERANDO: ' + quizpack);
// Add the new current if it isn't in history
if (historySnap[quizpack] == undefined) {
admin.database().ref('quiz/freepacks/current').set(quizpack);
break;
}
}
});
})
});
});
What I get from the previous code
Starting point:
First execution: history updates well but updating current didn't work
Second execution ad so on...
current doesn't update anymore (it is stuck on 0)
My experience with JavaScript and Firebase Admin is ~0... What is the problem with my code? Thanks in advance for the help!
First thing is all read/write operations return promises hence you should handle them. In this answer I used async-await syntax. .ref("quiz/freepacks") fetches the complete node i.e. current and the history so you don't have to query the history node again as in original code. Other changes are just Javascript tweaks such as using .find() instead of for-loop and so on..
Try changing your function to:
exports.scheduledFunction = functions.pubsub
.schedule("* * * * *")
.onRun(async (context) => {
// Getting Date
const dt = new Date();
const timestamp = `${(dt.getMonth() + 1).toString().padStart(2, "0")}/${dt
.getDate()
.toString()
.padStart(2, "0")}/${dt.getFullYear().toString().padStart(4, "0")} ${dt
.getHours()
.toString()
.padStart(2, "0")}:${dt.getMinutes().toString().padStart(2, "0")}:${dt
.getSeconds()
.toString()
.padStart(2, "0")}`;
// Download the entire node 'freepacks'
const currentSnap = await firebase
.database()
.ref("quiz/freepacks")
.once("value");
// Checking current free pack ID and array of previous free packs
const currentPack = currentSnap.val().current || "default";
const freeHistoryIDs = [
...Object.keys(currentSnap.val().history || {}),
currentPack,
];
// Add current free pack to free history
await firebase
.database()
.ref("quiz/freepacks/history/" + currentPack)
.set(timestamp);
// Download entire quizpacks node
const quizpacksSnap = await firebase
.database()
.ref("quiz/quizpacks")
.once("value");
const quizPackIDs = Object.keys(quizpacksSnap.val() || {});
const newPack = quizPackIDs.find((id) => !freeHistoryIDs.includes(id));
console.log(newPack);
if (!newPack) {
console.log("No new pack found")
}
return firebase.database().ref("quiz/freepacks/current").set(newPack || "none");
});
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 )
I'm finding document by _id from array. Then I change the field 'balance' and save the document. This action is performed five times, but the balance is changed only once. Code:
users.forEach(async(user) => {
if (user.active) {
/* SOME STUFF */
const owner = await Owner.findById(user.owner)
owner.balance = (owner.balance * 100 - 0.01 * 100) / 100
await owner.save()
}
})
Tried like that:
Owner.findById(user.owner).then((owner) => {
owner.balance = (owner.balance * 100 - 0.01 * 100) / 100
owner.save(err => {
if(err) console.log(err)
})
})
Also tried:
owner.markModified(balance);
Owner schema:
const ownerSchema = new Schema({
balance: {
type: Number
}
});
Test output from console
On this picture you can see test output. Balance before is 99.53.
As a result, the balance should be 99.48, but it is 99.52.
You might be expecting that each user would be processed one by one inside forEach(), but this is not what would happen, everything would rather run simultaneously.
What you would need to do for your code to run in order is to use for...of instead, which would ensure execution order. Something like below:
for(let user of users) {
if (user.active) {
/* SOME STUFF */
const owner = await Owner.findById(user.owner)
owner.balance = (owner.balance * 100 - 0.01 * 100) / 100
await owner.save()
}
}
why don't you try something like
Owner.findByIdAndUpdate()
it will find owner by id & update it it is shortened and better (clean) version of your code
The problem lies in your use of the forEach function.
when you write async in-front of a function you basically wrap it as a promise meaning its return value is changed to be a promise.
forEach does not have a return value, meaning when you wrap it as a promise no-one is waiting for that promise, that leads to unexpected behaviour. and in your case it actually does update 5 times, but not synchronicity as you expect.
i recommend using a library like bluebird as it gives alot of power, the code would look like this:
let Promise = require("bluebird")
....
let users = [user array];
await Promise.mapSeries(users, (user) => {
if (user.active) {
/* SOME STUFF */
const owner = await Owner.findById(user.owner)
owner.balance = (owner.balance * 100 - 0.01 * 100) / 100
await owner.save()
}
})
it will now work as you want.
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);
});
}