Files
Cleanuparr/code/backend/Cleanuparr.Infrastructure/Features/Notifications/Pushover/PushoverProxy.cs
T

113 lines
3.9 KiB
C#

using System.Net;
using System.Text.Json;
using Cleanuparr.Infrastructure.Json;
using Cleanuparr.Shared.Helpers;
namespace Cleanuparr.Infrastructure.Features.Notifications.Pushover;
public sealed class PushoverProxy : IPushoverProxy
{
private const string ApiUrl = "https://api.pushover.net/1/messages.json";
private readonly HttpClient _httpClient;
public PushoverProxy(IHttpClientFactory httpClientFactory)
{
_httpClient = httpClientFactory.CreateClient(Constants.HttpClientWithRetryName);
}
public async Task SendNotification(PushoverPayload payload)
{
try
{
var formData = new Dictionary<string, string>
{
["token"] = payload.Token,
["user"] = payload.User,
["message"] = payload.Message,
["priority"] = payload.Priority.ToString()
};
if (!string.IsNullOrWhiteSpace(payload.Title))
formData["title"] = payload.Title;
if (!string.IsNullOrWhiteSpace(payload.Device))
formData["device"] = payload.Device;
if (!string.IsNullOrWhiteSpace(payload.Sound))
formData["sound"] = payload.Sound;
// Emergency priority requires retry and expire
if (payload.Priority == 2)
{
if (payload.Retry.HasValue)
formData["retry"] = payload.Retry.Value.ToString();
if (payload.Expire.HasValue)
formData["expire"] = payload.Expire.Value.ToString();
}
if (!string.IsNullOrWhiteSpace(payload.Tags))
formData["tags"] = payload.Tags;
using var content = new FormUrlEncodedContent(formData);
using var response = await _httpClient.PostAsync(ApiUrl, content);
var responseBody = await response.Content.ReadAsStringAsync();
PushoverResponse? pushoverResponse = ReadResponse(responseBody);
if (!response.IsSuccessStatusCode || pushoverResponse?.IsSuccess != true)
{
string errorMessage = pushoverResponse?.Errors?.FirstOrDefault()
?? (pushoverResponse is null
? $"unreadable response body ({response.StatusCode}): {Truncate(responseBody)}"
: $"Pushover API error: {response.StatusCode}");
throw response.StatusCode switch
{
HttpStatusCode.BadRequest => new PushoverException($"Bad request: {errorMessage}"),
HttpStatusCode.Unauthorized => new PushoverException("Invalid API token or user key"),
(HttpStatusCode)429 => new PushoverException("Rate limit exceeded - monthly quota reached"),
_ => new PushoverException($"Failed to send notification: {errorMessage}")
};
}
}
catch (PushoverException)
{
throw;
}
catch (HttpRequestException ex)
{
throw new PushoverException("Unable to connect to Pushover API", ex);
}
}
/// <summary>
/// Reads the body of a response from Pushover. A body that is not JSON gives null.
/// </summary>
private static PushoverResponse? ReadResponse(string responseBody)
{
if (string.IsNullOrWhiteSpace(responseBody))
{
return null;
}
try
{
return JsonSerializer.Deserialize<PushoverResponse>(responseBody, CleanuparrJsonOptions.ExternalApiRead);
}
catch (JsonException)
{
return null;
}
}
private static string Truncate(string responseBody)
{
if (string.IsNullOrWhiteSpace(responseBody))
{
return "<empty>";
}
return responseBody.Length > 200 ? responseBody[..200] : responseBody;
}
}