Skip to content

Commit 72fb881

Browse files
committed
Introduce working FirebaseCloudMessaging!
1 parent 2696f6d commit 72fb881

File tree

5 files changed

+220
-23
lines changed

5 files changed

+220
-23
lines changed

src/Firebase.h

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@
2323
#include <Arduino.h>
2424
#include <memory>
2525
#include "FirebaseHttpClient.h"
26-
// TODO(edcoyne): move this into our mock_arduino fork where we actually do the
27-
// override.
28-
#define ARDUINO_STRING_OVERRIDE
26+
#include "FirebaseError.h"
2927
#include "third-party/arduino-json-5.3/include/ArduinoJson.h"
3028

3129
class FirebaseGet;
@@ -71,19 +69,6 @@ class Firebase {
7169
std::string auth_;
7270
};
7371

74-
class FirebaseError {
75-
public:
76-
FirebaseError() {}
77-
FirebaseError(int code, const std::string& message) : code_(code), message_(message) {
78-
}
79-
operator bool() const { return code_ != 0; }
80-
int code() const { return code_; }
81-
const std::string& message() const { return message_; }
82-
private:
83-
int code_ = 0;
84-
std::string message_ = "";
85-
};
86-
8772
class FirebaseCall {
8873
public:
8974
FirebaseCall() {}

src/FirebaseCloudMessaging.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#include "FirebaseCloudMessaging.h"
2+
3+
FirebaseCloudMessage FirebaseCloudMessage::SimpleNotification(
4+
const std::string& title, const std::string& body) {
5+
FirebaseCloudMessage message;
6+
message.notification.title = title;
7+
message.notification.body = body;
8+
return message;
9+
}
10+
11+
FirebaseCloudMessaging::FirebaseCloudMessaging(const std::string& server_key) {
12+
auth_header_ = "key=";
13+
auth_header_ += server_key;
14+
}
15+
16+
const FirebaseError FirebaseCloudMessaging::SendMessageToUser(
17+
const std::string& registration_id,
18+
const FirebaseCloudMessage& message) {
19+
DynamicJsonBuffer buffer;
20+
JsonObject& root = buffer.createObject();
21+
root["to"] = registration_id.c_str();
22+
23+
AddToJson(message, root);
24+
25+
char payload[root.measureLength() + 1];
26+
root.printTo(payload, sizeof(payload));
27+
return SendPayload(payload);
28+
}
29+
30+
const FirebaseError FirebaseCloudMessaging::SendMessageToUsers(
31+
const std::vector<std::string>& registration_ids,
32+
const FirebaseCloudMessage& message) {
33+
DynamicJsonBuffer buffer;
34+
JsonObject& root = buffer.createObject();
35+
JsonArray& ids = root.createNestedArray("registration_ids");
36+
for (const std::string& id : registration_ids) {
37+
ids.add(id.c_str());
38+
}
39+
40+
AddToJson(message, root);
41+
42+
char payload[root.measureLength() + 1];
43+
root.printTo(payload, sizeof(payload));
44+
return SendPayload(payload);
45+
}
46+
47+
48+
const FirebaseError FirebaseCloudMessaging::SendMessageToTopic(
49+
const std::string& topic, const FirebaseCloudMessage& message) {
50+
std::string to("/topics/");
51+
to += topic;
52+
53+
DynamicJsonBuffer buffer;
54+
JsonObject& root = buffer.createObject();
55+
root["to"] = to.c_str();
56+
57+
AddToJson(message, root);
58+
59+
char payload[root.measureLength() + 1];
60+
root.printTo(payload, sizeof(payload));
61+
return SendPayload(payload);
62+
}
63+
64+
const FirebaseError FirebaseCloudMessaging::SendPayload(
65+
const char* payload) {
66+
std::unique_ptr<FirebaseHttpClient> client(FirebaseHttpClient::create());
67+
client->begin("http://fcm.googleapis.com/fcm/send");
68+
client->addHeader("Authorization", auth_header_.c_str());
69+
client->addHeader("Content-Type", "application/json");
70+
71+
int status = client->sendRequest("POST", payload);
72+
if (status != 200) {
73+
return FirebaseError(status, client->errorToString(status));
74+
} else {
75+
return FirebaseError::OK();
76+
}
77+
}
78+
79+
const void FirebaseCloudMessaging::AddToJson(
80+
const FirebaseCloudMessage& message, JsonObject& json) const {
81+
if (!message.collapse_key.empty()) {
82+
json["collapse_key"] = message.collapse_key.c_str();
83+
}
84+
85+
json["priority"] = message.high_priority ? "high" : "normal";
86+
json["delay_while_idle"] = message.delay_while_idle;
87+
if (message.time_to_live > 0 && message.time_to_live < 2419200) {
88+
json["time_to_live"] = message.time_to_live;
89+
}
90+
91+
if (!message.data.empty()) {
92+
JsonObject& data = json.createNestedObject("data");
93+
for (const auto& datum : message.data) {
94+
data[datum.first.c_str()] = datum.second.c_str();
95+
}
96+
}
97+
98+
if (!message.notification.title.empty() || !message.notification.body.empty()) {
99+
JsonObject& notification = json.createNestedObject("notification");
100+
if (!message.notification.title.empty()) {
101+
notification["title"] = message.notification.title.c_str();
102+
}
103+
if (!message.notification.body.empty()) {
104+
notification["body"] = message.notification.body.c_str();
105+
}
106+
}
107+
}
108+

src/FirebaseCloudMessaging.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//
2+
// Copyright 2016 Google Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
// firebase-arduino is an Arduino client for Firebase.
18+
// It is currently limited to the ESP8266 board family.
19+
20+
#ifndef firebase_cloud_messaging_h
21+
#define firebase_cloud_messaging_h
22+
23+
#include <Arduino.h>
24+
#include <memory>
25+
#include <utility>
26+
#include <vector>
27+
#include "FirebaseHttpClient.h"
28+
#include "FirebaseError.h"
29+
#include "third-party/arduino-json-5.3/include/ArduinoJson.h"
30+
31+
// Defines the actual message to the client, for more detail on
32+
// options and settings see:
33+
// https://firebase.google.com/docs/cloud-messaging/http-server-ref
34+
struct FirebaseCloudMessage {
35+
// If you set a collapse_key then when the server receives a
36+
// message, if it already has messages waiting for the client
37+
// with the same collapse_key it will discard them and deliver
38+
// this instead.
39+
std::string collapse_key;
40+
41+
// If true the user's device will wake to receive the message.
42+
bool high_priority = false;
43+
44+
// If true message will not be delivered until device is active.
45+
bool delay_while_idle = false;
46+
47+
// Optional, The message will expire after this many seconds.
48+
// Valid values are 0 to 2,419,200, defaults to max value (4 weeks).
49+
int time_to_live = -1;
50+
51+
// Optional, defines the notification to be displayed to the user.
52+
struct Notification {
53+
std::string title;
54+
std::string body;
55+
};
56+
Notification notification;
57+
58+
// Optional, defines data to be delivered to client application.
59+
std::vector<std::pair<std::string, std::string>> data;
60+
61+
static FirebaseCloudMessage SimpleNotification(const std::string& title, const std::string& body);
62+
};
63+
64+
// Firebase REST API client.
65+
class FirebaseCloudMessaging {
66+
public:
67+
FirebaseCloudMessaging(const std::string& server_key);
68+
const FirebaseError SendMessageToUser(const std::string& registration_id,
69+
const FirebaseCloudMessage& message);
70+
const FirebaseError SendMessageToUsers(const std::vector<std::string>& registration_ids,
71+
const FirebaseCloudMessage& message);
72+
73+
// TODO: The protocol supports sending a message to multiple topics but it is
74+
// not implemented here.
75+
const FirebaseError SendMessageToTopic(const std::string& topic,
76+
const FirebaseCloudMessage& message);
77+
78+
private:
79+
// Make the actual call to the backend.
80+
const FirebaseError SendPayload(const char* payload);
81+
82+
const void AddToJson(const FirebaseCloudMessage& message, JsonObject& json) const;
83+
84+
std::string auth_header_;
85+
};
86+
#endif // firebase_cloud_messaging_h

src/FirebaseError.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#ifndef firebase_error_h
2+
#define firebase_error_h
3+
4+
class FirebaseError {
5+
public:
6+
// Make it explicit that the empty constructor mean no error.
7+
static FirebaseError OK() {
8+
return FirebaseError();
9+
}
10+
11+
FirebaseError() {}
12+
FirebaseError(int code, const std::string& message) : code_(code), message_(message) {
13+
}
14+
15+
operator bool() const { return code_ != 0; }
16+
int code() const { return code_; }
17+
const std::string& message() const { return message_; }
18+
19+
private:
20+
int code_ = 0;
21+
std::string message_ = "";
22+
};
23+
24+
#endif //firebase_error_h

src/FirebaseHttpClient_Esp8266.cpp

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,7 @@ class FirebaseHttpClientEsp8266 : public FirebaseHttpClient {
6060
}
6161

6262
std::string errorToString(int error_code) override {
63-
#ifdef USE_ESP_ARDUINO_CORE_2_0_0
64-
char buff[11];
65-
itoa(error_code, buff, 10);
66-
return buff;
67-
#else
68-
return HTTPClient::errorToString(error_code).c_str();
69-
#endif
63+
return HTTPClient::errorToString(error_code).c_str();
7064
}
7165

7266
private:

0 commit comments

Comments
 (0)