Skip to content

Commit 9b8bf60

Browse files
authored
Merge pull request #3 from panicbit/serde
Switch to serde for serialization/deserialization
2 parents da934ac + 3f5113e commit 9b8bf60

File tree

10 files changed

+595
-355
lines changed

10 files changed

+595
-355
lines changed

Cargo.lock

+311-132
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ documentation = "https://panicbit.github.io/fcm-rust/fcm/"
1313
keywords = ["fcm", "firebase", "cloud", "messaging", "tokio"]
1414

1515
[dependencies]
16-
rustc-serialize = "0.3.19"
16+
serde = "1.0"
17+
serde_json = "1.0"
18+
erased-serde = "0.3"
19+
serde_derive = "1.0"
1720
futures = "0.1"
1821
tokio-core = "0.1"
1922
tokio-service = "0.1"

examples/simple_sender.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@ extern crate fcm;
22
extern crate argparse;
33
extern crate futures;
44
extern crate tokio_core;
5+
#[macro_use] extern crate serde_derive;
56

67
use argparse::{ArgumentParser, Store};
78
use fcm::{MessageBuilder, Client};
8-
use std::collections::HashMap;
9+
10+
#[derive(Serialize)]
11+
struct CustomData {
12+
message: &'static str,
13+
}
914

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

26-
let mut data = HashMap::new();
27-
data.insert("message", "howdy");
31+
let data = CustomData {
32+
message: "howdy",
33+
};
2834

2935
let mut builder = MessageBuilder::new(api_key.as_ref(), device_token.as_ref());
30-
builder.data(data);
36+
builder.data(&data).unwrap();
3137

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

src/client/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use hyper_tls::HttpsConnector;
1010
use hyper::header::{Authorization, ContentType, ContentLength, RetryAfter};
1111
use hyper::Post;
1212
use hyper::StatusCode;
13-
use rustc_serialize::json::{self, ToJson};
13+
use serde_json;
1414
use futures::{Future, Poll};
1515
use futures::future::{ok, err};
1616
use futures::stream::Stream;
@@ -65,7 +65,7 @@ impl Service for Client {
6565
type Future = FutureResponse;
6666

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

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

9292
match fcm_response.error.as_ref().map(String::as_ref) {
9393
Some("Unavailable") =>

src/client/response.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use hyper::header::RetryAfter;
22

3-
#[derive(RustcDecodable, Debug)]
3+
#[derive(Deserialize, Debug)]
44
pub struct FcmResponse {
55
pub message_id: Option<u64>,
66
pub error: Option<String>,
@@ -11,7 +11,7 @@ pub struct FcmResponse {
1111
pub results: Option<Vec<MessageResult>>,
1212
}
1313

14-
#[derive(RustcDecodable, Debug)]
14+
#[derive(Deserialize, Debug)]
1515
pub struct MessageResult {
1616
pub message_id: Option<String>,
1717
pub registration_id: Option<String>,

src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
//! map.insert("message", "Howdy!");
3939
//!
4040
//! let mut builder = fcm::MessageBuilder::new("<FCM API Key>", "<registration id>");
41-
//! builder.data(map);
41+
//! builder.data(&map);
4242
//!
4343
//! let work = client.send(builder.finalize());
4444
//!
@@ -91,7 +91,10 @@
9191
//! # }
9292
//! ```
9393
94-
extern crate rustc_serialize;
94+
#[macro_use] extern crate serde_derive;
95+
#[macro_use] extern crate serde_json;
96+
extern crate serde;
97+
extern crate erased_serde;
9598
extern crate hyper;
9699
extern crate futures;
97100
extern crate tokio_core;

src/message/mod.rs

+66-96
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,50 @@
22
mod tests;
33

44
use notification::Notification;
5-
use std::collections::HashMap;
6-
use std::collections::BTreeMap;
7-
use rustc_serialize::json::{Json, ToJson};
5+
use erased_serde::Serialize;
6+
use serde_json::{self, Value};
87

9-
#[derive(PartialEq, Debug, Clone, Copy)]
8+
#[derive(Serialize, PartialEq, Debug)]
9+
#[serde(rename_all = "lowercase")]
1010
pub enum Priority {
1111
Normal, High
1212
}
1313

14+
#[derive(Serialize, Debug, PartialEq)]
15+
pub struct MessageBody {
16+
#[serde(skip_serializing_if = "Option::is_none")]
17+
collapse_key: Option<String>,
18+
19+
#[serde(skip_serializing_if = "Option::is_none")]
20+
content_available: Option<bool>,
21+
22+
#[serde(skip_serializing_if = "Option::is_none")]
23+
data: Option<Value>,
24+
25+
#[serde(skip_serializing_if = "Option::is_none")]
26+
delay_while_idle: Option<bool>,
27+
28+
#[serde(skip_serializing_if = "Option::is_none")]
29+
dry_run: Option<bool>,
30+
31+
#[serde(skip_serializing_if = "Option::is_none")]
32+
notification: Option<Notification>,
33+
34+
#[serde(skip_serializing_if = "Option::is_none")]
35+
priority: Option<Priority>,
36+
37+
#[serde(skip_serializing_if = "Option::is_none")]
38+
registration_ids: Option<Vec<String>>,
39+
40+
#[serde(skip_serializing_if = "Option::is_none")]
41+
restricted_package_name: Option<String>,
42+
43+
#[serde(skip_serializing_if = "Option::is_none")]
44+
time_to_live: Option<i32>,
45+
46+
to: String,
47+
}
48+
1449
/// Represents a FCM message. Construct the FCM message
1550
/// using various utility methods and finally send it.
1651
/// # Examples:
@@ -24,71 +59,7 @@ pub enum Priority {
2459
#[derive(Debug)]
2560
pub struct Message {
2661
pub api_key: String,
27-
to: String,
28-
registration_ids: Option<Vec<String>>,
29-
collapse_key: Option<String>,
30-
priority: Option<Priority>,
31-
content_available: Option<bool>,
32-
delay_while_idle: Option<bool>,
33-
time_to_live: Option<i32>,
34-
restricted_package_name: Option<String>,
35-
dry_run: Option<bool>,
36-
data: Option<HashMap<String, String>>,
37-
notification: Option<Notification>,
38-
}
39-
40-
impl ToJson for Message {
41-
fn to_json(&self) -> Json {
42-
let mut root = BTreeMap::new();
43-
44-
root.insert("to".to_string(), self.to.to_json());
45-
46-
if self.registration_ids.is_some() {
47-
root.insert("registration_ids".to_string(),
48-
self.registration_ids.clone().unwrap().to_json());
49-
}
50-
51-
if self.collapse_key.is_some() {
52-
root.insert("collapse_key".to_string(), self.collapse_key.clone().unwrap().to_json());
53-
}
54-
55-
if self.priority.is_some() {
56-
root.insert("priority".to_string(), match self.priority.clone().unwrap() {
57-
Priority::Normal => Json::String("normal".to_string()),
58-
Priority::High => Json::String("high".to_string()),
59-
});
60-
}
61-
62-
if self.content_available.is_some() {
63-
root.insert("content_available".to_string(), self.content_available.unwrap().to_json());
64-
}
65-
66-
if self.delay_while_idle.is_some() {
67-
root.insert("delay_while_idle".to_string(), self.delay_while_idle.unwrap().to_json());
68-
}
69-
70-
if self.time_to_live.is_some() {
71-
root.insert("time_to_live".to_string(), self.time_to_live.unwrap().to_json());
72-
}
73-
74-
if self.restricted_package_name.is_some() {
75-
root.insert("restricted_package_name".to_string(), self.restricted_package_name.clone().unwrap().to_json());
76-
}
77-
78-
if self.dry_run.is_some() {
79-
root.insert("dry_run".to_string(), self.dry_run.unwrap().to_json());
80-
}
81-
82-
if self.data.is_some() {
83-
root.insert("data".to_string(), self.data.clone().unwrap().to_json());
84-
}
85-
86-
if self.notification.is_some() {
87-
root.insert("notification".to_string(), self.notification.clone().unwrap().to_json());
88-
}
89-
90-
Json::Object(root)
91-
}
62+
pub body: MessageBody,
9263
}
9364

9465
///
@@ -106,17 +77,17 @@ impl ToJson for Message {
10677
#[derive(Debug)]
10778
pub struct MessageBuilder {
10879
api_key: String,
109-
to: String,
110-
registration_ids: Option<Vec<String>>,
11180
collapse_key: Option<String>,
112-
priority: Option<Priority>,
11381
content_available: Option<bool>,
82+
data: Option<Value>,
11483
delay_while_idle: Option<bool>,
115-
time_to_live: Option<i32>,
116-
restricted_package_name: Option<String>,
11784
dry_run: Option<bool>,
118-
data: Option<HashMap<String, String>>,
11985
notification: Option<Notification>,
86+
priority: Option<Priority>,
87+
registration_ids: Option<Vec<String>>,
88+
restricted_package_name: Option<String>,
89+
time_to_live: Option<i32>,
90+
to: String,
12091
}
12192

12293
impl MessageBuilder {
@@ -197,7 +168,9 @@ impl MessageBuilder {
197168
}
198169

199170
/// Use this to add custom key-value pairs to the message. This data
200-
/// must be handled appropriately on the client end.
171+
/// must be handled appropriately on the client end. The data can be
172+
/// anything that Serde can serialize to JSON.
173+
///
201174
/// # Examples:
202175
/// ```rust
203176
/// use fcm::MessageBuilder;
@@ -207,17 +180,12 @@ impl MessageBuilder {
207180
/// map.insert("message", "Howdy!");
208181
///
209182
/// let mut builder = MessageBuilder::new("<FCM API Key>", "<registration id>");
210-
/// builder.data(map);
183+
/// builder.data(&map);
211184
/// let message = builder.finalize();
212185
/// ```
213-
pub fn data<'a>(&mut self, data: HashMap<&'a str, &'a str>) -> &mut MessageBuilder {
214-
let mut datamap: HashMap<String, String> = HashMap::new();
215-
for (key, val) in data.iter() {
216-
datamap.insert(key.to_string(), val.to_string());
217-
}
218-
219-
self.data = Some(datamap);
220-
self
186+
pub fn data(&mut self, data: &Serialize) -> Result<&mut MessageBuilder, serde_json::Error> {
187+
self.data = Some(serde_json::to_value(data)?);
188+
Ok(self)
221189
}
222190

223191
/// Use this to set a `Notification` for the message.
@@ -243,17 +211,19 @@ impl MessageBuilder {
243211
pub fn finalize(self) -> Message {
244212
Message {
245213
api_key: self.api_key,
246-
to: self.to,
247-
registration_ids: self.registration_ids.clone(),
248-
collapse_key: self.collapse_key,
249-
priority: self.priority,
250-
content_available: self.content_available,
251-
delay_while_idle: self.delay_while_idle,
252-
time_to_live: self.time_to_live,
253-
restricted_package_name: self.restricted_package_name,
254-
dry_run: self.dry_run,
255-
data: self.data.clone(),
256-
notification: self.notification.clone(),
214+
body: MessageBody {
215+
to: self.to,
216+
registration_ids: self.registration_ids.clone(),
217+
collapse_key: self.collapse_key,
218+
priority: self.priority,
219+
content_available: self.content_available,
220+
delay_while_idle: self.delay_while_idle,
221+
time_to_live: self.time_to_live,
222+
restricted_package_name: self.restricted_package_name,
223+
dry_run: self.dry_run,
224+
data: self.data.clone(),
225+
notification: self.notification,
226+
}
257227
}
258228
}
259229
}

0 commit comments

Comments
 (0)