I am using Firebase to monitor machines across the building.
So architecture is multiple front-ends and multiple machines.
At a certain moment I want to be able to trigger some actions on these machines like:
take screenshot and put to ftp
encode a certain video file
analyze a large data-set
I am used to Actionscript, there are NetConnection and
Client objects to whom one could invoke remote methods.
Is there something similar in Firebase ?
How would you implement such a feature easily ?
I thought of having a message box, using an Array, where a message could be a data structure like:
{
'client_id': 'xxx-yyy-zzz',
'name': 'takeScrenshot',
'body': { 'creator': 'my-name' },
'timestamp': 1406214344
}
How it might work
a method call is a message entering this message box Array
listening with value_changed over this message box
pop item from array (this will trigger another value changed)
use the item to perform async operation
when async operation is done, using the client_id, notify the invoker about the operation
But to implement it correctly a lot of work must be done, does anyone know if there is an easy way to achieve this kind of functionality ?
Since Firebase is a powerful backend service, scalable, and has a RESTful API in addition to SDKs (not yet for Python, unfortunately), it generally makes the most sense to just use it directly, rather than fashioning API services on top of it.
One fast and effective way to do this is to utilize a queue approach. Have each client write data into an in/ path, and have the recipient of the event listen for child_added on that path. Then perform the remote invocation, and write data back to an out/ path for the requesting client.
client
// send it
var ref = new Firebase(QUEUE_URL);
var request = ref.child('in').push( requestData );
// wait for a reply and remove after processing
ref.child('out/'+request.name()).on('value', function(snap) {
if( snap.val() !== null ) {
console.log(snap.val());
request.remove();
// stop listening
snap.ref().off();
}
});
remote service
var ref = new Firebase(QUEUE_URL);
// listen for queue events
ref.child('in').on('child_added', function(snap) {
/*
... process queue event ...
*/
doneProcessing(snap, resultData);
});
function doneProcessing(snap, results) {
ref.child('out/'+snap.name()).set(results);
snap.ref().remove();
}
Related
So I am attempting to use the Cloud Firestore offline cache ONLY as an API for my instrumentation tests, to avoid having to read and write from the server database during my integration tests.
First, in my test setup method, I call this method
protected fun setFirestoreToOfflineMode() {
Tasks.await(FirebaseFirestore.getInstance().disableNetwork())
}
Then, at the beginning of each relevant test, I use
fun givenHasTrips(vararg trips: Trip) {
GlobalScope.launch(Dispatchers.Default) {
trips.forEach {
firestoreTripApi.put(it)
}
}
}
In that put method, I have the following code:
try {
Tasks.await(tripCollection().document(tripData.id).set(tripData)),
firestoreApiTimeoutSeconds, TimeUnit.SECONDS)
Either.Right(Unit)
} catch (e: Throwable) {
Either.Left(Failure.ServerError)
}
I am calling the set() method and am waiting for a successful result in order to be able to return that the operation was a success, to update my UI afterward.
What happens is the cache DB is written correctly BUT the "set()" function times out because the database is in offline mode. I have read that Firestore only confirms a success if the Server DB was correctly written. If that is the case, I do not know if it is possible to have this call not time-out when operating strictly in offline-cache mode.
Is there a solution to have Firestore act as if the local cache database was the source of truth and return successes if placed in offline mode, just for tests?
The Task returned by the methods that modify the database (set, update, delete) only issues a callback when the data is fully committed to the cloud. There is no way to change this behavior.
What you can do instead is set up a listener to the document(s) that are expected to change, and wait for the listener to trigger. The listener will trigger even while offline.
Currently developing a hybrid mobile app using ionic. When the app starts up, and a user writes to the Realtime Database for the first time, it's always delayed by around 10 or more seconds. But any subsequent writes are almost instantaneous (less than 1 second).
My calculation of delay is based on watching the database in the Firebase console.
Is this a known issue, or maybe I am doing something wrong. Please share your views.
EDIT:
The write is happening via Firebase Cloud Function.
This is the call to the Firebase Cloud function
this.http.post(url+"/favouritesAndNotes", obj, this.httpOptions)
.subscribe((data) => {
console.log(data);
},(error)=>{
console.log(error);
});
This is the actual function
app.post('/favouritesAndNotes', (request, response) => {
var db = admin.database().ref("users/" + request.body.uid);
var favourites = request.body.favourites;
var notes = request.body.notes;
if(favourites!==undefined){
db.child("favourites/").set(favourites);
}
if(notes!==undefined){
db.child("notes/").set(notes);
}
console.log("Write successfull");
response.status(200).end();
});
The first time you interact with the Firebase Database in a client instance, the client/SDK has to do quite some things:
If you're using authentication, it needs to check if the token that it has is still valid, and if not refresh it.
It needs to find the server that the database is currently hosted on.
It needs to establish a web socket connection.
Each of these may take multiple round trips, so even if you're a few hundred ms from the servers, it adds up.
Subsequent operations from the same client don't have to perform these steps, so are going to be much faster.
If you want to see what's actually happening, I recommend checking the Network tab of your browser. For the realtime database specifically, I recommend checking the WS/Web Socket panel of the Network tab, where you can see the actual data frames.
Retrieving multiple documents in the loop with Firebase JavaScript library is almost as fast as retrieving one document. Whether it is thanks to websocket of anything else.
Doing same with the REST Api is linearly slow. Each request takes a bit less than one second, 10 GET requests takes about 9 seconds on my machine. Setting 'Connection' header to 'keep-alive' does not improve the speed.
Given that quote from Firebase docs, I'd like to know how can one optimise the speed of the multiple lookup requests via REST Api.
Is it really okay to look up each record individually? Yes. The Firebase protocol uses web sockets, and the client libraries do a great deal of internal optimization of incoming and outgoing requests. Until we get into tens of thousands of records, this approach is perfectly reasonable. In fact, the time required to download the data (i.e. the byte count) eclipses any other concerns regarding connection overhead.
You can use Firebase JavaScript SDK in node.js for backend functions to take advantage of sockets.
For example, I'm using JavaScript API to send SMS on child_added event in firebase.
var Firebase = require('firebase');
var ref = new Firebase('YOUR_FIREBASE_URL_REFERENCE');
ref.authWithCustomToken("YOUR_SECRET_TOKEN", function(error, aut$
if (error) {
console.log("Authentication Failed!", error);
} else {
console.log("Authenticated successfully with payload:", authData);
}
});
var messageRef = new Firebase('https://cozywait.firebaseio.com/messages');
messageRef.orderByChild('status').equalTo('requested').on('child_added', function(snaps$
console.log('Message notification sending to ', snapshot.val().number);
initSendSMS(snapshot);
});
Basically, I need to initiate a background process when a user logs in. The background process returns some sensitive data, the server side should further process it and then make it available for the client.
Is this where Meteor.Publish and Subscribe methods come into play? Or do I need to use Meteor.methods? Are there any other approaches?
For this kind of thing you might want to use a call instead of a publish. This is because the use case of the publish function is more to decide what the user should see & not really to process data (i.e do a web scrape or something and collect this) & the process might be blocking so all clients might to wait for this task to finish.
I would suggest you migrate over to meteorite: https://github.com/oortcloud/meteorite via
npm install -g meteorite
You would now have access to the wonderful collection of community packages at http://atmosphere.meteor.com.
Ted Blackman's event-horizon package lets you create events when the user logs in on the client.
You can then create an event for this:
Client Js
EventHorizon.fireWhenTrue('loggedIn',function(){
return Meteor.userId() !== null;
});
EventHorizon.on('loggedIn',function(){
Meteor.call("userloggedin", function(err,result) {
console.log("Ready")
if(result) {
//do stuff that you wanted after the task is complete
}
}
});
Server js
Meteor.methods({
'userloggedin' : function() {
this.unblock(); //unblocks the thread for long tasks
//Do your stuff to Meteor.user();
return true; //Tell the client the task is done.
}
});
is it possible to stop a web service from executing?
I have a flex web application that searches clients with both full name and client id, when searching by name sometimes the usuer just types the last name and it takes a long time.
Since the app is used when clients are waiting in line, I would like to be able to stop the search and use their full name or id instead, and avoid waiting for the results and then having to search the user manually within the results.
thanks
edit: Sorry, I didn't explain myself correctly, when I meant "web service" I actually meant mx.rpc.soap.mxml.WebService, I want to stop it from waiting for the result event and the fault event. thanks.
There is actually a cancel(..) method explicitly for this purpose, though it is a little burried. Using the cancel method will cause the result and fault handlers not to be called and will also remove the busy cursor etc.
Depending on how you run your searches (ie. separate worker process etc), it is also possible to extend this by added in a cancelSearch() web service method to kill these worker processes and free up server resources etc.
private var _searchToken:AsyncToken;
public function doSearch(query:String):void
{
_searchToken = this.searchService.doSearch(query);
}
protected function doSearch_resultHandler(event:ResultEvent):void
{
trace("doSearch result");
trace("TODO: Do stuff with results");
_searchToken = null;
}
protected function doSearch_faultHandler(event:FaultEvent):void
{
trace("doSearch fault: " + event.fault);
_searchToken = null;
}
public function cancelSearch():void
{
var searchMessageId:String = _searchToken.message.messageId;
// Cancels the last service invocation or an invokation with the
// specified ID. Even though the network operation may still
// continue, no result or fault event is dispatched.
searchService.getOperation("doSearch").cancel(searchMessageId);
_searchToken = null;
trace("The search was cancelled, result/fault handlers not called");
// TODO: If your web service search method is using worker processes
// to do a search and is likely to continue processing for some time,
// you may want to implement a 'cancel()' method on the web service
// to stop any search threads that may be running.
}
Update
You could use disconnect() to remove any pending request responders, but it also disconnects the service's connection. Then call initialize().
/Update
You cannot stop the web service from executing, because that's beyond the Flex app's control, but you can limit the processing of the web service's response. For instance on the app, have a button like Cancel Search which sets a boolean bSearchCanceled to true.
The result handler for the web service call checks bSearchCanceled; if true just return.