Haris Hashim
Haris Hashim

Reputation: 55

Google Cloud Endpoint execute async code in endpoints

I am trying to authenticate client token created by Firebase authentication library in Android in GCE endpoint.

The guide of how to do this can be found here

Basically I need to call this code snippet from the end point (i.e. server backend code not android code).

FirebaseAuth.getInstance().verifyIdToken(idToken)
    .addOnSuccessListener(new OnSuccessListener<FirebaseToken>() {
        @Override
        public void onSuccess(FirebaseToken decodedToken) {
            String uid = decodedToken.getUid();
            // ...
        }
});

Let say I want to execute that code and return the user to android client code. How should I do that?

This is my sample code that does not make sense. But it demonstrate what I want to do!

@ApiMethod(name = "serverAuth")
public MyUser serverAuth(@Named("token") String token) {
    FirebaseAuth.getInstance().verifyIdToken(token)
            .addOnSuccessListener(new OnSuccessListener<FirebaseToken>() {
                @Override
                public void onSuccess(FirebaseToken decodedToken) {
                    String uid = decodedToken.getUid();
                    String email = decodedToken.getEmail();
                    String name = decodedToken.getName();
                    Map<String, Object> claims = decodedToken.getClaims();

                    String claimString = "";

                    for (Object claim : claims.values()) {
                        claimString += claims.toString();
                    }

                    MyUser user = new MyUser(uid, email, name, claimString);
                    //How to return this user?

                }
            });

    //This is compile error since user varriable does not exist here    
    return user;

}

I have google search how to execute async code in GCE endpoints. But getting nowhere with that. What I get is something about code execution that is blocking until done and then return the user. But how to code so that async code as above become blocking?

Upvotes: 4

Views: 230

Answers (1)

Benoit
Benoit

Reputation: 5394

CountDownLatch is the magic class you need. It will let you wait till the OnSuccessListener is actually completed.

Adapt your method this way: (I removed the steps that lead to MyUser's creation in order to focus on important points.)

@ApiMethod(name = "serverAuth")
public MyUser serverAuth(@Named("token") String token) {
    final List<MyUser> users = new ArrayList<>();
    final CountDownLatch cdl = new CountDownLatch(1);
    FirebaseAuth.getInstance().verifyIdToken(token)
            .addOnSuccessListener(new OnSuccessListener<FirebaseToken>() {
                @Override
                public void onSuccess(FirebaseToken decodedToken) {
                    // ... init uid, email, name and claimString
                    users.add(new MyUser(uid, email, name, claimString));
                    cdl.countDown();
                }
            });
    try {
        cdl.await(); // This line blocks execution till count down latch is 0
    } catch (InterruptedException ie) {

    }
    if (users.size() > 0) {
        return users.get(0);
    } else {
        return null ;
    }
}

This is the basic version of what you need. IMHO, it requires 2 more improvements :

  • You should also take the possibility of failure into account :

    FirebaseAuth.getInstance().verifyIdToken(token)
    .addOnSuccessListener(new OnSuccessListener<FirebaseToken>() {
        @Override
        public void onSuccess(FirebaseToken decodedToken) {
            cdl.countDown();
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            // log error, ...
            cdl.countDown();
        }
    });
    
  • You should also take the possibility that none of the listeners are called. In this situation your method will never return. To avoid that, you can set a timeout on the await() method :

    try {
         // This line blocks execution till count down latch is 0
         // or after 30 seconds.
        cdl.await(30l, TimeUnit.SECONDS);
    } catch (InterruptedException ie) {
    
    }
    

That's it. Hope this may help.

Upvotes: 4

Related Questions