Parse Cloud Code Defines with Parse 3.0.0 - javascript

I'm trying to return values from Parse.Cloud.define functions in cloud code using Parse. I'm using Parse 3.0.0 and I can get it to return values from simple cloud code defines but not complex ones.
I'm coding client side iOS in Objective-C.
Here's the cloud code function (I don't care if this is unsafe, I'm not changing it)
Parse.Cloud.define("doStuff", (request) => {
const query = new Parse.Query(Parse.User);
query.equalTo("username", request.params.username);
query.first({useMasterKey:true})
.then((results) => {
Parse.User.requestPasswordReset(results.get("email"))
.then(() => {
return "good work";
}).catch((error) => {
});
})
.catch((error) => {
});
});
This works just fine, it sends the email to the user as expected by using the User's username field.
In iOS I'm calling it like this:
[PFCloud callFunctionInBackground:#"doStuff" withParameters:#{#"username" : cleanEntryData} block:^(NSString * object, NSError * error) {
if (!error) {
NSLog(#"success %#", object);
} else {
NSLog(#"error %#", error);
}
}];
This call works in iOS and the email is successfully sent to the user for password reset. However, here's the problem.
when I call
NSLog(#"success %#", object);
the value in Xcode debug window is
success (null)
I expect it to be
success good work
When I a simple cloud code define like so:
Parse.Cloud.define("testing", (req) => {
return "very good";
});
with iOS like so:
[PFCloud callFunctionInBackground:#"testing" withParameters:#{#"nothing" : #"nothing"} block:^(NSString * object, NSError * error) {
if (!error) {
NSLog(#"success %#", object);
} else {
}
}];
then i get the result in Xcode debugger that i'm looking for
success very good
i don't know why the "doStuff" cloud code define is not returning the string "good work" when the function is clearly executing and sending the email as it should. I've read both the Parse 3.0.0 and JS 2.0.0 guides and they aren't very descriptive on how this should work with Parse Cloud defines. I'm not a JS coder, I only code in mobile, so I'm probably doing something stupid. Any help would be great. Thanks.

There's no issue in your iOS code, the issue lies in the cloud code, so you'll need to change the cloud code, since it's not necessarily unsafe, but rather flawed.
The issue is that you are nesting Promises inside each other instead of chaining them together, hence the single nested return value is lost in the several nested layers.
Parse.Cloud.define("doStuff", (request) => {
const query = new Parse.Query(Parse.User);
query.equalTo("username", request.params.username);
return query.first({useMasterKey:true})
.then((results) => {
return Parse.User.requestPasswordReset(results.get("email"));
}).then(() => {
return "good work";
})
});

Related

chrome.tabs.sendMessage - why callback fails?

I have been experimenting with messaging APIs in Chrome extensions. I wanted to send a message from the background script to the content script and get some response back. I prepared a function just for that. Here are the two versions of that funcion:
V1:
public static async sendToContentScript<R>(tabId: number, command: CommandToContent): Promise<R> {
const payload: CommandBody = { command };
return await chrome.tabs.sendMessage(tabId, payload);
}
V2:
public static async sendToContentScript<R>(tabId: number, command: CommandToContent): Promise<R> {
return new Promise((resolve, _) => {
const payload: CommandBody = { command };
chrome.runtime.sendMessage(payload, function (response: R) {
resolve(response);
return true;
});
});
}
Version V1 works, while versions V2 does not. It throws the following error:
Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
I've read a few posts about that error and it's not the first time that I see it. However, I did not find any explanation that would really "click" for me, I basically don't understand why V1 works and V2 does not. It would be great if you could help me understand that.

Why cant i see any notifications when i send data to device over BLE?

I'm trying to make an app that sends commands to a BLE device and i cant get any feedback. I am using a library called ble.plx which has an option to monitor characteristics but it wont output anything for me.
I need to read values from notifications to use later in my code. This is my first time working with BLE in general so i have no idea what i am doing wrong. I know serviceUUID and characteristicUUID are correct. I am out of ideas.
Here is my code:
function scanAndConnect() {
BLTManager.startDeviceScan(null, null, (error, device) => {
if (error) {
// Handle error (scanning will be stopped automatically)
return
}
// Check if it is a device you are looking for based on advertisement data
// or other criteria.
if (device.name=='Audio PCM Streamer') {
console.log(device.name);
// Stop scanning as it's not necessary if you are scanning for one device.
BLTManager.stopDeviceScan();
device.connect()
.then((device) => {
return device.discoverAllServicesAndCharacteristics()
})
.then( (device) => {
device.monitorCharacteristicForService(SERVICE_UUID,CHARACTERISTIC_UUID,(err,result)=>{
if(err) {
console.log(err)
return;
}
console.log(result);
}); Subscription
device.requestMTU(251)
let data = Uint8Array(9);
data[0]=0xA5;
data[1]=0xA5;
data[2]=0xA5;
data[3]=0xA5;
var b64encoded = btoa(decoder.decode(data));
device.writeCharacteristicWithoutResponseForService(SERVICE_UUID,CHARACTERISTIC_UUID,b64encoded);
})
.catch((error) => {
// Handle errors
});
}
});
}
I did this completely wrong do not use this or try to fix this its just bad.

How to feed a String to a Google Cloud Function as input?

I need a Google Cloud Function that I can call from my Android app. The function should call Vision API Safe Search and return the results to the app.
My problem: The function I have is simple and it works. But ONLY from the Cloud Test-Console. Not from the android app. When I call the function from my app, with the exact same JSON as input, it says FirebaseFunctionsException: INVALID_ARGUMENT
Function:
exports.starte = async (req, res) => {
try {
let pfad = req.body.pfad;
console.log('Input is: ' + pfad);
// Imports the Google Cloud client libraries
const vision = require('#google-cloud/vision');
// Creates a client
const client = new vision.ImageAnnotatorClient();
const visionRequest = {
features: [
{ type: 'SAFE_SEARCH_DETECTION' },
],
image: { source: { imageUri: pfad } },
};
const [result] = await client.annotateImage(visionRequest);
const detections = result.safeSearchAnnotation;
console.log('Ergebnis: ' + result);
console.log('Ergebnis: ' + detections);
res.status(200).send(detections);
} catch(err) {
console.log('Error: ' + err.message);
const errorJSON = { message: 'unknown' };
res.status(400).send(errorJSON);
}
};
Android code:
Map<String, Object> data = new HashMap<>();
data.put("pfad", path);
FirebaseFunctions.getInstance()
.getHttpsCallable("nsfw_test2")
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) throws Exception {
try {
Object result = task.getResult().getData();
Log.v(TAG, "CloudFunktion: Worked!");
return result.toString();
} catch (Exception e) {
e.printStackTrace();
Log.v(TAG, "CloudFunktion: Failed!");
return e.getMessage();
}
}
});
Example JSON input that works in the Cloud Console, but not in Android:
{"pfad":"gs:\/\/xxx.appspot.com\/photos\/xxx"}
Error I get in Android:
com.google.android.gms.tasks.RuntimeExecutionException: com.google.firebase.functions.FirebaseFunctionsException: INVALID_ARGUMENT
at com.google.android.gms.tasks.zzw.getResult(com.google.android.gms:play-services-tasks##18.0.1:3)
When I check the logs in Google Cloud, it logs: Input is: undefined (When running from the app)
When I run it from the Cloud Console instead, it works and prints the path I passed.
I have absolutely no idea why this happens. I have now checked easily 30 websites and stackoverflow questions on this. To me it seems that my Android code is correct.
But why doesn't the function read the input then? Why is the input undefined? The input in the android app is not null, I log the input before I pass it in, and it is the correct file.
According to this document, the invalid argument is because we failed to specify an argument correctly:
public static final FirebaseFunctionsException.Code INVALID_ARGUMENT
Client specified an invalid argument. Note that this differs from
FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments that are
problematic regardless of the state of the system (e.g., an invalid
field name).
You need to create callable functions, instead of using an HTTP triggered Cloud Function.
The Callable functions require to have the following format:
exports.addMessage = functions.https.onCall((data, context) => {
// ...
});
It's not the same as an HTTP triggered Cloud Function (which is what you are using). You can still access it if you use an HTTP request from the Android app, but you need to use a Callable Cloud Function.

Dialogflow api call works, but chatbot shuts off

In Dialogflow, i use the free edition (V2) with the blaze plan from Firebase.
I have an Intent that works on the word "test". When i enter "test" in the simulator, the chatbot gives an non response and leaves the chat. It is suppose to make an call to my API and retrieves information.
The weird part is, there is a console.log that prints out the body and that returns the JSON from the API. So that means the API call works fine, but there is still an error somewhere within the bot.
I found this question: Dialogflow v2 error “MalformedResponse 'final_response' must be set”
It looks alot like my problem, yet i cant seem to figure out what i should change to make mine work.
Thanks in advance for your time.
The Fulfullment:
function testcommand(agent) {
callNPApi().then((output) => {
agent.add(output);
}).catch(() => {
agent.add("That went wrong!");
});
}
function callNPApi() {
return new Promise((resolve, reject) => {
request2(url, function (error, response2, body){
//The substring is too ensure it doesnt crash for the character limit yet
body = body.substring(1,10);
console.log('Api errors: ' + JSON.stringify(error));
console.log('Api body: ' + JSON.stringify(body));
if (error) {
reject();
}
resolve('api call returned: ');
});
});
}
The Response in the console:
{
"responseMetadata": {
"status": {
"code": 10,
"message": "Failed to parse Dialogflow response into AppResponse because of empty speech response",
"details": [
{
"#type": "type.googleapis.com/google.protobuf.Value",
"value": "{\"id\":\"bca7bd81-58f1-40e7-a5d5-e36b60986b66\",\"timestamp\":\"2018-09-06T12:45:26.718Z\",\"lang\":\"nl\",\"result\":{},\"alternateResult\":{},\"status\":{\"code\":200,\"errorType\":\"success\"},\"sessionId\":\"ABwppHFav_2zx7FWHNQn7d0uw8B_I06cY91SKfn1eJnVNFa3q_Y6CrE_OAJPV-ajaZXl7o2ZHfdlVAZwXw\"}"
}
]
}
}
}
The Error in the console:
MalformedResponse
'final_response' must be set.
Yup, this is the same problem.
The issue is that you're returning a Promise from callNPApi(), but your event handler (which I assume is testcommand()) isn't also returning a Promise. If you are doing async calls anywhere in your handler, you must use a Promise, and if you are using a Promise you must also return that Promise from the handler.
In your case, this should be a simple change. Simply add "return" to your handler. So it might look something like this
function testcommand(agent) {
return callNPApi().then((output) => {
agent.add(output);
}).catch(() => {
agent.add("That went wrong!");
});
}

Firebase-admin won't write to database, gives no errors

Firebase admin isn't writing to the database.
I am instantiating the database:
var db = admin.database();
Then setting up a reference to the table I want:
var systemsRef = db.ref("systems/");
I then have a function to check if the 'system', (an encrypted hardware id), exists.
function isSystemRegistered(id){
var isTrue;
systemsRef.once('value', function(snapshot) {
isTrue = (snapshot.hasChild(id))? true : false;
});
return isTrue;
}
Which, as of yet returns false; which is true, because it doesn't exist yet. If the system doesn't exist, it writes the data.
const sysID = getSysID();
var sys.info.name = generateUniqueSystemName();
if(isSystemRegistered(sysID){
console.log("system is already registered!");
} else {
msystemsRef.set({
sysID : sys.info.name
}, function(error){
console.log('There was an error while attempting to write to database: ' + error);
});
});
}
I've experimented, and temporarily made my prototype database fully public for a few minutes, just to be sure my rules weren't the issue... They weren't: still no bueno. No writes to the database... and no errors.
I tried a different set, just be sure:
msystemsRef.set("I'm writing data", function(error) {
if (error) {
alert("Data could not be saved." + error);
} else {
alert("Data saved successfully.");
}
});
Again, I'm using an admin account, with public rules, so I should see a now I'm writing data table, just below root. Nothing...
So I switched tactics and attempted to push to the database with the canned tutorial, with my database still fully public:
systemsRef.push({sysID : sys.info.name});
And nothing... Want am I missing?
Make sure the credentials and databaseURL are correct.
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: databaseURL
});
Check if they're matching - credential from one app and databaseURL from another existing app could produce such result.
If you are not loading credential's data from file but from somewhere else, make sure it's not modified - I had an issue with newlines in private key when putting the credential's data to shell variable.
In isSystemRegistered you're returning the synchronized value of isTrue which is undefined.
You should return the promise of the .once('value') method and in the calling method attach a then() to check if it exists.
You can also use the snapshot.exists() to check on a reference for existence.
Edit:
Suggested edit:
var systemRef = admin.database('system');
function isSystemRegistered(id) {
return systemRef.child(id).once('value')
.then(function (snap) {
return snap.exists();
});
}
function writeData(aSystem) {
var sysId = generateUniqueSystemName();
return systemRef.child(sysId)
.once('value')
.then(function (snapshot) {
if (!snapshot.exists()) {
return systemRef.child(sysId).update(aSystem);
}
// Here `sysId === snapshot.key`
return systemRef.child(sysId).set(aSystem);
})
.catch(function (err) {
console.error(err);
});
}
Running on Raspberry Pi raises some more questions.
How does it connect to the internet?
How fast is the connection?
What NodeJS version do you run?
Did this run successfully on your PC?
Same issue here. I eventually realised that the database went offline before the command was even sent to firebase. This made sense because there was no error, since it never even sent the request.
Eg. .set({blah: 123}) does not immediately transmit to the server. Instead, something is placed on the node event queue to execute. If you let the database go offline too soon, it won't process the queue.
Perhaps (like me) you're calling admin.database().goOffline(); at the end of the script? If so, you may just need to defer or delay the offline method until after the transmission.
// (TYPESCRIPT)
import * as admin from 'firebase-admin';
let app = admin.initializeApp({
credential: admin.credential.applicationDefault(),
databaseURL: "https://blahblah.firebaseio.com/",
});
admin.database().ref().push({ something: 123 }).then(() => {
console.log("push complete");
});
// delay before going offline
setTimeout(() => {
admin.database().goOffline();
process.abort();
}, 2000);

Categories

Resources