Files
keepass2android/src/Kp2aBusinessLogic/database/SynchronizeCachedDatabase.cs

134 lines
4.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Android.App;
using Android.Content;
using KeePassLib.Serialization;
using keepass2android.Io;
using KeePass.Util;
namespace keepass2android
{
public class SynchronizeCachedDatabase: OperationWithFinishHandler
{
private readonly Context _context;
private readonly IKp2aApp _app;
private SaveDb _saveDb;
public SynchronizeCachedDatabase(IKp2aApp app, OnOperationFinishedHandler operationFinishedHandler)
: base(app, operationFinishedHandler)
{
_app = app;
}
public override void Run()
{
try
{
IOConnectionInfo ioc = _app.CurrentDb.Ioc;
IFileStorage fileStorage = _app.GetFileStorage(ioc);
if (!(fileStorage is CachingFileStorage))
{
throw new Exception("Cannot sync a non-cached database!");
}
StatusLogger.UpdateMessage(UiStringKey.SynchronizingCachedDatabase);
CachingFileStorage cachingFileStorage = (CachingFileStorage) fileStorage;
//download file from remote location and calculate hash:
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.DownloadingRemoteFile));
string hash;
//TODO remove
Thread.Sleep(5000);
MemoryStream remoteData;
try
{
remoteData = cachingFileStorage.GetRemoteDataAndHash(ioc, out hash);
Kp2aLog.Log("Checking for file change. Current hash = " + hash);
}
catch (FileNotFoundException)
{
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.RestoringRemoteFile));
cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
Kp2aLog.Log("Checking for file change: file not found");
return;
}
//check if remote file was modified:
var baseVersionHash = cachingFileStorage.GetBaseVersionHash(ioc);
Kp2aLog.Log("Checking for file change. baseVersionHash = " + baseVersionHash);
if (baseVersionHash != hash ||
true//TODO remove
)
{
//remote file is modified
if (cachingFileStorage.HasLocalChanges(ioc)
|| true //TODO remove
)
{
//conflict! need to merge
_saveDb = new SaveDb(_app, new ActionOnOperationFinished(_app, (success, result, activity) =>
{
if (!success)
{
Finish(false, result);
}
else
{
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
}
_saveDb = null;
}), _app.CurrentDb, false, remoteData);
_saveDb.SetStatusLogger(StatusLogger);
_saveDb.DoNotSetStatusLoggerMessage = true; //Keep "sync db" as main message
_saveDb.SyncInBackground = false;
_saveDb.Run();
_app.CurrentDb.UpdateGlobals();
_app.MarkAllGroupsAsDirty();
}
else
{
//only the remote file was modified -> reload database.
//note: it's best to lock the database and do a complete reload here (also better for UI consistency in case something goes wrong etc.)
_app.TriggerReload(_context, (bool result) => Finish(result));
}
}
else
{
//remote file is unmodified
if (cachingFileStorage.HasLocalChanges(ioc))
{
//but we have local changes -> upload:
StatusLogger.UpdateSubMessage(_app.GetResourceString(UiStringKey.UploadingFile));
cachingFileStorage.UpdateRemoteFile(ioc, _app.GetBooleanPreference(PreferenceKey.UseFileTransactions));
StatusLogger.UpdateSubMessage("");
Finish(true, _app.GetResourceString(UiStringKey.SynchronizedDatabaseSuccessfully));
}
else
{
//files are in sync: just set the result
Finish(true, _app.GetResourceString(UiStringKey.FilesInSync));
}
}
}
catch (Exception e)
{
Kp2aLog.LogUnexpectedError(e);
Finish(false, ExceptionUtil.GetErrorMessage(e));
}
}
public void JoinWorkerThread()
{
if (_saveDb != null)
_saveDb.JoinWorkerThread();
}
}
}