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

Switch to serde for serialization/deserialization #3

Merged
merged 4 commits into from
Oct 19, 2017
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
443 changes: 311 additions & 132 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ documentation = "https://panicbit.github.io/fcm-rust/fcm/"
keywords = ["fcm", "firebase", "cloud", "messaging", "tokio"]

[dependencies]
rustc-serialize = "0.3.19"
serde = "1.0"
serde_json = "1.0"
erased-serde = "0.3"
serde_derive = "1.0"
futures = "0.1"
tokio-core = "0.1"
tokio-service = "0.1"
Expand Down
14 changes: 10 additions & 4 deletions examples/simple_sender.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ extern crate fcm;
extern crate argparse;
extern crate futures;
extern crate tokio_core;
#[macro_use] extern crate serde_derive;

use argparse::{ArgumentParser, Store};
use fcm::{MessageBuilder, Client};
use std::collections::HashMap;

#[derive(Serialize)]
struct CustomData {
message: &'static str,
}

fn main() {
let mut device_token = String::new();
Expand All @@ -23,11 +28,12 @@ fn main() {
let handle = core.handle();
let client = Client::new(&handle).unwrap();

let mut data = HashMap::new();
data.insert("message", "howdy");
let data = CustomData {
message: "howdy",
};

let mut builder = MessageBuilder::new(api_key.as_ref(), device_token.as_ref());
builder.data(data);
builder.data(&data).unwrap();

let work = client.send(builder.finalize());

Expand Down
6 changes: 3 additions & 3 deletions src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use hyper_tls::HttpsConnector;
use hyper::header::{Authorization, ContentType, ContentLength, RetryAfter};
use hyper::Post;
use hyper::StatusCode;
use rustc_serialize::json::{self, ToJson};
use serde_json;
use futures::{Future, Poll};
use futures::future::{ok, err};
use futures::stream::Stream;
Expand Down Expand Up @@ -65,7 +65,7 @@ impl Service for Client {
type Future = FutureResponse;

fn call(&self, message: Self::Request) -> Self::Future {
let payload = message.to_json().to_string().into_bytes();
let payload = serde_json::to_vec(&message.body).unwrap();
let auth_header = format!("key={}", message.api_key);

let mut request = Request::new(Post, "https://fcm.googleapis.com/fcm/send".parse().unwrap());
Expand All @@ -87,7 +87,7 @@ impl Service for Client {
if let Ok(body) = String::from_utf8(body_chunk.to_vec()) {
match response_status {
StatusCode::Ok => {
let fcm_response: FcmResponse = json::decode(&body).unwrap();
let fcm_response: FcmResponse = serde_json::from_str(&body).unwrap();

match fcm_response.error.as_ref().map(String::as_ref) {
Some("Unavailable") =>
Expand Down
4 changes: 2 additions & 2 deletions src/client/response.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use hyper::header::RetryAfter;

#[derive(RustcDecodable, Debug)]
#[derive(Deserialize, Debug)]
pub struct FcmResponse {
pub message_id: Option<u64>,
pub error: Option<String>,
Expand All @@ -11,7 +11,7 @@ pub struct FcmResponse {
pub results: Option<Vec<MessageResult>>,
}

#[derive(RustcDecodable, Debug)]
#[derive(Deserialize, Debug)]
pub struct MessageResult {
pub message_id: Option<String>,
pub registration_id: Option<String>,
Expand Down
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
//! map.insert("message", "Howdy!");
//!
//! let mut builder = fcm::MessageBuilder::new("<FCM API Key>", "<registration id>");
//! builder.data(map);
//! builder.data(&map);
//!
//! let work = client.send(builder.finalize());
//!
Expand Down Expand Up @@ -91,7 +91,10 @@
//! # }
//! ```

extern crate rustc_serialize;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate serde_json;
extern crate serde;
extern crate erased_serde;
extern crate hyper;
extern crate futures;
extern crate tokio_core;
Expand Down
162 changes: 66 additions & 96 deletions src/message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,50 @@
mod tests;

use notification::Notification;
use std::collections::HashMap;
use std::collections::BTreeMap;
use rustc_serialize::json::{Json, ToJson};
use erased_serde::Serialize;
use serde_json::{self, Value};

#[derive(PartialEq, Debug, Clone, Copy)]
#[derive(Serialize, PartialEq, Debug)]
#[serde(rename_all = "lowercase")]
pub enum Priority {
Normal, High
}

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

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

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

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

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

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

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

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

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

#[serde(skip_serializing_if = "Option::is_none")]
time_to_live: Option<i32>,

to: String,
}

/// Represents a FCM message. Construct the FCM message
/// using various utility methods and finally send it.
/// # Examples:
Expand All @@ -24,71 +59,7 @@ pub enum Priority {
#[derive(Debug)]
pub struct Message {
pub api_key: String,
to: String,
registration_ids: Option<Vec<String>>,
collapse_key: Option<String>,
priority: Option<Priority>,
content_available: Option<bool>,
delay_while_idle: Option<bool>,
time_to_live: Option<i32>,
restricted_package_name: Option<String>,
dry_run: Option<bool>,
data: Option<HashMap<String, String>>,
notification: Option<Notification>,
}

impl ToJson for Message {
fn to_json(&self) -> Json {
let mut root = BTreeMap::new();

root.insert("to".to_string(), self.to.to_json());

if self.registration_ids.is_some() {
root.insert("registration_ids".to_string(),
self.registration_ids.clone().unwrap().to_json());
}

if self.collapse_key.is_some() {
root.insert("collapse_key".to_string(), self.collapse_key.clone().unwrap().to_json());
}

if self.priority.is_some() {
root.insert("priority".to_string(), match self.priority.clone().unwrap() {
Priority::Normal => Json::String("normal".to_string()),
Priority::High => Json::String("high".to_string()),
});
}

if self.content_available.is_some() {
root.insert("content_available".to_string(), self.content_available.unwrap().to_json());
}

if self.delay_while_idle.is_some() {
root.insert("delay_while_idle".to_string(), self.delay_while_idle.unwrap().to_json());
}

if self.time_to_live.is_some() {
root.insert("time_to_live".to_string(), self.time_to_live.unwrap().to_json());
}

if self.restricted_package_name.is_some() {
root.insert("restricted_package_name".to_string(), self.restricted_package_name.clone().unwrap().to_json());
}

if self.dry_run.is_some() {
root.insert("dry_run".to_string(), self.dry_run.unwrap().to_json());
}

if self.data.is_some() {
root.insert("data".to_string(), self.data.clone().unwrap().to_json());
}

if self.notification.is_some() {
root.insert("notification".to_string(), self.notification.clone().unwrap().to_json());
}

Json::Object(root)
}
pub body: MessageBody,
}

///
Expand All @@ -106,17 +77,17 @@ impl ToJson for Message {
#[derive(Debug)]
pub struct MessageBuilder {
api_key: String,
to: String,
registration_ids: Option<Vec<String>>,
collapse_key: Option<String>,
priority: Option<Priority>,
content_available: Option<bool>,
data: Option<Value>,
delay_while_idle: Option<bool>,
time_to_live: Option<i32>,
restricted_package_name: Option<String>,
dry_run: Option<bool>,
data: Option<HashMap<String, String>>,
notification: Option<Notification>,
priority: Option<Priority>,
registration_ids: Option<Vec<String>>,
restricted_package_name: Option<String>,
time_to_live: Option<i32>,
to: String,
}

impl MessageBuilder {
Expand Down Expand Up @@ -197,7 +168,9 @@ impl MessageBuilder {
}

/// Use this to add custom key-value pairs to the message. This data
/// must be handled appropriately on the client end.
/// must be handled appropriately on the client end. The data can be
/// anything that Serde can serialize to JSON.
///
/// # Examples:
/// ```rust
/// use fcm::MessageBuilder;
Expand All @@ -207,17 +180,12 @@ impl MessageBuilder {
/// map.insert("message", "Howdy!");
///
/// let mut builder = MessageBuilder::new("<FCM API Key>", "<registration id>");
/// builder.data(map);
/// builder.data(&map);
/// let message = builder.finalize();
/// ```
pub fn data<'a>(&mut self, data: HashMap<&'a str, &'a str>) -> &mut MessageBuilder {
let mut datamap: HashMap<String, String> = HashMap::new();
for (key, val) in data.iter() {
datamap.insert(key.to_string(), val.to_string());
}

self.data = Some(datamap);
self
pub fn data(&mut self, data: &Serialize) -> Result<&mut MessageBuilder, serde_json::Error> {
self.data = Some(serde_json::to_value(data)?);
Ok(self)
}

/// Use this to set a `Notification` for the message.
Expand All @@ -243,17 +211,19 @@ impl MessageBuilder {
pub fn finalize(self) -> Message {
Message {
api_key: self.api_key,
to: self.to,
registration_ids: self.registration_ids.clone(),
collapse_key: self.collapse_key,
priority: self.priority,
content_available: self.content_available,
delay_while_idle: self.delay_while_idle,
time_to_live: self.time_to_live,
restricted_package_name: self.restricted_package_name,
dry_run: self.dry_run,
data: self.data.clone(),
notification: self.notification.clone(),
body: MessageBody {
to: self.to,
registration_ids: self.registration_ids.clone(),
collapse_key: self.collapse_key,
priority: self.priority,
content_available: self.content_available,
delay_while_idle: self.delay_while_idle,
time_to_live: self.time_to_live,
restricted_package_name: self.restricted_package_name,
dry_run: self.dry_run,
data: self.data.clone(),
notification: self.notification,
}
}
}
}
Loading