| 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));
|
| +}
|
|
|