blob: 7e2589656e197d2990f5bcf493526dd7084e30bf [file] [log] [blame]
// Copyright 2019 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 "remoting/signaling/ftl_registration_manager.h"
#include <utility>
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "remoting/base/grpc_support/grpc_async_unary_request.h"
#include "remoting/base/grpc_support/grpc_authenticated_executor.h"
#include "remoting/base/grpc_support/grpc_executor.h"
#include "remoting/proto/ftl/v1/ftl_services.grpc.pb.h"
#include "remoting/signaling/ftl_device_id_provider.h"
#include "remoting/signaling/ftl_grpc_context.h"
namespace remoting {
namespace {
constexpr remoting::ftl::ChromotingCapability::Feature
kChromotingCapabilities[] = {
remoting::ftl::ChromotingCapability_Feature_SERIALIZED_XMPP_SIGNALING};
constexpr size_t kChromotingCapabilityCount =
sizeof(kChromotingCapabilities) /
sizeof(ftl::ChromotingCapability::Feature);
constexpr remoting::ftl::FtlCapability::Feature kFtlCapabilities[] = {
remoting::ftl::FtlCapability_Feature_RECEIVE_CALLS_FROM_GAIA,
remoting::ftl::FtlCapability_Feature_GAIA_REACHABLE};
constexpr size_t kFtlCapabilityCount =
sizeof(kFtlCapabilities) / sizeof(ftl::FtlCapability::Feature);
constexpr base::TimeDelta kRefreshBufferTime = base::TimeDelta::FromHours(1);
} // namespace
class FtlRegistrationManager::RegistrationClientImpl final
: public FtlRegistrationManager::RegistrationClient {
public:
explicit RegistrationClientImpl(OAuthTokenGetter* token_getter);
~RegistrationClientImpl() override;
// RegistrationClient implementations.
void SignInGaia(const ftl::SignInGaiaRequest& request,
SignInGaiaResponseCallback on_done) override;
void CancelPendingRequests() override;
private:
using Registration =
google::internal::communications::instantmessaging::v1::Registration;
GrpcAuthenticatedExecutor executor_;
std::unique_ptr<Registration::Stub> registration_stub_;
DISALLOW_COPY_AND_ASSIGN(RegistrationClientImpl);
};
FtlRegistrationManager::RegistrationClientImpl::RegistrationClientImpl(
OAuthTokenGetter* token_getter)
: executor_(token_getter),
registration_stub_(
Registration::NewStub(FtlGrpcContext::CreateChannel())) {}
FtlRegistrationManager::RegistrationClientImpl::~RegistrationClientImpl() =
default;
void FtlRegistrationManager::RegistrationClientImpl::SignInGaia(
const ftl::SignInGaiaRequest& request,
SignInGaiaResponseCallback on_done) {
auto grpc_request = CreateGrpcAsyncUnaryRequest(
base::BindOnce(&Registration::Stub::AsyncSignInGaia,
base::Unretained(registration_stub_.get())),
request, std::move(on_done));
FtlGrpcContext::FillClientContext(grpc_request->context());
executor_.ExecuteRpc(std::move(grpc_request));
}
void FtlRegistrationManager::RegistrationClientImpl::CancelPendingRequests() {
executor_.CancelPendingRequests();
}
// End of RegistrationClientImplImpl
FtlRegistrationManager::FtlRegistrationManager(
OAuthTokenGetter* token_getter,
std::unique_ptr<FtlDeviceIdProvider> device_id_provider)
: registration_client_(
std::make_unique<RegistrationClientImpl>(token_getter)),
device_id_provider_(std::move(device_id_provider)),
sign_in_backoff_(&FtlGrpcContext::GetBackoffPolicy()) {
DCHECK(device_id_provider_);
}
FtlRegistrationManager::~FtlRegistrationManager() = default;
void FtlRegistrationManager::SignInGaia(DoneCallback on_done) {
VLOG(1) << "SignInGaia will be called with backoff: "
<< sign_in_backoff_.GetTimeUntilRelease();
sign_in_backoff_timer_.Start(
FROM_HERE, sign_in_backoff_.GetTimeUntilRelease(),
base::BindOnce(&FtlRegistrationManager::DoSignInGaia,
base::Unretained(this), std::move(on_done)));
}
void FtlRegistrationManager::SignOut() {
if (!IsSignedIn()) {
return;
}
registration_client_->CancelPendingRequests();
sign_in_refresh_timer_.Stop();
registration_id_.clear();
ftl_auth_token_.clear();
}
bool FtlRegistrationManager::IsSignedIn() const {
return !ftl_auth_token_.empty();
}
std::string FtlRegistrationManager::GetRegistrationId() const {
return registration_id_;
}
std::string FtlRegistrationManager::GetFtlAuthToken() const {
return ftl_auth_token_;
}
void FtlRegistrationManager::DoSignInGaia(DoneCallback on_done) {
ftl::SignInGaiaRequest request;
*request.mutable_header() = FtlGrpcContext::CreateRequestHeader();
request.set_app(FtlGrpcContext::GetChromotingAppIdentifier());
request.set_mode(ftl::SignInGaiaMode_Value_DEFAULT_CREATE_ACCOUNT);
*request.mutable_register_data()->mutable_device_id() =
device_id_provider_->GetDeviceId();
for (size_t i = 0; i < kChromotingCapabilityCount; i++) {
request.mutable_register_data()->add_caps(kChromotingCapabilities[i]);
}
for (size_t i = 0; i < kFtlCapabilityCount; i++) {
request.mutable_register_data()->add_caps(kFtlCapabilities[i]);
}
registration_client_->SignInGaia(
request, base::BindOnce(&FtlRegistrationManager::OnSignInGaiaResponse,
base::Unretained(this), std::move(on_done)));
}
void FtlRegistrationManager::OnSignInGaiaResponse(
DoneCallback on_done,
const grpc::Status& status,
const ftl::SignInGaiaResponse& response) {
registration_id_.clear();
if (!status.ok()) {
LOG(ERROR) << "Failed to sign in."
<< " Error code: " << status.error_code()
<< ", message: " << status.error_message();
sign_in_backoff_.InformOfRequest(false);
std::move(on_done).Run(status);
return;
}
sign_in_backoff_.Reset();
registration_id_ = response.registration_id();
if (registration_id_.empty()) {
std::move(on_done).Run(
grpc::Status(grpc::StatusCode::UNKNOWN, "registration_id is empty."));
return;
}
// TODO(yuweih): Consider caching auth token.
ftl_auth_token_ = response.auth_token().payload();
VLOG(1) << "Auth token set on FtlClient";
base::TimeDelta refresh_delay =
base::TimeDelta::FromMicroseconds(response.auth_token().expires_in());
if (refresh_delay > kRefreshBufferTime) {
refresh_delay -= kRefreshBufferTime;
} else {
LOG(WARNING) << "Refresh time is too short. Buffer time is not applied.";
}
sign_in_refresh_timer_.Start(
FROM_HERE, refresh_delay,
base::BindOnce(&FtlRegistrationManager::SignInGaia,
base::Unretained(this),
base::DoNothing::Once<const grpc::Status&>()));
VLOG(1) << "Scheduled auth token refresh in: " << refresh_delay;
std::move(on_done).Run(status);
}
} // namespace remoting