Stash upload (#2505)

* Introduce Single<UploadResult>

* Two stage upload process

- split upload process and use stash
- resolve filename conflict after upload not before
- use NotificationManagerCompat; add notification tag; assign temporaty stash file name
This commit is contained in:
Yusuke Matsubara 2019-03-19 00:37:29 +09:00 committed by Vivek Maskara
parent 341f9614a7
commit ee7af37d00
5 changed files with 213 additions and 72 deletions

View file

@ -1,7 +1,6 @@
package fr.free.nrw.commons.upload;
import android.annotation.SuppressLint;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.ContentValues;
@ -10,6 +9,7 @@ import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import android.widget.Toast;
import java.io.File;
@ -34,8 +34,9 @@ import fr.free.nrw.commons.contributions.ContributionDao;
import fr.free.nrw.commons.contributions.ContributionsContentProvider;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.mwapi.MediaWikiApi;
import fr.free.nrw.commons.mwapi.UploadResult;
import fr.free.nrw.commons.wikidata.WikidataEditService;
import io.reactivex.Single;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
public class UploadService extends HandlerService<Contribution> {
@ -54,7 +55,7 @@ public class UploadService extends HandlerService<Contribution> {
@Inject SessionManager sessionManager;
@Inject ContributionDao contributionDao;
private NotificationManager notificationManager;
private NotificationManagerCompat notificationManager;
private NotificationCompat.Builder curNotification;
private int toUpload;
@ -106,7 +107,7 @@ public class UploadService extends HandlerService<Contribution> {
} else {
curNotification.setProgress(100, (int) (((double) transferred / (double) total) * 100), false);
}
notificationManager.notify(NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
notificationManager.notify(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
contribution.setTransferred(transferred);
contributionDao.save(contribution);
@ -124,7 +125,7 @@ public class UploadService extends HandlerService<Contribution> {
public void onCreate() {
super.onCreate();
CommonsApplication.createNotificationChannel(getApplicationContext());
notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager = NotificationManagerCompat.from(this);
curNotification = getNotificationBuilder(CommonsApplication.NOTIFICATION_CHANNEL_ID_ALL);
}
@ -152,7 +153,7 @@ public class UploadService extends HandlerService<Contribution> {
if (curNotification != null && toUpload != 1) {
curNotification.setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload));
Timber.d("%d uploads left", toUpload);
notificationManager.notify(NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
notificationManager.notify(contribution.getLocalUri().toString(), NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
}
super.queue(what, contribution);
@ -217,15 +218,12 @@ public class UploadService extends HandlerService<Contribution> {
curNotification.setContentTitle(getString(R.string.upload_progress_notification_title_start, contribution.getDisplayTitle()))
.setContentText(getResources().getQuantityString(R.plurals.uploads_pending_notification_indicator, toUpload, toUpload))
.setTicker(getString(R.string.upload_progress_notification_title_in_progress, contribution.getDisplayTitle()));
startForeground(NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
notificationManager.notify(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS, curNotification.build());
String filename = contribution.getFilename();
try {
synchronized (unfinishedUploads) {
Timber.d("making sure of uniqueness of name: %s", filename);
filename = findUniqueFilename(filename);
unfinishedUploads.add(filename);
}
if (!mwApi.validateLogin()) {
// Need to revalidate!
if (sessionManager.revalidateAuthToken()) {
@ -244,27 +242,60 @@ public class UploadService extends HandlerService<Contribution> {
getString(R.string.upload_progress_notification_title_finishing, contribution.getDisplayTitle()),
contribution
);
UploadResult uploadResult = mwApi.uploadFile(filename, fileInputStream, contribution.getDataLength(),
contribution.getPageContents(getApplicationContext()), contribution.getEditSummary(), localUri, contribution.getContentProviderUri(), notificationUpdater);
String stashFilename = "Temp_" + contribution.hashCode() + filename;
mwApi.uploadFile(
stashFilename, fileInputStream, contribution.getDataLength(),
localUri, contribution.getContentProviderUri(), notificationUpdater)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.flatMap(uploadStash -> {
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
Timber.d("Response is %s", uploadResult.toString());
Timber.d("Stash upload response 1 is %s", uploadStash.toString());
String resultStatus = uploadResult.getResultStatus();
if (!resultStatus.equals("Success")) {
Timber.d("Contribution upload failed. Wikidata entity won't be edited");
showFailedNotification(contribution);
} else {
Timber.d("Contribution upload success. Initiating Wikidata edit for entity id %s", contribution.getWikiDataEntityId());
wikidataEditService.createClaimWithLogging(contribution.getWikiDataEntityId(), filename);
contribution.setFilename(uploadResult.getCanonicalFilename());
contribution.setImageUrl(uploadResult.getImageUrl());
contribution.setState(Contribution.STATE_COMPLETED);
contribution.setDateUploaded(uploadResult.getDateUploaded());
contributionDao.save(contribution);
}
String resultStatus = uploadStash.getResultStatus();
if (!resultStatus.equals("Success")) {
Timber.d("Contribution upload failed. Wikidata entity won't be edited");
showFailedNotification(contribution);
return Single.never();
} else {
synchronized (unfinishedUploads) {
Timber.d("making sure of uniqueness of name: %s", filename);
String uniqueFilename = findUniqueFilename(filename);
unfinishedUploads.add(uniqueFilename);
return mwApi.uploadFileFinalize(
uniqueFilename,
uploadStash.getFilekey(),
contribution.getPageContents(getApplicationContext()),
contribution.getEditSummary());
}
}
})
.subscribe(uploadResult -> {
Timber.d("Stash upload response 2 is %s", uploadResult.toString());
notificationManager.cancel(notificationTag, NOTIFICATION_UPLOAD_IN_PROGRESS);
String resultStatus = uploadResult.getResultStatus();
if (!resultStatus.equals("Success")) {
Timber.d("Contribution upload failed. Wikidata entity won't be edited");
showFailedNotification(contribution);
} else {
String canonicalFilename = uploadResult.getCanonicalFilename();
Timber.d("Contribution upload success. Initiating Wikidata edit for entity id %s",
contribution.getWikiDataEntityId());
wikidataEditService.createClaimWithLogging(contribution.getWikiDataEntityId(), canonicalFilename);
contribution.setFilename(canonicalFilename);
contribution.setImageUrl(uploadResult.getImageUrl());
contribution.setState(Contribution.STATE_COMPLETED);
contribution.setDateUploaded(uploadResult.getDateUploaded());
contributionDao.save(contribution);
}
}, throwable -> {
throw new RuntimeException(throwable);
});
} catch (IOException e) {
Timber.d("I have a network fuckup");
Timber.w(e,"IOException during upload");
notificationManager.cancel(NOTIFICATION_UPLOAD_IN_PROGRESS);
showFailedNotification(contribution);
} finally {
@ -287,7 +318,7 @@ public class UploadService extends HandlerService<Contribution> {
.setContentTitle(getString(R.string.upload_failed_notification_title, contribution.getDisplayTitle()))
.setContentText(getString(R.string.upload_failed_notification_subtitle))
.setProgress(0, 0, false);
notificationManager.notify(NOTIFICATION_UPLOAD_FAILED, curNotification.build());
notificationManager.notify(contribution.getLocalUri().toString(), NOTIFICATION_UPLOAD_FAILED, curNotification.build());
contribution.setState(Contribution.STATE_FAILED);
contributionDao.save(contribution);