Flutter: info: 'await' applied to 'RemoteConfig', which is not a 'Future' - firebase

I am getting an info message after upgrading my Firebase packages. The documentation wasn't helpful. The line below is triggering the info compiler alert.
RemoteConfig remoteConfig = await RemoteConfig.instance;
The info message is:
info: 'await' applied to 'RemoteConfig', which is not a 'Future'. (await_only_futures at lib/splash.dart:72)
While this is just an 'info' message and doesn't prevent compilation, I want to make sure that I am not doing anything wrong. Please help.

As the FlutterFire documentation on using Remote Config shows, the call to RemoteConfig.instance is not asynchronous and is:
RemoteConfig remoteConfig = RemoteConfig.instance;
Where you will need to deal with asynchronous behavior is when fetching the remote config, which can be done with:
bool updated = await remoteConfig.fetchAndActivate();
if (updated) {
// the config has been updated, new parameter values are available.
} else {
// the config values were previously updated.
}
both snippets are from the linked documentation, so I recommend keeping that page handy.

Related

Why Isn't app.initailzation() working in my Teams Add-in OAuth flow?

I am trying to get simple auth in my Teams app working with Adobe ID (a third party Oauth provider that I use on my site).
I am following the sample here. Everything is working to authorize with the Adobe ID, but when it gets to my end authentication page like this, I get an exception thrown with the message "SDK initialization timed out." when I call await app.initialize();. The sample shown does not have the await term before app.initialize(). Is that incorrect? If I remove the await, my code later on to notify authentication of success, fails with the exception "The library has not yet been initialized".
authentication.notifySuccess("Yippee");
What do I need to do to allow app.initialize() to work?
How can the sample work if there is no await before it?
Here is the TypeScript code for my OAuth End page that is loaded after the Adobe Authentication succeeds.
import $ from "jquery";
import {app, authentication} from "#microsoft/teams-js";
startup();
async function startup(){
try{
$("#status").text("Initializing");
await app.initialize();
$("#status").text("Initialized");
console.log("notifying of success");
authentication.notifySuccess("Yippee");
}
catch(error){
handleError(error, "initializing");
}
}
function handleError(error:Error, context: string){
console.error(`💥 Error ${context}: ${error.message}`);
$("#status").text(error.message);
}
What version of the js library are you using?
There have been some changes to how app.initialize is handled depending on the version of the SDK you are using- see details here
https://learn.microsoft.com/en-us/microsoftteams/platform/tabs/how-to/using-teams-client-library?tabs=typescript%2Cmanifest-teams-toolkit#callbacks-converted-to-promises
You should be able to see this in package.json for typescript, although I think there may be other areas where you may need to update this.
Try this with the version referenced in the sample- 2.0.0 does that resolve the issue?
re: await- that just tells the application to wait until a response is returned (a success or failure) before moving on to the next line. In your case, you need the await as your next line is dependent on the value of status, but your function is async, so it won't block the execution of other async functions. You want to use await where you have other requests that must have a response on that call- like getauthtoken.

Custom logging from firebase function

I'm trying to follow this guide to put some custom logging into a firebase function. The function itself is running, and I can see the data being passed in (it's an https 'callable' function). But as soon as it hits the line where it tries to actually write that log entry, I get "Error: 7 PERMISSION_DENIED"
Since the console.log() calls write to the cloud logs, I'd assumed the firebase function has access to Cloud Logging. But perhaps it needs additional permission? I can't find any reference to where this should be set on that page though.
// Logging, logName, region, functions are provided by the surrounding app
const logging = new Logging()
const log = logging.log(logName)
const METADATA = {
resource: {
type: 'cloud_function',
labels: {
function_name: 'CustomLog',
region
}
}
};
exports = module.exports = functions.https.onCall(async data => {
const exVersion = 6
const exId = data.exId
console.log('***** exVersion:', exVersion, 'exId:', exId) // exId from caller
const entry = log.entry(METADATA, data.error) // data.error from caller
console.log('METADATA:', METADATA) // Shows in Logs Explorer
console.log('entry:', entry) // Shows in Logs Explorer
log.write(entry) // Results in Error: 7 PERMISSION_DENIED
return {
exVersion,
exId,
}
})
If I run it from the CLI using firebase function:shell, the log entry is created correctly, so I'm pretty confident the code is correct.
OK, I finally tracked it down. According to this answer, the service account used by firebase functions is {project-id}#appspot.gserviceaccount.com, and in my project, that account did not have the 'Logs Writer' role. Adding that role solves the problem.
I find it odd that the firebase functions don't need that role to log messages using console.log(), but perhaps that call is intercepted by the functions environment, and the logs are written as a different service account. It also explains why the functions running locally were able to write the logs, as they run using the 'owner' service account, which has full access.
According to the Firebase documentation page you have linked:
The recommended solution for logging from a function is to use the
logger SDK. You can instead use standard JavaScript logging calls such
as console.log and console.error, but you first need to require a
special module to patch the standard methods to work correctly:
require("firebase-functions/lib/logger/compat");
Once you have required the logger compatibility module, you can use console.log() methods as normal in your code.
Thus you might to require this library, however I am not sure this is producing your "Error: 7 PERMISSION_DENIED error, but you might also try some solutions that have worked for some members of the community.
Perhaps the logging API is not enabled in your project. You'll get a permission denied error when attempting to use it in that case.
It's a couple levels in, but the guide you linked points to
https://github.com/googleapis/nodejs-logging#before-you-begin, which includes a step to "Enable the Cloud Logging API"

Firebase Callable Function: Response for preflight in invalid

I have created a Firebase callable function, with a simple text return, but am receiving an error when I call the function, both on local and on my deployed app.
The callable function is a simple function to return some text for now:
exports.getSomeInfo = functions.https.onCall(async (data, context) => {
return 'some info';
});
In my app I load the function with:
const getSomeInfo = firebase.functions().httpsCallable('getSomeInfo');
And call it in the app with:
getSomeInfo();
This produces an error of:
Failed to load https://us-central1-[project-ID].cloudfunctions.net/getSomeInfo: Response for preflight is invalid (redirect)
This error occurs when calling the function on local using firebase serve and on the deployed app.
Viewing the logs in the Firebase Console shows no logs or errors.
Other issues mention this could be a CORS issue, or an incorrect Firebase config. I've ensured the Firebase config is correct. And tried a few of the CORS solutions, but continue to get the error above.
Using Firebase#5.5.2.
What else could be causing this error?
As indicated in the documentation, for an HTTPS Callable function you need to "return data that can be JSON encoded".
So if you do something like the following, it should work.
exports.getSomeInfo = functions.https.onCall((data, context) => {
return {result: 'some info'};
});
Update: removed the async
April 2020, I just learned the hard way that callable functions have their module name prepended...
In index.js:
const functions = require('firebase-functions')
// ...
exports.callable = require('./callable')
In callable.js:
const functions = require('firebase-functions');
// ... other stuff
exports.myCloudFunction = functions.https.onCall((data, context) => {
// ...
The way to call this "myCloudFunction" from a JS client is to use its name, prepended with its module name, like this
const fn = firebase.functions().httpsCallable("callable-myCloudFunction")
fn().then(result => { //...
This is documented nowhere, as far as I have found, and, as others have mentioned, almost any error that occurs prior to actually executing the cloud function ends up mislabeled as a CORS error.
After trying across 2 days a variety of refreshes/clean-ups and stuff with CORS, finally found it working after first deleting the function via Firebase console and then deploying the function.
In my case it seems the deployed version got corrupted somehow. It started yesterday when deploy for functions was getting stuck - it would hang and never exit - even though Firebase Status page said all is well. It lasted all day, and I finally let it go to see if it will work today. I thought it was my code, but the deploy is back to working today.
This happened to me a couple days ago. The problem was that when i ran firebase deploythe functions in my src directory were not being compiled. There were typescript errors which stopped it from compiling. You can see if it compiled by checking your lib folder and index.ts inside there I believe.

Firebase Admin 6.2.0 upgrade issue: server can't access Realtime Database

I've recently upgraded my Google Cloud Endpoints server from Firebase Admin 4.1.2 to 6.2.0. After the upgrade, however, the server does not seem to be able to access my Firebase Realtime Database in the way that it could before the upgrade.
The only code I've changed, apart from the Gradle file where I specify Firebase Admin 6.2.0 instead of 4.1.2, is in this initialization block:
static {
FirebaseOptions options = null;
FileInputStream serviceAccount =
null;
try {
serviceAccount = new FileInputStream(new File("WEB-INF/path_to_file.json"));
options = new FirebaseOptions.Builder()
//.setCredential(FirebaseCredentials.fromCertificate(serviceAccount)) OLD VERSION
.setCredentials(GoogleCredentials.fromStream(serviceAccount)) // NEW VERSION
.setDatabaseUrl(FIREBASE_NAME)
.build();
FirebaseApp.initializeApp(options);
} catch (Exception e) {
Log.warning(e.getMessage());
e.printStackTrace();
}
}
The only line that has changed here is the setCredentials() line.
My current hypothesis is that the problem is some kind authentication issue. But presumably there can't be anything wrong with the service account key in the json file, otherwise the old version of the server would also have the same problem. Has anyone encountered this kind of issue before? Any theories as to what the source of problem might be?
UPDATE: I've tried playing around with the initialization block, seeing what happens if I comment out the setCredentials() line, or give the wrong path to the FileInputStream, or pass the wrong url to setDatabaseUrl(). In all of those cases, I log some kind of error which indicates that the initialization has failed. With the code as it is above, however, I do not log any error. So the problem remains a mystery.
The test code I'm using to try to access my Realtime Database is very simple:
final FirebaseDatabase database = FirebaseDatabase.getInstance();
final DatabaseReference ref = database.getReferenceFromUrl(FIREBASE_NAME);
Map<String, Object> testMap = new HashMap<String, Object>();
testMap.put("test", "test");
ref.child("server_test").updateChildrenAsync(testMap);
Nothing gets written, however.
By a process of elimination, I eventually managed to track the source of the problem down to my appengine-web.xml file. That file contained one line which needed to be changed in order for the upgraded server to work properly:
Before: <url-stream-handler>urlfetch</url-stream-handler>
After: <url-stream-handler>native</url-stream-handler>
If anyone faces a similar problem, I hope this might prove useful.

Get detailed error for exception in SignalR Core Hub method execution

When I call Hub method I get frame response:
{"invocationId":"1","type":3,"error":"An error occurred while updating
the entries. See the inner exception for details."}
How can I get detailed error report (row and file where error occurred) without manually debugging and using step over and check where the code raise exception.
On net I found plenty codes where EnableDetailedErrors is used
services.AddSignalR(options =>
{
options.Hubs.EnableDetailedErrors = true;
});
but options (at least in version 1.0.0-alpha2-final) does not have property Hubs.
This is what you need to do in core (not sure the exact version this was added):
// signalR
services.AddSignalR(options =>
{
if (Environment.IsDevelopment()) {
options.EnableDetailedErrors = true;
}
});
It goes without saying that the reason this is disabled by default in production is for security reasons. So be careful not to expose things you may not wish 'hackers' to see in any of the exceptions you may throw.
Implementing the above setting will reveal a more detailed message in the browser console, whcih you can also see in the websocket debugging tab:
Quick tip:
I've set up SignalR twice now on ASPNetCore and I think I've made the same mistake both times:
// from typescript client arguments are passed like this
this.hubConnection.invoke('SendMessage', 'simon', 'hello');
// not like this
this.hubConnection.invoke('SendMessage', ['simon', 'hello']);
Also invoke will wait for a response, while send does not. So you may not see errors using send.
Currently the option to enable detailed errors is not implemented. There is an issue tracking this. My recommendation would be to turn on logging on the server side - the original exception will be logged there.

Resources