Skip to content

Commit 9ab0c91

Browse files
authored
Merge pull request #277 from spoonconsulting/revert-226-one-running-worker
Revert "Manage WorkManager: One Running Worker to upload a Batch of Files"
2 parents b27c663 + 1605cd8 commit 9ab0c91

9 files changed

+322
-357
lines changed

plugin.xml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,20 @@
4747
<source-file src="src/android/AckDatabase.java" target-dir="src/com/spoon/backgroundfileupload" />
4848
<source-file src="src/android/UploadEventDao.java" target-dir="src/com/spoon/backgroundfileupload" />
4949
<source-file src="src/android/UploadEvent.java" target-dir="src/com/spoon/backgroundfileupload" />
50-
<source-file src="src/android/PendingUploadDao.java" target-dir="src/com/spoon/backgroundfileupload" />
51-
<source-file src="src/android/PendingUpload.java" target-dir="src/com/spoon/backgroundfileupload" />
5250
<source-file src="src/android/ProgressRequestBody.java" target-dir="src/com/spoon/backgroundfileupload" />
5351
<source-file src="src/android/UploadForegroundNotification.java" target-dir="src/com/spoon/backgroundfileupload" />
5452
<source-file src="src/android/UploadNotification.java" target-dir="src/com/spoon/backgroundfileupload" />
5553
<resource-file src="src/android/res/ic_upload.png" target="res/drawable/ic_upload.png" />
5654
</platform>
5755
<platform name="ios">
58-
<framework src="AFNetworking" type="podspec" spec="~> 4.0.1" />
56+
<podspec>
57+
<config>
58+
<source url="https://cdn.cocoapods.org/"/>
59+
</config>
60+
<pods use-frameworks="true">
61+
<pod name="AFNetworking" spec="~> 4.0.1" />
62+
</pods>
63+
</podspec>
5964
<config-file target="config.xml" parent="/*">
6065
<feature name="FileTransferBackground">
6166
<param name="ios-package" value="FileTransferBackground" />

src/android/AckDatabase.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import androidx.room.TypeConverters;
99
import androidx.work.Data;
1010

11-
@Database(entities = {UploadEvent.class, PendingUpload.class}, version = 4)
11+
@Database(entities = {UploadEvent.class}, version = 5)
1212
@TypeConverters(value = {Data.class})
1313
public abstract class AckDatabase extends RoomDatabase {
1414
private static AckDatabase instance;
@@ -30,6 +30,4 @@ public static void closeInstance() {
3030
}
3131

3232
public abstract UploadEventDao uploadEventDao();
33-
34-
public abstract PendingUploadDao pendingUploadDao();
3533
}

src/android/FileTransferBackground.java

Lines changed: 102 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import androidx.work.OutOfQuotaPolicy;
1818
import androidx.work.WorkInfo;
1919
import androidx.work.WorkManager;
20+
import androidx.work.WorkQuery;
2021

2122
import org.apache.cordova.CallbackContext;
2223
import org.apache.cordova.CordovaPlugin;
@@ -29,29 +30,33 @@
2930
import java.io.IOException;
3031
import java.io.InputStreamReader;
3132
import java.util.ArrayList;
33+
import java.util.Arrays;
34+
import java.util.Collections;
3235
import java.util.HashMap;
3336
import java.util.Iterator;
3437
import java.util.List;
3538
import java.util.Map;
39+
import java.util.UUID;
3640
import java.util.concurrent.ExecutionException;
3741
import java.util.concurrent.Executors;
3842
import java.util.concurrent.ScheduledExecutorService;
3943
import java.util.concurrent.TimeUnit;
4044

4145
public class FileTransferBackground extends CordovaPlugin {
46+
47+
private static final String TAG = "FileTransferBackground";
4248
public static final String WORK_TAG_UPLOAD = "work_tag_upload";
4349

4450
private CallbackContext uploadCallback;
4551
private boolean ready = false;
4652

4753
private Data httpClientBaseConfig = Data.EMPTY;
4854

49-
public static boolean workerIsStarted;
55+
private static String currentTag;
56+
private static long currentTagFetchedAt;
5057

5158
private ScheduledExecutorService executorService = null;
5259

53-
private int ccUpload;
54-
5560
public void sendCallback(JSONObject obj) {
5661
/* we check the webview has been initialized */
5762
if (ready) {
@@ -158,7 +163,8 @@ private void initManager(String options, final CallbackContext callbackContext)
158163

159164
try {
160165
final JSONObject settings = new JSONObject(options);
161-
ccUpload = settings.getInt("parallelUploadsLimit");
166+
int ccUpload = settings.getInt("parallelUploadsLimit");
167+
162168
// Rebuild base HTTP config
163169
httpClientBaseConfig = new Data.Builder()
164170
.putInt(UploadTask.KEY_INPUT_CONFIG_CONCURRENT_DOWNLOADS, ccUpload)
@@ -200,32 +206,31 @@ private void initManager(String options, final CallbackContext callbackContext)
200206
.observeForever((tasks) -> {
201207
int completedTasks = 0;
202208
for (WorkInfo info : tasks) {
203-
// No db in main thread
204-
executorService.schedule(() -> {
205-
final List<UploadEvent> uploadEventsList = ackDatabase
206-
.uploadEventDao()
207-
.getAll();
208-
for (UploadEvent ack : uploadEventsList) {
209-
handleAck(ack.getOutputData());
210-
}
211-
}, 0, TimeUnit.MILLISECONDS);
212209
switch (info.getState()) {
213210
// If the upload in not finished, publish its progress
214211
case RUNNING:
215212
if (info.getProgress() != Data.EMPTY) {
216213
String id = info.getProgress().getString(UploadTask.KEY_PROGRESS_ID);
217214
int progress = info.getProgress().getInt(UploadTask.KEY_PROGRESS_PERCENT, 0);
218215

219-
logMessage("initManager: " + info.getId() + " (" + info.getState() + ") Progress: " + progress);
216+
Log.d(TAG, "initManager: " + info.getId() + " (" + info.getState() + ") Progress: " + progress);
220217
sendProgress(id, progress);
221218
}
222219
break;
223220
case CANCELLED:
224221
case BLOCKED:
225222
case ENQUEUED:
226223
case SUCCEEDED:
227-
logMessage("Task succeeded: " + info.getId());
228224
completedTasks++;
225+
// No db in main thread
226+
executorService.schedule(() -> {
227+
// The corresponding ACK is already in the DB, if it not, the task is just a leftover
228+
String id = info.getOutputData().getString(UploadTask.KEY_OUTPUT_ID);
229+
if (ackDatabase.uploadEventDao().exists(id)) {
230+
handleAck(info.getOutputData());
231+
}
232+
}, 0, TimeUnit.MILLISECONDS);
233+
break;
229234
case FAILED:
230235
// The task can't fail completely so something really bad has happened.
231236
logMessage("eventLabel='Uploader failed inexplicably' error='" + info.getOutputData() + "'");
@@ -295,67 +300,59 @@ private void addUpload(JSONObject jsonPayload) {
295300
} catch(PackageManager.NameNotFoundException e) {
296301
e.printStackTrace();
297302
}
298-
299-
AckDatabase.getInstance(cordova.getContext()).pendingUploadDao().insert(
300-
new PendingUpload(
301-
uploadId,
302-
new Data.Builder()
303-
// Put base info
304-
.putString(UploadTask.KEY_INPUT_ID, uploadId)
305-
.putString(UploadTask.KEY_INPUT_URL, (String) payload.get("serverUrl"))
306-
.putString(UploadTask.KEY_INPUT_FILEPATH, (String) payload.get("filePath"))
307-
.putString(UploadTask.KEY_INPUT_FILE_KEY, (String) payload.get("fileKey"))
308-
.putString(UploadTask.KEY_INPUT_HTTP_METHOD, (String) payload.get("requestMethod"))
309-
// Put headers
310-
.putInt(UploadTask.KEY_INPUT_HEADERS_COUNT, headersNames.size())
311-
.putStringArray(UploadTask.KEY_INPUT_HEADERS_NAMES, headersNames.toArray(new String[0]))
312-
.putAll(headerValues)
313-
// Put query parameters
314-
.putInt(UploadTask.KEY_INPUT_PARAMETERS_COUNT, parameterNames.size())
315-
.putStringArray(UploadTask.KEY_INPUT_PARAMETERS_NAMES, parameterNames.toArray(new String[0]))
316-
.putAll(parameterValues)
317-
// Put notification stuff
318-
.putString(UploadTask.KEY_INPUT_NOTIFICATION_TITLE, (String) payload.get("notificationTitle"))
319-
.putString(UploadTask.KEY_INPUT_NOTIFICATION_ICON, cordova.getActivity().getPackageName() + ":drawable/ic_upload")
320-
.putString(UploadTask.KEY_INPUT_CONFIG_INTENT_ACTIVITY, intentActivity)
321-
322-
// Put config stuff
323-
.putAll(httpClientBaseConfig)
324-
.build()
325-
)
303+
startUpload(uploadId, new Data.Builder()
304+
// Put base info
305+
.putString(UploadTask.KEY_INPUT_ID, uploadId)
306+
.putString(UploadTask.KEY_INPUT_URL, (String) payload.get("serverUrl"))
307+
.putString(UploadTask.KEY_INPUT_FILEPATH, (String) payload.get("filePath"))
308+
.putString(UploadTask.KEY_INPUT_FILE_KEY, (String) payload.get("fileKey"))
309+
.putString(UploadTask.KEY_INPUT_HTTP_METHOD, (String) payload.get("requestMethod"))
310+
311+
// Put headers
312+
.putInt(UploadTask.KEY_INPUT_HEADERS_COUNT, headersNames.size())
313+
.putStringArray(UploadTask.KEY_INPUT_HEADERS_NAMES, headersNames.toArray(new String[0]))
314+
.putAll(headerValues)
315+
316+
// Put query parameters
317+
.putInt(UploadTask.KEY_INPUT_PARAMETERS_COUNT, parameterNames.size())
318+
.putStringArray(UploadTask.KEY_INPUT_PARAMETERS_NAMES, parameterNames.toArray(new String[0]))
319+
.putAll(parameterValues)
320+
321+
// Put notification stuff
322+
.putString(UploadTask.KEY_INPUT_NOTIFICATION_TITLE, (String) payload.get("notificationTitle"))
323+
.putString(UploadTask.KEY_INPUT_NOTIFICATION_ICON, cordova.getActivity().getPackageName() + ":drawable/ic_upload")
324+
.putString(UploadTask.KEY_INPUT_CONFIG_INTENT_ACTIVITY, intentActivity)
325+
326+
// Put config stuff
327+
.putAll(httpClientBaseConfig)
328+
.build()
326329
);
327-
328-
if (!workerIsStarted) {
329-
startWorkers();
330-
workerIsStarted = true;
331-
}
332330
}
333331

334-
private void startWorkers() {
335-
logMessage("startUpload: Starting worker via work manager");
336-
337-
for (int i = 0; i < ccUpload; i++) {
338-
OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder(UploadTask.class)
339-
.setConstraints(new Constraints.Builder()
340-
.setRequiredNetworkType(NetworkType.CONNECTED)
341-
.build()
342-
)
343-
.keepResultsForAtLeast(0, TimeUnit.MILLISECONDS)
344-
.setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.SECONDS)
345-
.addTag(FileTransferBackground.WORK_TAG_UPLOAD);
346-
347-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
348-
workRequestBuilder.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST);
349-
}
350-
351-
OneTimeWorkRequest workRequest = workRequestBuilder.build();
332+
private void startUpload(final String uploadId, final Data payload) {
333+
Log.d(TAG, "startUpload: Starting work via work manager");
334+
335+
OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder(UploadTask.class)
336+
.setConstraints(new Constraints.Builder()
337+
.setRequiredNetworkType(NetworkType.CONNECTED)
338+
.build()
339+
)
340+
.keepResultsForAtLeast(0, TimeUnit.MILLISECONDS)
341+
.setBackoffCriteria(BackoffPolicy.LINEAR, 30, TimeUnit.SECONDS)
342+
.addTag(FileTransferBackground.WORK_TAG_UPLOAD)
343+
.addTag(getCurrentTag(cordova.getContext()))
344+
.setInputData(payload);
345+
346+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
347+
workRequestBuilder.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST);
348+
}
352349

353-
WorkManager.getInstance(cordova.getContext())
354-
.enqueueUniqueWork(FileTransferBackground.WORK_TAG_UPLOAD + "_" + i, ExistingWorkPolicy.KEEP, workRequest);
350+
OneTimeWorkRequest workRequest = workRequestBuilder.build();
355351

356-
logMessage("eventLabel=Uploader starting uploads via worker" + i);
357-
}
352+
WorkManager.getInstance(cordova.getContext())
353+
.enqueueUniqueWork(uploadId, ExistingWorkPolicy.APPEND, workRequest);
358354

355+
logMessage("eventLabel='Uploader starting upload' uploadId='" + uploadId + "'");
359356
}
360357

361358
private void sendAddingUploadError(String uploadId, Exception error) {
@@ -433,7 +430,6 @@ private void handleAck(final Data ackData) {
433430
*/
434431
private void cleanupUpload(final String uploadId) {
435432
final UploadEvent ack = AckDatabase.getInstance(cordova.getContext()).uploadEventDao().getById(uploadId);
436-
437433
// If the upload is done there is an ACK of it, so get file name from there
438434
if (ack != null) {
439435
if (ack.getOutputData().getString(UploadTask.KEY_OUTPUT_RESPONSE_FILE) != null) {
@@ -505,15 +501,44 @@ public static HashMap<String, Object> convertToHashMap(JSONObject jsonObject) th
505501
return hashMap;
506502
}
507503

508-
public static void logMessage(String message) {
509-
Log.d("CordovaBackgroundUpload", message);
504+
public static String getCurrentTag(Context context) {
505+
final long now = System.currentTimeMillis();
506+
if (currentTag != null && now - currentTagFetchedAt <= 5000) {
507+
return currentTag;
508+
}
509+
currentTagFetchedAt = now;
510+
currentTag = fetchCurrentTag(context);
511+
return currentTag;
510512
}
511513

512-
public static void logMessageInfo(String message) {
513-
Log.i("CordovaBackgroundUpload", message);
514+
public static String fetchCurrentTag(Context context) {
515+
WorkQuery workQuery = WorkQuery.Builder
516+
.fromTags(Arrays.asList(FileTransferBackground.WORK_TAG_UPLOAD))
517+
.addStates(Arrays.asList(WorkInfo.State.RUNNING, WorkInfo.State.ENQUEUED))
518+
.build();
519+
List<WorkInfo> workInfo;
520+
try {
521+
workInfo = WorkManager.getInstance(context)
522+
.getWorkInfos(workQuery)
523+
.get();
524+
} catch (ExecutionException | InterruptedException e) {
525+
Log.w(TAG, "getForegroundInfo: Problem while retrieving task list:", e);
526+
workInfo = Collections.emptyList();
527+
}
528+
String prefix = "packet_";
529+
for (WorkInfo info : workInfo) {
530+
if (!info.getState().isFinished()) {
531+
for (String tag : info.getTags()) {
532+
if (tag.startsWith(prefix)) {
533+
return tag;
534+
}
535+
}
536+
}
537+
}
538+
return prefix + UUID.randomUUID().toString();
514539
}
515540

516-
public static void logMessageError(String message, Exception exception) {
517-
Log.e("CordovaBackgroundUpload", message, exception);
541+
public static void logMessage(String message) {
542+
Log.d("CordovaBackgroundUpload", message);
518543
}
519544
}

src/android/PendingUpload.java

Lines changed: 0 additions & 48 deletions
This file was deleted.

0 commit comments

Comments
 (0)