From 70cfccd23a24a8acc2de9b06ee4d4fba4850a8db Mon Sep 17 00:00:00 2001 From: adnanjpg Date: Sun, 3 Mar 2024 11:27:49 +0300 Subject: [PATCH] refactor: move to fcm package --- Cargo.toml | 2 +- src/notification_service.rs | 147 ++++++++---------------------------- 2 files changed, 31 insertions(+), 118 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d129df4..935898a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ 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" @@ -31,6 +30,7 @@ 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" diff --git a/src/notification_service.rs b/src/notification_service.rs index 0387f72..a63156b 100644 --- a/src/notification_service.rs +++ b/src/notification_service.rs @@ -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 { - 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 { - 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 { - 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 { - 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 { - 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::>()[1]; - - Ok(token_no_bearer.to_string()) -} - -async fn get_auth_token() -> Result { - 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, @@ -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 { - // 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 = @@ -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); @@ -177,22 +102,10 @@ pub async fn send_notification_to_multi( message: &NotificationMessage, notification_type: &NotificationType, ) -> Result { - 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),