According to the docs Realm can notify you when certain actions are taking place like "every time a write transaction is committed". I am using the Realm Object Server and the first time a user opens my app a large set of data is synched from the server down to the app. I would like to show a loading screen and not present the main UI of my app until Realm has completed its initial sync. Is there a way to be notified / determine when this process is complete?
The realm.io website just posted documentation on how to do this.
Asynchronously Opening Realms
If opening a Realm might require a time-consuming operation, such as applying migrations or downloading the remote contents of a synchronized Realm, you should use the openAsync API to perform all work needed to get the Realm to a usable state on a background thread before dispatching to the given queue. You should also use openAsync with Realms that are set read-only.
For example:
Realm.openAsync({
schema: [PersonSchema],
schemaVersion: 42,
migration: function(oldRealm, newRealm) {
// perform migration (see "Migrations" in docs)
}
}, (error, realm) => {
if (error) {
return;
}
// do things with the realm object returned by openAsync to the callback
console.log(realm);
})
The openAsync command takes a configuration object as its first parameter and a callback as its second; the callback function receives a boolean error flag and the opened Realm.
Initial Downloads
In some cases, you might not want to open a Realm until it has all remote data available. In such a case, use openAsync. When used with a synchronized Realm, this will download all of the Realm’s contents before the callback is invoked.
var carRealm;
Realm.openAsync({
schema: [CarSchema],
sync: {
user: user,
url: 'realm://object-server-url:9080/~/cars'
}
}, (error, realm) => {
if (error) {
return;
}
// Realm is now downloaded and ready for use
carRealm = realm;
});
Related
I have a handler to initiate a password reset. It always returns a successful 200 status code, so that an attacker cannot use it to find out which email addresses are stored in the database. The problem is, if an email is in the database, it'll take a while for the request to be fulfilled (blocking user lookup and sending the actual email with a reset token). If the user is not in the db, the request returns very quickly, so an attacked would know the email is not there.
How would I go about returning the HTTP response right away while processing the request in the background?
pub async fn forgot_password_handler(
email_from_path: web::Path<String>,
pool: web::Data<Pool>,
redis_client: web::Data<redis::Client>,
) -> HttpResponse {
let conn: &PgConnection = &pool.get().unwrap();
let email_address = &email_from_path.into_inner();
// search for user with email address in users table
match users.filter(email.eq(email_address)).first::<User>(conn) {
Ok(user) => {
// some stuff omitted.. this is what happens:
// create random token for user and store a hash of it in redis (it'll expire after some time)
// send email with password reset link and token (not hashed) to client
// then return with
HttpResponse::Ok().finish(),
}
_ => HttpResponse::Ok().finish(),
}
}
You can use an Actix Arbiter to schedule an asynchronous task:
use actix::Arbiter;
async fn do_the_database_stuff(
email: String,
pool: web::Data<Pool>,
redis_client: web::Data<redis::Client>)
{
// async database code here
}
pub async fn forgot_password_handler(
email_from_path: web::Path<String>,
pool: web::Data<Pool>,
redis_client: web::Data<redis::Client>,
) -> HttpResponse {
let email = email_from_path.clone();
Arbiter::spawn(async {
do_the_database_stuff(
email,
pool,
redis_client
);
});
HttpResponse::Ok().finish()
}
If your database code is blocking, to prevent hogging the long-lived Actix worker threads, you could instead create a new Arbiter, with its own thread:
fn do_the_database_stuff(email: String) {
// blocking database code here
}
pub async fn forgot_password_handler(email_from_path: String) -> HttpResponse {
let email = email_from_path.clone();
Arbiter::new().exec_fn(move || {
async move {
do_the_database_stuff(email).await;
};
});
HttpResponse::Ok().finish()
}
This may be a bit more work because Pool and redis::Client are unlikely to be safe to share between threads, so you will have to solve that too. That's why I didn't include them in the example code.
It's better to use Arbiters than be tempted to spawn a new native thread with std::thread. If you mix the two, you can end up accidentally including code that messes up the worker. For example using std::thread::sleep in an async context would pause unrelated tasks that just happen to be scheduled on the same worker, and may not even have any effect on the task you intended.
Finally, you might also consider an architectural change. If you factor database-heavy tasks into their own microservices, you would solve this problem automatically. The web handler can then just send a message (Kafka, RabbitMQ, ZMQ, HTTP, or whatever you choose) and immediately return. This will let you scale the microservices independently of the webserver - 10x web server instances doesn't have to mean 10x database connections, if you only need one instance for the password reset service.
I am working on a game connect two players with firebase realtime databsee. but I want a way to can delete player data if lose his connection with the Internet.
This can be updated via the OnDisconnect method.
This original answer from Frank originally describes more details on the OnDisconnect method.
Read more about the interface here.
You can set up a "connected presence" with this Firebase example that uses the Realtime Database and Cloud Functions with OnDisconnect to show the status of a user.
Pulled from the example:
var userStatusDatabaseRef = firebase.database().ref('/status/' + uid);
firebase.database().ref('.info/connected').on('value', function(snapshot) {
// If we're not currently connected, don't do anything.
if (snapshot.val() == false) {
return;
};
// If we are currently connected, then use the 'onDisconnect()'
// method to add a set which will only trigger once this
// client has disconnected by closing the app,
// losing internet, or any other means.
userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() {
// The promise returned from .onDisconnect().set() will
// resolve as soon as the server acknowledges the onDisconnect()
// request, NOT once we've actually disconnected:
// https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect
// We can now safely set ourselves as 'online' knowing that the
// server will mark us as offline once we lose connection.
userStatusDatabaseRef.set(isOnlineForDatabase);
});
});
Is it possible to test the Meteor client while the server is running using tinytest? Here's my example testing the client only:
Tinytest.add("Add object to a collection", function(test) {
var people = new Meteor.Collection("people");
people.insert({"name": "Andrew"}, function(error, id) {
test.isNull(error);
});
});
For a fraction of a second this passes, but then it goes into the state of "waiting". I'm also positive that error is not null.
Meteor.Error {error: 404, reason: "Method not found", details: undefined}
I know this is happening because their is no server for the client to communicate with. When I try to run this test on the server and client, I continue to get the same issue with the client. Is there a way to test the client while the server is running?
Thanks, Andrew
Use new Meteor.Collection with no argument to create a stub collection that doesn't require the server. See the docs on Collections:
If you pass null as the name, then you're creating a local collection. It's not synchronized anywhere; it's just a local scratchpad that supports Mongo-style find, insert, update, and remove operations.
This is an async test, so you'll have to use addAsync.
Tinytest.addAsync("Add object to a collection", function(test, next) {
var people = new Meteor.Collection("people");
people.insert({"name": "Andrew"}, function(error, id) {
test.isNull(error);
next();
});
});
Note the next argument which signals that you are done in the callback.
Using Signalr (1.0.0-alpha2), I want to know if it is possible to add client functions after a connection has been started.
Say I create my connection and grab the proxy. Then I add some Server Fired client functions to the hub to do a few things. Then I start my connection. I then want to add some more Server Fired functions to my hub object. Is this possible?
var myHub= $.connection.myHub;
myHub.SomeClientFunction = function() {
alert("serverside called 'Clients.SomeClientFunction()'");
};
$.connection.hub.start()
.done(function() {
myHub.SomeNewClientFunction = function() {
alert("serverside called 'Clients.SomeNewClientFunction()'");
}
})
This example is not realistic, but I basically want to send my 'myHub' variable to a different object after the hub is started to subscribe to new events that the original code did not care for.
Real Life Example: A dashboard with a number of different hub events (new site visits, chat message, site error). I 'subscribe' after the connection has started and then pass my hub proxy to all of my different UI components to handle their specific 'message types'. Should I create separate Hubs for these or should I be able to add more Server Fired client functions on the fly?
Yes you can. Use the .on method.
Example:
myHub.on('somethingNew', function() {
alert("This was called after the connection started!");
});
If you want to remove it later on use the .off method.
I have the exact same situation. You might want to consider adding another layout of abstraction if you're trying to call it from multiple places.
Here's a preliminary version of what I've come up with (typescript).
I'll start with the usage. SignalRManager is my 'manager' class that abstracts my debuggingHub hub. I have a client method fooChanged that is triggered on the server.
Somewhere in the module that is using SignalR I just call the start method, which is not re-started if already started.
// ensure signalR is started
SignalRManager.start().done(() =>
{
$.connection.debuggingHub.server.init();
});
Your 'module' simply registers its callback through the manager class and whenever the SignalR client method is triggered your handler is called.
// handler for foo changed
SignalRManager.onFooChanged((guid: string) =>
{
if (this.currentSession().guid == guid)
{
alert('changed');
}
});
This is a simple version of SignalRManager that uses jQuery $.Callbacks to pass on the request to as many modules as you have. Of course you could use any mechanism you wanted, but this seems to be the simplest.
module RR
{
export class SignalRManager
{
// the original promise returned when calling hub.Start
static _start: JQueryPromise<any>;
private static _fooChangedCallback = $.Callbacks();
// add callback for 'fooChanged' callback
static onfooChanged(callback: (guid: string) => any)
{
SignalRManager._fooChangedCallback.add(callback);
}
static start(): JQueryPromise<any>
{
if (!SignalRManager._start)
{
// callback for fooChanged
$.connection.debuggingHub.client.fooChanged = (guid: string) =>
{
console.log('foo Changed ' + guid);
SignalRManager._fooChangedCallback.fire.apply(arguments);
};
// start hub and save the promise returned
SignalRManager._start = $.connection.hub.start().done(() =>
{
console.log('Signal R initialized');
});
}
return SignalRManager._start;
}
}
}
Note: there may be extra work involved to handle disconnections or connections lost.
Why this code shows "0"? Shouldn't it return "1"?
Messages = new Meteor.Collection("messages");
if (Meteor.is_client) {
Meteor.startup(function () {
alert(Messages.find().count());
});
}
if (Meteor.is_server) {
Meteor.startup(function () {
Messages.insert({text: "server says hello"});
});
}
If I do the "Messages.find().count()" later, it returns 1.
By default, when a Meteor client starts up, it connects to the server and subscribes to documents in any Meteor.Collection you defined. That takes some time to complete, since there's always some amount of delay in establishing the server connection and receiving documents.
Meteor.startup() on the client is a lot like $() in jQuery -- it runs its argument once the client DOM is ready. It does not wait for your client's collections to receive all their documents from the server. So the way you wrote the code, the call to find() will always run too early and return 0.
If you want to wait to run code until after a collection is first downloaded from the server, you need to use Meteor.subscribe() to explicitly subscribe to a collection. subscribe() takes a callback that will run when the initial set of documents are on the client.
See:
meteor-publish
and meteor-subscribe
Just to follow up with a code example of how to know when a collection is ready to use on the client.
As #debergalis described, you should use the Meteor.subscribe approach - it accepts a couple of callbacks, notably onReady
For example:
if(Meteor.isClient){
Meteor.subscribe("myCollection", {
onReady: function(){
// do stuff with my collection
}
});
}