blob: f2e3b19e64ca3b5471e0dc1cdc3f164c8541afad [file] [log] [blame]
// Copyright 2018 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.
#ifndef CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_BASE_H_
#define CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_BASE_H_
#include "base/bind.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/services/secure_channel/connect_to_device_operation.h"
#include "chromeos/services/secure_channel/device_id_pair.h"
#include "chromeos/services/secure_channel/public/cpp/shared/connection_priority.h"
namespace chromeos {
namespace secure_channel {
// Base class for concrete ConnectToDeviceOperation implementations.
// ConnectToDeviceOperationBase objects take a device to which to connect as a
// parameter to their constructors and immediately attempt a connection to the
// device when instantiated.
//
// Derived classes should alert clients of success/failure by invoking the
// OnSuccessfulConnectionAttempt() or OnFailedConnectionAttempt() functions.
template <typename FailureDetailType>
class ConnectToDeviceOperationBase
: public ConnectToDeviceOperation<FailureDetailType> {
protected:
ConnectToDeviceOperationBase(
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionSuccessCallback success_callback,
typename ConnectToDeviceOperation<
FailureDetailType>::ConnectionFailedCallback failure_callback,
const DeviceIdPair& device_id_pair,
ConnectionPriority connection_priority,
scoped_refptr<base::TaskRunner> task_runner =
base::ThreadTaskRunnerHandle::Get())
: ConnectToDeviceOperation<FailureDetailType>(std::move(success_callback),
std::move(failure_callback),
connection_priority),
device_id_pair_(device_id_pair),
task_runner_(task_runner),
pending_connection_attempt_priority_(connection_priority),
weak_ptr_factory_(this) {
// Attempt a connection; however, post this as a task to be run after the
// constructor is finished. This ensures that the derived type is fully
// constructed before a virtual function is invoked.
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&ConnectToDeviceOperationBase<
FailureDetailType>::AttemptConnectionToDevice,
weak_ptr_factory_.GetWeakPtr()));
}
~ConnectToDeviceOperationBase() override = default;
void AttemptConnectionToDevice() {
// If there is no longer a pending connection attempt, this means that the
// attempt was canceled before it could be started.
if (!pending_connection_attempt_priority_)
return;
// Get the current priority, then reset the pending request.
ConnectionPriority priority = *pending_connection_attempt_priority_;
pending_connection_attempt_priority_.reset();
PerformAttemptConnectionToDevice(priority);
}
void CancelInternal() override {
// If the attempt is still pending, it has been canceled before it even
// was started. In this case, invalidate the pending request to ensure
// that it never ends up being attempted.
if (pending_connection_attempt_priority_) {
pending_connection_attempt_priority_.reset();
return;
}
// Otherwise, the attempt is already active, so cancel it directly.
PerformCancellation();
}
void UpdateConnectionPriorityInternal(
ConnectionPriority connection_priority) override {
// If the attempt is still pending, update the connection priorty so that
// when the attempt is started, the correct priority will be provided.
if (pending_connection_attempt_priority_) {
pending_connection_attempt_priority_ = connection_priority;
return;
}
// Otherwise, the attempt is already active, so update its priority.
PerformUpdateConnectionPriority(connection_priority);
}
virtual void PerformAttemptConnectionToDevice(
ConnectionPriority connection_priority) = 0;
virtual void PerformCancellation() = 0;
virtual void PerformUpdateConnectionPriority(
ConnectionPriority connection_priority) = 0;
const DeviceIdPair& device_id_pair() const { return device_id_pair_; }
private:
const DeviceIdPair& device_id_pair_;
scoped_refptr<base::TaskRunner> task_runner_;
base::Optional<ConnectionPriority> pending_connection_attempt_priority_;
base::WeakPtrFactory<ConnectToDeviceOperationBase> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ConnectToDeviceOperationBase);
};
} // namespace secure_channel
} // namespace chromeos
#endif // CHROMEOS_SERVICES_SECURE_CHANNEL_CONNECT_TO_DEVICE_OPERATION_BASE_H_