Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: build new api #4

Merged
merged 7 commits into from
Mar 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 74 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,70 @@

This fork is a rewrite to use Google's HTTP v1 API.


# Getting started

## Installation

Add the following to your `Cargo.toml` file:

```toml
[dependencies]
fcm = { git = "https://github.com/rj76/fcm-rust.git" }
```

Then, you need to add the credentials described in the [Credentials](#credentials) to a `.env` file at the root of your project.

## Usage

For a complete usage example, you may check the [Examples](#examples) section.

### Import

```rust
use fcm;
```

### Create a client instance

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

### Construct a message

```rust
let message = fcm::Message {
data: None,
notification: Some(Notification {
title: Some("I'm high".to_string()),
body: Some(format!("it's {}", chrono::Utc::now())),
..Default::default()
}),
target: Target::Token(device_token),
fcm_options: Some(FcmOptions {
analytics_label: "analytics_label".to_string(),
}),
android: Some(AndroidConfig {
priority: Some(fcm::AndroidMessagePriority::High),
notification: Some(AndroidNotification {
title: Some("I'm Android high".to_string()),
body: Some(format!("Hi Android, it's {}", chrono::Utc::now())),
..Default::default()
}),
..Default::default()
}),
apns: Some(ApnsConfig { ..Default::default() }),
webpush: Some(WebpushConfig { ..Default::default() }),
}
```

### Send the message

```rust
let response = client.send(message).await?;
```

# Credentials

This library expects the Google credentials JSON location to be
Expand All @@ -19,4 +83,13 @@ Please follow the instructions in the [Firebase Documentation](https://firebase.

## Examples

Check out the examples directory for a simple sender.
For a complete usage example, you may check out the [`simple_sender`](examples/simple_sender.rs) example.

To run the example, first of all clone the [`.env.example`](.env.example) file to `.env` and fill in the required values.

You can find info about the required credentials in the [Credentials](#credentials) section.

Then run the example with `cargo run --example simple_sender -- -t <device_token>`



47 changes: 35 additions & 12 deletions examples/simple_sender.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use argparse::{ArgumentParser, Store};
use fcm::{Client, MessageBuilder, Target};
use serde::Serialize;
// cargo run --example simple_sender -- -t <device_token>

#[derive(Serialize)]
struct CustomData {
message: &'static str,
}
use argparse::{ArgumentParser, Store};
use fcm::{
AndroidConfig, AndroidNotification, ApnsConfig, Client, FcmOptions, Message, Notification, Target, WebpushConfig,
};
use serde_json::json;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
Expand All @@ -22,12 +21,36 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
}

let client = Client::new();
let data = CustomData { message: "howdy" };

let mut builder = MessageBuilder::new(Target::Token(device_token));
builder.data(&data)?;

let response = client.send(builder.finalize()).await?;
let data = json!({
"key": "value",
});

let builder = Message {
data: Some(data),
notification: Some(Notification {
title: Some("I'm high".to_string()),
body: Some(format!("it's {}", chrono::Utc::now())),
..Default::default()
}),
target: Target::Token(device_token),
fcm_options: Some(FcmOptions {
analytics_label: "analytics_label".to_string(),
}),
android: Some(AndroidConfig {
priority: Some(fcm::AndroidMessagePriority::High),
notification: Some(AndroidNotification {
title: Some("I'm Android high".to_string()),
body: Some(format!("Hi Android, it's {}", chrono::Utc::now())),
..Default::default()
}),
..Default::default()
}),
apns: Some(ApnsConfig { ..Default::default() }),
webpush: Some(WebpushConfig { ..Default::default() }),
};

let response = client.send(builder).await?;
println!("Sent: {:?}", response);

Ok(())
Expand Down
80 changes: 80 additions & 0 deletions src/android/android_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use serde::Serialize;
use serde_json::Value;

use super::{
android_fcm_options::{AndroidFcmOptions, AndroidFcmOptionsInternal},
android_message_priority::AndroidMessagePriority,
android_notification::{AndroidNotification, AndroidNotificationInternal},
};

#[derive(Serialize, Debug)]
pub(crate) struct AndroidConfigInternal {
#[serde(skip_serializing_if = "Option::is_none")]
collapse_key: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
priority: Option<AndroidMessagePriority>,

#[serde(skip_serializing_if = "Option::is_none")]
ttl: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
restricted_package_name: Option<String>,

#[serde(skip_serializing_if = "Option::is_none")]
data: Option<Value>,

#[serde(skip_serializing_if = "Option::is_none")]
notification: Option<AndroidNotificationInternal>,

#[serde(skip_serializing_if = "Option::is_none")]
fcm_options: Option<AndroidFcmOptionsInternal>,

#[serde(skip_serializing_if = "Option::is_none")]
direct_boot_ok: Option<bool>,
}

#[derive(Debug, Default)]
/// https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages?authuser=0#androidconfig
pub struct AndroidConfig {
/// An identifier of a group of messages that can be collapsed, so that only the last message gets
/// sent when delivery can be resumed.
pub collapse_key: Option<String>,

/// Message priority.
pub priority: Option<AndroidMessagePriority>,

/// How long (in seconds) the message should be kept in FCM storage if the device is offline.
/// Duration format: https://developers.google.com/protocol-buffers/docs/reference/google.protobuf?authuser=0#google.protobuf.Duration
pub ttl: Option<String>,

/// Package name of the application where the registration token must match in order to receive the message.
pub restricted_package_name: Option<String>,

/// Arbitrary key/value payload.
pub data: Option<Value>,

/// Notification to send to android devices.
pub notification: Option<AndroidNotification>,

/// Options for features provided by the FCM SDK for Android.
pub fcm_options: Option<AndroidFcmOptions>,

/// If set to true, messages will be allowed to be delivered to the app while the device is in direct boot mode.
pub direct_boot_ok: Option<bool>,
}

impl AndroidConfig {
pub(crate) fn finalize(self) -> AndroidConfigInternal {
AndroidConfigInternal {
collapse_key: self.collapse_key,
priority: self.priority,
ttl: self.ttl,
restricted_package_name: self.restricted_package_name,
data: self.data,
notification: self.notification.map(|n| n.finalize()),
fcm_options: self.fcm_options.map(|f| f.finalize()),
direct_boot_ok: self.direct_boot_ok,
}
}
}
21 changes: 21 additions & 0 deletions src/android/android_fcm_options.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use serde::Serialize;

#[derive(Serialize, Debug)]
pub(crate) struct AndroidFcmOptionsInternal {
analytics_label: String,
}

#[derive(Debug, Default)]
/// https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages?authuser=0#androidconfig
pub struct AndroidFcmOptions {
/// Label associated with the message's analytics data.
pub analytics_label: String,
}

impl AndroidFcmOptions {
pub(crate) fn finalize(self) -> AndroidFcmOptionsInternal {
AndroidFcmOptionsInternal {
analytics_label: self.analytics_label,
}
}
}
10 changes: 10 additions & 0 deletions src/android/android_message_priority.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use serde::Serialize;

#[allow(dead_code)]
#[derive(Serialize, Debug)]
#[serde(rename_all = "UPPERCASE")]
/// https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages?authuser=0#androidmessagepriority
pub enum AndroidMessagePriority {
Normal,
High,
}
Loading
Loading