Skip to content

Commit

Permalink
Merge pull request #4 from rj76/new-api
Browse files Browse the repository at this point in the history
feat: build new api
  • Loading branch information
rj76 authored Mar 3, 2024
2 parents a8babd2 + 2128a95 commit 4f9dedb
Show file tree
Hide file tree
Showing 25 changed files with 1,013 additions and 584 deletions.
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

0 comments on commit 4f9dedb

Please sign in to comment.