Prevent KeepAlive Job from alerting user on 409 error.

fork-5.53.8
Alex Hart 2021-12-21 16:01:05 -04:00 zatwierdzone przez Greyson Parrelli
rodzic 46dd7f8a06
commit fde1e5ab77
3 zmienionych plików z 47 dodań i 17 usunięć

Wyświetl plik

@ -28,6 +28,7 @@ public class DonationReceiptRedemptionJob extends BaseJob {
public static final String KEY = "DonationReceiptRedemptionJob"; public static final String KEY = "DonationReceiptRedemptionJob";
public static final String INPUT_RECEIPT_CREDENTIAL_PRESENTATION = "data.receipt.credential.presentation"; public static final String INPUT_RECEIPT_CREDENTIAL_PRESENTATION = "data.receipt.credential.presentation";
public static final String INPUT_PAYMENT_FAILURE = "data.payment.failure"; public static final String INPUT_PAYMENT_FAILURE = "data.payment.failure";
public static final String INPUT_KEEP_ALIVE_409 = "data.keep.alive.409";
public static DonationReceiptRedemptionJob createJobForSubscription() { public static DonationReceiptRedemptionJob createJobForSubscription() {
return new DonationReceiptRedemptionJob( return new DonationReceiptRedemptionJob(
@ -72,6 +73,9 @@ public class DonationReceiptRedemptionJob extends BaseJob {
if (inputData != null && inputData.getBooleanOrDefault(INPUT_PAYMENT_FAILURE, false)) { if (inputData != null && inputData.getBooleanOrDefault(INPUT_PAYMENT_FAILURE, false)) {
DonorBadgeNotifications.PaymentFailed.INSTANCE.show(context); DonorBadgeNotifications.PaymentFailed.INSTANCE.show(context);
} else if (inputData != null && inputData.getBooleanOrDefault(INPUT_KEEP_ALIVE_409, false)) {
Log.i(TAG, "Skipping redemption due to 409 error during keep-alive.");
return;
} else { } else {
DonorBadgeNotifications.RedemptionFailed.INSTANCE.show(context); DonorBadgeNotifications.RedemptionFailed.INSTANCE.show(context);
} }
@ -79,6 +83,7 @@ public class DonationReceiptRedemptionJob extends BaseJob {
if (isForSubscription()) { if (isForSubscription()) {
Log.d(TAG, "Marking subscription failure", true); Log.d(TAG, "Marking subscription failure", true);
SignalStore.donationsValues().markSubscriptionRedemptionFailed(); SignalStore.donationsValues().markSubscriptionRedemptionFailed();
MultiDeviceSubscriptionSyncRequestJob.enqueue();
} }
} }

Wyświetl plik

@ -15,6 +15,7 @@ import org.whispersystems.signalservice.internal.EmptyResponse;
import org.whispersystems.signalservice.internal.ServiceResponse; import org.whispersystems.signalservice.internal.ServiceResponse;
import java.io.IOException; import java.io.IOException;
import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
@ -95,8 +96,14 @@ public class SubscriptionKeepAliveJob extends BaseJob {
} }
if (activeSubscription.getActiveSubscription().getEndOfCurrentPeriod() > SignalStore.donationsValues().getLastEndOfPeriod()) { if (activeSubscription.getActiveSubscription().getEndOfCurrentPeriod() > SignalStore.donationsValues().getLastEndOfPeriod()) {
Log.i(TAG, "Last end of period change. Requesting receipt refresh.", true); Log.i(TAG,
SubscriptionReceiptRequestResponseJob.createSubscriptionContinuationJobChain().enqueue(); String.format(Locale.US,
"Last end of period change. Requesting receipt refresh. (old: %d to new: %d)",
SignalStore.donationsValues().getLastEndOfPeriod(),
activeSubscription.getActiveSubscription().getEndOfCurrentPeriod()),
true);
SubscriptionReceiptRequestResponseJob.createSubscriptionContinuationJobChain(true).enqueue();
} }
} }

Wyświetl plik

@ -39,16 +39,18 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
public static final String KEY = "SubscriptionReceiptCredentialsSubmissionJob"; public static final String KEY = "SubscriptionReceiptCredentialsSubmissionJob";
private static final String DATA_REQUEST_BYTES = "data.request.bytes"; private static final String DATA_REQUEST_BYTES = "data.request.bytes";
private static final String DATA_SUBSCRIBER_ID = "data.subscriber.id"; private static final String DATA_SUBSCRIBER_ID = "data.subscriber.id";
private static final String DATA_IS_FOR_KEEP_ALIVE = "data.is.for.keep.alive";
public static final Object MUTEX = new Object(); public static final Object MUTEX = new Object();
private ReceiptCredentialRequestContext requestContext; private ReceiptCredentialRequestContext requestContext;
private final SubscriberId subscriberId; private final SubscriberId subscriberId;
private final boolean isForKeepAlive;
static SubscriptionReceiptRequestResponseJob createJob(SubscriberId subscriberId) { private static SubscriptionReceiptRequestResponseJob createJob(SubscriberId subscriberId, boolean isForKeepAlive) {
return new SubscriptionReceiptRequestResponseJob( return new SubscriptionReceiptRequestResponseJob(
new Parameters new Parameters
.Builder() .Builder()
@ -59,13 +61,18 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
.setMaxAttempts(Parameters.UNLIMITED) .setMaxAttempts(Parameters.UNLIMITED)
.build(), .build(),
null, null,
subscriberId subscriberId,
isForKeepAlive
); );
} }
public static JobManager.Chain createSubscriptionContinuationJobChain() { public static JobManager.Chain createSubscriptionContinuationJobChain() {
return createSubscriptionContinuationJobChain(false);
}
public static JobManager.Chain createSubscriptionContinuationJobChain(boolean isForKeepAlive) {
Subscriber subscriber = SignalStore.donationsValues().requireSubscriber(); Subscriber subscriber = SignalStore.donationsValues().requireSubscriber();
SubscriptionReceiptRequestResponseJob requestReceiptJob = createJob(subscriber.getSubscriberId()); SubscriptionReceiptRequestResponseJob requestReceiptJob = createJob(subscriber.getSubscriberId(), isForKeepAlive);
DonationReceiptRedemptionJob redeemReceiptJob = DonationReceiptRedemptionJob.createJobForSubscription(); DonationReceiptRedemptionJob redeemReceiptJob = DonationReceiptRedemptionJob.createJobForSubscription();
RefreshOwnProfileJob refreshOwnProfileJob = RefreshOwnProfileJob.forSubscription(); RefreshOwnProfileJob refreshOwnProfileJob = RefreshOwnProfileJob.forSubscription();
@ -77,16 +84,19 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
private SubscriptionReceiptRequestResponseJob(@NonNull Parameters parameters, private SubscriptionReceiptRequestResponseJob(@NonNull Parameters parameters,
@Nullable ReceiptCredentialRequestContext requestContext, @Nullable ReceiptCredentialRequestContext requestContext,
@NonNull SubscriberId subscriberId) @NonNull SubscriberId subscriberId,
boolean isForKeepAlive)
{ {
super(parameters); super(parameters);
this.requestContext = requestContext; this.requestContext = requestContext;
this.subscriberId = subscriberId; this.subscriberId = subscriberId;
this.isForKeepAlive = isForKeepAlive;
} }
@Override @Override
public @NonNull Data serialize() { public @NonNull Data serialize() {
Data.Builder builder = new Data.Builder().putBlobAsString(DATA_SUBSCRIBER_ID, subscriberId.getBytes()); Data.Builder builder = new Data.Builder().putBlobAsString(DATA_SUBSCRIBER_ID, subscriberId.getBytes())
.putBoolean(DATA_IS_FOR_KEEP_ALIVE, isForKeepAlive);
if (requestContext != null) { if (requestContext != null) {
builder.putBlobAsString(DATA_REQUEST_BYTES, requestContext.serialize()); builder.putBlobAsString(DATA_REQUEST_BYTES, requestContext.serialize());
@ -102,9 +112,6 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
@Override @Override
public void onFailure() { public void onFailure() {
DonorBadgeNotifications.RedemptionFailed.INSTANCE.show(context);
SignalStore.donationsValues().markSubscriptionRedemptionFailed();
MultiDeviceSubscriptionSyncRequestJob.enqueue();
} }
@Override @Override
@ -231,8 +238,8 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
Log.w(TAG, "SubscriberId not found or misformed.", response.getApplicationError().get(), true); Log.w(TAG, "SubscriberId not found or misformed.", response.getApplicationError().get(), true);
throw new Exception(response.getApplicationError().get()); throw new Exception(response.getApplicationError().get());
case 409: case 409:
Log.w(TAG, "Latest paid receipt on subscription already redeemed with a different request credential.", response.getApplicationError().get(), true); onAlreadyRedeemed(response);
throw new Exception(response.getApplicationError().get()); break;
default: default:
Log.w(TAG, "Encountered a server failure response: " + response.getStatus(), response.getApplicationError().get(), true); Log.w(TAG, "Encountered a server failure response: " + response.getStatus(), response.getApplicationError().get(), true);
throw new RetryableException(); throw new RetryableException();
@ -245,6 +252,16 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
MultiDeviceSubscriptionSyncRequestJob.enqueue(); MultiDeviceSubscriptionSyncRequestJob.enqueue();
} }
private void onAlreadyRedeemed(ServiceResponse<ReceiptCredentialResponse> response) throws Exception {
if (isForKeepAlive) {
Log.i(TAG, "KeepAlive: Latest paid receipt on subscription already redeemed with a different request credential, ignoring.", response.getApplicationError().get(), true);
setOutputData(new Data.Builder().putBoolean(DonationReceiptRedemptionJob.INPUT_KEEP_ALIVE_409, true).build());
} else {
Log.w(TAG, "Latest paid receipt on subscription already redeemed with a different request credential.", response.getApplicationError().get(), true);
throw new Exception(response.getApplicationError().get());
}
}
/** /**
* Checks that the generated Receipt Credential has the following characteristics * Checks that the generated Receipt Credential has the following characteristics
* - level should match the current subscription level and be the same level you signed up for at the time the subscription was last updated * - level should match the current subscription level and be the same level you signed up for at the time the subscription was last updated
@ -282,16 +299,17 @@ public class SubscriptionReceiptRequestResponseJob extends BaseJob {
public static class Factory implements Job.Factory<SubscriptionReceiptRequestResponseJob> { public static class Factory implements Job.Factory<SubscriptionReceiptRequestResponseJob> {
@Override @Override
public @NonNull SubscriptionReceiptRequestResponseJob create(@NonNull Parameters parameters, @NonNull Data data) { public @NonNull SubscriptionReceiptRequestResponseJob create(@NonNull Parameters parameters, @NonNull Data data) {
SubscriberId subscriberId = SubscriberId.fromBytes(data.getStringAsBlob(DATA_SUBSCRIBER_ID)); SubscriberId subscriberId = SubscriberId.fromBytes(data.getStringAsBlob(DATA_SUBSCRIBER_ID));
boolean isForKeepAlive = data.getBooleanOrDefault(DATA_IS_FOR_KEEP_ALIVE, false);
try { try {
if (data.hasString(DATA_REQUEST_BYTES)) { if (data.hasString(DATA_REQUEST_BYTES)) {
byte[] blob = data.getStringAsBlob(DATA_REQUEST_BYTES); byte[] blob = data.getStringAsBlob(DATA_REQUEST_BYTES);
ReceiptCredentialRequestContext requestContext = new ReceiptCredentialRequestContext(blob); ReceiptCredentialRequestContext requestContext = new ReceiptCredentialRequestContext(blob);
return new SubscriptionReceiptRequestResponseJob(parameters, requestContext, subscriberId); return new SubscriptionReceiptRequestResponseJob(parameters, requestContext, subscriberId, isForKeepAlive);
} else { } else {
return new SubscriptionReceiptRequestResponseJob(parameters, null, subscriberId); return new SubscriptionReceiptRequestResponseJob(parameters, null, subscriberId, isForKeepAlive);
} }
} catch (InvalidInputException e) { } catch (InvalidInputException e) {
throw new IllegalStateException(e); throw new IllegalStateException(e);