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

Major update #10

Merged
merged 40 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
6ec7e92
Revert "nix settings"
jutuon May 19, 2024
caa4c4c
Remove unnecessary documentation config
jutuon May 19, 2024
8961acd
Remove unnecessary dependencies
jutuon May 19, 2024
25d0f03
Remove .env support
jutuon May 20, 2024
dacd72c
Update example
jutuon May 20, 2024
921f2a4
Rewrite client
jutuon May 20, 2024
21c4d3e
Fix warnings
jutuon May 20, 2024
7a98316
Create client using builder pattern
jutuon May 20, 2024
16e28be
Reintroduce .env file support
jutuon May 20, 2024
9f95b1c
Simplify example
jutuon May 20, 2024
212ae91
Remove duplicate code
jutuon May 20, 2024
a35f845
Return error if Retry-After header is invalid
jutuon May 20, 2024
a6ff6a0
Add tests for wait time method
jutuon May 20, 2024
a1a5fc3
Simplify wait time calculation code
jutuon May 20, 2024
de0f397
Reintroduce gauth support
jutuon May 21, 2024
aaee211
Convert text URLs in doc comments to links
jutuon May 21, 2024
b720b7e
Improve error handling
jutuon May 21, 2024
bdf7e51
Improve example CLI options
jutuon May 21, 2024
3b6b876
Update instructions and examples
jutuon May 21, 2024
8b24941
Allow building with --all-features
jutuon May 21, 2024
f1264df
Fix example compiling
jutuon May 21, 2024
220f4be
Allow selecting OAuth client with generics
jutuon May 21, 2024
03edb40
Reorganize public API
jutuon May 21, 2024
a9a950f
Add missing case to access token error detection
jutuon May 21, 2024
dc6957b
Add new trait for access token error check
jutuon May 21, 2024
f59543d
Replace dotenv with dotenvy
jutuon May 21, 2024
86ddc01
Move OAuth client trait methods to internal trait
jutuon May 22, 2024
10fa8d5
Improve FCM response API
jutuon May 22, 2024
bb453d2
Support creating client with key string
jutuon May 22, 2024
1cdc211
Improve wait time calculation
jutuon May 22, 2024
d467623
Allow sending with Message reference
jutuon May 23, 2024
4a04e98
Fix request timeout documentation
jutuon May 23, 2024
07b9ec8
Lower dependency version requirements
jutuon May 26, 2024
52789ae
Remove gauth
jutuon May 26, 2024
07146e8
Improve OAuth related API
jutuon May 26, 2024
ee10da1
Rename module oauth_yup_oauth2 to oauth
jutuon May 26, 2024
c8d2713
Change public API to have response module
jutuon May 26, 2024
dc15c89
Possibly fix unspecified error detection
jutuon May 26, 2024
4501d9b
Run rustfmt
jutuon May 26, 2024
32471f2
Remove code coverage
jutuon May 26, 2024
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
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
# follow the instructions in the [Firebase Documentation](https://firebase.google.com/docs/cloud-messaging/auth-server#provide-credentials-manually) to create a service account. after you create a service account, and download the json file then change the value of `GOOGLE_APPLICATION_CREDENTIALS` to the path of the json file you downloaded.
# Follow the instructions in the
# [Firebase Documentation](https://firebase.google.com/docs/cloud-messaging/auth-server#provide-credentials-manually)
# to download service account key JSON file. After downloading
# the JSON file then change the value of `GOOGLE_APPLICATION_CREDENTIALS` to
# the path of the JSON file you downloaded.
GOOGLE_APPLICATION_CREDENTIALS="/path/to/your/firebase/file.json"
6 changes: 0 additions & 6 deletions .envrc

This file was deleted.

18 changes: 2 additions & 16 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
runs-on: ${{ matrix.os }}

env:
RUSTFLAGS: "-Dwarnings -Cinstrument-coverage -Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
RUSTFLAGS: "-Dwarnings -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
CARGO_INCREMENTAL: "0"
RUSTDOCFLAGS: "-Cpanic=abort"
RUSTC_BOOTSTRAP: "1"
Expand All @@ -61,7 +61,6 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
toolchain: ${{matrix.rust}}
components: llvm-tools-preview

- uses: actions/cache@v2
with:
Expand All @@ -72,18 +71,5 @@ jobs:
- name: Build
run: cargo build

- name: Install grcov
run: cargo install grcov

- name: Run tests
run: LLVM_PROFILE_FILE="fcm-rust-%p-%m.profraw" cargo test

- name: Collect results
run: grcov . -s . --binary-path ./target/debug/ -t lcov --branch --ignore-not-existing -o ./tests.lcov

- name: Coveralls GitHub Action
uses: coverallsapp/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
file: ./tests.lcov

run: cargo test
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ Cargo.lock

.DS_Store

.direnv
.idea/

# local env files
# do not commit any .env files to git, except for the .env.example file. https://create.t3.gg/en/usage/env-variables#using-environment-variables
# Local env files
# Do not commit any .env files to git, except for the .env.example file.
# https://create.t3.gg/en/usage/env-variables#using-environment-variables
.env
.env*.local
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,21 @@ edition = "2018"

[features]
default = ["native-tls"]

native-tls = ["reqwest/native-tls"]
rustls = ["reqwest/rustls-tls"]
vendored-tls = ["reqwest/native-tls-vendored"]

[dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["preserve_order"] }
erased-serde = "0.4.1"
reqwest = {version = "0.11.0", features = ["json"], default-features=false}
tokio = { version = "1", features = ["fs"] }
reqwest = { version = "0.11", features = ["json"], default-features = false }
chrono = "0.4"
log = "0.4"
gauth = "0.7.0"
dotenv = "0.15.0"
thiserror = "1"
dotenvy = "0.15"
yup-oauth2 = "9"

[dev-dependencies]
argparse = "0.2.1"
tokio = { version = "1.0", features = ["rt-multi-thread", "macros"] }
pretty_env_logger = "0.5.0"
clap = { version = "4.5", features = ["cargo", "derive"] }
79 changes: 46 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# fcm-rust
[![Cargo tests](https://github.com/rj76/fcm-rust/actions/workflows/test.yml/badge.svg)](https://github.com/rj76/fcm-rust/actions/workflows/test.yml)
[![Coverage Status](https://coveralls.io/repos/github/rj76/fcm-rust/badge.svg)](https://coveralls.io/github/rj76/fcm-rust)

[//]: # ([![Crates.io Version](https://img.shields.io/crates/v/fcm.svg?style=flat-square))
[//]: # ([![Crates.io Downloads](https://img.shields.io/crates/dv/fcm.svg?style=flat-square))
Expand All @@ -23,7 +22,8 @@ Add the following to your `Cargo.toml` file:
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.
Optionally, add the credentials described in the [Credentials](#credentials)
to a `.env` file at the root of your project.

## Usage

Expand All @@ -38,58 +38,71 @@ use fcm;
### Create a client instance

```rust
let client = fcm::Client::new();
let client = fcm::FcmClient::builder()
// Comment to use GOOGLE_APPLICATION_CREDENTIALS environment
// variable. The variable can also be defined in .env file.
.service_account_key_json_path("service_account_key.json")
.build()
.await
.unwrap();
```

### Construct a message

```rust
let message = fcm::Message {
data: None,
use fcm::message::{Message, Notification, Target};

// Replace "device_token" with the actual device token
let device_token = "device_token".to_string();
let message = Message {
data: Some(json!({
"message": "Howdy!",
})),
notification: Some(Notification {
title: Some("I'm high".to_string()),
title: Some("Hello".to_string()),
body: Some(format!("it's {}", chrono::Utc::now())),
..Default::default()
image: None,
}),
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() }),
}
android: None,
webpush: None,
apns: None,
fcm_options: None,
};
```

### Send the message

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

# Credentials

This library expects the Google credentials JSON location to be
defined as `GOOGLE_APPLICATION_CREDENTIALS` in the `.env` file.
Please follow the instructions in the [Firebase Documentation](https://firebase.google.com/docs/cloud-messaging/auth-server#provide-credentials-manually) to create a service account.

## Examples

For a complete usage example, you may check out the [`simple_sender`](examples/simple_sender.rs) example.
If client is not configured with service account key JSON file path
then this library expects the Google credentials JSON location to be
defined in `GOOGLE_APPLICATION_CREDENTIALS` environment variable.
The variable definition can also be located in the `.env` file.

To run the example, first of all clone the [`.env.example`](.env.example) file to `.env` and fill in the required values.
Please follow the instructions in the
[Firebase Documentation](https://firebase.google.com/docs/cloud-messaging/auth-server#provide-credentials-manually)
to create a service account key JSON file.

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

Then run the example with `cargo run --example simple_sender -- -t <device_token>`
For a complete usage example, you may check out the
[`simple_sender`](examples/simple_sender.rs) example.

The example can be run with
```
cargo run --example simple_sender -- -t <device_token> -k <service_account_key_path>
```

If `GOOGLE_APPLICATION_CREDENTIALS` environment variable is defined in current
environment or in `.env` file, then the example can be run with
```
cargo run --example simple_sender -- -t <device_token>
```

To define the environment variable using `.env` file copy the [`.env.example`](.env.example)
file to `.env` and fill in the required values.
77 changes: 37 additions & 40 deletions examples/simple_sender.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,54 @@
// cargo run --example simple_sender -- -t <device_token>
// cargo run --example simple_sender -- --help

use argparse::{ArgumentParser, Store};
use std::path::PathBuf;

use clap::Parser;
use fcm::{
AndroidConfig, AndroidNotification, ApnsConfig, Client, FcmOptions, Message, Notification, Target, WebpushConfig,
message::{Message, Notification, Target},
FcmClient,
};
use serde_json::json;

#[derive(Parser, Debug)]
struct CliArgs {
#[arg(short = 't', long)]
device_token: String,
/// Set path to the service account key JSON file. Default is to use
/// path from the `GOOGLE_APPLICATION_CREDENTIALS` environment variable
/// (which can be also located in `.env` file).
#[arg(short = 'k', long, value_name = "FILE")]
service_account_key_path: Option<PathBuf>,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
pretty_env_logger::init();

let mut device_token = String::new();

{
let mut ap = ArgumentParser::new();
ap.set_description("A simple FCM notification sender");
ap.refer(&mut device_token)
.add_option(&["-t", "--device_token"], Store, "Device token");
ap.parse_args_or_exit();
}

let client = Client::new();
let args = CliArgs::parse();
let builder = FcmClient::builder();
let builder = if let Some(path) = args.service_account_key_path {
builder.service_account_key_json_path(path)
} else {
builder
};

let data = json!({
"key": "value",
});
let client = builder.build().await.unwrap();

let builder = Message {
data: Some(data),
let message = Message {
data: Some(json!({
"key": "value",
})),
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()
}),
title: Some("Title".to_string()),
..Default::default()
}),
apns: Some(ApnsConfig { ..Default::default() }),
webpush: Some(WebpushConfig { ..Default::default() }),
target: Target::Token(args.device_token),
fcm_options: None,
android: None,
apns: None,
webpush: None,
};

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

Ok(())
}
80 changes: 0 additions & 80 deletions flake.lock

This file was deleted.

Loading
Loading