Skip to content

Commit f4ddb2b

Browse files
authored
feat: add support for ubuntu touch
Documentation for reference: https://docs.ubports.com/en/latest/appdev/guides/pushnotifications.html
1 parent 43ac774 commit f4ddb2b

File tree

5 files changed

+78
-5
lines changed

5 files changed

+78
-5
lines changed

Cargo.lock

Lines changed: 10 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ a2 = { git = "https://github.com/WalletConnect/a2/", branch = "master" }
1010
anyhow = "1.0.32"
1111
axum = "0.7.5"
1212
base64 = "0.22.1"
13+
chrono = { version = "0.4.41", default-features = false }
1314
femme = "2.1.0"
1415
humantime = "2.0.1"
1516
log = "0.4.11"

src/metrics.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ pub struct Metrics {
2727
/// Number of successfully sent visible FCM notifications.
2828
pub fcm_notifications_total: Counter,
2929

30+
/// Number of successfully sent visible UBports notifications.
31+
pub ubports_notifications_total: Counter,
32+
3033
/// Number of successfully sent heartbeat notifications.
3134
pub heartbeat_notifications_total: Counter,
3235

@@ -58,6 +61,13 @@ impl Metrics {
5861
fcm_notifications_total.clone(),
5962
);
6063

64+
let ubports_notifications_total = Counter::default();
65+
registry.register(
66+
"ubports_notifications",
67+
"Number of UBports notifications",
68+
ubports_notifications_total.clone(),
69+
);
70+
6171
let heartbeat_notifications_total = Counter::default();
6272
registry.register(
6373
"heartbeat_notifications",
@@ -88,8 +98,9 @@ impl Metrics {
8898

8999
Self {
90100
registry,
91-
fcm_notifications_total,
92101
direct_notifications_total,
102+
fcm_notifications_total,
103+
ubports_notifications_total,
93104
heartbeat_notifications_total,
94105
heartbeat_registrations_total,
95106
heartbeat_tokens,

src/notifier.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ async fn wakeup(
8585
let device_token: NotificationToken = key_device_token.as_str().parse()?;
8686

8787
let (client, device_token) = match device_token {
88-
NotificationToken::Fcm { .. } => {
88+
NotificationToken::Fcm { .. } | NotificationToken::UBports(..) => {
8989
// Only APNS tokens can be registered for periodic notifications.
9090
info!("Removing FCM token {key_device_token}");
9191
schedule

src/server.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use anyhow::{bail, Error, Result};
66
use axum::http::StatusCode;
77
use axum::response::{IntoResponse, Response};
88
use axum::routing::{get, post};
9+
use chrono::{Local, TimeDelta};
910
use log::*;
1011
use serde::Deserialize;
1112
use std::str::FromStr;
@@ -76,6 +77,9 @@ async fn register_device(
7677
}
7778

7879
pub(crate) enum NotificationToken {
80+
/// Ubuntu touch app
81+
UBports(String),
82+
7983
/// Android App.
8084
Fcm {
8185
/// Package name such as `chat.delta`.
@@ -105,6 +109,8 @@ impl FromStr for NotificationToken {
105109
} else {
106110
bail!("Invalid FCM token");
107111
}
112+
} else if let Some(s) = s.strip_prefix("ubports-") {
113+
Ok(Self::UBports(s.to_string()))
108114
} else if let Some(token) = s.strip_prefix("sandbox:") {
109115
Ok(Self::ApnsSandbox(token.to_string()))
110116
} else {
@@ -113,6 +119,49 @@ impl FromStr for NotificationToken {
113119
}
114120
}
115121

122+
/// Notify the UBports push server
123+
///
124+
/// API documentation is available at
125+
/// <https://docs.ubports.com/en/latest/appdev/guides/pushnotifications.html>
126+
async fn notify_ubports(
127+
client: &reqwest::Client,
128+
token: &str,
129+
metrics: &Metrics,
130+
) -> Result<StatusCode> {
131+
if !token
132+
.chars()
133+
.all(|c| c.is_ascii_alphanumeric() || c == '_' || c == ':' || c == '-')
134+
{
135+
return Ok(StatusCode::GONE);
136+
}
137+
138+
let url = "https://push.ubports.com/notify";
139+
let expire_on = (Local::now() + TimeDelta::weeks(1)).to_rfc3339();
140+
let body = format!(
141+
r#"{{"expire_on":"{expire_on}","appid":"deltatouch.lotharketterer_deltatouch","token":"{token}","data":{{"notification":{{"tag":"sent_by_chatmail_server","card":{{"popup":true,"persist":true,"summary":"New message","body":"You have a new message"}},"sound":true,"vibrate":{{"pattern":[200],"duration":200,"repeat":1}} }},"sent-by":"Chatmail Server"}} }}"#
142+
);
143+
let res = client
144+
.post(url)
145+
.body(body.clone())
146+
.header("Content-Type", "application/json")
147+
.send()
148+
.await?;
149+
let status = res.status();
150+
if status.is_client_error() {
151+
warn!("Failed to deliver UBports notification to {token}");
152+
warn!("BODY: {body:?}");
153+
warn!("RES: {res:?}");
154+
return Ok(StatusCode::GONE);
155+
}
156+
if status.is_server_error() {
157+
warn!("Internal server error while attempting to deliver UBports notification to {token}");
158+
return Ok(StatusCode::INTERNAL_SERVER_ERROR);
159+
}
160+
info!("Delivered notification to UBports token {token}");
161+
metrics.ubports_notifications_total.inc();
162+
Ok(StatusCode::OK)
163+
}
164+
116165
/// Notifies a single FCM token.
117166
///
118167
/// API documentation is available at
@@ -247,6 +296,11 @@ async fn notify_device(
247296
let device_token: NotificationToken = device_token.as_str().parse()?;
248297

249298
let status_code = match device_token {
299+
NotificationToken::UBports(token) => {
300+
let client = state.fcm_client().clone();
301+
let metrics = state.metrics();
302+
notify_ubports(&client, &token, metrics).await?
303+
}
250304
NotificationToken::Fcm {
251305
package_name,
252306
token,

0 commit comments

Comments
 (0)