Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Firebase server timestamp to create a synchronized countdown timer on Android

I want to display a count down timer unified for all users. I choose a way to do it but i'm not sure if it is the best option.

server side:

  1. node server calls to Firebase with a server timestamp request.
  2. server added X millis to timestamp
  3. server updates Firebase db with the the new future timestamp

user side:

  1. receives a a future timestamp from db (created by the server)
  2. send a request to Firebase db with to receive the current server timestamp
  3. calculates delta between server timestamp and current timestamp (local)
  4. add the calculated delta to future timestamp received in stage 1
  5. displays the corrected count down time left.

The main issue i see with this method is that the user have unlimited read/write access to "timestamp" value. Can this be used against me to make fake calls to db thus increasing my Firebase usage (costing me money)

Is there a better way syncing all devices into a unified time in the future?

like image 594
zvikachu Avatar asked Nov 21 '16 15:11

zvikachu


1 Answers

While I didn't find perfect solution, there is a way to avoid needing to write to a field each time. Firebase offers a built-in field /.info/serverTimeOffset, which contains what Firebase thinks is the time difference between the client and server.

I'm using a class like this to convert timestamps received from the server to local timestamps to achieve a (decently) synced countdown.

public class ServerTimeSyncer {

    private static final String TAG = "ServerTimeSyncer";

    private DatabaseReference mServerTimeOffsetReference;
    private long mServerTimeOffset;

    public long convertServerTimestampToLocal(final long serverTimestamp) {
        return serverTimestamp - mServerTimeOffset;
    }

    public void startServerTimeSync() {
        if (mServerTimeOffsetReference == null) {
            mServerTimeOffsetReference = FirebaseDatabase.getInstance().getReference("/.info/serverTimeOffset");
            mServerTimeOffsetReference.addValueEventListener(mServerTimeOffsetListener);
        }
    }

    public void stopServerTimeSync() {
        if (mServerTimeOffsetReference != null) {
            mServerTimeOffsetReference.removeEventListener(mServerTimeOffsetListener);
            mServerTimeOffsetReference = null;
        }
    }

    private final ValueEventListener mServerTimeOffsetListener = new ValueEventListener() {
        @Override
        public void onDataChange(final DataSnapshot snapshot) {
            mServerTimeOffset = snapshot.getValue(Long.class);
            Log.i(TAG, "Server time offset set to: " + mServerTimeOffset);
        }

        @Override
        public void onCancelled(DatabaseError error) {
            Log.w(TAG, "Server time sync cancelled");
        }
    };

}

See https://firebase.google.com/docs/database/android/offline-capabilities#clock-skew for more info.

Additional note: It seems this is only triggered when starting the connection, so after changing your device time, the app must be restarted in order to get the correct offset.

like image 147
tvkanters Avatar answered Nov 10 '22 11:11

tvkanters