[GCM] Extracting GCMConnectionObserver from GCMAppHandler
[chromium-blink-merge.git] / components / invalidation / gcm_invalidation_bridge.cc
blob691be33a0e4088329e0ce8ee816d990f2bfc8e2d
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 "base/bind.h"
6 #include "base/location.h"
7 #include "base/single_thread_task_runner.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "components/gcm_driver/gcm_driver.h"
10 #include "components/invalidation/gcm_invalidation_bridge.h"
11 #include "components/signin/core/browser/profile_oauth2_token_service.h"
12 #include "components/signin/core/browser/signin_manager.h"
13 #include "google_apis/gaia/gaia_constants.h"
14 #include "google_apis/gaia/identity_provider.h"
16 namespace invalidation {
17 namespace {
18 // For 3rd party developers SenderId should come from application dashboard when
19 // server side application is registered with Google. Android invalidations use
20 // legacy format where gmail account can be specificed. Below value is copied
21 // from Android.
22 const char kInvalidationsSenderId[] = "ipc.invalidation@gmail.com";
23 // In Android world AppId is provided by operating system and should
24 // match package name and hash of application. In desktop world these values
25 // are arbitrary and not verified/enforced by registration service (yet).
26 const char kInvalidationsAppId[] = "com.google.chrome.invalidations";
28 // Cacheinvalidation specific gcm message keys.
29 const char kContentKey[] = "content";
30 const char kEchoTokenKey[] = "echo-token";
31 } // namespace
33 // Core should be very simple class that implements GCMNetwrokChannelDelegate
34 // and passes all calls to GCMInvalidationBridge. All calls should be serialized
35 // through GCMInvalidationBridge to avoid race conditions.
36 class GCMInvalidationBridge::Core : public syncer::GCMNetworkChannelDelegate,
37 public base::NonThreadSafe {
38 public:
39 Core(base::WeakPtr<GCMInvalidationBridge> bridge,
40 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner);
41 virtual ~Core();
43 // syncer::GCMNetworkChannelDelegate implementation.
44 virtual void Initialize(ConnectionStateCallback callback) OVERRIDE;
45 virtual void RequestToken(RequestTokenCallback callback) OVERRIDE;
46 virtual void InvalidateToken(const std::string& token) OVERRIDE;
47 virtual void Register(RegisterCallback callback) OVERRIDE;
48 virtual void SetMessageReceiver(MessageCallback callback) OVERRIDE;
50 void RequestTokenFinished(RequestTokenCallback callback,
51 const GoogleServiceAuthError& error,
52 const std::string& token);
54 void RegisterFinished(RegisterCallback callback,
55 const std::string& registration_id,
56 gcm::GCMClient::Result result);
58 void OnIncomingMessage(const std::string& message,
59 const std::string& echo_token);
61 void OnConnectionStateChanged(bool online);
63 private:
64 base::WeakPtr<GCMInvalidationBridge> bridge_;
65 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner_;
67 MessageCallback message_callback_;
68 ConnectionStateCallback connection_state_callback_;
70 base::WeakPtrFactory<Core> weak_factory_;
72 DISALLOW_COPY_AND_ASSIGN(Core);
75 GCMInvalidationBridge::Core::Core(
76 base::WeakPtr<GCMInvalidationBridge> bridge,
77 scoped_refptr<base::SingleThreadTaskRunner> ui_thread_task_runner)
78 : bridge_(bridge),
79 ui_thread_task_runner_(ui_thread_task_runner),
80 weak_factory_(this) {
81 // Core is created on UI thread but all calls happen on IO thread.
82 DetachFromThread();
85 GCMInvalidationBridge::Core::~Core() {}
87 void GCMInvalidationBridge::Core::Initialize(ConnectionStateCallback callback) {
88 DCHECK(CalledOnValidThread());
89 connection_state_callback_ = callback;
90 // Pass core WeapPtr and TaskRunner to GCMInvalidationBridge for it to be able
91 // to post back.
92 ui_thread_task_runner_->PostTask(
93 FROM_HERE,
94 base::Bind(&GCMInvalidationBridge::CoreInitializationDone,
95 bridge_,
96 weak_factory_.GetWeakPtr(),
97 base::ThreadTaskRunnerHandle::Get()));
100 void GCMInvalidationBridge::Core::RequestToken(RequestTokenCallback callback) {
101 DCHECK(CalledOnValidThread());
102 ui_thread_task_runner_->PostTask(
103 FROM_HERE,
104 base::Bind(&GCMInvalidationBridge::RequestToken, bridge_, callback));
107 void GCMInvalidationBridge::Core::InvalidateToken(const std::string& token) {
108 DCHECK(CalledOnValidThread());
109 ui_thread_task_runner_->PostTask(
110 FROM_HERE,
111 base::Bind(&GCMInvalidationBridge::InvalidateToken, bridge_, token));
114 void GCMInvalidationBridge::Core::Register(RegisterCallback callback) {
115 DCHECK(CalledOnValidThread());
116 ui_thread_task_runner_->PostTask(
117 FROM_HERE,
118 base::Bind(&GCMInvalidationBridge::Register, bridge_, callback));
121 void GCMInvalidationBridge::Core::SetMessageReceiver(MessageCallback callback) {
122 message_callback_ = callback;
123 ui_thread_task_runner_->PostTask(
124 FROM_HERE,
125 base::Bind(&GCMInvalidationBridge::SubscribeForIncomingMessages,
126 bridge_));
129 void GCMInvalidationBridge::Core::RequestTokenFinished(
130 RequestTokenCallback callback,
131 const GoogleServiceAuthError& error,
132 const std::string& token) {
133 DCHECK(CalledOnValidThread());
134 callback.Run(error, token);
137 void GCMInvalidationBridge::Core::RegisterFinished(
138 RegisterCallback callback,
139 const std::string& registration_id,
140 gcm::GCMClient::Result result) {
141 DCHECK(CalledOnValidThread());
142 callback.Run(registration_id, result);
145 void GCMInvalidationBridge::Core::OnIncomingMessage(
146 const std::string& message,
147 const std::string& echo_token) {
148 DCHECK(!message_callback_.is_null());
149 message_callback_.Run(message, echo_token);
152 void GCMInvalidationBridge::Core::OnConnectionStateChanged(bool online) {
153 if (!connection_state_callback_.is_null()) {
154 connection_state_callback_.Run(online);
158 GCMInvalidationBridge::GCMInvalidationBridge(
159 gcm::GCMDriver* gcm_driver,
160 IdentityProvider* identity_provider)
161 : OAuth2TokenService::Consumer("gcm_network_channel"),
162 gcm_driver_(gcm_driver),
163 identity_provider_(identity_provider),
164 subscribed_for_incoming_messages_(false),
165 weak_factory_(this) {}
167 GCMInvalidationBridge::~GCMInvalidationBridge() {
168 if (subscribed_for_incoming_messages_) {
169 gcm_driver_->RemoveAppHandler(kInvalidationsAppId);
170 gcm_driver_->RemoveConnectionObserver(this);
174 scoped_ptr<syncer::GCMNetworkChannelDelegate>
175 GCMInvalidationBridge::CreateDelegate() {
176 DCHECK(CalledOnValidThread());
177 scoped_ptr<syncer::GCMNetworkChannelDelegate> core(new Core(
178 weak_factory_.GetWeakPtr(), base::ThreadTaskRunnerHandle::Get()));
179 return core.Pass();
182 void GCMInvalidationBridge::CoreInitializationDone(
183 base::WeakPtr<Core> core,
184 scoped_refptr<base::SingleThreadTaskRunner> core_thread_task_runner) {
185 DCHECK(CalledOnValidThread());
186 core_ = core;
187 core_thread_task_runner_ = core_thread_task_runner;
190 void GCMInvalidationBridge::RequestToken(
191 syncer::GCMNetworkChannelDelegate::RequestTokenCallback callback) {
192 DCHECK(CalledOnValidThread());
193 if (access_token_request_ != NULL) {
194 // Report previous request as cancelled.
195 GoogleServiceAuthError error(GoogleServiceAuthError::REQUEST_CANCELED);
196 std::string access_token;
197 core_thread_task_runner_->PostTask(
198 FROM_HERE,
199 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished,
200 core_,
201 request_token_callback_,
202 error,
203 access_token));
205 request_token_callback_ = callback;
206 OAuth2TokenService::ScopeSet scopes;
207 scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
208 access_token_request_ = identity_provider_->GetTokenService()->StartRequest(
209 identity_provider_->GetActiveAccountId(), scopes, this);
212 void GCMInvalidationBridge::OnGetTokenSuccess(
213 const OAuth2TokenService::Request* request,
214 const std::string& access_token,
215 const base::Time& expiration_time) {
216 DCHECK(CalledOnValidThread());
217 DCHECK_EQ(access_token_request_, request);
218 core_thread_task_runner_->PostTask(
219 FROM_HERE,
220 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished,
221 core_,
222 request_token_callback_,
223 GoogleServiceAuthError::AuthErrorNone(),
224 access_token));
225 request_token_callback_.Reset();
226 access_token_request_.reset();
229 void GCMInvalidationBridge::OnGetTokenFailure(
230 const OAuth2TokenService::Request* request,
231 const GoogleServiceAuthError& error) {
232 DCHECK(CalledOnValidThread());
233 DCHECK_EQ(access_token_request_, request);
234 core_thread_task_runner_->PostTask(
235 FROM_HERE,
236 base::Bind(&GCMInvalidationBridge::Core::RequestTokenFinished,
237 core_,
238 request_token_callback_,
239 error,
240 std::string()));
241 request_token_callback_.Reset();
242 access_token_request_.reset();
245 void GCMInvalidationBridge::InvalidateToken(const std::string& token) {
246 DCHECK(CalledOnValidThread());
247 OAuth2TokenService::ScopeSet scopes;
248 scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
249 identity_provider_->GetTokenService()->InvalidateToken(
250 identity_provider_->GetActiveAccountId(), scopes, token);
253 void GCMInvalidationBridge::Register(
254 syncer::GCMNetworkChannelDelegate::RegisterCallback callback) {
255 DCHECK(CalledOnValidThread());
256 // No-op if GCMClient is disabled.
257 if (gcm_driver_ == NULL)
258 return;
260 std::vector<std::string> sender_ids;
261 sender_ids.push_back(kInvalidationsSenderId);
262 gcm_driver_->Register(kInvalidationsAppId,
263 sender_ids,
264 base::Bind(&GCMInvalidationBridge::RegisterFinished,
265 weak_factory_.GetWeakPtr(),
266 callback));
269 void GCMInvalidationBridge::RegisterFinished(
270 syncer::GCMNetworkChannelDelegate::RegisterCallback callback,
271 const std::string& registration_id,
272 gcm::GCMClient::Result result) {
273 DCHECK(CalledOnValidThread());
274 core_thread_task_runner_->PostTask(
275 FROM_HERE,
276 base::Bind(&GCMInvalidationBridge::Core::RegisterFinished,
277 core_,
278 callback,
279 registration_id,
280 result));
283 void GCMInvalidationBridge::SubscribeForIncomingMessages() {
284 // No-op if GCMClient is disabled.
285 if (gcm_driver_ == NULL)
286 return;
288 DCHECK(!subscribed_for_incoming_messages_);
289 gcm_driver_->AddAppHandler(kInvalidationsAppId, this);
290 gcm_driver_->AddConnectionObserver(this);
291 core_thread_task_runner_->PostTask(
292 FROM_HERE,
293 base::Bind(&GCMInvalidationBridge::Core::OnConnectionStateChanged,
294 core_,
295 gcm_driver_->IsConnected()));
297 subscribed_for_incoming_messages_ = true;
300 void GCMInvalidationBridge::ShutdownHandler() {
301 // Nothing to do.
304 void GCMInvalidationBridge::OnMessage(
305 const std::string& app_id,
306 const gcm::GCMClient::IncomingMessage& message) {
307 gcm::GCMClient::MessageData::const_iterator it;
308 std::string content;
309 std::string echo_token;
310 it = message.data.find(kContentKey);
311 if (it != message.data.end())
312 content = it->second;
313 it = message.data.find(kEchoTokenKey);
314 if (it != message.data.end())
315 echo_token = it->second;
317 core_thread_task_runner_->PostTask(
318 FROM_HERE,
319 base::Bind(&GCMInvalidationBridge::Core::OnIncomingMessage,
320 core_,
321 content,
322 echo_token));
325 void GCMInvalidationBridge::OnMessagesDeleted(const std::string& app_id) {
326 // Cacheinvalidation doesn't use long lived non-collapsable messages with GCM.
327 // Android implementation of cacheinvalidation doesn't handle MessagesDeleted
328 // callback so this should be no-op in desktop version as well.
331 void GCMInvalidationBridge::OnSendError(
332 const std::string& app_id,
333 const gcm::GCMClient::SendErrorDetails& send_error_details) {
334 // cacheinvalidation doesn't send messages over GCM.
335 NOTREACHED();
338 void GCMInvalidationBridge::OnSendAcknowledged(
339 const std::string& app_id,
340 const std::string& message_id) {
341 // cacheinvalidation doesn't send messages over GCM.
342 NOTREACHED();
345 void GCMInvalidationBridge::OnConnected(const net::IPEndPoint& ip_endpoint) {
346 core_thread_task_runner_->PostTask(
347 FROM_HERE,
348 base::Bind(
349 &GCMInvalidationBridge::Core::OnConnectionStateChanged, core_, true));
352 void GCMInvalidationBridge::OnDisconnected() {
353 core_thread_task_runner_->PostTask(
354 FROM_HERE,
355 base::Bind(&GCMInvalidationBridge::Core::OnConnectionStateChanged,
356 core_,
357 false));
361 } // namespace invalidation