Some test text!
Web / Guides / Connect to Server
In realtime collaboration, a server will merely act as an online database that triggers events upon data creation/modification/deletion. As long as the above requirement is met, your server can be built in any language and stack of your choice. For the simplicity of this guide, we will be using Firebase.
storageBucket
is empty, close the popup and try again (that's a known bug from Firebase).server.js
.window.Server = function() {
const config = {
apiKey: "YOUR_API_KEY",
authDomain: "PROJECT_ID.firebaseapp.com",
databaseURL: "https://PROJECT_ID.firebaseio.com",
storageBucket: "PROJECT_ID.appspot.com",
messagingSenderId: "YOUR_SENDER_ID"
};
firebase.initializeApp(config);
this.annotationsRef = firebase.database().ref().child('annotations');
this.authorsRef = firebase.database().ref().child('authors');
};
Server.prototype.bind = function(action, callbackFunction) {
switch(action) {
case 'onAuthStateChanged':
firebase.auth().onAuthStateChanged(callbackFunction);
break;
case 'onAnnotationCreated':
this.annotationsRef.on('child_added', callbackFunction);
break;
case 'onAnnotationUpdated':
this.annotationsRef.on('child_changed', callbackFunction);
break;
case 'onAnnotationDeleted':
this.annotationsRef.on('child_removed', callbackFunction);
break;
default:
console.error('The action is not defined.');
break;
}
};
Server.prototype.checkAuthor = function(authorId, openReturningAuthorPopup, openNewAuthorPopup) {
this.authorsRef.once('value', authors => {
if (authors.hasChild(authorId)) {
this.authorsRef.child(authorId).once('value', author => {
openReturningAuthorPopup(author.val().authorName);
});
} else {
openNewAuthorPopup();
}
});
};
Server.prototype.signInAnonymously = function() {
firebase.auth().signInAnonymously().catch(error => {
if (error.code === 'auth/operation-not-allowed') {
alert('You must enable Anonymous auth in the Firebase Console.');
} else {
console.error(error);
}
});
};
From the Firebase console click the "Authentication" button on the left panel and then click the "Sign-in Method" tab, just to the right of "Users". From this page click the "Anonymous" button and choose to enable Anonymous login.
Define data-write methods using firebase.database.Reference#set and firebase.database.Reference#remove.
Server.prototype.createAnnotation = function(annotationId, annotationData) {
this.annotationsRef.child(annotationId).set(annotationData);
};
Server.prototype.updateAnnotation = function(annotationId, annotationData) {
this.annotationsRef.child(annotationId).set(annotationData);
};
Server.prototype.deleteAnnotation = function(annotationId) {
this.annotationsRef.child(annotationId).remove();
};
Server.prototype.updateAuthor = function(authorId, authorData) {
this.authorsRef.child(authorId).set(authorData);
};
Last but not least, you should add server-side permission rules for writing data. Although client-side permission checking is supported in WebViewer, every user does have access to each annotation's information (including authorId and authorName). Thus, data-write permission should be regulated in the server as well. In this guide, we have used Firebase's Database Rules.
{
"rules": {
".read": "auth != null",
"annotations": {
"$annotationId": {
".write": "auth.uid === newData.child('authorId').val() || auth.uid === data.child('authorId').val() || auth.uid === newData.child('parentAuthorId').val() || auth.uid === data.child('parentAuthorId').val()"
}
},
"authors": {
"$authorId": {
".write": "auth.uid === $authorId"
}
}
}
}
Trial setup questions? Ask experts on Discord
Need other help? Contact Support
Pricing or product questions? Contact Sales