use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use thiserror::Error;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Priority {
#[default]
Immediate,
Conserve,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Notification {
pub title: String,
pub body: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub thread_id: Option<String>,
#[serde(default)]
pub data: Value,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub collapse_id: Option<String>,
#[serde(default)]
pub priority: Priority,
}
impl Notification {
#[must_use]
pub fn new(title: impl Into<String>, body: impl Into<String>) -> Self {
Self {
title: title.into(),
body: body.into(),
category: None,
thread_id: None,
data: Value::Null,
collapse_id: None,
priority: Priority::Immediate,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum PushOutcome {
Delivered { id: Option<String> },
NotConfigured,
}
#[derive(Debug, Clone, Error)]
pub enum PushError {
#[error("device token is no longer registered; delete it")]
Unregistered,
#[error("push rejected: {0}")]
Rejected(String),
#[error("push failed, retryable: {0}")]
Transient(String),
}
#[async_trait]
pub trait Push: Send + Sync {
async fn send(
&self,
device_token: &str,
notification: &Notification,
) -> Result<PushOutcome, PushError>;
}