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 DCHECK(!app_id
.empty());
74 DCHECK(!callback
.is_null());
76 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
77 if (result
!= GCMClient::SUCCESS
) {
82 // If previous un/register operation is still in progress, bail out.
83 if (register_callbacks_
.find(app_id
) != register_callbacks_
.end() ||
84 unregister_callbacks_
.find(app_id
) != unregister_callbacks_
.end()) {
85 callback
.Run(GCMClient::ASYNC_OPERATION_PENDING
);
89 unregister_callbacks_
[app_id
] = callback
;
91 UnregisterImpl(app_id
);
94 void GCMDriver::Send(const std::string
& app_id
,
95 const std::string
& receiver_id
,
96 const GCMClient::OutgoingMessage
& message
,
97 const SendCallback
& callback
) {
98 DCHECK(!app_id
.empty());
99 DCHECK(!receiver_id
.empty());
100 DCHECK(!callback
.is_null());
102 GCMClient::Result result
= EnsureStarted(GCMClient::IMMEDIATE_START
);
103 if (result
!= GCMClient::SUCCESS
) {
104 callback
.Run(std::string(), result
);
108 // If the message with send ID is still in progress, bail out.
109 std::pair
<std::string
, std::string
> key(app_id
, message
.id
);
110 if (send_callbacks_
.find(key
) != send_callbacks_
.end()) {
111 callback
.Run(message
.id
, GCMClient::INVALID_PARAMETER
);
115 send_callbacks_
[key
] = callback
;
117 SendImpl(app_id
, receiver_id
, message
);
120 void GCMDriver::RegisterFinished(const std::string
& app_id
,
121 const std::string
& registration_id
,
122 GCMClient::Result result
) {
123 std::map
<std::string
, RegisterCallback
>::iterator callback_iter
=
124 register_callbacks_
.find(app_id
);
125 if (callback_iter
== register_callbacks_
.end()) {
126 // The callback could have been removed when the app is uninstalled.
130 RegisterCallback callback
= callback_iter
->second
;
131 register_callbacks_
.erase(callback_iter
);
132 callback
.Run(registration_id
, result
);
135 void GCMDriver::UnregisterFinished(const std::string
& app_id
,
136 GCMClient::Result result
) {
137 std::map
<std::string
, UnregisterCallback
>::iterator callback_iter
=
138 unregister_callbacks_
.find(app_id
);
139 if (callback_iter
== unregister_callbacks_
.end())
142 UnregisterCallback callback
= callback_iter
->second
;
143 unregister_callbacks_
.erase(callback_iter
);
144 callback
.Run(result
);
147 void GCMDriver::SendFinished(const std::string
& app_id
,
148 const std::string
& message_id
,
149 GCMClient::Result result
) {
150 std::map
<std::pair
<std::string
, std::string
>, SendCallback
>::iterator
151 callback_iter
= send_callbacks_
.find(
152 std::pair
<std::string
, std::string
>(app_id
, message_id
));
153 if (callback_iter
== send_callbacks_
.end()) {
154 // The callback could have been removed when the app is uninstalled.
158 SendCallback callback
= callback_iter
->second
;
159 send_callbacks_
.erase(callback_iter
);
160 callback
.Run(message_id
, result
);
163 void GCMDriver::Shutdown() {
164 for (GCMAppHandlerMap::const_iterator iter
= app_handlers_
.begin();
165 iter
!= app_handlers_
.end(); ++iter
) {
166 DVLOG(1) << "Calling ShutdownHandler for: " << iter
->first
;
167 iter
->second
->ShutdownHandler();
169 app_handlers_
.clear();
172 void GCMDriver::AddAppHandler(const std::string
& app_id
,
173 GCMAppHandler
* handler
) {
174 DCHECK(!app_id
.empty());
176 DCHECK_EQ(app_handlers_
.count(app_id
), 0u);
177 app_handlers_
[app_id
] = handler
;
178 DVLOG(1) << "App handler added for: " << app_id
;
181 void GCMDriver::RemoveAppHandler(const std::string
& app_id
) {
182 DCHECK(!app_id
.empty());
183 app_handlers_
.erase(app_id
);
184 DVLOG(1) << "App handler removed for: " << app_id
;
187 GCMAppHandler
* GCMDriver::GetAppHandler(const std::string
& app_id
) {
188 // Look for exact match.
189 GCMAppHandlerMap::const_iterator iter
= app_handlers_
.find(app_id
);
190 if (iter
!= app_handlers_
.end())
193 // Ask the handlers whether they know how to handle it.
194 for (iter
= app_handlers_
.begin(); iter
!= app_handlers_
.end(); ++iter
) {
195 if (iter
->second
->CanHandle(app_id
))
199 return &default_app_handler_
;
202 bool GCMDriver::HasRegisterCallback(const std::string
& app_id
) {
203 return register_callbacks_
.find(app_id
) != register_callbacks_
.end();
206 void GCMDriver::ClearCallbacks() {
207 register_callbacks_
.clear();
208 unregister_callbacks_
.clear();
209 send_callbacks_
.clear();
212 void GCMDriver::RegisterAfterUnregister(
213 const std::string
& app_id
,
214 const std::vector
<std::string
>& normalized_sender_ids
,
215 const UnregisterCallback
& unregister_callback
,
216 GCMClient::Result result
) {
217 // Invoke the original unregister callback.
218 unregister_callback
.Run(result
);
220 // Trigger the pending registration.
221 DCHECK(register_callbacks_
.find(app_id
) != register_callbacks_
.end());
222 RegisterImpl(app_id
, normalized_sender_ids
);