1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/gcm_driver/gcm_driver.h"
10 #include "base/logging.h"
11 #include "components/gcm_driver/gcm_app_handler.h"
16 const size_t kMaxSenders
= 100;
19 InstanceIDHandler::InstanceIDHandler() {
22 InstanceIDHandler::~InstanceIDHandler() {
25 void InstanceIDHandler::DeleteAllTokensForApp(
26 const std::string
& app_id
, const DeleteTokenCallback
& callback
) {
27 DeleteToken(app_id
, "*", "*", callback
);
30 GCMDriver::GCMDriver() : weak_ptr_factory_(this) {
33 GCMDriver::~GCMDriver() {
36 void GCMDriver::Register(const std::string
& app_id
,
37 const std::vector
<std::string
>& sender_ids
,
38 const RegisterCallback
& callback
) {
39 DCHECK(!app_id
.empty());
40 DCHECK(!sender_ids
.empty() && sender_ids
.size() <= kMaxSenders
);
41 DCHECK(!callback
.is_null());
43 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
44 if (result
!= GCMClient::SUCCESS
) {
45 callback
.Run(std::string(), result
);
49 // If previous register operation is still in progress, bail out.
50 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end()) {
51 callback
.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING
);
55 // Normalize the sender IDs by making them sorted.
56 std::vector
<std::string
> normalized_sender_ids
= sender_ids
;
57 std::sort(normalized_sender_ids
.begin(), normalized_sender_ids
.end());
59 register_callbacks_
[app_id
] = callback
;
61 // If previous unregister operation is still in progress, wait until it
62 // finishes. We don't want to throw ASYNC_OPERATION_PENDING when the user
63 // uninstalls an app (ungistering) and then reinstalls the app again
65 std::map
<std::string
, UnregisterCallback
>::iterator unregister_iter
=
66 unregister_callbacks_
.find(app_id
);
67 if (unregister_iter
!= unregister_callbacks_
.end()) {
68 // Replace the original unregister callback with an intermediate callback
69 // that will invoke the original unregister callback and trigger the pending
70 // registration after the unregistration finishes.
71 // Note that some parameters to RegisterAfterUnregister are specified here
72 // when the callback is created (base::Bind supports the partial binding
74 unregister_iter
->second
= base::Bind(
75 &GCMDriver::RegisterAfterUnregister
,
76 weak_ptr_factory_
.GetWeakPtr(),
78 normalized_sender_ids
,
79 unregister_iter
->second
);
83 RegisterImpl(app_id
, normalized_sender_ids
);
86 void GCMDriver::Unregister(const std::string
& app_id
,
87 const UnregisterCallback
& callback
) {
88 UnregisterInternal(app_id
, nullptr /* sender_id */, callback
);
91 void GCMDriver::UnregisterWithSenderId(
92 const std::string
& app_id
,
93 const std::string
& sender_id
,
94 const UnregisterCallback
& callback
) {
95 DCHECK(!sender_id
.empty());
96 UnregisterInternal(app_id
, &sender_id
, callback
);
99 void GCMDriver::UnregisterInternal(const std::string
& app_id
,
100 const std::string
* sender_id
,
101 const UnregisterCallback
& callback
) {
102 DCHECK(!app_id
.empty());
103 DCHECK(!callback
.is_null());
105 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
106 if (result
!= GCMClient::SUCCESS
) {
107 callback
.Run(result
);
111 // If previous un/register operation is still in progress, bail out.
112 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end() ||
113 unregister_callbacks_
.find(app_id
) != unregister_callbacks_
.end()) {
114 callback
.Run(GCMClient::ASYNC_OPERATION_PENDING
);
118 unregister_callbacks_
[app_id
] = callback
;
121 UnregisterWithSenderIdImpl(app_id
, *sender_id
);
123 UnregisterImpl(app_id
);
126 void GCMDriver::Send(const std::string
& app_id
,
127 const std::string
& receiver_id
,
128 const OutgoingMessage
& message
,
129 const SendCallback
& callback
) {
130 DCHECK(!app_id
.empty());
131 DCHECK(!receiver_id
.empty());
132 DCHECK(!callback
.is_null());
134 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
135 if (result
!= GCMClient::SUCCESS
) {
136 callback
.Run(std::string(), result
);
140 // If the message with send ID is still in progress, bail out.
141 std::pair
<std::string
, std::string
> key(app_id
, message
.id
);
142 if (send_callbacks_
.find(key
) != send_callbacks_
.end()) {
143 callback
.Run(message
.id
, GCMClient::INVALID_PARAMETER
);
147 send_callbacks_
[key
] = callback
;
149 SendImpl(app_id
, receiver_id
, message
);
152 void GCMDriver::UnregisterWithSenderIdImpl(const std::string
& app_id
,
153 const std::string
& sender_id
) {
157 void GCMDriver::RegisterFinished(const std::string
& app_id
,
158 const std::string
& registration_id
,
159 GCMClient::Result result
) {
160 std::map
<std::string
, RegisterCallback
>::iterator callback_iter
=
161 register_callbacks_
.find(app_id
);
162 if (callback_iter
== register_callbacks_
.end()) {
163 // The callback could have been removed when the app is uninstalled.
167 RegisterCallback callback
= callback_iter
->second
;
168 register_callbacks_
.erase(callback_iter
);
169 callback
.Run(registration_id
, result
);
172 void GCMDriver::UnregisterFinished(const std::string
& app_id
,
173 GCMClient::Result result
) {
174 std::map
<std::string
, UnregisterCallback
>::iterator callback_iter
=
175 unregister_callbacks_
.find(app_id
);
176 if (callback_iter
== unregister_callbacks_
.end())
179 UnregisterCallback callback
= callback_iter
->second
;
180 unregister_callbacks_
.erase(callback_iter
);
181 callback
.Run(result
);
184 void GCMDriver::SendFinished(const std::string
& app_id
,
185 const std::string
& message_id
,
186 GCMClient::Result result
) {
187 std::map
<std::pair
<std::string
, std::string
>, SendCallback
>::iterator
188 callback_iter
= send_callbacks_
.find(
189 std::pair
<std::string
, std::string
>(app_id
, message_id
));
190 if (callback_iter
== send_callbacks_
.end()) {
191 // The callback could have been removed when the app is uninstalled.
195 SendCallback callback
= callback_iter
->second
;
196 send_callbacks_
.erase(callback_iter
);
197 callback
.Run(message_id
, result
);
200 void GCMDriver::Shutdown() {
201 for (GCMAppHandlerMap::const_iterator iter
= app_handlers_
.begin();
202 iter
!= app_handlers_
.end(); ++iter
) {
203 DVLOG(1) << "Calling ShutdownHandler for: " << iter
->first
;
204 iter
->second
->ShutdownHandler();
206 app_handlers_
.clear();
209 void GCMDriver::AddAppHandler(const std::string
& app_id
,
210 GCMAppHandler
* handler
) {
211 DCHECK(!app_id
.empty());
213 DCHECK_EQ(app_handlers_
.count(app_id
), 0u);
214 app_handlers_
[app_id
] = handler
;
215 DVLOG(1) << "App handler added for: " << app_id
;
218 void GCMDriver::RemoveAppHandler(const std::string
& app_id
) {
219 DCHECK(!app_id
.empty());
220 app_handlers_
.erase(app_id
);
221 DVLOG(1) << "App handler removed for: " << app_id
;
224 GCMAppHandler
* GCMDriver::GetAppHandler(const std::string
& app_id
) {
225 // Look for exact match.
226 GCMAppHandlerMap::const_iterator iter
= app_handlers_
.find(app_id
);
227 if (iter
!= app_handlers_
.end())
230 // Ask the handlers whether they know how to handle it.
231 for (iter
= app_handlers_
.begin(); iter
!= app_handlers_
.end(); ++iter
) {
232 if (iter
->second
->CanHandle(app_id
))
236 return &default_app_handler_
;
239 bool GCMDriver::HasRegisterCallback(const std::string
& app_id
) {
240 return register_callbacks_
.find(app_id
) != register_callbacks_
.end();
243 void GCMDriver::ClearCallbacks() {
244 register_callbacks_
.clear();
245 unregister_callbacks_
.clear();
246 send_callbacks_
.clear();
249 void GCMDriver::RegisterAfterUnregister(
250 const std::string
& app_id
,
251 const std::vector
<std::string
>& normalized_sender_ids
,
252 const UnregisterCallback
& unregister_callback
,
253 GCMClient::Result result
) {
254 // Invoke the original unregister callback.
255 unregister_callback
.Run(result
);
257 // Trigger the pending registration.
258 DCHECK(register_callbacks_
.find(app_id
) != register_callbacks_
.end());
259 RegisterImpl(app_id
, normalized_sender_ids
);