Index: google_apis/gaia/oauth2_token_service_proxy.cc |
diff --git a/google_apis/gaia/oauth2_token_service_proxy.cc b/google_apis/gaia/oauth2_token_service_proxy.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..39894167bff432f438d1e4d2b40017c0ad0083c7 |
--- /dev/null |
+++ b/google_apis/gaia/oauth2_token_service_proxy.cc |
@@ -0,0 +1,232 @@ |
+// Copyright 2014 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "google_apis/gaia/oauth2_token_service_proxy.h" |
+ |
+#include "base/bind.h" |
+#include "base/containers/scoped_ptr_hash_map.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/threading/non_thread_safe.h" |
+#include "google_apis/gaia/google_service_auth_error.h" |
+ |
+namespace { |
+ |
+// Retains an OAuth2TokenService::Request and proxies calls to |
+// OAuth2TokenService::Consumer methods to |callback| on the |
+// |callback_task_runner| thread. |
+class RequestContext : public OAuth2TokenService::Consumer, |
+ public base::NonThreadSafe { |
+ public: |
+ // |requester_id| is a string that describes the service requesting the token. |
+ // |
+ // |callback_task_runner| is the thread that |callback| lives on. |
+ // |
+ // |callback| will be invoked when the request has completed. |
+ // |
+ // |request_done_closure| is a closure used by RequestContext to signal that |
+ // its job is all done and can be destroyed. This closure will be posted to |
+ // the same thread on which RequestContext is constructed. |
+ RequestContext( |
+ const std::string& requester_id, |
+ const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner, |
+ const OAuth2TokenServiceProxy::RequestTokenCallback& callback, |
+ const base::Closure& request_done_closure); |
+ |
+ virtual ~RequestContext(); |
+ |
+ // OAuth2TokenService::Consumer implementation. |
+ virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request, |
+ const std::string& access_token, |
+ const base::Time& expiration_time) OVERRIDE; |
+ virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request, |
+ const GoogleServiceAuthError& error) OVERRIDE; |
+ |
+ void SetRequest(scoped_ptr<OAuth2TokenService::Request> request); |
+ |
+ private: |
+ scoped_refptr<base::SequencedTaskRunner> callback_task_runner_; |
+ OAuth2TokenServiceProxy::RequestTokenCallback callback_; |
+ base::Closure request_done_closure_; |
+ scoped_ptr<OAuth2TokenService::Request> request_; |
+}; |
+ |
+RequestContext::RequestContext( |
+ const std::string& requester_id, |
+ const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner, |
+ const OAuth2TokenServiceProxy::RequestTokenCallback& callback, |
+ const base::Closure& request_done_closure) |
+ : OAuth2TokenService::Consumer(requester_id), |
+ callback_task_runner_(callback_task_runner), |
+ callback_(callback), |
+ request_done_closure_(request_done_closure) { |
+ DCHECK(CalledOnValidThread()); |
+ DCHECK(callback_task_runner_); |
+} |
+ |
+RequestContext::~RequestContext() { |
+ DCHECK(CalledOnValidThread()); |
+} |
+ |
+void RequestContext::OnGetTokenSuccess( |
+ const OAuth2TokenService::Request* request, |
+ const std::string& access_token, |
+ const base::Time& expiration_time) { |
+ DCHECK(CalledOnValidThread()); |
+ callback_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(callback_, |
+ GoogleServiceAuthError::AuthErrorNone(), |
+ access_token, |
+ expiration_time)); |
+ base::MessageLoop::current()->PostTask(FROM_HERE, request_done_closure_); |
+} |
+ |
+void RequestContext::OnGetTokenFailure( |
+ const OAuth2TokenService::Request* request, |
+ const GoogleServiceAuthError& error) { |
+ const std::string access_token; |
+ const base::Time expiration_time; |
+ DCHECK(CalledOnValidThread()); |
+ callback_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(callback_, error, access_token, expiration_time)); |
+ base::MessageLoop::current()->PostTask(FROM_HERE, request_done_closure_); |
+} |
+ |
+void RequestContext::SetRequest( |
+ scoped_ptr<OAuth2TokenService::Request> request) { |
+ DCHECK(CalledOnValidThread()); |
+ request_ = request.Pass(); |
+} |
+ |
+} // namespace |
+ |
+// Core lives on the same thread as the OAuth2TokenService and retains |
+// OAuth2TokenService::Request objects returned by StartRequest. |
+class OAuth2TokenServiceProxy::Core |
+ : public base::RefCountedThreadSafe<OAuth2TokenServiceProxy::Core>, |
+ public base::NonThreadSafe { |
+ public: |
+ Core(OAuth2TokenService* token_service); |
+ |
+ virtual void RequestToken( |
+ const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner, |
+ const RequestTokenCallback& callback, |
+ const std::string& requester_id); |
+ |
+ virtual void InvalidateToken(const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ const std::string& access_token); |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<OAuth2TokenServiceProxy::Core>; |
+ virtual ~Core(); |
+ void RemoveRequest(int64 request_id); |
+ |
+ OAuth2TokenService* token_service_; |
+ // Used to identify RequestContexts in the request_context_map_. When |
+ // completed, RequestContexts can be removed from the map by their id. |
+ int64 next_id_; |
+ base::ScopedPtrHashMap<int64, RequestContext> request_context_map_; |
+}; |
+ |
+OAuth2TokenServiceProxy::Core::Core(OAuth2TokenService* token_service) |
+ : token_service_(token_service), next_id_(0) { |
+ DCHECK(token_service_); |
+ DetachFromThread(); |
+} |
+ |
+OAuth2TokenServiceProxy::Core::~Core() { |
+ DCHECK(CalledOnValidThread()); |
+} |
+ |
+void OAuth2TokenServiceProxy::Core::RemoveRequest(int64 request_id) { |
+ request_context_map_.erase(request_id); |
+} |
+ |
+void OAuth2TokenServiceProxy::Core::RequestToken( |
+ const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ const scoped_refptr<base::SequencedTaskRunner>& callback_task_runner, |
+ const RequestTokenCallback& callback, |
+ const std::string& requester_id) { |
+ DCHECK(CalledOnValidThread()); |
+ |
+ // Create a Closure that can be used to remove the RequestContext we are about |
+ // to create. |
+ int64 request_id = next_id_++; |
+ base::Closure request_done_closure = base::Bind( |
+ &OAuth2TokenServiceProxy::Core::RemoveRequest, this, request_id); |
+ |
+ // Create a RequestContext that will retain a Request and adapt the Consumer |
+ // interface to the user's callback. |
+ scoped_ptr<RequestContext> request_context(new RequestContext( |
+ requester_id, callback_task_runner, callback, request_done_closure)); |
+ |
+ // Start a Request. |
+ scoped_ptr<OAuth2TokenService::Request> request = |
+ token_service_->StartRequest(account_id, scopes, request_context.get()); |
+ |
+ // Then stash it. |
+ request_context->SetRequest(request.Pass()); |
+ request_context_map_.set(request_id, request_context.Pass()); |
+} |
+ |
+void OAuth2TokenServiceProxy::Core::InvalidateToken( |
+ const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ const std::string& access_token) { |
+ DCHECK(CalledOnValidThread()); |
+ token_service_->InvalidateToken(account_id, scopes, access_token); |
+} |
+ |
+OAuth2TokenServiceProxy::OAuth2TokenServiceProxy( |
+ const scoped_refptr<base::SequencedTaskRunner>& token_service_task_runner, |
+ OAuth2TokenService* token_service) |
+ : core_task_runner_(token_service_task_runner), |
+ core_(new Core(token_service)) { |
+ DCHECK(CalledOnValidThread()); |
+ DCHECK(core_task_runner_); |
+} |
+ |
+OAuth2TokenServiceProxy::~OAuth2TokenServiceProxy() { |
+ DCHECK(CalledOnValidThread()); |
+ // core_ lives on the core_task_runner_ thread so we need to ensure it is |
+ // destroyed there. |
+ core_->AddRef(); |
+ core_task_runner_->ReleaseSoon(FROM_HERE, core_.get()); |
+ core_ = NULL; |
+} |
+ |
+void OAuth2TokenServiceProxy::RequestToken( |
+ const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ const RequestTokenCallback& callback, |
+ const std::string& requester_id) { |
+ DCHECK(CalledOnValidThread()); |
+ core_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&OAuth2TokenServiceProxy::Core::RequestToken, |
+ core_, |
+ account_id, |
+ scopes, |
+ base::MessageLoopProxy::current(), |
+ callback, |
+ requester_id)); |
+} |
+ |
+void OAuth2TokenServiceProxy::InvalidateToken( |
+ const std::string& account_id, |
+ const OAuth2TokenService::ScopeSet& scopes, |
+ const std::string& access_token) { |
+ DCHECK(CalledOnValidThread()); |
+ core_task_runner_->PostTask( |
+ FROM_HERE, |
+ base::Bind(&OAuth2TokenServiceProxy::Core::InvalidateToken, |
+ core_, |
+ account_id, |
+ scopes, |
+ access_token)); |
+} |