Files
LMEMappeCatastaliProApp/Services/PlayPurchaseVerificationService.cs

88 lines
3.3 KiB
C#

using System.Net.Http.Json;
using System.Reflection;
namespace LMEMappeCatastaliApp.Services;
public sealed class PlayPurchaseVerificationService
{
private const string EndpointMetadataKey = "PlayBillingVerificationUrl";
private const string RequiredMetadataKey = "PlayBillingVerificationRequired";
private readonly HttpClient _httpClient = new() { Timeout = TimeSpan.FromSeconds(20) };
public bool IsConfigured => VerificationEndpoint is not null;
public bool IsRequired => ReadMetadata(RequiredMetadataKey).Equals("true", StringComparison.OrdinalIgnoreCase);
private static Uri? VerificationEndpoint
{
get
{
var value = ReadMetadata(EndpointMetadataKey);
return Uri.TryCreate(value, UriKind.Absolute, out var endpoint)
&& endpoint.Scheme == Uri.UriSchemeHttps
? endpoint
: null;
}
}
public async Task<PlayPurchaseVerificationResult> VerifyAsync(
string purchaseToken,
CancellationToken cancellationToken = default)
{
var endpoint = VerificationEndpoint;
if (endpoint is null)
{
return PlayPurchaseVerificationResult.NotConfigured();
}
try
{
using var response = await _httpClient.PostAsJsonAsync(endpoint, new
{
packageName = AppInfo.Current.PackageName,
productId = EntitlementService.ProductId,
purchaseToken
}, cancellationToken);
if (!response.IsSuccessStatusCode)
{
return PlayPurchaseVerificationResult.Failed(
$"Verifica acquisto non disponibile ({(int)response.StatusCode}).");
}
var result = await response.Content.ReadFromJsonAsync<VerificationResponse>(cancellationToken);
return result is null
? PlayPurchaseVerificationResult.Failed("Risposta di verifica acquisto non valida.")
: new(true, true, result.Active, result.ExpiresAt, result.Message ?? string.Empty);
}
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
{
return PlayPurchaseVerificationResult.Failed("Il server di verifica acquisti non ha risposto in tempo.");
}
catch (Exception error)
{
return PlayPurchaseVerificationResult.Failed(
$"Verifica acquisto non disponibile: {error.GetBaseException().Message}");
}
}
private static string ReadMetadata(string key) =>
typeof(PlayPurchaseVerificationService).Assembly
.GetCustomAttributes<AssemblyMetadataAttribute>()
.FirstOrDefault(attribute => attribute.Key == key)?.Value?.Trim() ?? string.Empty;
private sealed record VerificationResponse(bool Active, DateTimeOffset? ExpiresAt, string? Message);
}
public sealed record PlayPurchaseVerificationResult(
bool Configured,
bool Verified,
bool Active,
DateTimeOffset? ExpiresAt,
string Message)
{
public static PlayPurchaseVerificationResult NotConfigured() =>
new(false, false, false, null, "Server di verifica acquisti non configurato.");
public static PlayPurchaseVerificationResult Failed(string message) =>
new(true, false, false, null, message);
}