Добавить в корзинуПозвонить
Найти в Дзене
Один Rust не п...Rust

Планировщик пуш-уведомлений на Rust с Firebase Cloud Messaging (FCM)

t.me/oneRustnoqRust Для чего нужна данная статья? : - Использовать библиотеку reqwest для взаимодействия с FCM и tokio. Зачем Вам это уметь? : Создать планировщик пуш-уведомлений на Rust, который работает поверх Firebase: // Cargo.toml dependencies: // [dependencies] // tokio = { version = "1", features = ["full"] } // reqwest = { version = "0.11", features = ["json"] } // serde = { version = "1", features = ["derive"] } // serde_json = "1" // dotenv = "0.15" use reqwest::Client; use serde::Serialize; use std::time::Duration; use tokio::{sync::mpsc, time}; use dotenv::dotenv; use std::env; #[derive(Serialize)] struct FcmMessage { to: String, notification: Notification, data: Option<serde_json::Value>, } #[derive(Serialize)] struct Notification { title: String, body: String, } struct PushScheduler { client: Client, fcm_url: String, fcm_key: String, } impl PushScheduler { fn new() -> Self { dotenv().ok(); let fcm_url = "https://fcm.googleapis.com/fcm/send".to_string(); let fcm_key = env:
ML на RUST без заморочек

t.me/oneRustnoqRust

Для чего нужна данная статья? :

- Использовать библиотеку reqwest для взаимодействия с FCM и tokio.

Зачем Вам это уметь? :

Создать планировщик пуш-уведомлений на Rust, который работает поверх Firebase:

// Cargo.toml dependencies:

// [dependencies]

// tokio = { version = "1", features = ["full"] }

// reqwest = { version = "0.11", features = ["json"] }

// serde = { version = "1", features = ["derive"] }

// serde_json = "1"

// dotenv = "0.15"

use reqwest::Client;

use serde::Serialize;

use std::time::Duration;

use tokio::{sync::mpsc, time};

use dotenv::dotenv;

use std::env;

#[derive(Serialize)]

struct FcmMessage {

to: String,

notification: Notification,

data: Option<serde_json::Value>,

}

#[derive(Serialize)]

struct Notification {

title: String,

body: String,

}

struct PushScheduler {

client: Client,

fcm_url: String,

fcm_key: String,

}

impl PushScheduler {

fn new() -> Self {

dotenv().ok();

let fcm_url = "https://fcm.googleapis.com/fcm/send".to_string();

let fcm_key = env::var("FCM_SERVER_KEY").expect("FCM_SERVER_KEY must be set in .env");

Self {

client: Client::new(),

fcm_url,

fcm_key,

}

}

async fn send_push_notification(&self, device_token: &str, title: &str, body: &str) -> Result<(), reqwest::Error> {

let message = FcmMessage {

to: device_token.to_string(),

notification: Notification {

title: title.to_string(),

body: body.to_string(),

},

data: None,

};

let response = self

.client

.post(&self.fcm_url)

.bearer_auth(&self.fcm_key)

.json(&message)

.send()

.await?;

if response.status().is_success() {

println!("Notification sent to {}", device_token);

} else {

eprintln!(

"Failed to send notification to {}: {:?}",

device_token,

response.text().await?

);

}

Ok(())

}

}

#[tokio::main]

async fn main() {

dotenv().ok();

// Simulate a large list of device tokens

let device_tokens = (1..=1_000_000)

.map(|i| format!("fake_device_token_{}", i))

.collect::<Vec<_>>();

let scheduler = PushScheduler::new();

// Create a channel for batching tasks

let (tx, mut rx) = mpsc::channel(100);

// Task generator

let generator = tokio::spawn(async move {

for token in device_tokens {

if tx.send(token).await.is_err() {

eprintln!("Receiver dropped");

break;

}

}

});

// Worker pool

let workers = (0..10).map(|_| {

let scheduler = &scheduler;

let mut rx = rx.clone();

tokio::spawn(async move {

while let Some(device_token) = rx.recv().await {

if let Err(e) = scheduler

.send_push_notification(&device_token, "Hello!", "This is a test notification")

.await

{

eprintln!("Error sending notification: {:?}", e);

}

// Simulate rate limiting or delays

time::sleep(Duration::from_millis(10)).await;

}

})

});

// Wait for all tasks to complete

generator.await.unwrap();

futures::future::join_all(workers).await;

}