#include "ash/webui/eche_app_ui/eche_connection_scheduler_impl.h"
#include "base/functional/bind.h"
#include "base/task/sequenced_task_runner.h"
#include "chromeos/ash/components/multidevice/logging/logging.h"
namespace ash {
namespace eche_app {
constexpr net::BackoffEntry::Policy kRetryBackoffPolicy = {
0,
10 * 1000,
2.0,
0.2,
60 * 60 * 1000,
-1,
true,
};
EcheConnectionSchedulerImpl::EcheConnectionSchedulerImpl(
secure_channel::ConnectionManager* connection_manager,
FeatureStatusProvider* feature_status_provider)
: connection_manager_(connection_manager),
feature_status_provider_(feature_status_provider),
retry_backoff_(&kRetryBackoffPolicy) {
DCHECK(connection_manager_);
DCHECK(feature_status_provider_);
current_feature_status_ = feature_status_provider_->GetStatus();
feature_status_provider_->AddObserver(this);
current_connection_status_ = connection_manager_->GetStatus();
connection_manager_->AddObserver(this);
}
EcheConnectionSchedulerImpl::~EcheConnectionSchedulerImpl() {
feature_status_provider_->RemoveObserver(this);
connection_manager_->RemoveObserver(this);
weak_ptr_factory_.InvalidateWeakPtrs();
}
void EcheConnectionSchedulerImpl::ScheduleConnectionNow() {
if (feature_status_provider_->GetStatus() == FeatureStatus::kDisabled &&
connection_manager_->GetStatus() != ConnectionStatus::kDisconnected) {
PA_LOG(WARNING) << "ScheduleConnectionNow() could not request a connection "
<< "attempt because the current feature status is "
"kDisabled and current connection status is:"
<< connection_manager_->GetStatus() << ".";
return;
}
if (feature_status_provider_->GetStatus() != FeatureStatus::kDisconnected &&
feature_status_provider_->GetStatus() != FeatureStatus::kDisabled) {
PA_LOG(WARNING) << "ScheduleConnectionNow() could not request a connection "
<< "attempt because the current feature status is: "
<< feature_status_provider_->GetStatus() << ".";
return;
}
PA_LOG(VERBOSE) << "ScheduleConnectionNow()";
connection_manager_->AttemptNearbyConnection();
}
void EcheConnectionSchedulerImpl::OnFeatureStatusChanged() {
ScheduleConnectionIfNeeded();
}
void EcheConnectionSchedulerImpl::OnConnectionStatusChanged() {
if (feature_status_provider_->GetStatus() != FeatureStatus::kDisabled)
return;
ScheduleConnectionIfNeeded();
}
void EcheConnectionSchedulerImpl::ScheduleConnectionIfNeeded() {
const FeatureStatus previous_feature_status = current_feature_status_;
current_feature_status_ = feature_status_provider_->GetStatus();
const ConnectionStatus previous_connection_status =
current_connection_status_;
current_connection_status_ = connection_manager_->GetStatus();
if (previous_feature_status == current_feature_status_ &&
previous_connection_status == current_connection_status_)
return;
switch (current_feature_status_) {
case FeatureStatus::kIneligible:
[[fallthrough]];
case FeatureStatus::kDependentFeature:
[[fallthrough]];
case FeatureStatus::kDependentFeaturePending:
DisconnectAndClearBackoffAttempts();
return;
case FeatureStatus::kConnected:
ClearBackoffAttempts();
return;
case FeatureStatus::kConnecting:
return;
case FeatureStatus::kDisabled:
[[fallthrough]];
case FeatureStatus::kDisconnected:
break;
}
if (previous_connection_status == ConnectionStatus::kConnecting) {
PA_LOG(WARNING) << "Scheduling connection to retry in: "
<< retry_backoff_.GetTimeUntilRelease().InSeconds()
<< " seconds.";
retry_backoff_.InformOfRequest(false);
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&EcheConnectionSchedulerImpl::ScheduleConnectionNow,
weak_ptr_factory_.GetWeakPtr()),
retry_backoff_.GetTimeUntilRelease());
} else if (current_connection_status_ == ConnectionStatus::kDisconnected) {
PA_LOG(VERBOSE) << "ConnectionStatus has been updated to "
<< "kDisconnected, scheduling connection now.";
ScheduleConnectionNow();
}
}
void EcheConnectionSchedulerImpl::ClearBackoffAttempts() {
weak_ptr_factory_.InvalidateWeakPtrs();
retry_backoff_.Reset();
}
void EcheConnectionSchedulerImpl::DisconnectAndClearBackoffAttempts() {
ClearBackoffAttempts();
connection_manager_->Disconnect();
}
base::TimeDelta
EcheConnectionSchedulerImpl::GetCurrentBackoffDelayTimeForTesting() {
return retry_backoff_.GetTimeUntilRelease();
}
int EcheConnectionSchedulerImpl::GetBackoffFailureCountForTesting() {
return retry_backoff_.failure_count();
}
}
}