/** * Clean the server, aborting the current sync. * * <p> * * <ol> * <li>Wipe the server storage. * <li>Reset all stages and purge cached state: (meta/global and crypto/keys records). * <li>Upload fresh meta/global record. * <li>Upload fresh crypto/keys record. * <li>Restart the sync entirely in order to re-download meta/global and crypto/keys record. * </ol> * * @param session the current session. * @param freshStartDelegate delegate to notify on fresh start or failure. */ protected static void freshStart( final GlobalSession session, final FreshStartDelegate freshStartDelegate) { Logger.debug(LOG_TAG, "Fresh starting."); final MetaGlobal mg = session.generateNewMetaGlobal(); session.wipeServer( session.getAuthHeaderProvider(), new WipeServerDelegate() { @Override public void onWiped(long timestamp) { Logger.debug( LOG_TAG, "Successfully wiped server. Resetting all stages and purging cached meta/global and crypto/keys records."); session.resetAllStages(); session.config.purgeMetaGlobal(); session.config.purgeCryptoKeys(); session.config.persistToPrefs(); Logger.info(LOG_TAG, "Uploading new meta/global with sync ID " + mg.syncID + "."); // It would be good to set the X-If-Unmodified-Since header to `timestamp` // for this PUT to ensure at least some level of transactionality. // Unfortunately, the servers don't support it after a wipe right now // (bug 693893), so we're going to defer this until bug 692700. mg.upload( new MetaGlobalDelegate() { @Override public void handleSuccess( MetaGlobal uploadedGlobal, SyncStorageResponse uploadResponse) { Logger.info( LOG_TAG, "Uploaded new meta/global with sync ID " + uploadedGlobal.syncID + "."); // Generate new keys. CollectionKeys keys = null; try { keys = session.generateNewCryptoKeys(); } catch (CryptoException e) { Logger.warn( LOG_TAG, "Got exception generating new keys; failing fresh start.", e); freshStartDelegate.onFreshStartFailed(e); } if (keys == null) { Logger.warn( LOG_TAG, "Got null keys from generateNewKeys; failing fresh start."); freshStartDelegate.onFreshStartFailed(null); } // Upload new keys. Logger.info(LOG_TAG, "Uploading new crypto/keys."); session.uploadKeys( keys, new KeyUploadDelegate() { @Override public void onKeysUploaded() { Logger.info(LOG_TAG, "Uploaded new crypto/keys."); freshStartDelegate.onFreshStart(); } @Override public void onKeyUploadFailed(Exception e) { Logger.warn(LOG_TAG, "Got exception uploading new keys.", e); freshStartDelegate.onFreshStartFailed(e); } }); } @Override public void handleMissing(MetaGlobal global, SyncStorageResponse response) { // Shouldn't happen on upload. Logger.warn(LOG_TAG, "Got 'missing' response uploading new meta/global."); freshStartDelegate.onFreshStartFailed( new Exception("meta/global missing while uploading.")); } @Override public void handleFailure(SyncStorageResponse response) { Logger.warn( LOG_TAG, "Got failure " + response.getStatusCode() + " uploading new meta/global."); session.interpretHTTPFailure(response.httpResponse()); freshStartDelegate.onFreshStartFailed(new HTTPFailureException(response)); } @Override public void handleError(Exception e) { Logger.warn(LOG_TAG, "Got error uploading new meta/global.", e); freshStartDelegate.onFreshStartFailed(e); } }); } @Override public void onWipeFailed(Exception e) { Logger.warn(LOG_TAG, "Wipe failed."); freshStartDelegate.onFreshStartFailed(e); } }); }