83 lines
3.4 KiB
C#
83 lines
3.4 KiB
C#
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using AMREZ.EOP.Abstractions.Infrastructures.Integrations.SCB.Clients;
|
|
using AMREZ.EOP.Contracts.DTOs.Integrations.SCB.OAuth;
|
|
using AMREZ.EOP.Contracts.DTOs.Integrations.SCB.SlipVerification;
|
|
using AMREZ.EOP.Domain.Shared.Payments;
|
|
|
|
namespace AMREZ.EOP.Infrastructures.Integrations.SCB.Clients;
|
|
|
|
public sealed class ScbSlipClient : IScbSlipClient
|
|
{
|
|
private readonly HttpClient _http;
|
|
private readonly SCBOptions _opts;
|
|
private readonly JsonSerializerOptions _json = new()
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
|
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
|
|
};
|
|
|
|
private string? _token;
|
|
private DateTimeOffset _exp;
|
|
private readonly SemaphoreSlim _gate = new(1,1);
|
|
|
|
public ScbSlipClient(HttpClient http, SCBOptions opts)
|
|
{
|
|
_http = http;
|
|
_opts = opts;
|
|
}
|
|
|
|
public async Task<SlipVerificationEnvelope?> VerifyAsync(string transRef, string sendingBank, CancellationToken ct)
|
|
{
|
|
var bearer = await GetTokenAsync(ct);
|
|
var path = $"payment/billpayment/transactions/{Uri.EscapeDataString(transRef)}?sendingBank={Uri.EscapeDataString(sendingBank)}";
|
|
|
|
using var req = new HttpRequestMessage(HttpMethod.Get, path);
|
|
AddHeaders(req.Headers, bearer);
|
|
|
|
using var res = await _http.SendAsync(req, ct);
|
|
var body = await res.Content.ReadAsStringAsync(ct);
|
|
if (!res.IsSuccessStatusCode) return null;
|
|
|
|
return JsonSerializer.Deserialize<SlipVerificationEnvelope>(body, _json);
|
|
}
|
|
|
|
private async Task<string> GetTokenAsync(CancellationToken ct)
|
|
{
|
|
if (!string.IsNullOrEmpty(_token) && _exp > DateTimeOffset.UtcNow.AddSeconds(30)) return _token!;
|
|
await _gate.WaitAsync(ct);
|
|
try
|
|
{
|
|
if (!string.IsNullOrEmpty(_token) && _exp > DateTimeOffset.UtcNow.AddSeconds(30)) return _token!;
|
|
|
|
var json = JsonSerializer.Serialize(new OAuthRequest(_opts.SCBApplicationKey, _opts.SCBApplicationSecret), _json);
|
|
using var req = new HttpRequestMessage(HttpMethod.Post, "oauth/token")
|
|
{ Content = new StringContent(json, Encoding.UTF8, "application/json") };
|
|
AddHeaders(req.Headers, null);
|
|
|
|
using var res = await _http.SendAsync(req, ct);
|
|
var body = await res.Content.ReadAsStringAsync(ct);
|
|
res.EnsureSuccessStatusCode();
|
|
|
|
var parsed = JsonSerializer.Deserialize<OAuthResponse>(body, _json)
|
|
?? throw new UnauthorizedAccessException("OAuth parse failed");
|
|
if (parsed.Status?.Code != 1000) throw new UnauthorizedAccessException(parsed.Status?.Description ?? "OAuth not OK");
|
|
|
|
_token = parsed.Data?.AccessToken ?? throw new UnauthorizedAccessException("No token");
|
|
var ttl = parsed.Data?.ExpiresIn ?? 300;
|
|
_exp = DateTimeOffset.UtcNow.AddSeconds(ttl);
|
|
return _token!;
|
|
}
|
|
finally { _gate.Release(); }
|
|
}
|
|
|
|
private void AddHeaders(HttpRequestHeaders h, string? bearer)
|
|
{
|
|
h.TryAddWithoutValidation("accept-language", _opts.DefaultLanguage);
|
|
h.TryAddWithoutValidation("requestUId", Guid.NewGuid().ToString());
|
|
h.TryAddWithoutValidation("resourceOwnerId", _opts.SCBResourceOwnerId);
|
|
if (!string.IsNullOrEmpty(bearer))
|
|
h.Authorization = new AuthenticationHeaderValue("Bearer", bearer);
|
|
}
|
|
} |