Firebase Cloud Functions - multiple returns in sequnce - node.js

I am new to Firebase cloud functions. I would like to have a function in index.js that trigger when a node in database is created - 1. it will take the params of the context 2. and find a value of a node, 3. get value from another database, 4. adding that value to 3 diff places.
exports.runningNumber = functions.database.ref("Main/Enemy/{enem_Id}/{event_Id}"}
.onCreate((snapshot, context) => {
var enemid = context.params.enem_Id;
var eventid = context.params.event_Id;
return admin.database().ref("Main/Enemy/" + enemid + "/SequenceNumber").once('value', (snapshot) => {
var newSeqNum = snapshot.val() + 1;
//then, get var userid through database().ref("Main/Enemy/" + enemid + "/" + eventid + "/user_Id")
//and then, use newSeqNum to:
//1. Replacing "Main/Enemy/" + enemid + "/SequenceNumber"
//2. Adding as string into "Main/Enemy/" + enemid + "/" + eventid + "/SeqNum"
//3. Adding as string into "Main/Users/" + userid + "/" + eventid + "/SeqNum"
});
});
Hope somebody can help on how to do this...

Related

How to find threadID in Realtime Database chat query

I'm working with Firebase Realtime Database and am a fairly new developer. I'm working on a chat application and need to detect which thread to put a message in that comes to a firebase function. The function gets the fromID (sender) and the userID (receiver) and needs to detect which thread belongs to the users.
Issue: The problem is that it successfully detects the thread the first time the message comes in, but then continues afterward - creating a new thread as if the relationship doesn't exist.
Structure:
users
- uid
- threads
- $threadKey
threadMembers
- $threadKey
- members
- $fromID_$userID
Code:
const db2 = admin.database();
db2.ref('users/' + userId + '/threads').once('value').then(snapshot => {
if (!snapshot.exists()) {
console.log("User does not have any threads")
return functions.logger.log('User doesnt have a Thread.');
}
snapshot.forEach((doc) => {
console.log("SNAP : " + doc.key)
checkThreads(doc.key)
})
return functions.logger.log('Finished checking user/uid/threads');
})
function checkThreads(threadId){
const threadRef = db2.ref('threadMembers/' + threadId);
threadRef.once('value', (snapshot) => {
const members = snapshot.child("members").val()
console.log("Members Val: " + members)
if(members == `${fromId}_${userId}` || members == `${userId}_${fromId}`){ //ISSUES WITH REPEATING
console.log("Both users are in the thread")
console.log("Key for thread: " + snapshot.key)
setThread(snapshot.key)
return functions.logger.log('Found membership and set thread');
} else {
const newThreadKey = db2.ref('threads').push().key;
const userThreadRef = db2.ref('users');
userThreadRef.child(fromId + '/threads/' + newThreadKey).set({
timestamp: DBTimestamp.TIMESTAMP
});
userThreadRef.child(userId + '/threads/' + newThreadKey).set({
timestamp: DBTimestamp.TIMESTAMP
});
const threadMembersRef = db2.ref('threadMembers');
threadMembersRef.child(newThreadKey + '/' + userId).set(true);
threadMembersRef.child(newThreadKey + '/' + fromId).set(true);
threadMembersRef.child(newThreadKey + '/members').set(userId + "_" + fromId);
setThread(newThreadKey)
return functions.logger.log('Created membership and set thread');
}
})
}

How to avoid having “quota exceeded for 'ReadGroup'” error in google api

I've created a bot which goes in Google Spreadsheet getting some datas before sending them by DM to 50 guild members into Discord.
However, due to high requests of datas, I've got an error message saying that I've exceeded the quota for group 'ReadGroup' and limit 'USER-100s'.
To avoid getting this error, I've created a buffer function however it still doesn't work, does anyone know how to avoid getting this limit error?
Here is the main code which is launched when I type a specific commande in Discord :
const client1 = new google.auth.JWT(keys.client_email, null, keys.private_key, ['https://www.googleapis.com/auth/spreadsheets']);
const client2 = new discord.Client();
.
.
.
let valeur1 = await liste(client1);
await sleep(100000);
console.log("End of first buffering time (100s)");
for (i = 0; i < valeur1.length; i++){
if (valeur1[i] != undefined){
try{
let valeur2 = await envoi(client1, valeur1[i]);
const user = client2.users.get(String(valeur1[i])) || await client2.fetchUser(String(valeur1[i]));
console.log("Ready to send to : " + user.id);
await user.send("The character you need to improve is : " + valeur2[0] + "\n 1. " + valeur2[1] + " = " + valeur2[2] + " >>> " + valeur2[3] + "\n 2. " + valeur2[4] + " = " + valeur2[5] + " >>> " + valeur2[6] + "\n 3. " + valeur2[7] + " = " + valeur2[8] + " >>> " + valeur2[9]);
console.log("Message sent for : " + user.id);
}
catch(err){
console.error(err);
console.log("Error detected for : " + valeur1[i]);
break;
}
}
}
Here is the first function called ("liste") which return the list of the 50 members id :
async function liste(client){
const gsapi = google.sheets({version:'v4',auth: client});
let data1 = new Array();
for (i = 0; i < 50; i++) {
const opt1 = {spreadsheetId: 'XXXXXX', range: 'Serveur!C' + (3+i)};
let data2 = await gsapi.spreadsheets.values.get(opt1);
data1.push(data2.data.values);
}
return data1;
}
And here is the second function called ("envoi") which is supposed to send the DM to the 50 different members of the guild :
async function envoi(client, id){
const gsapi = google.sheets({version:'v4',auth: client});
for (i = 0; i < 50; i++){
const opt1 = {spreadsheetId: 'XXXXXX', range: 'Discord!A' + (3+i)};
let data1 = await gsapi.spreadsheets.values.get(opt1);
if (parseInt(id) === parseInt(data1.data.values)){
const opt2 = {spreadsheetId: 'XXXXXX', range: 'Discord!C' + (3+i)};
let data2 = await gsapi.spreadsheets.values.get(opt2);
const opt3 = {spreadsheetId: 'XXXXXX', range: 'Discord!D' + (3+i)};
let data3 = await gsapi.spreadsheets.values.get(opt3);
.
.
.
const opt10 = {spreadsheetId: 'XXXXXX', range: 'Discord!K' + (3+i)};
let data10 = await gsapi.spreadsheets.values.get(opt10);
const opt11 = {spreadsheetId: 'XXXXXX', range: 'Discord!L' + (3+i)};
let data11 = await gsapi.spreadsheets.values.get(opt11);
var stats = [data2.data.values,data3.data.values,data4.data.values,data5.data.values,data6.data.values,data7.data.values,data8.data.values,data9.data.values,data10.data.values,data11.data.values];
await sleep(10000);
console.log("Extraction done for " + parseInt(id));
return stats;
}
}
console.log("Member not found");
return "erreur";
}
As a result, I would like to get all the members to get their DM. However after the 18th member, an error appear, even though I put some buffering time.
In the console.log, I get :
End of first buffering time (100s)
Extraction done for 408575708424699900
Ready to send to : 408575708424699925
Message sent for : 408575708424699925
.
.
.
Extraction done for 438420776652374000
Ready to send to : 438420776652374036
Message sent for : 438420776652374036
Error: Quota exceeded for quota group 'ReadGroup' and limit 'USER-100s' of service 'sheets.googleapis.com'
.
.
.
Error detected for : 493854774446391296
This is even more strange that the error concerns a member who already have received his DM (he is one the the first 10 members in the list)
Thanks to Tanaike, I updated my code using spreadsheets.values.batchGet() method. In that way instead of extraction values by values, I extracted a batch of values.
And then I made my formula. Now I don't have any issues anymore and even better, my script is way much quicker :)

Waiting for a transaction to complete to execute in Node.js/Solidity

I have been looking for a way to execute a set of commands after the completion of a transaction I sent.
In short, I have been testing small Node.js scripts with Web3.js to post thermometer readings to a smart contract and after the transaction is mined to get back the last 5 values posted.
I haven't found a specific Web3 method to do so, so I coded a .on method in Node.js. I am now looking for more optimised ways of doing it and together to query if there is a way of doing it using any of the Web3 methods.
PS - I suppressed the smart contract and parts of the Node script to save space on the post.
Cheers,
// Transaction
web3.eth.getTransactionCount(account1, (err, txCount) => {
const txObject = {
nonce: web3.utils.toHex(txCount),
gasLimit: web3.utils.toHex(100000),
gasPrice: web3.utils.toHex(web3.utils.toWei('1', 'gwei')),
to: contractAddress,
data: contract.methods.postTemperature((Date.now() / 1000 | 0), temp).encodeABI()
}
const tx = new Tx(txObject)
tx.sign(privateKey1)
const serializedTx = tx.serialize()
const raw = '0x' + serializedTx.toString('hex')
web3.eth.sendSignedTransaction(raw, (err, txHash) => {
txH = txHash;
console.log('err:', err, 'txHash:', txHash)
}).on('receipt', receipt =>
contract.methods.seeTemperatures().call((err, result) => {
const tempDisplay = 'The last five temperature submissions were: \n' +
(result[1].slice(-10))[8].toString() + 'ºC at ' + timeConverter((result[1].slice(-10))[9]).toString() + '\n' +
(result[1].slice(-10))[6].toString() + 'ºC at ' + timeConverter((result[1].slice(-10))[7]).toString() + '\n' +
(result[1].slice(-10))[4].toString() + 'ºC at ' + timeConverter((result[1].slice(-10))[5]).toString() + '\n' +
(result[1].slice(-10))[2].toString() + 'ºC at ' + timeConverter((result[1].slice(-10))[3]).toString() + '\n' +
(result[1].slice(-10))[0].toString() + 'ºC at ' + timeConverter((result[1].slice(-10))[1]).toString();
console.log(tempDisplay)
contract.methods.seeBill().call((err, result) => {console.log('Your current bill is at ' + result + ' (currency)')})
})
)
})

Async for loop nodeJS

I have a simple for loop containing an async function, my problem is that the loop goes through all the values, then only executes the async function inside.
for(key in splitedDataArray){
calculatePower(splitedDataArray[key]);
var octopusMAC = getOctopusIDFromRaw(splitedDataArray[key]);
var channelID = getChannelIDFromRaw(splitedDataArray[key]);
console.log("outside")
getChannelCTSize(octopusMAC, channelID, function (result) {
console.log("inside")
var timestamp = convertDateTimeToInt(transmission.date);
var adcTicks = getAdcTicksFromRaw(splitedDataArray[key]);
var power = convertAdcTicksToAmps(parseInt(adcTicks, 16), result);
console.log("channelID: " + channelID + " ADC ticks HEX: " + adcTicks + " timestamp: " + timestamp + " power for " + result + "A CT Size: " + power);
});
}
So it prints outside for every element in the array then it only prints inside after all of the outised's, I want to have an outside then and inside and so on. I have looked at https://www.promisejs.org/ but I am not sure on how to implement this with my code.
You can use lodash.eachSeries but it is not best solution. If i were you i would try to move everything inside of for loop into a function so you will have all variables visible inside.
More like this:
function calculate(value){
calculatePower(value);
var octopusMAC = getOctopusIDFromRaw(value);
var channelID = getChannelIDFromRaw(value);
console.log("outside")
getChannelCTSize(octopusMAC, channelID, function (result) {
console.log("inside")
var timestamp = convertDateTimeToInt(transmission.date);
var adcTicks = getAdcTicksFromRaw(value);
var power = convertAdcTicksToAmps(parseInt(adcTicks, 16), result);
console.log("channelID: " + channelID + " ADC ticks HEX: " + adcTicks + " timestamp: " + timestamp + " power for " + result + "A CT Size: " + power);
});
}
for(key in splitedDataArray){
calc(splitedDataArray[key]);
}
It will not print out: out/in/out/in, but will get good values in each loop.
If you require that order /out/in/out/in i would go for eachSeries from lodash.

How to access this inside prototype function in js

I am using nodejs and mysql client in nodejs
I am trying to use pool function od the mysql module.
"use strict";
var mysqlClient = require('mysql')
, dbPool = mysqlClient.createPool(require('../config/database'));
function MyModel(params) {
this.tbl = params.tbl;
this.primary_key = params.primary_key;
this.primary_name = params.primary_name;
this.dbPool = dbPool;
}
module.exports = MyModel;
//primary key
MyModel.prototype.fromPK = function fromPK(pk, callback) {
this.dbPool.getConnection(function (err, connection) {
var query = "SELECT * FROM " + this.tbl + " WHERE " + this.primary_key + " = " + connection.escape(pk);
connection.query(query, callback);
});
};
I know I cannot access this inside getConnection and I could simply set var t = this outside it and access it with var t, but is there any other way to access this var in this condition. Should I define var t = this in each prototype function I write?
I have following detailed gist
https://gist.github.com/yalamber/6bd1df0cc27849eb09b3
You can determine what this is in a function using .bind().
The elaborate syntax is:
var newfunction = oldfunction.bind(THIS_OBJECT);
That would make THIS_OBJECT be the this object inside the oldfunction. As you can see, .bind() returns a new (bound) function.
You don't need that elaborate syntax though, it works on anonymous functions as well:
var newfunction = function() { ... }.bind(THIS_OBJECT);
In your case, you could use this:
this.dbPool.getConnection(function (err, connection) {
var query = "SELECT * FROM " + this.tbl + " WHERE " + this.primary_name + " = " + connection.escape(pn);
connection.query(query, callback);
}.bind(this));
This makes the this inside the callback function the same as the this on the outside.

Resources