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"
15 GCMDriver::GCMDriver() : weak_ptr_factory_(this) {
18 GCMDriver::~GCMDriver() {
21 void GCMDriver::Register(const std::string
& app_id
,
22 const std::vector
<std::string
>& sender_ids
,
23 const RegisterCallback
& callback
) {
24 DCHECK(!app_id
.empty());
25 DCHECK(!sender_ids
.empty());
26 DCHECK(!callback
.is_null());
28 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
29 if (result
!= GCMClient::SUCCESS
) {
30 callback
.Run(std::string(), result
);
34 // If previous register operation is still in progress, bail out.
35 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end()) {
36 callback
.Run(std::string(), GCMClient::ASYNC_OPERATION_PENDING
);
40 // Normalize the sender IDs by making them sorted.
41 std::vector
<std::string
> normalized_sender_ids
= sender_ids
;
42 std::sort(normalized_sender_ids
.begin(), normalized_sender_ids
.end());
44 register_callbacks_
[app_id
] = callback
;
46 // If previous unregister operation is still in progress, wait until it
47 // finishes. We don't want to throw ASYNC_OPERATION_PENDING when the user
48 // uninstalls an app (ungistering) and then reinstalls the app again
50 std::map
<std::string
, UnregisterCallback
>::iterator unregister_iter
=
51 unregister_callbacks_
.find(app_id
);
52 if (unregister_iter
!= unregister_callbacks_
.end()) {
53 // Replace the original unregister callback with an intermediate callback
54 // that will invoke the original unregister callback and trigger the pending
55 // registration after the unregistration finishes.
56 // Note that some parameters to RegisterAfterUnregister are specified here
57 // when the callback is created (base::Bind supports the partial binding
59 unregister_iter
->second
= base::Bind(
60 &GCMDriver::RegisterAfterUnregister
,
61 weak_ptr_factory_
.GetWeakPtr(),
63 normalized_sender_ids
,
64 unregister_iter
->second
);
68 RegisterImpl(app_id
, normalized_sender_ids
);
71 void GCMDriver::Unregister(const std::string
& app_id
,
72 const UnregisterCallback
& callback
) {
73 UnregisterInternal(app_id
, nullptr /* sender_id */, callback
);
76 void GCMDriver::UnregisterWithSenderId(
77 const std::string
& app_id
,
78 const std::string
& sender_id
,
79 const UnregisterCallback
& callback
) {
80 DCHECK(!sender_id
.empty());
81 UnregisterInternal(app_id
, &sender_id
, callback
);
84 void GCMDriver::UnregisterInternal(const std::string
& app_id
,
85 const std::string
* sender_id
,
86 const UnregisterCallback
& callback
) {
87 DCHECK(!app_id
.empty());
88 DCHECK(!callback
.is_null());
90 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
91 if (result
!= GCMClient::SUCCESS
) {
96 // If previous un/register operation is still in progress, bail out.
97 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end() ||
98 unregister_callbacks_
.find(app_id
) != unregister_callbacks_
.end()) {
99 callback
.Run(GCMClient::ASYNC_OPERATION_PENDING
);
103 unregister_callbacks_
[app_id
] = callback
;
106 UnregisterWithSenderIdImpl(app_id
, *sender_id
);
108 UnregisterImpl(app_id
);
111 void GCMDriver::Send(const std::string
& app_id
,
112 const std::string
& receiver_id
,
113 const GCMClient::OutgoingMessage
& message
,
114 const SendCallback
& callback
) {
115 DCHECK(!app_id
.empty());
116 DCHECK(!receiver_id
.empty());
117 DCHECK(!callback
.is_null());
119 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
120 if (result
!= GCMClient::SUCCESS
) {
121 callback
.Run(std::string(), result
);
125 // If the message with send ID is still in progress, bail out.
126 std::pair
<std::string
, std::string
> key(app_id
, message
.id
);
127 if (send_callbacks_
.find(key
) != send_callbacks_
.end()) {
128 callback
.Run(message
.id
, GCMClient::INVALID_PARAMETER
);
132 send_callbacks_
[key
] = callback
;
134 SendImpl(app_id
, receiver_id
, message
);
137 void GCMDriver::UnregisterWithSenderIdImpl(const std::string
& app_id
,
138 const std::string
& sender_id
) {
142 void GCMDriver::RegisterFinished(const std::string
& app_id
,
143 const std::string
& registration_id
,
144 GCMClient::Result result
) {
145 std::map
<std::string
, RegisterCallback
>::iterator callback_iter
=
146 register_callbacks_
.find(app_id
);
147 if (callback_iter
== register_callbacks_
.end()) {
148 // The callback could have been removed when the app is uninstalled.
152 RegisterCallback callback
= callback_iter
->second
;
153 register_callbacks_
.erase(callback_iter
);
154 callback
.Run(registration_id
, result
);
157 void GCMDriver::UnregisterFinished(const std::string
& app_id
,
158 GCMClient::Result result
) {
159 std::map
<std::string
, UnregisterCallback
>::iterator callback_iter
=
160 unregister_callbacks_
.find(app_id
);
161 if (callback_iter
== unregister_callbacks_
.end())
164 UnregisterCallback callback
= callback_iter
->second
;
165 unregister_callbacks_
.erase(callback_iter
);
166 callback
.Run(result
);
169 void GCMDriver::SendFinished(const std::string
& app_id
,
170 const std::string
& message_id
,
171 GCMClient::Result result
) {
172 std::map
<std::pair
<std::string
, std::string
>, SendCallback
>::iterator
173 callback_iter
= send_callbacks_
.find(
174 std::pair
<std::string
, std::string
>(app_id
, message_id
));
175 if (callback_iter
== send_callbacks_
.end()) {
176 // The callback could have been removed when the app is uninstalled.
180 SendCallback callback
= callback_iter
->second
;
181 send_callbacks_
.erase(callback_iter
);
182 callback
.Run(message_id
, result
);
185 void GCMDriver::Shutdown() {
186 for (GCMAppHandlerMap::const_iterator iter
= app_handlers_
.begin();
187 iter
!= app_handlers_
.end(); ++iter
) {
188 DVLOG(1) << "Calling ShutdownHandler for: " << iter
->first
;
189 iter
->second
->ShutdownHandler();
191 app_handlers_
.clear();
194 void GCMDriver::AddAppHandler(const std::string
& app_id
,
195 GCMAppHandler
* handler
) {
196 DCHECK(!app_id
.empty());
198 DCHECK_EQ(app_handlers_
.count(app_id
), 0u);
199 app_handlers_
[app_id
] = handler
;
200 DVLOG(1) << "App handler added for: " << app_id
;
203 void GCMDriver::RemoveAppHandler(const std::string
& app_id
) {
204 DCHECK(!app_id
.empty());
205 app_handlers_
.erase(app_id
);
206 DVLOG(1) << "App handler removed for: " << app_id
;
209 GCMAppHandler
* GCMDriver::GetAppHandler(const std::string
& app_id
) {
210 // Look for exact match.
211 GCMAppHandlerMap::const_iterator iter
= app_handlers_
.find(app_id
);
212 if (iter
!= app_handlers_
.end())
215 // Ask the handlers whether they know how to handle it.
216 for (iter
= app_handlers_
.begin(); iter
!= app_handlers_
.end(); ++iter
) {
217 if (iter
->second
->CanHandle(app_id
))
221 return &default_app_handler_
;
224 bool GCMDriver::HasRegisterCallback(const std::string
& app_id
) {
225 return register_callbacks_
.find(app_id
) != register_callbacks_
.end();
228 void GCMDriver::ClearCallbacks() {
229 register_callbacks_
.clear();
230 unregister_callbacks_
.clear();
231 send_callbacks_
.clear();
234 void GCMDriver::RegisterAfterUnregister(
235 const std::string
& app_id
,
236 const std::vector
<std::string
>& normalized_sender_ids
,
237 const UnregisterCallback
& unregister_callback
,
238 GCMClient::Result result
) {
239 // Invoke the original unregister callback.
240 unregister_callback
.Run(result
);
242 // Trigger the pending registration.
243 DCHECK(register_callbacks_
.find(app_id
) != register_callbacks_
.end());
244 RegisterImpl(app_id
, normalized_sender_ids
);