Skip to content

Commit

Permalink
Merge pull request #15 from adnanjpg/fcm-rust
Browse files Browse the repository at this point in the history
refactor: move to fcm package
  • Loading branch information
isaidsari authored Mar 3, 2024
2 parents e6bfeac + 70cfccd commit 5c1f072
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 118 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ sqlx = { version = "0.7.2", features = ["sqlite", "runtime-tokio"] }
sysinfo = "0.30.3"
tokio = { version = "1.33.0", features = ["full"] }
totp-rs = "5.4.0"
gauth = "0.7.0"
env_logger = "0.10.0"
log = "0.4.14"
local-ip-address = "0.5.6"
blake3 = "1.5.0"
maplit = "1.0.2"
lazy_static = "1.4.0"
async_once = "0.2.6"
fcm = { git = "https://github.com/rj76/fcm-rust.git", branch = "new-api" }

[dev-dependencies]
ctor = "0.2.6"
147 changes: 30 additions & 117 deletions src/notification_service.rs
Original file line number Diff line number Diff line change
@@ -1,86 +1,12 @@
use gauth::serv_account::ServiceAccount;
use log::error;
use serde_derive::{Deserialize, Serialize};
use serde_json::json;

use fcm;

use crate::persistence::notification_logs::{
insert_notification_log, NotificationLog, NotificationType,
};

// reads the service key file name from the environment
// variable GOOGLE_APPLICATION_CREDENTIALS
fn get_service_key_file_name() -> Result<String, String> {
let key_path = match dotenv::var("GOOGLE_APPLICATION_CREDENTIALS") {
Ok(key_path) => key_path,
Err(err) => return Err(err.to_string()),
};

Ok(key_path)
}

fn read_service_key_file() -> Result<String, String> {
let key_path = get_service_key_file_name()?;

let private_key_content = match std::fs::read(key_path) {
Ok(content) => content,
Err(err) => return Err(err.to_string()),
};

Ok(String::from_utf8(private_key_content).unwrap())
}

fn read_service_key_file_json() -> Result<serde_json::Value, String> {
let file_content = match read_service_key_file() {
Ok(content) => content,
Err(err) => return Err(err),
};

let json_content: serde_json::Value = match serde_json::from_str(&file_content) {
Ok(json) => json,
Err(err) => return Err(err.to_string()),
};

Ok(json_content)
}

fn get_project_id() -> Result<String, String> {
let json_content = match read_service_key_file_json() {
Ok(json) => json,
Err(err) => return Err(err),
};

let project_id = match json_content["project_id"].as_str() {
Some(project_id) => project_id,
None => return Err("could not get project_id".to_string()),
};

Ok(project_id.to_string())
}

pub async fn access_token() -> Result<String, String> {
let scopes = vec!["https://www.googleapis.com/auth/firebase.messaging"];
let key_path = get_service_key_file_name()?;

let mut service_account = ServiceAccount::from_file(&key_path, scopes);
let access_token = match service_account.access_token().await {
Ok(access_token) => access_token,
Err(err) => return Err(err.to_string()),
};

let token_no_bearer = access_token.split(" ").collect::<Vec<&str>>()[1];

Ok(token_no_bearer.to_string())
}

async fn get_auth_token() -> Result<String, String> {
let tkn = match access_token().await {
Ok(tkn) => tkn,
Err(_) => return Err("could not get access token".to_string()),
};

Ok(tkn)
}

#[derive(Debug, Serialize, Deserialize)]
pub struct NotificationMessage {
pub title: String,
Expand All @@ -90,40 +16,39 @@ pub struct NotificationMessage {
async fn send_notification_to(
device_id: &str,
fcm_token: &str,
auth_token: &str,
project_id: &str,
message: &NotificationMessage,
notification_type: &NotificationType,
) -> Result<bool, String> {
// https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send
let url = format!(
"https://fcm.googleapis.com/v1/projects/{}/messages:send",
project_id
);

let body = json!({
"message": {
"token": fcm_token,
"notification": {
"title": message.title,
"body": message.body,
}
}
});
let builder = fcm::Message {
data: None,
notification: Some(fcm::Notification {
title: Some(message.title.to_owned()),
body: Some(message.body.to_owned()),
..Default::default()
}),
target: fcm::Target::Token(fcm_token.to_owned()),
android: Some(fcm::AndroidConfig {
priority: Some(fcm::AndroidMessagePriority::High),
..Default::default()
}),
apns: None,
webpush: None,
fcm_options: None,
};

let client = fcm::Client::new();

let client = reqwest::Client::new();
let req = client
.post(&url)
.header("Content-Type", "application/json")
.bearer_auth(auth_token)
.body(body.to_string());
let response = client.send(builder).await;

let res = req.send().await;
let sent_notification_count = 1;

match res {
match response {
Ok(res) => {
let stat = res.status();
let suc = stat.is_success();
// let stat = res.status();
// let suc = stat.is_success();
let suc_count = res.success;

let is_suc = suc_count == Some(sent_notification_count);

let sent_at = chrono::Utc::now().timestamp_millis();
let add_res =
Expand All @@ -134,7 +59,7 @@ async fn send_notification_to(
return Err("failed to insert notifiaction log".to_string());
};

Ok(suc)
Ok(is_suc)
}
Err(err) => {
println!("err: {:?}", err);
Expand Down Expand Up @@ -177,22 +102,10 @@ pub async fn send_notification_to_multi(
message: &NotificationMessage,
notification_type: &NotificationType,
) -> Result<bool, String> {
let project_id = match get_project_id() {
Ok(project_id) => project_id,
Err(err) => return Err(err),
};

let tkn = match get_auth_token().await {
Ok(tkn) => tkn,
Err(err) => return Err(err),
};

let mut results = Vec::new();

for dev in device_ids_and_tokens {
let res =
send_notification_to(dev.0, dev.1, &tkn, &project_id, &message, notification_type)
.await;
let res = send_notification_to(dev.0, dev.1, &message, notification_type).await;

match res {
Ok(res) => results.push(res),
Expand Down

0 comments on commit 5c1f072

Please sign in to comment.