mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 10:20:25 +01:00
Store Job data as bytes.
This commit is contained in:
@@ -24,10 +24,10 @@ import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
|
||||
* often they should be retried, and how long they should be retried for.
|
||||
*
|
||||
* Never rely on a specific instance of this class being run. It can be created and destroyed as the
|
||||
* job is retried. State that you want to save is persisted to a {@link Data} object in
|
||||
* job is retried. State that you want to save is persisted to a {@link JsonJobData} object in
|
||||
* {@link #serialize()}. Your job is then recreated using a {@link Factory} that you register in
|
||||
* {@link JobManager.Configuration.Builder#setJobFactories(Map)}, which is given the saved
|
||||
* {@link Data} bundle.
|
||||
* {@link JsonJobData} bundle.
|
||||
*/
|
||||
public abstract class Job {
|
||||
|
||||
@@ -62,11 +62,11 @@ public abstract class Job {
|
||||
return nextRunAttemptTime;
|
||||
}
|
||||
|
||||
public final @Nullable Data getInputData() {
|
||||
public final @Nullable byte[] getInputData() {
|
||||
return parameters.getInputData();
|
||||
}
|
||||
|
||||
public final @NonNull Data requireInputData() {
|
||||
public final @NonNull byte[] requireInputData() {
|
||||
return Objects.requireNonNull(parameters.getInputData());
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ public abstract class Job {
|
||||
/**
|
||||
* Serialize your job state so that it can be recreated in the future.
|
||||
*/
|
||||
public abstract @NonNull Data serialize();
|
||||
public abstract @Nullable byte[] serialize();
|
||||
|
||||
/**
|
||||
* Returns the key that can be used to find the relevant factory needed to create your job.
|
||||
@@ -146,7 +146,7 @@ public abstract class Job {
|
||||
public abstract void onFailure();
|
||||
|
||||
public interface Factory<T extends Job> {
|
||||
@NonNull T create(@NonNull Parameters parameters, @NonNull Data data);
|
||||
@NonNull T create(@NonNull Parameters parameters, @Nullable byte[] serializedData);
|
||||
}
|
||||
|
||||
public static final class Result {
|
||||
@@ -158,10 +158,10 @@ public abstract class Job {
|
||||
|
||||
private final ResultType resultType;
|
||||
private final RuntimeException runtimeException;
|
||||
private final Data outputData;
|
||||
private final byte[] outputData;
|
||||
private final long backoffInterval;
|
||||
|
||||
private Result(@NonNull ResultType resultType, @Nullable RuntimeException runtimeException, @Nullable Data outputData, long backoffInterval) {
|
||||
private Result(@NonNull ResultType resultType, @Nullable RuntimeException runtimeException, @Nullable byte[] outputData, long backoffInterval) {
|
||||
this.resultType = resultType;
|
||||
this.runtimeException = runtimeException;
|
||||
this.outputData = outputData;
|
||||
@@ -174,7 +174,7 @@ public abstract class Job {
|
||||
}
|
||||
|
||||
/** Job completed successfully and wants to provide some output data. */
|
||||
public static Result success(@Nullable Data outputData) {
|
||||
public static Result success(@Nullable byte[] outputData) {
|
||||
return new Result(ResultType.SUCCESS, null, outputData, INVALID_BACKOFF);
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ public abstract class Job {
|
||||
return runtimeException;
|
||||
}
|
||||
|
||||
@Nullable Data getOutputData() {
|
||||
@Nullable byte[] getOutputData() {
|
||||
return outputData;
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ public abstract class Job {
|
||||
private final int maxInstancesForQueue;
|
||||
private final String queue;
|
||||
private final List<String> constraintKeys;
|
||||
private final Data inputData;
|
||||
private final byte[] inputData;
|
||||
private final boolean memoryOnly;
|
||||
|
||||
private Parameters(@NonNull String id,
|
||||
@@ -270,7 +270,7 @@ public abstract class Job {
|
||||
int maxInstancesForQueue,
|
||||
@Nullable String queue,
|
||||
@NonNull List<String> constraintKeys,
|
||||
@Nullable Data inputData,
|
||||
@Nullable byte[] inputData,
|
||||
boolean memoryOnly)
|
||||
{
|
||||
this.id = id;
|
||||
@@ -317,7 +317,7 @@ public abstract class Job {
|
||||
return constraintKeys;
|
||||
}
|
||||
|
||||
@Nullable Data getInputData() {
|
||||
@Nullable byte[] getInputData() {
|
||||
return inputData;
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ public abstract class Job {
|
||||
private int maxInstancesForQueue;
|
||||
private String queue;
|
||||
private List<String> constraintKeys;
|
||||
private Data inputData;
|
||||
private byte[] inputData;
|
||||
private boolean memoryOnly;
|
||||
|
||||
public Builder() {
|
||||
@@ -358,7 +358,7 @@ public abstract class Job {
|
||||
int maxInstancesForQueue,
|
||||
@Nullable String queue,
|
||||
@NonNull List<String> constraintKeys,
|
||||
@Nullable Data inputData,
|
||||
@Nullable byte[] inputData,
|
||||
boolean memoryOnly)
|
||||
{
|
||||
this.id = id;
|
||||
@@ -465,10 +465,10 @@ public abstract class Job {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the input data that will be made availabe to the job when it is run.
|
||||
* Sets the input data that will be made available to the job when it is run.
|
||||
* Should only be set by {@link JobController}.
|
||||
*/
|
||||
@NonNull Builder setInputData(@Nullable Data inputData) {
|
||||
@NonNull Builder setInputData(@Nullable byte[] inputData) {
|
||||
this.inputData = inputData;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ class JobController {
|
||||
private final JobStorage jobStorage;
|
||||
private final JobInstantiator jobInstantiator;
|
||||
private final ConstraintInstantiator constraintInstantiator;
|
||||
private final Data.Serializer dataSerializer;
|
||||
private final JobTracker jobTracker;
|
||||
private final Scheduler scheduler;
|
||||
private final Debouncer debouncer;
|
||||
@@ -51,7 +50,6 @@ class JobController {
|
||||
@NonNull JobStorage jobStorage,
|
||||
@NonNull JobInstantiator jobInstantiator,
|
||||
@NonNull ConstraintInstantiator constraintInstantiator,
|
||||
@NonNull Data.Serializer dataSerializer,
|
||||
@NonNull JobTracker jobTracker,
|
||||
@NonNull Scheduler scheduler,
|
||||
@NonNull Debouncer debouncer,
|
||||
@@ -61,7 +59,6 @@ class JobController {
|
||||
this.jobStorage = jobStorage;
|
||||
this.jobInstantiator = jobInstantiator;
|
||||
this.constraintInstantiator = constraintInstantiator;
|
||||
this.dataSerializer = dataSerializer;
|
||||
this.jobTracker = jobTracker;
|
||||
this.scheduler = scheduler;
|
||||
this.debouncer = debouncer;
|
||||
@@ -229,7 +226,7 @@ class JobController {
|
||||
List<JobSpec> updatedJobs = new LinkedList<>();
|
||||
|
||||
for (JobSpec job : allJobs) {
|
||||
JobSpec updated = updater.update(job, dataSerializer);
|
||||
JobSpec updated = updater.update(job);
|
||||
if (updated != job) {
|
||||
updatedJobs.add(updated);
|
||||
}
|
||||
@@ -255,7 +252,7 @@ class JobController {
|
||||
|
||||
int nextRunAttempt = job.getRunAttempt() + 1;
|
||||
long nextRunAttemptTime = System.currentTimeMillis() + backoffInterval;
|
||||
String serializedData = dataSerializer.serialize(job.serialize());
|
||||
byte[] serializedData = job.serialize();
|
||||
|
||||
jobStorage.updateJobAfterRetry(job.getId(), false, nextRunAttempt, nextRunAttemptTime, serializedData);
|
||||
jobTracker.onStateChange(job, JobTracker.JobState.PENDING);
|
||||
@@ -279,7 +276,7 @@ class JobController {
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
synchronized void onSuccess(@NonNull Job job, @Nullable Data outputData) {
|
||||
synchronized void onSuccess(@NonNull Job job, @Nullable byte[] outputData) {
|
||||
if (outputData != null) {
|
||||
List<JobSpec> updates = Stream.of(jobStorage.getDependencySpecsThatDependOnJob(job.getId()))
|
||||
.map(DependencySpec::getJobId)
|
||||
@@ -452,7 +449,7 @@ class JobController {
|
||||
job.getRunAttempt(),
|
||||
job.getParameters().getMaxAttempts(),
|
||||
job.getParameters().getLifespan(),
|
||||
dataSerializer.serialize(job.serialize()),
|
||||
job.serialize(),
|
||||
null,
|
||||
false,
|
||||
job.getParameters().isMemoryOnly());
|
||||
@@ -511,8 +508,7 @@ class JobController {
|
||||
Job.Parameters parameters = buildJobParameters(jobSpec, constraintSpecs);
|
||||
|
||||
try {
|
||||
Data data = dataSerializer.deserialize(jobSpec.getSerializedData());
|
||||
Job job = jobInstantiator.instantiate(jobSpec.getFactoryKey(), parameters, data);
|
||||
Job job = jobInstantiator.instantiate(jobSpec.getFactoryKey(), parameters, jobSpec.getSerializedData());
|
||||
|
||||
job.setRunAttempt(jobSpec.getRunAttempt());
|
||||
job.setNextRunAttemptTime(jobSpec.getNextRunAttemptTime());
|
||||
@@ -542,11 +538,11 @@ class JobController {
|
||||
.setMaxAttempts(jobSpec.getMaxAttempts())
|
||||
.setQueue(jobSpec.getQueueKey())
|
||||
.setConstraints(Stream.of(constraintSpecs).map(ConstraintSpec::getFactoryKey).toList())
|
||||
.setInputData(jobSpec.getSerializedInputData() != null ? dataSerializer.deserialize(jobSpec.getSerializedInputData()) : null)
|
||||
.setInputData(jobSpec.getSerializedInputData())
|
||||
.build();
|
||||
}
|
||||
|
||||
private @NonNull JobSpec mapToJobWithInputData(@NonNull JobSpec jobSpec, @NonNull Data inputData) {
|
||||
private @NonNull JobSpec mapToJobWithInputData(@NonNull JobSpec jobSpec, @NonNull byte[] inputData) {
|
||||
return new JobSpec(jobSpec.getId(),
|
||||
jobSpec.getFactoryKey(),
|
||||
jobSpec.getQueueKey(),
|
||||
@@ -556,7 +552,7 @@ class JobController {
|
||||
jobSpec.getMaxAttempts(),
|
||||
jobSpec.getLifespan(),
|
||||
jobSpec.getSerializedData(),
|
||||
dataSerializer.serialize(inputData),
|
||||
inputData,
|
||||
jobSpec.isRunning(),
|
||||
jobSpec.isMemoryOnly());
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.jobmanager;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -13,7 +14,7 @@ class JobInstantiator {
|
||||
this.jobFactories = new HashMap<>(jobFactories);
|
||||
}
|
||||
|
||||
public @NonNull Job instantiate(@NonNull String jobFactoryKey, @NonNull Job.Parameters parameters, @NonNull Data data) {
|
||||
public @NonNull Job instantiate(@NonNull String jobFactoryKey, @NonNull Job.Parameters parameters, @Nullable byte[] data) {
|
||||
Job.Factory factory = jobFactories.get(jobFactoryKey);
|
||||
if (factory != null) {
|
||||
Job job = factory.create(parameters, data);
|
||||
|
||||
@@ -13,7 +13,6 @@ import androidx.annotation.WorkerThread;
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.DefaultExecutorFactory;
|
||||
import org.thoughtcrime.securesms.jobmanager.impl.JsonDataSerializer;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobSpec;
|
||||
import org.thoughtcrime.securesms.jobmanager.persistence.JobStorage;
|
||||
import org.thoughtcrime.securesms.util.Debouncer;
|
||||
@@ -66,7 +65,6 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
configuration.getJobStorage(),
|
||||
configuration.getJobInstantiator(),
|
||||
configuration.getConstraintFactories(),
|
||||
configuration.getDataSerializer(),
|
||||
configuration.getJobTracker(),
|
||||
Build.VERSION.SDK_INT < 26 ? new AlarmManagerScheduler(application)
|
||||
: new CompositeScheduler(new InAppScheduler(this), new JobSchedulerScheduler(application)),
|
||||
@@ -78,7 +76,7 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
JobStorage jobStorage = configuration.getJobStorage();
|
||||
jobStorage.init();
|
||||
|
||||
int latestVersion = configuration.getJobMigrator().migrate(jobStorage, configuration.getDataSerializer());
|
||||
int latestVersion = configuration.getJobMigrator().migrate(jobStorage);
|
||||
TextSecurePreferences.setJobManagerVersion(application, latestVersion);
|
||||
|
||||
jobController.init();
|
||||
@@ -544,7 +542,6 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
private final JobInstantiator jobInstantiator;
|
||||
private final ConstraintInstantiator constraintInstantiator;
|
||||
private final List<ConstraintObserver> constraintObservers;
|
||||
private final Data.Serializer dataSerializer;
|
||||
private final JobStorage jobStorage;
|
||||
private final JobMigrator jobMigrator;
|
||||
private final JobTracker jobTracker;
|
||||
@@ -555,7 +552,6 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
@NonNull JobInstantiator jobInstantiator,
|
||||
@NonNull ConstraintInstantiator constraintInstantiator,
|
||||
@NonNull List<ConstraintObserver> constraintObservers,
|
||||
@NonNull Data.Serializer dataSerializer,
|
||||
@NonNull JobStorage jobStorage,
|
||||
@NonNull JobMigrator jobMigrator,
|
||||
@NonNull JobTracker jobTracker,
|
||||
@@ -566,7 +562,6 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
this.jobInstantiator = jobInstantiator;
|
||||
this.constraintInstantiator = constraintInstantiator;
|
||||
this.constraintObservers = new ArrayList<>(constraintObservers);
|
||||
this.dataSerializer = dataSerializer;
|
||||
this.jobStorage = jobStorage;
|
||||
this.jobMigrator = jobMigrator;
|
||||
this.jobTracker = jobTracker;
|
||||
@@ -594,10 +589,6 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
return constraintObservers;
|
||||
}
|
||||
|
||||
@NonNull Data.Serializer getDataSerializer() {
|
||||
return dataSerializer;
|
||||
}
|
||||
|
||||
@NonNull JobStorage getJobStorage() {
|
||||
return jobStorage;
|
||||
}
|
||||
@@ -621,7 +612,6 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
private Map<String, Job.Factory> jobFactories = new HashMap<>();
|
||||
private Map<String, Constraint.Factory> constraintFactories = new HashMap<>();
|
||||
private List<ConstraintObserver> constraintObservers = new ArrayList<>();
|
||||
private Data.Serializer dataSerializer = new JsonDataSerializer();
|
||||
private JobStorage jobStorage = null;
|
||||
private JobMigrator jobMigrator = null;
|
||||
private JobTracker jobTracker = new JobTracker();
|
||||
@@ -657,11 +647,6 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Builder setDataSerializer(@NonNull Data.Serializer dataSerializer) {
|
||||
this.dataSerializer = dataSerializer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NonNull Builder setJobStorage(@NonNull JobStorage jobStorage) {
|
||||
this.jobStorage = jobStorage;
|
||||
return this;
|
||||
@@ -678,7 +663,6 @@ public class JobManager implements ConstraintObserver.Notifier {
|
||||
new JobInstantiator(jobFactories),
|
||||
new ConstraintInstantiator(constraintFactories),
|
||||
new ArrayList<>(constraintObservers),
|
||||
dataSerializer,
|
||||
jobStorage,
|
||||
jobMigrator,
|
||||
jobTracker,
|
||||
|
||||
@@ -31,9 +31,9 @@ public abstract class JobMigration {
|
||||
|
||||
private final String factoryKey;
|
||||
private final String queueKey;
|
||||
private final Data data;
|
||||
private final byte[] data;
|
||||
|
||||
public JobData(@NonNull String factoryKey, @Nullable String queueKey, @NonNull Data data) {
|
||||
public JobData(@NonNull String factoryKey, @Nullable String queueKey, @Nullable byte[] data) {
|
||||
this.factoryKey = factoryKey;
|
||||
this.queueKey = queueKey;
|
||||
this.data = data;
|
||||
@@ -47,7 +47,7 @@ public abstract class JobMigration {
|
||||
return new JobData(factoryKey, newQueueKey, data);
|
||||
}
|
||||
|
||||
public @NonNull JobData withData(@NonNull Data newData) {
|
||||
public @NonNull JobData withData(@Nullable byte[] newData) {
|
||||
return new JobData(factoryKey, queueKey, newData);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public abstract class JobMigration {
|
||||
return queueKey;
|
||||
}
|
||||
|
||||
public @NonNull Data getData() {
|
||||
public @NonNull byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class JobMigrator {
|
||||
/**
|
||||
* @return The version that has been migrated to.
|
||||
*/
|
||||
int migrate(@NonNull JobStorage jobStorage, @NonNull Data.Serializer dataSerializer) {
|
||||
int migrate(@NonNull JobStorage jobStorage) {
|
||||
List<JobSpec> jobSpecs = jobStorage.getAllJobSpecs();
|
||||
|
||||
for (int i = lastSeenVersion; i < currentVersion; i++) {
|
||||
@@ -58,22 +58,21 @@ public class JobMigrator {
|
||||
assert migration != null;
|
||||
|
||||
while (iter.hasNext()) {
|
||||
JobSpec jobSpec = iter.next();
|
||||
Data data = dataSerializer.deserialize(jobSpec.getSerializedData());
|
||||
JobData originalJobData = new JobData(jobSpec.getFactoryKey(), jobSpec.getQueueKey(), data);
|
||||
JobData updatedJobData = migration.migrate(originalJobData);
|
||||
JobSpec updatedJobSpec = new JobSpec(jobSpec.getId(),
|
||||
updatedJobData.getFactoryKey(),
|
||||
updatedJobData.getQueueKey(),
|
||||
jobSpec.getCreateTime(),
|
||||
jobSpec.getNextRunAttemptTime(),
|
||||
jobSpec.getRunAttempt(),
|
||||
jobSpec.getMaxAttempts(),
|
||||
jobSpec.getLifespan(),
|
||||
dataSerializer.serialize(updatedJobData.getData()),
|
||||
jobSpec.getSerializedInputData(),
|
||||
jobSpec.isRunning(),
|
||||
jobSpec.isMemoryOnly());
|
||||
JobSpec jobSpec = iter.next();
|
||||
JobData originalJobData = new JobData(jobSpec.getFactoryKey(), jobSpec.getQueueKey(), jobSpec.getSerializedData());
|
||||
JobData updatedJobData = migration.migrate(originalJobData);
|
||||
JobSpec updatedJobSpec = new JobSpec(jobSpec.getId(),
|
||||
updatedJobData.getFactoryKey(),
|
||||
updatedJobData.getQueueKey(),
|
||||
jobSpec.getCreateTime(),
|
||||
jobSpec.getNextRunAttemptTime(),
|
||||
jobSpec.getRunAttempt(),
|
||||
jobSpec.getMaxAttempts(),
|
||||
jobSpec.getLifespan(),
|
||||
updatedJobData.getData(),
|
||||
jobSpec.getSerializedInputData(),
|
||||
jobSpec.isRunning(),
|
||||
jobSpec.isMemoryOnly());
|
||||
|
||||
iter.set(updatedJobSpec);
|
||||
}
|
||||
|
||||
@@ -9,11 +9,8 @@ public interface JobUpdater {
|
||||
* Called for each enqueued job, giving you an opportunity to update each one.
|
||||
*
|
||||
* @param jobSpec An object representing data about an enqueued job.
|
||||
* @param serializer An object that can be used to serialize/deserialize data if necessary for
|
||||
* your update.
|
||||
*
|
||||
* @return The updated JobSpec you want persisted. If you do not wish to make an update, return
|
||||
* the literal same JobSpec instance you were provided.
|
||||
* the literal same JobSpec instance you were provided.
|
||||
*/
|
||||
@NonNull JobSpec update(@NonNull JobSpec jobSpec, @NonNull Data.Serializer serializer);
|
||||
@NonNull JobSpec update(@NonNull JobSpec jobSpec);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,12 @@ import androidx.annotation.Nullable;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -14,9 +18,11 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class Data {
|
||||
public class JsonJobData {
|
||||
|
||||
public static final Data EMPTY = new Data.Builder().build();
|
||||
public static final String TAG = Log.tag(JsonJobData.class);
|
||||
|
||||
public static final JsonJobData EMPTY = new JsonJobData.Builder().build();
|
||||
|
||||
@JsonProperty private final Map<String, String> strings;
|
||||
@JsonProperty private final Map<String, String[]> stringArrays;
|
||||
@@ -31,18 +37,31 @@ public class Data {
|
||||
@JsonProperty private final Map<String, Boolean> booleans;
|
||||
@JsonProperty private final Map<String, boolean[]> booleanArrays;
|
||||
|
||||
public Data(@JsonProperty("strings") @NonNull Map<String, String> strings,
|
||||
@JsonProperty("stringArrays") @NonNull Map<String, String[]> stringArrays,
|
||||
@JsonProperty("integers") @NonNull Map<String, Integer> integers,
|
||||
@JsonProperty("integerArrays") @NonNull Map<String, int[]> integerArrays,
|
||||
@JsonProperty("longs") @NonNull Map<String, Long> longs,
|
||||
@JsonProperty("longArrays") @NonNull Map<String, long[]> longArrays,
|
||||
@JsonProperty("floats") @NonNull Map<String, Float> floats,
|
||||
@JsonProperty("floatArrays") @NonNull Map<String, float[]> floatArrays,
|
||||
@JsonProperty("doubles") @NonNull Map<String, Double> doubles,
|
||||
@JsonProperty("doubleArrays") @NonNull Map<String, double[]> doubleArrays,
|
||||
@JsonProperty("booleans") @NonNull Map<String, Boolean> booleans,
|
||||
@JsonProperty("booleanArrays") @NonNull Map<String, boolean[]> booleanArrays)
|
||||
public static @NonNull JsonJobData deserialize(@Nullable byte[] data) {
|
||||
if (data == null) {
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
try {
|
||||
return JsonUtils.fromJson(data, JsonJobData.class);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to deserialize JSON.", e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private JsonJobData(@JsonProperty("strings") @NonNull Map<String, String> strings,
|
||||
@JsonProperty("stringArrays") @NonNull Map<String, String[]> stringArrays,
|
||||
@JsonProperty("integers") @NonNull Map<String, Integer> integers,
|
||||
@JsonProperty("integerArrays") @NonNull Map<String, int[]> integerArrays,
|
||||
@JsonProperty("longs") @NonNull Map<String, Long> longs,
|
||||
@JsonProperty("longArrays") @NonNull Map<String, long[]> longArrays,
|
||||
@JsonProperty("floats") @NonNull Map<String, Float> floats,
|
||||
@JsonProperty("floatArrays") @NonNull Map<String, float[]> floatArrays,
|
||||
@JsonProperty("doubles") @NonNull Map<String, Double> doubles,
|
||||
@JsonProperty("doubleArrays") @NonNull Map<String, double[]> doubleArrays,
|
||||
@JsonProperty("booleans") @NonNull Map<String, Boolean> booleans,
|
||||
@JsonProperty("booleanArrays") @NonNull Map<String, boolean[]> booleanArrays)
|
||||
{
|
||||
this.strings = strings;
|
||||
this.stringArrays = stringArrays;
|
||||
@@ -256,6 +275,34 @@ public class Data {
|
||||
return new Builder(this);
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return strings.isEmpty() &&
|
||||
stringArrays.isEmpty() &&
|
||||
integers.isEmpty() &&
|
||||
integerArrays.isEmpty() &&
|
||||
longs.isEmpty() &&
|
||||
longArrays.isEmpty() &&
|
||||
floats.isEmpty() &&
|
||||
floatArrays.isEmpty() &&
|
||||
doubles.isEmpty() &&
|
||||
doubleArrays.isEmpty() &&
|
||||
booleans.isEmpty() &&
|
||||
booleanArrays.isEmpty();
|
||||
}
|
||||
|
||||
public @Nullable byte[] serialize() {
|
||||
if (isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
try {
|
||||
return JsonUtils.toJson(this).getBytes(StandardCharsets.UTF_8);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to serialize to JSON.", e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Builder {
|
||||
|
||||
@@ -274,7 +321,7 @@ public class Data {
|
||||
|
||||
public Builder() { }
|
||||
|
||||
private Builder(@NonNull Data oldData) {
|
||||
private Builder(@NonNull JsonJobData oldData) {
|
||||
strings.putAll(oldData.strings);
|
||||
stringArrays.putAll(oldData.stringArrays);
|
||||
integers.putAll(oldData.integers);
|
||||
@@ -385,24 +432,28 @@ public class Data {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Data build() {
|
||||
return new Data(strings,
|
||||
stringArrays,
|
||||
integers,
|
||||
integerArrays,
|
||||
longs,
|
||||
longArrays,
|
||||
floats,
|
||||
floatArrays,
|
||||
doubles,
|
||||
doubleArrays,
|
||||
booleans,
|
||||
booleanArrays);
|
||||
public JsonJobData build() {
|
||||
return new JsonJobData(strings,
|
||||
stringArrays,
|
||||
integers,
|
||||
integerArrays,
|
||||
longs,
|
||||
longArrays,
|
||||
floats,
|
||||
floatArrays,
|
||||
doubles,
|
||||
doubleArrays,
|
||||
booleans,
|
||||
booleanArrays);
|
||||
}
|
||||
|
||||
public @Nullable byte[] serialize() {
|
||||
return build().serialize();
|
||||
}
|
||||
}
|
||||
|
||||
public interface Serializer {
|
||||
@NonNull String serialize(@NonNull Data data);
|
||||
@NonNull Data deserialize(@NonNull String serialized);
|
||||
@NonNull String serialize(@NonNull JsonJobData data);
|
||||
@NonNull JsonJobData deserialize(@NonNull String serialized);
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package org.thoughtcrime.securesms.jobmanager.impl;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.util.JsonUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class JsonDataSerializer implements Data.Serializer {
|
||||
|
||||
private static final String TAG = Log.tag(JsonDataSerializer.class);
|
||||
|
||||
@Override
|
||||
public @NonNull String serialize(@NonNull Data data) {
|
||||
try {
|
||||
return JsonUtils.toJson(data);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to serialize to JSON.", e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Data deserialize(@NonNull String serialized) {
|
||||
try {
|
||||
return JsonUtils.fromJson(serialized, Data.class);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to deserialize JSON.", e);
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.database.NoSuchMessageException;
|
||||
import org.thoughtcrime.securesms.database.PushTable;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
import org.thoughtcrime.securesms.jobs.FailingJob;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceEnvelope;
|
||||
@@ -39,16 +39,15 @@ public class PushDecryptMessageJobEnvelopeMigration extends JobMigration {
|
||||
}
|
||||
|
||||
private static @NonNull JobData migratePushDecryptMessageJob(@NonNull PushTable pushDatabase, @NonNull JobData jobData) {
|
||||
Data data = jobData.getData();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
if (data.hasLong("message_id")) {
|
||||
long messageId = data.getLong("message_id");
|
||||
try {
|
||||
SignalServiceEnvelope envelope = pushDatabase.get(messageId);
|
||||
return jobData.withData(jobData.getData()
|
||||
.buildUpon()
|
||||
.putBlobAsString("envelope", envelope.serialize())
|
||||
.build());
|
||||
return jobData.withData(data.buildUpon()
|
||||
.putBlobAsString("envelope", envelope.serialize())
|
||||
.serialize());
|
||||
} catch (NoSuchMessageException e) {
|
||||
Log.w(TAG, "Failed to find envelope in DB! Failing.");
|
||||
return jobData.withFactoryKey(FailingJob.KEY);
|
||||
|
||||
@@ -5,14 +5,12 @@ import android.content.Context;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.groups.BadGroupIdException;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.Base64;
|
||||
import org.thoughtcrime.securesms.util.GroupUtil;
|
||||
import org.whispersystems.signalservice.api.messages.SignalServiceContent;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -47,7 +45,7 @@ public class PushProcessMessageQueueJobMigration extends JobMigration {
|
||||
}
|
||||
|
||||
private static @NonNull JobData migratePushProcessMessageJob(@NonNull Context context, @NonNull JobData jobData) throws IOException {
|
||||
Data data = jobData.getData();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
String suffix = "";
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
|
||||
/**
|
||||
@@ -31,7 +31,9 @@ public class RecipientIdFollowUpJobMigration extends JobMigration {
|
||||
}
|
||||
|
||||
private static @NonNull JobData migrateRequestGroupInfoJob(@NonNull JobData jobData) {
|
||||
if (!jobData.getData().hasString("source") || !jobData.getData().hasString("group_id")) {
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
if (!data.hasString("source") || !data.hasString("group_id")) {
|
||||
return failingJobData();
|
||||
} else {
|
||||
return jobData;
|
||||
@@ -39,9 +41,11 @@ public class RecipientIdFollowUpJobMigration extends JobMigration {
|
||||
}
|
||||
|
||||
private static @NonNull JobData migrateSendDeliveryReceiptJob(@NonNull JobData jobData) {
|
||||
if (!jobData.getData().hasString("recipient") ||
|
||||
!jobData.getData().hasLong("message_id") ||
|
||||
!jobData.getData().hasLong("timestamp"))
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
if (!data.hasString("recipient") ||
|
||||
!data.hasLong("message_id") ||
|
||||
!data.hasLong("timestamp"))
|
||||
{
|
||||
return failingJobData();
|
||||
} else {
|
||||
@@ -50,6 +54,6 @@ public class RecipientIdFollowUpJobMigration extends JobMigration {
|
||||
}
|
||||
|
||||
private static JobData failingJobData() {
|
||||
return new JobData("FailingJob", null, new Data.Builder().build());
|
||||
return new JobData("FailingJob", null, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
@@ -47,120 +47,142 @@ public class RecipientIdJobMigration extends JobMigration {
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateMultiDeviceContactUpdateJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().hasString("address") ? jobData.getData().getString("address") : null;
|
||||
Data updatedData = new Data.Builder().putString("recipient", address != null ? Recipient.external(application, address).getId().serialize() : null)
|
||||
.putBoolean("force_sync", jobData.getData().getBoolean("force_sync"))
|
||||
.build();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
String address = data.hasString("address") ? data.getString("address") : null;
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("recipient", address != null ? Recipient.external(application, address).getId().serialize() : null)
|
||||
.putBoolean("force_sync", data.getBoolean("force_sync"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateMultiDeviceViewOnceOpenJob(@NonNull JobData jobData) {
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
try {
|
||||
String rawOld = jobData.getData().getString("message_id");
|
||||
String rawOld = data.getString("message_id");
|
||||
OldSerializableSyncMessageId old = JsonUtils.fromJson(rawOld, OldSerializableSyncMessageId.class);
|
||||
Recipient recipient = Recipient.external(application, old.sender);
|
||||
NewSerializableSyncMessageId updated = new NewSerializableSyncMessageId(recipient.getId().serialize(), old.timestamp);
|
||||
String rawUpdated = JsonUtils.toJson(updated);
|
||||
Data updatedData = new Data.Builder().putString("message_id", rawUpdated).build();
|
||||
String rawUpdated = JsonUtils.toJson(updated);
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("message_id", rawUpdated).build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
return jobData.withData(updatedData.serialize());
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateRequestGroupInfoJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("source");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("source", recipient.getId().serialize())
|
||||
.putString("group_id", jobData.getData().getString("group_id"))
|
||||
.build();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
String address = data.getString("source");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("source", recipient.getId().serialize())
|
||||
.putString("group_id", data.getString("group_id"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateSendDeliveryReceiptJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("address");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("recipient", recipient.getId().serialize())
|
||||
.putLong("message_id", jobData.getData().getLong("message_id"))
|
||||
.putLong("timestamp", jobData.getData().getLong("timestamp"))
|
||||
.build();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
String address = data.getString("address");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("recipient", recipient.getId().serialize())
|
||||
.putLong("message_id", data.getLong("message_id"))
|
||||
.putLong("timestamp", data.getLong("timestamp"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateMultiDeviceVerifiedUpdateJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("destination");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("destination", recipient.getId().serialize())
|
||||
.putString("identity_key", jobData.getData().getString("identity_key"))
|
||||
.putInt("verified_status", jobData.getData().getInt("verified_status"))
|
||||
.putLong("timestamp", jobData.getData().getLong("timestamp"))
|
||||
.build();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
String address = data.getString("destination");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("destination", recipient.getId().serialize())
|
||||
.putString("identity_key", data.getString("identity_key"))
|
||||
.putInt("verified_status", data.getInt("verified_status"))
|
||||
.putLong("timestamp", data.getLong("timestamp"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateRetrieveProfileJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("address");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("recipient", recipient.getId().serialize()).build();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
String address = data.getString("address");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("recipient", recipient.getId().serialize()).build();
|
||||
|
||||
return jobData.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migratePushGroupSendJob(@NonNull JobData jobData) {
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
// noinspection ConstantConditions
|
||||
Recipient queueRecipient = Recipient.external(application, jobData.getQueueKey());
|
||||
String address = jobData.getData().hasString("filter_address") ? jobData.getData().getString("filter_address") : null;
|
||||
String address = data.hasString("filter_address") ? data.getString("filter_address") : null;
|
||||
RecipientId recipientId = address != null ? Recipient.external(application, address).getId() : null;
|
||||
Data updatedData = new Data.Builder().putString("filter_recipient", recipientId != null ? recipientId.serialize() : null)
|
||||
.putLong("message_id", jobData.getData().getLong("message_id"))
|
||||
.build();
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("filter_recipient", recipientId != null ? recipientId.serialize() : null)
|
||||
.putLong("message_id", data.getLong("message_id"))
|
||||
.build();
|
||||
|
||||
return jobData.withQueueKey(queueRecipient.getId().toQueueKey())
|
||||
.withData(updatedData);
|
||||
.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migratePushGroupUpdateJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().getString("source");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("source", recipient.getId().serialize())
|
||||
.putString("group_id", jobData.getData().getString("group_id"))
|
||||
.build();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
String address = data.getString("source");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("source", recipient.getId().serialize())
|
||||
.putString("group_id", data.getString("group_id"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateDirectoryRefreshJob(@NonNull JobData jobData) {
|
||||
String address = jobData.getData().hasString("address") ? jobData.getData().getString("address") : null;
|
||||
Recipient recipient = address != null ? Recipient.external(application, address) : null;
|
||||
Data updatedData = new Data.Builder().putString("recipient", recipient != null ? recipient.getId().serialize() : null)
|
||||
.putBoolean("notify_of_new_users", jobData.getData().getBoolean("notify_of_new_users"))
|
||||
.build();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
String address = data.hasString("address") ? data.getString("address") : null;
|
||||
Recipient recipient = address != null ? Recipient.external(application, address) : null;
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("recipient", recipient != null ? recipient.getId().serialize() : null)
|
||||
.putBoolean("notify_of_new_users", data.getBoolean("notify_of_new_users"))
|
||||
.build();
|
||||
|
||||
return jobData.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateRetrieveProfileAvatarJob(@NonNull JobData jobData) {
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
//noinspection ConstantConditions
|
||||
String queueAddress = jobData.getQueueKey().substring("RetrieveProfileAvatarJob".length());
|
||||
Recipient queueRecipient = Recipient.external(application, queueAddress);
|
||||
String address = jobData.getData().getString("address");
|
||||
String address = data.getString("address");
|
||||
Recipient recipient = Recipient.external(application, address);
|
||||
Data updatedData = new Data.Builder().putString("recipient", recipient.getId().serialize())
|
||||
.putString("profile_avatar", jobData.getData().getString("profile_avatar"))
|
||||
.build();
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putString("recipient", recipient.getId().serialize())
|
||||
.putString("profile_avatar", data.getString("profile_avatar"))
|
||||
.build();
|
||||
|
||||
return jobData.withQueueKey("RetrieveProfileAvatarJob::" + queueRecipient.getId().toQueueKey())
|
||||
.withData(updatedData);
|
||||
.withData(updatedData.serialize());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateMultiDeviceReadUpdateJob(@NonNull JobData jobData) {
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
try {
|
||||
String[] rawOld = jobData.getData().getStringArray("message_ids");
|
||||
String[] rawOld = data.getStringArray("message_ids");
|
||||
String[] rawUpdated = new String[rawOld.length];
|
||||
|
||||
for (int i = 0; i < rawOld.length; i++) {
|
||||
@@ -171,27 +193,33 @@ public class RecipientIdJobMigration extends JobMigration {
|
||||
rawUpdated[i] = JsonUtils.toJson(updated);
|
||||
}
|
||||
|
||||
Data updatedData = new Data.Builder().putStringArray("message_ids", rawUpdated).build();
|
||||
JsonJobData updatedData = new JsonJobData.Builder().putStringArray("message_ids", rawUpdated).build();
|
||||
|
||||
return jobData.withData(updatedData);
|
||||
return jobData.withData(updatedData.serialize());
|
||||
} catch (IOException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private @NonNull JobData migratePushTextSendJob(@NonNull JobData jobData) {
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
//noinspection ConstantConditions
|
||||
Recipient recipient = Recipient.external(application, jobData.getQueueKey());
|
||||
return jobData.withQueueKey(recipient.getId().toQueueKey());
|
||||
}
|
||||
|
||||
private @NonNull JobData migratePushMediaSendJob(@NonNull JobData jobData) {
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
//noinspection ConstantConditions
|
||||
Recipient recipient = Recipient.external(application, jobData.getQueueKey());
|
||||
return jobData.withQueueKey(recipient.getId().toQueueKey());
|
||||
}
|
||||
|
||||
private @NonNull JobData migrateSmsSendJob(@NonNull JobData jobData) {
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (jobData.getQueueKey() != null) {
|
||||
Recipient recipient = Recipient.external(application, jobData.getQueueKey());
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
|
||||
public class RetrieveProfileJobMigration extends JobMigration {
|
||||
@@ -25,15 +25,15 @@ public class RetrieveProfileJobMigration extends JobMigration {
|
||||
}
|
||||
|
||||
private static @NonNull JobData migrateRetrieveProfileJob(@NonNull JobData jobData) {
|
||||
Data data = jobData.getData();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
if (data.hasString("recipient")) {
|
||||
Log.i(TAG, "Migrating job.");
|
||||
|
||||
String recipient = data.getString("recipient");
|
||||
return jobData.withData(new Data.Builder()
|
||||
return jobData.withData(new JsonJobData.Builder()
|
||||
.putStringArray("recipients", new String[] { recipient })
|
||||
.build());
|
||||
.serialize());
|
||||
} else {
|
||||
return jobData;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.thoughtcrime.securesms.jobmanager.migrations;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.database.MessageTable;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
|
||||
import java.util.SortedSet;
|
||||
@@ -27,10 +27,10 @@ public class SendReadReceiptsJobMigration extends JobMigration {
|
||||
}
|
||||
|
||||
private static @NonNull JobData migrateSendReadReceiptJob(@NonNull MessageTable messageTable, @NonNull JobData jobData) {
|
||||
Data data = jobData.getData();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
if (!data.hasLong("thread")) {
|
||||
long[] messageIds = jobData.getData().getLongArray("message_ids");
|
||||
long[] messageIds = data.getLongArray("message_ids");
|
||||
SortedSet<Long> threadIds = new TreeSet<>();
|
||||
|
||||
for (long id : messageIds) {
|
||||
@@ -41,9 +41,9 @@ public class SendReadReceiptsJobMigration extends JobMigration {
|
||||
}
|
||||
|
||||
if (threadIds.size() != 1) {
|
||||
return new JobData("FailingJob", null, new Data.Builder().build());
|
||||
return new JobData("FailingJob", null, null);
|
||||
} else {
|
||||
return jobData.withData(data.buildUpon().putLong("thread", threadIds.first()).build());
|
||||
return jobData.withData(data.buildUpon().putLong("thread", threadIds.first()).serialize());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -8,7 +8,7 @@ import org.thoughtcrime.securesms.database.GroupTable;
|
||||
import org.thoughtcrime.securesms.database.model.GroupRecord;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.JsonJobData;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobMigration;
|
||||
import org.thoughtcrime.securesms.jobs.FailingJob;
|
||||
|
||||
@@ -44,7 +44,7 @@ public class SenderKeyDistributionSendJobRecipientMigration extends JobMigration
|
||||
}
|
||||
|
||||
private static @NonNull JobData migrateJob(@NonNull JobData jobData, @NonNull GroupTable groupDatabase) {
|
||||
Data data = jobData.getData();
|
||||
JsonJobData data = JsonJobData.deserialize(jobData.getData());
|
||||
|
||||
if (data.hasString("group_id")) {
|
||||
GroupId groupId = GroupId.pushOrThrow(data.getStringAsBlob("group_id"));
|
||||
@@ -53,7 +53,7 @@ public class SenderKeyDistributionSendJobRecipientMigration extends JobMigration
|
||||
if (group.isPresent()) {
|
||||
return jobData.withData(data.buildUpon()
|
||||
.putString("thread_recipient_id", group.get().getRecipientId().serialize())
|
||||
.build());
|
||||
.serialize());
|
||||
|
||||
} else {
|
||||
return jobData.withFactoryKey(FailingJob.KEY);
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
package org.thoughtcrime.securesms.jobmanager.persistence;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
public final class JobSpec {
|
||||
|
||||
private final String id;
|
||||
private final String factoryKey;
|
||||
private final String queueKey;
|
||||
private final long createTime;
|
||||
private final long nextRunAttemptTime;
|
||||
private final int runAttempt;
|
||||
private final int maxAttempts;
|
||||
private final long lifespan;
|
||||
private final String serializedData;
|
||||
private final String serializedInputData;
|
||||
private final boolean isRunning;
|
||||
private final boolean memoryOnly;
|
||||
|
||||
public JobSpec(@NonNull String id,
|
||||
@NonNull String factoryKey,
|
||||
@Nullable String queueKey,
|
||||
long createTime,
|
||||
long nextRunAttemptTime,
|
||||
int runAttempt,
|
||||
int maxAttempts,
|
||||
long lifespan,
|
||||
@NonNull String serializedData,
|
||||
@Nullable String serializedInputData,
|
||||
boolean isRunning,
|
||||
boolean memoryOnly)
|
||||
{
|
||||
this.id = id;
|
||||
this.factoryKey = factoryKey;
|
||||
this.queueKey = queueKey;
|
||||
this.createTime = createTime;
|
||||
this.nextRunAttemptTime = nextRunAttemptTime;
|
||||
this.runAttempt = runAttempt;
|
||||
this.maxAttempts = maxAttempts;
|
||||
this.lifespan = lifespan;
|
||||
this.serializedData = serializedData;
|
||||
this.serializedInputData = serializedInputData;
|
||||
this.isRunning = isRunning;
|
||||
this.memoryOnly = memoryOnly;
|
||||
}
|
||||
|
||||
public @NonNull JobSpec withNextRunAttemptTime(long updated) {
|
||||
return new JobSpec(id, factoryKey, queueKey, createTime, updated, runAttempt, maxAttempts, lifespan, serializedData, serializedInputData, isRunning, memoryOnly);
|
||||
}
|
||||
|
||||
public @NonNull JobSpec withData(String updatedSerializedData) {
|
||||
return new JobSpec(id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, lifespan, updatedSerializedData, serializedInputData, isRunning, memoryOnly);
|
||||
}
|
||||
|
||||
public @NonNull String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public @NonNull String getFactoryKey() {
|
||||
return factoryKey;
|
||||
}
|
||||
|
||||
public @Nullable String getQueueKey() {
|
||||
return queueKey;
|
||||
}
|
||||
|
||||
public long getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public long getNextRunAttemptTime() {
|
||||
return nextRunAttemptTime;
|
||||
}
|
||||
|
||||
public int getRunAttempt() {
|
||||
return runAttempt;
|
||||
}
|
||||
|
||||
public int getMaxAttempts() {
|
||||
return maxAttempts;
|
||||
}
|
||||
|
||||
public long getLifespan() {
|
||||
return lifespan;
|
||||
}
|
||||
|
||||
public @NonNull String getSerializedData() {
|
||||
return serializedData;
|
||||
}
|
||||
|
||||
public @Nullable String getSerializedInputData() {
|
||||
return serializedInputData;
|
||||
}
|
||||
|
||||
public boolean isRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
public boolean isMemoryOnly() {
|
||||
return memoryOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
JobSpec jobSpec = (JobSpec) o;
|
||||
return createTime == jobSpec.createTime &&
|
||||
nextRunAttemptTime == jobSpec.nextRunAttemptTime &&
|
||||
runAttempt == jobSpec.runAttempt &&
|
||||
maxAttempts == jobSpec.maxAttempts &&
|
||||
lifespan == jobSpec.lifespan &&
|
||||
isRunning == jobSpec.isRunning &&
|
||||
memoryOnly == jobSpec.memoryOnly &&
|
||||
Objects.equals(id, jobSpec.id) &&
|
||||
Objects.equals(factoryKey, jobSpec.factoryKey) &&
|
||||
Objects.equals(queueKey, jobSpec.queueKey) &&
|
||||
Objects.equals(serializedData, jobSpec.serializedData) &&
|
||||
Objects.equals(serializedInputData, jobSpec.serializedInputData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, lifespan, serializedData, serializedInputData, isRunning, memoryOnly);
|
||||
}
|
||||
|
||||
@SuppressLint("DefaultLocale")
|
||||
@Override
|
||||
public @NonNull String toString() {
|
||||
return String.format(Locale.US, "id: JOB::%s | factoryKey: %s | queueKey: %s | createTime: %d | nextRunAttemptTime: %d | runAttempt: %d | maxAttempts: %d | lifespan: %d | isRunning: %b | memoryOnly: %b",
|
||||
id, factoryKey, queueKey, createTime, nextRunAttemptTime, runAttempt, maxAttempts, lifespan, isRunning, memoryOnly);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.thoughtcrime.securesms.jobmanager.persistence
|
||||
|
||||
data class JobSpec(
|
||||
val id: String,
|
||||
val factoryKey: String,
|
||||
val queueKey: String?,
|
||||
val createTime: Long,
|
||||
val nextRunAttemptTime: Long,
|
||||
val runAttempt: Int,
|
||||
val maxAttempts: Int,
|
||||
val lifespan: Long,
|
||||
val serializedData: ByteArray?,
|
||||
val serializedInputData: ByteArray?,
|
||||
val isRunning: Boolean,
|
||||
val isMemoryOnly: Boolean
|
||||
) {
|
||||
|
||||
fun withNextRunAttemptTime(updated: Long): JobSpec {
|
||||
return copy(nextRunAttemptTime = updated)
|
||||
}
|
||||
|
||||
fun withData(updatedSerializedData: ByteArray?): JobSpec {
|
||||
return copy(serializedData = updatedSerializedData)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "id: JOB::$id | factoryKey: $factoryKey | queueKey: $queueKey | createTime: $createTime | nextRunAttemptTime: $nextRunAttemptTime | runAttempt: $runAttempt | maxAttempts: $maxAttempts | lifespan: $lifespan | isRunning: $isRunning | memoryOnly: $isMemoryOnly"
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as JobSpec
|
||||
|
||||
if (id != other.id) return false
|
||||
if (factoryKey != other.factoryKey) return false
|
||||
if (queueKey != other.queueKey) return false
|
||||
if (createTime != other.createTime) return false
|
||||
if (nextRunAttemptTime != other.nextRunAttemptTime) return false
|
||||
if (runAttempt != other.runAttempt) return false
|
||||
if (maxAttempts != other.maxAttempts) return false
|
||||
if (lifespan != other.lifespan) return false
|
||||
if (serializedData != null) {
|
||||
if (other.serializedData == null) return false
|
||||
if (!serializedData.contentEquals(other.serializedData)) return false
|
||||
} else if (other.serializedData != null) return false
|
||||
if (serializedInputData != null) {
|
||||
if (other.serializedInputData == null) return false
|
||||
if (!serializedInputData.contentEquals(other.serializedInputData)) return false
|
||||
} else if (other.serializedInputData != null) return false
|
||||
if (isRunning != other.isRunning) return false
|
||||
if (isMemoryOnly != other.isMemoryOnly) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + factoryKey.hashCode()
|
||||
result = 31 * result + (queueKey?.hashCode() ?: 0)
|
||||
result = 31 * result + createTime.hashCode()
|
||||
result = 31 * result + nextRunAttemptTime.hashCode()
|
||||
result = 31 * result + runAttempt
|
||||
result = 31 * result + maxAttempts
|
||||
result = 31 * result + lifespan.hashCode()
|
||||
result = 31 * result + (serializedData?.contentHashCode() ?: 0)
|
||||
result = 31 * result + (serializedInputData?.contentHashCode() ?: 0)
|
||||
result = 31 * result + isRunning.hashCode()
|
||||
result = 31 * result + isMemoryOnly.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public interface JobStorage {
|
||||
void updateJobRunningState(@NonNull String id, boolean isRunning);
|
||||
|
||||
@WorkerThread
|
||||
void updateJobAfterRetry(@NonNull String id, boolean isRunning, int runAttempt, long nextRunAttemptTime, @NonNull String serializedData);
|
||||
void updateJobAfterRetry(@NonNull String id, boolean isRunning, int runAttempt, long nextRunAttemptTime, @Nullable byte[] serializedData);
|
||||
|
||||
@WorkerThread
|
||||
void updateAllJobsToBePending();
|
||||
|
||||
Reference in New Issue
Block a user