React Native Could not reach Cloud Firestore backend - javascript

I was previously using firebase realtime database however now want to switch over to Cloud Firestore but am getting the below error, even when authenticated. I'm currently using Android Simulator, tried disabling my realtime database but cannot find a solution.
Firebase v5.4.2
[2018-09-02T12:53:42.064Z] #firebase/firestore:', 'Firestore (5.0.4):
Could not reach Cloud Firestore backend. Backend didn't respond within
10 seconds. This typically indicates that your device does not have a
healthy Internet connection at the moment. The client will operate in
offline mode until it is able to successfully connect to the backend.
My config is setup:
{
"apiKey": "apiKey",
"authDomain": "authDomain.firebaseapp.com",
"databaseURL": "https://databaseURL.firebaseio.com",
"projectId": "projectID",
"storageBucket": "storageBucket.appspot.com",
"messagingSenderId": "messagingSenderId"
}
As per docs I'm adding a users collection. Note that I do not get into the .then or the .catch statement even if I setup a users collection manually against the database.
onTestPress() {
console.log("onTestPress");
var db = firebase.firestore();
//console.log(db);
const settings = { timestampsInSnapshots: true };
db.settings(settings);
db.collection("users").add({
first: "Ada",
last: "Lovelace"
}).then(function (docRef) {
console.log("adding document: ", docRef.id);
}).catch(function (error) {
console.log("Error adding document: ", error);
});
db.collection("users").get().then((querySnapshot) => {
console.log(`querySnapshot: ${querySnapshot}`)
querySnapshot.forEach((doc) => {
console.log(`${doc.id} => ${JSON.stringify(doc.data())}`);
});
});
}
This is from Android Logcat you can see the .get() query returns the local copy. Only thing suspicious is the duplicate layer name?
09-02 14:05:37.811 2987-4016/com.myApp I/ReactNativeJS: onTestPress
09-02 14:05:47.837 2987-4016/com.myApp E/ReactNativeJS: '[2018-09-02T13:05:47.837Z] #firebase/firestore:', 'Firestore (5.0.4): Could not reach Cloud Firestore backend. Backend didn\'t respond within 10 seconds.\nThis typically indicates that your device does not have a healthy Internet connection at the moment. The client will operate in offline mode until it is able to successfully connect to the backend.'
09-02 14:05:47.849 2987-4016/com.myApp I/ReactNativeJS: querySnapshot: [object Object]
09-02 14:05:47.849 2987-4016/com.myApp I/ReactNativeJS: 3jifIc5kyEkGU4Bzvau9 => {"first":"Ada","last":"Lovelace"}
09-02 14:05:47.858 1431-1431/? D/SurfaceFlinger: duplicate layer name: changing com.myApp/com.myApp.MainActivity to com.myApp/com.myApp.MainActivity#1
09-02 14:05:47.931 2987-3021/com.myApp D/EGL_emulation: eglMakeCurrent: 0x9d7857e0: ver 3 0 (tinfo 0x9d783540)
Here's my import:
import firebase from "firebase";
import '#firebase/firestore'
Rules setup which should allow read and write?
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this rule set in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
I'm really not sure what else I can check so any advise would be greatly appreciated!

I also had this issue. The warning should appear after 10 seconds. but in my case, it appears when i load the component, without timeout. because my laptop's time in not correct. I did correct time and still had that issue. so i had to turn on "Set time automatically" and "Set time zone automatically" in "Date & time" settings in windows. everything works out for me.

Related

Debugging firebase RT database connection

I'm following this tutorial on building in-app presence using cloud firestore and they recommend using Firebase realtime database. The relevant bit of code for this question is:
database.onValue(database.ref(db, '.info/connected'), function (snapshot) {
if (snapshot.val() == false) {
// Instead of simply returning, we'll also set Firestore's state
// to 'offline'. This ensures that our Firestore cache is aware
// of the switch to 'offline.'
console.log('not connected to rtdb');
firestore.setDoc(userStatusFirestoreRef, isOfflineForFirestore);
return;
};
userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function () {
console.log('connected to rtdb');
userStatusDatabaseRef.set(isOnlineForDatabase);
// We'll also add Firestore set here for when we come online.
firestore.setDoc(userStatusFirestoreRef, isOnlineForFirestore);
});
});
The line not connected to rtdb consistently prints to my console, but I haven't seen connected to rtdb once. Is there an additional step I need to do to establish a connection to the realtime database?

Does Firebase Firestore keep a local copy of snapshot

I am using firebase firestore for my chat room application.
I have a function to send messages to firebase as
const sendMessageHandler = message => {
if (message) {
firestore()
.collection(`ChatRooms/${roomId}/messages`)
.doc(moment().format('YYYY-MM-DD-HH-mm-sssss'))
.set({
message: Encrypt(message),
userId: userId,
});
}
};
and I am fetching messages into flatlist only from firestore as
// this messages const is getting data only from firestore
const [messages, setMessage] = useState([]);
firestore()
.collection(`ChatRooms/${roomId}/messages`)
.onSnapshot(
querySnapshot => {
const messages = [];
querySnapshot.forEach(dataSnapshot => {
messages.push({
id: dataSnapshot.id,
message: dataSnapshot.data().message,
userId: dataSnapshot.data().userId,
});
});
setMessage(messages.reverse());
setLoading(false);
},
error => {
console.log('error : ', error);
},
);
// And now I am using this messages somewhere in return function of a component as :
<FlatList
data={messages}
renderItem={flatListItemRenderer}
inverted={true}
/>
Notice I am fetching only from firestore and not locally.
Now I turned off the internet and tried sending messages so this happens
The data has not been updated to firestore (of course because of no internet), but the flatlist has been updated with the new message !!
The only possibility I can think of is that the setter methods of firestore is storing data in both local and remote database and the getter method is first getting snapshot from local database and then remote database.
So the question is does #react-native-firebase/firestore keep a local snapshot also and updates both local and remote snapshot of data whenever we change something?
Github Link
Edit :
Firestore docs says
Firestore provides out of the box support for offline capabilities. When reading and writing data, Firestore uses a local database which synchronizes automatically with the server.This functionality is enabled by default, however it can be disabled if you need it to be disabled
I tried turning off persistence, but this property is related to storing data offline not the state. i.e, now when my app loads it fetch all the data directly from server(previously fetching from storage and server both), but the flatlist still updates with the new message(maybe it is storing some state like useState also???)
The Firestore SDK keeps a local copy of:
All data that you have an active listener for.
All pending writes.
In addition, if offline persistence is enabled, it also keeps a local copy of data that your code has recently read.
When you make a write operation, the SDK:
Writes your operation to its queue of pending writes.
Fires an event for any local listeners.
Tries to synchronize the pending write with the server.
Steps 1 and 2 always happen, regardless of whether you are online or offline. Only step 3 won't complete immediately when you are offline.

Is there a way to close the connection after using firebase.initializeApp() with Cloud Firestore?

I'm attempting to make a Discord.js command that uploads data to Cloud Firestore. It works, just if I attempt to reuse the command it reruns the firebase.initializeApp() line, which throws an error. Is there any way to disconnect after I have uploaded the data?
It is not recommended to disconnect - the time and processing cycle cost of .initializeApp() is prohibitive unless these calls are quite rare.
There are a few of valid approaches:
=> Keep a state value that indicates that the app is already initialized
=> initialize firebase at a "higher point" in your code to avoid reloading the module
=> I believe you can actually "ask" firebase if there is a running app, in which case don't re-initialize (const app = firebase.app())
If for some reason you do need to remove a firebase app instance:
const app = firebase.app(); //retrieves the default instance
app.delete()
.then(function() {
console.log("App deleted successfully");
})
.catch(function(error) {
console.log("Error deleting app:", error);
});

Administrator Views for a Firebase Web Application: How To

My Firebase web app requires administrator access, i.e., the UI should show a few things only for admins (an 'administrator' section). I came up with the below as a means to authorize the UI to display the admin section for valid admins only. My question is, good or bad? Is this a sound means of authorizing? ...so many ways to do this. This particular way requires me to configure admins in the security rules (vs in a node/tree in a db/firestore)
My idea is that if the .get() fails due to unauthorized access, I tell my app logic the user is not an admin, if the .get() succeeds my logic shows the 'admin' sections. Of course, the 'sections' are just HTML skeletons/empty elements populated by the database so even if the end user hacks the JS/logic, no real data will be there - only the empty 'admin section' framework.
function isAdmin(){
return new Promise(function(resolve, reject){
var docRef = firebase.firestore().collection("authorize").doc("admin");
docRef.get().then(function(result) {
if (result) {
resolve (true);
}
}).catch(function(error) {
resolve (false);
});
});
}
The firestore rule specifies the 'admins' by UID.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid == "9mB3UxxxxxxxxxxxxxxxxxxCk1";
}
}
}
You're storing the role of each user in the database, and then looking it up in the client to update its UI. This used to be the idiomatic way for a long time on realtime database, and it still works on Firestore.
The only thing I'd change is to have the rules also read from /authorize/admin, instead of hard-coding the UID in them. That way you only have the UID in one place, instead of having it in both the rules and the document.
But you may also want to consider an alternative: set a custom claim on your admin user, that you can then read in both the server-side security rules (to enforce authorized access) and the front-end (to optimize the UI).
To set a custom claim you use the Firebase Admin SDK. You can do this on a custom server, in Cloud Functions, but in your scenario it may be simpler to just run it from your development machine.
Detailed How To: Firebase has what's called Custom Claims for this functionality as detailed in their Control Access with Custom Claims and Security Rules. Basically, you stand up a separate node server, install the Firebase AdminSDK:
npm install firebase-admin --save
Generate/Download a Private Key from the Service Accounts tab in the Firebase Console and put that on your node server. Then simply create a bare bones node app to assign Custom Claims against each UID (user) that you wish. Something like below worked for me:
var admin = require('firebase-admin');
var serviceAccount = require("./the-key-you-generated-and-downloaded.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://xxxxxxxxxxxxxxxxxxxx.firebaseio.com"
});
admin.auth().setCustomUserClaims("whatever-uid-you-want-to-assign-claim-to", {admin: true}).then(() => {
console.log("Custom Claim Added to UID. You can stop this app now.");
});
That's it. You can now verify if the custom claim is applied by logging out of your app (if you were previously logged in) and logging back in after you update your web app's .onAuthStateChanged method:
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
firebase.auth().currentUser.getIdToken()
.then((idToken) => {
// Parse the ID token.
const payload = JSON.parse(window.atob(idToken.split('.')[1]));
// Confirm the user is an Admin.
if (!!payload['admin']) {
//showAdminUI();
console.log("we ARE an admin");
}
else {
console.log("we ARE NOT an admin");
}
})
.catch((error) => {
console.log(error);
});
}
else {
//USER IS NOT SIGNED IN
}
});

Session cookies not working in Electron

I'm looking at implementing a login system in an Electron[0] application which I'm building but getting stuck on the part of handling the session. Basically I want to store the users session so it is persisted between application restarts (if "Remember me" is enabled).
I have to make use of an existing back-end which works with cookie authentication and I'm not able to change anything there.
From the Electron documentation on the Session object[1] I gathered that I should be using a partition like f.e. persist:someName in order to have a persistent storage, but this is not persisted between application restarts as it seems.
The way I currently set the cookie is as follows:
// main-process/login.js
const session = require('electron').session;
const currentSession = session.fromPartition('persist:someName').cookies;
currentSession.set({
name: 'myCookie',
url: 'https://www.example.com',
value: 'loggedin=1',
expirationDate: 1531036000
}, function(error) {
console.log('Cookie set');
if (error) {
console.dir(error);
}
});
After running this, I see the Cookie set output, but when restarting the app and running the following code:
// main.js
const session = require('electron').session;
const currentSession = session.fromPartition('persist:someName').cookies;
currentSession.get({}, function(error, cookies) {
console.dir(cookies);
if (error) {
console.dir(error);
}
});
The output returned is [].
Any pointers as to what I'm doing wrong or need to do differently would be highly appreciated!
[0] http://electron.atom.io
[1] http://electron.atom.io/docs/api/session/
An alternative might be to take a look at electron-json-storage. Using this plugin, you can write JSON to a system file throughout the user experience and then recall that file on the application load to replace the user "state".

Categories