Bug 1608304 part 3 - Fix offline replication of LDAP address books; r=mkmelin
--HG-- extra : rebase_source : 5b1105f79ccb2a9c24a969c40a33f6ef6f0c71df extra : histedit_source : 56d769ac55fd52663fcec0d1a5512f549416ee05
This commit is contained in:
Родитель
decc05d54d
Коммит
5fc8ad38d2
|
@ -100,15 +100,21 @@ AddrBookDirectory.prototype = {
|
|||
// nothing else ever tells us to close them.
|
||||
|
||||
var connections = new Map();
|
||||
var closeObserver = {
|
||||
observe() {
|
||||
Services.obs.addObserver(() => {
|
||||
for (let connection of connections.values()) {
|
||||
connection.asyncClose();
|
||||
}
|
||||
connections.clear();
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(closeObserver, "quit-application");
|
||||
directories.clear();
|
||||
}, "quit-application");
|
||||
|
||||
// Close a connection on demand. This serves as an escape hatch from C++ code.
|
||||
|
||||
Services.obs.addObserver(async file => {
|
||||
file.QueryInterface(Ci.nsIFile);
|
||||
await closeConnectionTo(file);
|
||||
Services.obs.notifyObservers(file, "addrbook-close-ab-complete");
|
||||
}, "addrbook-close-ab");
|
||||
|
||||
/**
|
||||
* Opens an SQLite connection to `file`, caches the connection, and upgrades
|
||||
|
|
|
@ -60,6 +60,12 @@
|
|||
} \
|
||||
}
|
||||
|
||||
//
|
||||
// JS/SQLite address book
|
||||
//
|
||||
#define NS_ABJSDIRECTORY_CONTRACTID \
|
||||
NS_AB_DIRECTORY_TYPE_CONTRACTID_PREFIX "jsaddrbook"
|
||||
|
||||
//
|
||||
// nsAddressBookDB
|
||||
//
|
||||
|
|
|
@ -125,8 +125,11 @@ NS_IMETHODIMP nsAbLDAPDirectory::GetChildCards(nsISimpleEnumerator **result) {
|
|||
do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIAbDirectory> directory;
|
||||
rv = abManager->GetDirectory(localDirectoryURI, getter_AddRefs(directory));
|
||||
nsCOMPtr<nsIAbDirectory> directory =
|
||||
do_CreateInstance(NS_ABJSDIRECTORY_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = directory->Init(localDirectoryURI.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = directory->GetChildCards(result);
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
#include "nsILDAPMessage.h"
|
||||
#include "nsAbLDAPReplicationData.h"
|
||||
#include "nsIAbManager.h"
|
||||
#include "nsIAbCard.h"
|
||||
#include "nsAbBaseCID.h"
|
||||
#include "nsAbUtils.h"
|
||||
|
@ -13,20 +12,25 @@
|
|||
#include "nsILDAPErrors.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsMsgUtils.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// once bug # 101252 gets fixed, this should be reverted back to be non
|
||||
// threadsafe implementation is not really thread safe since each object should
|
||||
// exist independently along with its related independent
|
||||
// nsAbLDAPReplicationQuery object.
|
||||
NS_IMPL_ISUPPORTS(nsAbLDAPProcessReplicationData,
|
||||
nsIAbLDAPProcessReplicationData, nsILDAPMessageListener)
|
||||
nsIAbLDAPProcessReplicationData, nsILDAPMessageListener,
|
||||
nsIObserver)
|
||||
|
||||
nsAbLDAPProcessReplicationData::nsAbLDAPProcessReplicationData()
|
||||
: nsAbLDAPListenerBase(),
|
||||
mState(kIdle),
|
||||
mProtocol(-1),
|
||||
mCount(0),
|
||||
mDBOpen(false),
|
||||
mInitialized(false) {}
|
||||
|
||||
nsAbLDAPProcessReplicationData::~nsAbLDAPProcessReplicationData() {}
|
||||
|
@ -127,24 +131,7 @@ NS_IMETHODIMP nsAbLDAPProcessReplicationData::Abort() {
|
|||
if (NS_SUCCEEDED(rv)) mState = kIdle;
|
||||
}
|
||||
|
||||
if (mReplicationDB && mDBOpen) {
|
||||
mDBOpen = false;
|
||||
|
||||
// delete the unsaved replication file
|
||||
if (mReplicationFile) {
|
||||
rv = mReplicationFile->Remove(false);
|
||||
if (NS_SUCCEEDED(rv) && mDirectory) {
|
||||
nsAutoCString fileName;
|
||||
rv = mDirectory->GetReplicationFileName(fileName);
|
||||
// now put back the backed up replicated file if aborted
|
||||
if (NS_SUCCEEDED(rv) && mBackupReplicationFile)
|
||||
rv = mBackupReplicationFile->MoveToNative(nullptr, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Done(false);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -153,7 +140,7 @@ nsresult nsAbLDAPProcessReplicationData::DoTask() {
|
|||
|
||||
nsresult rv = OpenABForReplicatedDir(true);
|
||||
if (NS_FAILED(rv))
|
||||
// do not call done here since it is called by OpenABForReplicationDir
|
||||
// do not call done here since it is called by OpenABForReplicatedDir
|
||||
return rv;
|
||||
|
||||
mOperation = do_CreateInstance(NS_LDAPOPERATION_CONTRACTID, &rv);
|
||||
|
@ -203,7 +190,7 @@ nsresult nsAbLDAPProcessReplicationData::OnLDAPSearchEntry(
|
|||
if (!mInitialized) return NS_ERROR_NOT_INITIALIZED;
|
||||
// since this runs on the main thread and is single threaded, this will
|
||||
// take care of entries returned by LDAP Connection thread after Abort.
|
||||
if (!mReplicationDB || !mDBOpen) return NS_ERROR_FAILURE;
|
||||
if (!mReplicationDB) return NS_ERROR_FAILURE;
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
|
@ -272,52 +259,21 @@ nsresult nsAbLDAPProcessReplicationData::OnLDAPSearchResult(
|
|||
if (errorCode == nsILDAPErrors::SUCCESS ||
|
||||
errorCode == nsILDAPErrors::SIZELIMIT_EXCEEDED) {
|
||||
Done(true);
|
||||
if (mReplicationDB && mDBOpen) {
|
||||
mDBOpen = false;
|
||||
// once we have saved the new replication file, delete the backup file
|
||||
if (mBackupReplicationFile) {
|
||||
rv = mBackupReplicationFile->Remove(false);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Replication BackupFile Remove on Success failed");
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// in case if GetErrorCode returned error or errorCode is not SUCCESS /
|
||||
// SIZELIMIT_EXCEEDED
|
||||
if (mReplicationDB && mDBOpen) {
|
||||
// if error result is returned close the DB without saving ???
|
||||
// should we commit anyway ??? whatever is returned is not lost then !!
|
||||
mDBOpen = false;
|
||||
// if error result is returned remove the replicated file
|
||||
if (mReplicationFile) {
|
||||
rv = mReplicationFile->Remove(false);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Replication File Remove on Failure failed");
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// now put back the backed up replicated file
|
||||
if (mBackupReplicationFile && mDirectory) {
|
||||
nsAutoCString fileName;
|
||||
rv = mDirectory->GetReplicationFileName(fileName);
|
||||
if (NS_SUCCEEDED(rv) && !fileName.IsEmpty()) {
|
||||
rv = mBackupReplicationFile->MoveToNative(nullptr, fileName);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Replication Backup File Move back on Failure failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Done(false);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsAbLDAPProcessReplicationData::OpenABForReplicatedDir(bool aCreate) {
|
||||
if (!mInitialized) return NS_ERROR_NOT_INITIALIZED;
|
||||
|
||||
mDirectory->GetReplicationFileName(mReplicationFileName);
|
||||
|
||||
nsresult rv =
|
||||
mDirectory->GetReplicationFile(getter_AddRefs(mReplicationFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
|
@ -325,101 +281,110 @@ nsresult nsAbLDAPProcessReplicationData::OpenABForReplicatedDir(bool aCreate) {
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If the database file already exists, create a new one and populate it,
|
||||
// then replace the old file with the new one. Otherwise, create the
|
||||
// database in place.
|
||||
bool fileExists;
|
||||
rv = mReplicationFile->Exists(&fileExists);
|
||||
if (NS_SUCCEEDED(rv) && fileExists) {
|
||||
rv = mReplicationFile->Clone(getter_AddRefs(mOldReplicationFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mReplicationFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0777);
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
mReplicationFile->Remove(false);
|
||||
}
|
||||
|
||||
nsCString fileName;
|
||||
rv = mReplicationFile->GetNativeLeafName(fileName);
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// if the AB DB already exists backup existing one,
|
||||
// in case if the user cancels or Abort put back the backed up file
|
||||
bool fileExists;
|
||||
rv = mReplicationFile->Exists(&fileExists);
|
||||
if (NS_SUCCEEDED(rv) && fileExists) {
|
||||
// create the backup file object same as the Replication file object.
|
||||
// we create a backup file here since we need to cleanup the existing file
|
||||
// for create and then commit so instead of deleting existing cards we just
|
||||
// clone the existing one for a much better performance - for Download All.
|
||||
// And also important in case if replication fails we donot lose user's
|
||||
// existing replicated data for both Download all and Changelog.
|
||||
nsCOMPtr<nsIFile> clone;
|
||||
rv = mReplicationFile->Clone(getter_AddRefs(clone));
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
mBackupReplicationFile = clone;
|
||||
rv = mBackupReplicationFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0777);
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
nsAutoString backupFileLeafName;
|
||||
rv = mBackupReplicationFile->GetLeafName(backupFileLeafName);
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
// remove the newly created unique backup file so that move and copy
|
||||
// succeeds.
|
||||
rv = mBackupReplicationFile->Remove(false);
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (aCreate) {
|
||||
// set backup file to existing replication file for move
|
||||
mBackupReplicationFile->SetNativeLeafName(fileName);
|
||||
|
||||
rv = mBackupReplicationFile->MoveTo(nullptr, backupFileLeafName);
|
||||
// set the backup file leaf name now
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mBackupReplicationFile->SetLeafName(backupFileLeafName);
|
||||
} else {
|
||||
// set backup file to existing replication file for copy
|
||||
mBackupReplicationFile->SetNativeLeafName(fileName);
|
||||
|
||||
// specify the parent here specifically,
|
||||
// passing nullptr to copy to the same dir actually renames existing file
|
||||
// instead of making another copy of the existing file.
|
||||
nsCOMPtr<nsIFile> parent;
|
||||
rv = mBackupReplicationFile->GetParent(getter_AddRefs(parent));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mBackupReplicationFile->CopyTo(parent, backupFileLeafName);
|
||||
// set the backup file leaf name now
|
||||
if (NS_SUCCEEDED(rv))
|
||||
mBackupReplicationFile->SetLeafName(backupFileLeafName);
|
||||
}
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
mDirectory->SetReplicationFileName(fileName);
|
||||
|
||||
nsCString uri(kJSDirectoryRoot);
|
||||
uri.Append(fileName);
|
||||
|
||||
nsCOMPtr<nsIAbManager> abManager(do_GetService(NS_ABMANAGER_CONTRACTID, &rv));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = abManager->GetDirectory(uri, getter_AddRefs(mReplicationDB));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mReplicationDB = do_CreateInstance(NS_ABJSDIRECTORY_CONTRACTID, &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
return rv;
|
||||
}
|
||||
rv = mReplicationDB->Init(uri.get());
|
||||
if (NS_FAILED(rv)) {
|
||||
Done(false);
|
||||
if (mBackupReplicationFile) mBackupReplicationFile->Remove(false);
|
||||
return rv;
|
||||
}
|
||||
|
||||
mDBOpen = true; // replication DB is now Open
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsAbLDAPProcessReplicationData::Observe(nsISupports *aSubject,
|
||||
const char *aTopic,
|
||||
const char16_t *aData) {
|
||||
if (mDatabaseClosedPromise) {
|
||||
mDatabaseClosedPromise->Resolve(true, __func__);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<GenericPromise> nsAbLDAPProcessReplicationData::PromiseDatabaseClosed(
|
||||
nsIFile *file) {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
observerService->NotifyObservers(file, "addrbook-close-ab", nullptr);
|
||||
|
||||
mDatabaseClosedPromise = new GenericPromise::Private(__func__);
|
||||
return mDatabaseClosedPromise;
|
||||
}
|
||||
|
||||
void nsAbLDAPProcessReplicationData::Done(bool aSuccess) {
|
||||
if (!mInitialized) return;
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
observerService->AddObserver(this, "addrbook-close-ab-complete", false);
|
||||
RefPtr<GenericPromise> promise;
|
||||
|
||||
if (aSuccess) {
|
||||
if (mOldReplicationFile) {
|
||||
// Close mReplicationFile.
|
||||
promise =
|
||||
this->PromiseDatabaseClosed(mReplicationFile)
|
||||
->Then(GetCurrentThreadSerialEventTarget(), __func__,
|
||||
[&] {
|
||||
// Close mOldReplicationFile.
|
||||
return this->PromiseDatabaseClosed(mOldReplicationFile);
|
||||
})
|
||||
->Then(GetCurrentThreadSerialEventTarget(), __func__, [&] {
|
||||
// Remove mOldReplicationFile.
|
||||
mOldReplicationFile->Remove(false);
|
||||
// Move mReplicationFile to the right place.
|
||||
mReplicationFile->MoveToNative(nullptr, mReplicationFileName);
|
||||
return GenericPromise::CreateAndResolve(true, __func__);
|
||||
});
|
||||
} else {
|
||||
promise = GenericPromise::CreateAndResolve(true, __func__);
|
||||
}
|
||||
} else {
|
||||
// Close mReplicationFile.
|
||||
mReplicationFile->Remove(false);
|
||||
promise = this->PromiseDatabaseClosed(mReplicationFile);
|
||||
}
|
||||
|
||||
promise->Then(GetCurrentThreadSerialEventTarget(), __func__, [&] {
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
observerService->RemoveObserver(this, "addrbook-close-ab-complete");
|
||||
|
||||
mDirectory->SetReplicationFileName(mReplicationFileName);
|
||||
mState = kReplicationDone;
|
||||
|
||||
if (mQuery) mQuery->Done(aSuccess);
|
||||
|
@ -428,9 +393,10 @@ void nsAbLDAPProcessReplicationData::Done(bool aSuccess) {
|
|||
// XXX Cast from bool to nsresult
|
||||
mListener->OnStateChange(nullptr, nullptr,
|
||||
nsIWebProgressListener::STATE_STOP,
|
||||
static_cast<nsresult>(aSuccess));
|
||||
aSuccess ? NS_OK : NS_ERROR_FAILURE);
|
||||
|
||||
// since this is called when all is done here, either on success,
|
||||
// failure or abort release the query now.
|
||||
mQuery = nullptr;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -10,18 +10,21 @@
|
|||
#include "nsIWebProgressListener.h"
|
||||
#include "nsIAbLDAPReplicationQuery.h"
|
||||
#include "nsAbLDAPListenerBase.h"
|
||||
#include "nsIAddrDatabase.h"
|
||||
#include "nsIAbDirectory.h"
|
||||
#include "nsIFile.h"
|
||||
#include "nsDirPrefs.h"
|
||||
#include "nsIAbLDAPAttributeMap.h"
|
||||
#include "nsIAbLDAPDirectory.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/MozPromise.h"
|
||||
|
||||
class nsAbLDAPProcessReplicationData : public nsIAbLDAPProcessReplicationData,
|
||||
public nsAbLDAPListenerBase {
|
||||
public nsAbLDAPListenerBase,
|
||||
public nsIObserver {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIABLDAPPROCESSREPLICATIONDATA
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsAbLDAPProcessReplicationData();
|
||||
|
||||
|
@ -40,13 +43,13 @@ class nsAbLDAPProcessReplicationData : public nsIAbLDAPProcessReplicationData,
|
|||
|
||||
nsCOMPtr<nsIAbDirectory> mReplicationDB;
|
||||
nsCOMPtr<nsIFile> mReplicationFile;
|
||||
nsCOMPtr<nsIFile> mBackupReplicationFile;
|
||||
nsCOMPtr<nsIFile> mOldReplicationFile;
|
||||
nsCString mReplicationFileName;
|
||||
|
||||
// state of processing, protocol used and count of results
|
||||
int32_t mState;
|
||||
int32_t mProtocol;
|
||||
int32_t mCount;
|
||||
bool mDBOpen;
|
||||
bool mInitialized;
|
||||
|
||||
nsCOMPtr<nsIAbLDAPDirectory> mDirectory;
|
||||
|
@ -57,6 +60,9 @@ class nsAbLDAPProcessReplicationData : public nsIAbLDAPProcessReplicationData,
|
|||
|
||||
nsresult OpenABForReplicatedDir(bool bCreate);
|
||||
void Done(bool aSuccess);
|
||||
|
||||
RefPtr<mozilla::GenericPromise> PromiseDatabaseClosed(nsIFile *file);
|
||||
RefPtr<mozilla::GenericPromise::Private> mDatabaseClosedPromise;
|
||||
};
|
||||
|
||||
#endif // nsAbLDAPReplicationData_h__
|
||||
|
|
Загрузка…
Ссылка в новой задаче