/*
* Copyright (C) 2012-2016 The Android Money Manager Ex Project Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.money.manager.ex.sync;
import android.content.Context;
import com.cloudrail.si.CloudRail;
import com.cloudrail.si.exceptions.ParseException;
import com.cloudrail.si.interfaces.CloudStorage;
import com.cloudrail.si.services.Box;
import com.cloudrail.si.services.Dropbox;
import com.cloudrail.si.services.GoogleDrive;
import com.cloudrail.si.services.OneDrive;
import com.cloudrail.si.types.CloudMetaData;
import com.money.manager.ex.R;
import com.money.manager.ex.settings.SyncPreferences;
import com.money.manager.ex.utils.NetworkUtils;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicReference;
import rx.Observable;
import rx.Single;
import rx.SingleSubscriber;
import rx.functions.Action0;
import timber.log.Timber;
/**
* Direct interface to the current cloud provider.
* Extracted from the Sync Manager.
*/
class CloudStorageClient {
public CloudStorageClient(Context context) {
mContext = context;
// Do not initialize providers if the network is not present.
NetworkUtils network = new NetworkUtils(getContext());
if (!network.isOnline()) return;
CloudRail.setAppKey("57d9a85c40cb6c08612de98f");
createProviders();
restoreProviderCache();
// Use current provider.
// todo read from the current db entry
String providerCode = getPreferences().loadPreference(R.string.pref_sync_provider, CloudStorageProviderEnum.DROPBOX.name());
CloudStorageProviderEnum provider = CloudStorageProviderEnum.DROPBOX;
if (CloudStorageProviderEnum.contains(providerCode)) {
provider = CloudStorageProviderEnum.valueOf(providerCode);
}
setProvider(provider);
}
private final AtomicReference<CloudStorage> dropbox = new AtomicReference<>();
private final AtomicReference<CloudStorage> box = new AtomicReference<>();
private final AtomicReference<CloudStorage> googledrive = new AtomicReference<>();
private final AtomicReference<CloudStorage> onedrive = new AtomicReference<>();
private Context mContext;
private AtomicReference<CloudStorage> currentProvider;
private SyncPreferences mPreferences;
public Context getContext() {
return mContext;
}
public Single<List<CloudMetaData>> getContents(final String folder) {
return Observable.fromCallable(new Callable<List<CloudMetaData>>() {
@Override
public List<CloudMetaData> call() throws Exception {
return getProvider().getChildren(folder);
}
})
.doOnCompleted(new Action0() {
@Override
public void call() {
// update any renewed tokens
cacheCredentials();
}
})
.toSingle();
}
public InputStream download(String s) {
return getProvider().download(s);
}
public CloudMetaData loadMetadata(final String remotePath) {
final CloudMetaData[] result = {null};
Single.fromCallable(new Callable<CloudMetaData>() {
@Override
public CloudMetaData call() throws Exception {
return getProvider().getMetadata(remotePath);
}
})
.retry(1)
.subscribe(new SingleSubscriber<CloudMetaData>() {
@Override
public void onSuccess(CloudMetaData value) {
// update any renewed tokens
CloudStorageClient.this.cacheCredentials();
result[0] = value;
}
@Override
public void onError(Throwable error) {
// handle DNS exceptions by just showing a message?
String errorMessage = error.getMessage();
if (error instanceof RuntimeException && errorMessage != null &&
(
errorMessage.equals("Unable to resolve host \"api.dropboxapi.com\": No address associated with hostname") ||
errorMessage.equals("Unable to resolve host \"www.googleapis.com\": No address associated with hostname") ||
errorMessage.equals("Unable to resolve host \"login.live.com\": Unknown error")
)
) {
Timber.w("Unable to contact remote provider");
} else {
Timber.e(error, "fetching remote metadata");
}
}
});
// .toBlocking().value()
return result[0];
}
public Single<Void> login() {
return Observable.fromCallable(new Callable<Void>() {
@Override
public Void call() throws Exception {
getProvider().login();
return null;
}
})
.doOnCompleted(new Action0() {
@Override
public void call() {
// cache credentials after login.
cacheCredentials();
}
})
.toSingle();
}
public Single<Void> logout() {
return Observable.fromCallable(new Callable<Void>() {
@Override
public Void call() throws Exception {
getProvider().logout();
return null;
}
})
.toSingle();
}
public void setProvider(CloudStorageProviderEnum provider) {
// Sync provider mapping
switch (provider) {
case DROPBOX:
currentProvider = dropbox;
break;
case ONEDRIVE:
// OneDrive
currentProvider = onedrive;
break;
case GOOGLEDRIVE:
// Google Drive
currentProvider = googledrive;
break;
case BOX:
// Box
currentProvider = box;
break;
default:
// default provider
currentProvider = dropbox;
break;
}
}
public void cacheCredentials() {
if (dropbox.get() != null) {
getPreferences().set(R.string.pref_dropbox_persistent, dropbox.get().saveAsString());
}
if (box.get() != null) {
getPreferences().set(R.string.pref_onedrive_persistent, box.get().saveAsString());
}
if (googledrive.get() != null) {
getPreferences().set(R.string.pref_gdrive_persistent, googledrive.get().saveAsString());
}
if (onedrive.get() != null) {
getPreferences().set(R.string.pref_box_persistent, onedrive.get().saveAsString());
}
}
public void upload(String s, InputStream inputStream, long l, boolean b) {
getProvider().upload(s, inputStream, l, b);
}
/*
Private
*/
protected void createProviders() {
try {
dropbox.set(new Dropbox(getContext(), "6328lyguu3wwii6", "oa7k0ju20qss11l"));
onedrive.set(new OneDrive(getContext(), "b76e0230-4f4e-4bff-9976-fd660cdebc4a", "fmAOPrAuq6a5hXzY1v7qcDn"));
googledrive.set(new GoogleDrive(getContext(), "843259487958-p65svijbdvj1knh5ove1ksp0hlnufli8.apps.googleusercontent.com", "cpU0rnBiMW9lQaYfaoW1dwLU"));
box.set(new Box(getContext(), "95f7air3i2ed19r28hi31vwtta4wgz1p", "i6j0NLd3G6Ui9FpZyuQfiLK8jLs4YZRM"));
} catch (Exception e) {
Timber.e(e, "creating cloud providers");
}
}
private SyncPreferences getPreferences() {
if (mPreferences == null) {
mPreferences = new SyncPreferences(getContext());
}
return mPreferences;
}
private CloudStorage getProvider() {
return currentProvider.get();
}
private void restoreProviderCache() {
try {
String persistent = getPreferences().loadPreference(R.string.pref_dropbox_persistent, null);
if (persistent != null) dropbox.get().loadAsString(persistent);
persistent = getPreferences().loadPreference(R.string.pref_box_persistent, null);
if (persistent != null) box.get().loadAsString(persistent);
persistent = getPreferences().loadPreference(R.string.pref_gdrive_persistent, null);
if (persistent != null) googledrive.get().loadAsString(persistent);
persistent = getPreferences().loadPreference(R.string.pref_onedrive_persistent, null);
if (persistent != null) onedrive.get().loadAsString(persistent);
} catch (Exception e) {
if (e instanceof ParseException) {
Timber.w(e.getMessage());
} else {
Timber.e(e, "restoring providers from cache");
}
}
}
}