#include "content/browser/sms/sms_fetcher_impl.h"
#include "base/functional/callback.h"
#include "content/browser/browser_main_loop.h"
#include "content/browser/sms/sms_parser.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_client.h"
namespace content {
const char kSmsFetcherImplKeyName[] = "sms_fetcher";
SmsFetcherImpl::SmsFetcherImpl(SmsProvider* provider) : provider_(provider) {
if (provider_)
provider_->AddObserver(this);
}
SmsFetcherImpl::~SmsFetcherImpl() {
if (provider_)
provider_->RemoveObserver(this);
}
SmsFetcher* SmsFetcher::Get(BrowserContext* context) {
if (!context->GetUserData(kSmsFetcherImplKeyName)) {
auto fetcher = std::make_unique<SmsFetcherImpl>(
BrowserMainLoop::GetInstance()->GetSmsProvider());
context->SetUserData(kSmsFetcherImplKeyName, std::move(fetcher));
}
return static_cast<SmsFetcherImpl*>(
context->GetUserData(kSmsFetcherImplKeyName));
}
void SmsFetcherImpl::Subscribe(const OriginList& origin_list,
SmsQueue::Subscriber& subscriber) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!subscribers_.HasSubscriber(origin_list, &subscriber));
subscribers_.Push(origin_list, &subscriber);
if (provider_)
provider_->Retrieve(nullptr, SmsFetchType::kRemote);
}
void SmsFetcherImpl::Subscribe(const OriginList& origin_list,
SmsQueue::Subscriber& subscriber,
RenderFrameHost& render_frame_host) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK_NE(render_frame_host.GetLifecycleState(),
RenderFrameHost::LifecycleState::kPrerendering);
DCHECK(!remote_cancel_callbacks_.count(&subscriber));
DCHECK(!subscribers_.HasSubscriber(origin_list, &subscriber));
subscribers_.Push(origin_list, &subscriber);
base::OnceClosure cancel_callback =
GetContentClient()->browser()->FetchRemoteSms(
WebContents::FromRenderFrameHost(&render_frame_host), origin_list,
base::BindOnce(&SmsFetcherImpl::OnRemote,
weak_ptr_factory_.GetWeakPtr()));
if (cancel_callback)
remote_cancel_callbacks_[&subscriber] = std::move(cancel_callback);
if (provider_)
provider_->Retrieve(&render_frame_host, SmsFetchType::kLocal);
}
void SmsFetcherImpl::Unsubscribe(const OriginList& origin_list,
SmsQueue::Subscriber* subscriber) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
subscribers_.Remove(origin_list, subscriber);
auto it = remote_cancel_callbacks_.find(subscriber);
if (it == remote_cancel_callbacks_.end())
return;
auto cancel_callback = std::move(it->second);
remote_cancel_callbacks_.erase(it);
std::move(cancel_callback).Run();
}
bool SmsFetcherImpl::Notify(const OriginList& origin_list,
const std::string& one_time_code,
UserConsent consent_requirement) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
auto* subscriber = subscribers_.Pop(origin_list);
if (!subscriber)
return false;
subscriber->OnReceive(origin_list, one_time_code, consent_requirement);
return true;
}
void SmsFetcherImpl::OnRemote(std::optional<OriginList> origin_list,
std::optional<std::string> one_time_code,
std::optional<FailureType> failure_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (failure_type) {
OnFailure(failure_type.value());
return;
}
if (!origin_list || !one_time_code)
return;
Notify(origin_list.value(), one_time_code.value(), UserConsent::kObtained);
}
bool SmsFetcherImpl::OnReceive(const OriginList& origin_list,
const std::string& one_time_code,
UserConsent consent_requirement) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return Notify(origin_list, one_time_code, consent_requirement);
}
bool SmsFetcherImpl::OnFailure(FailureType failure_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return subscribers_.NotifyFailure(failure_type);
}
bool SmsFetcherImpl::HasSubscribers() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return subscribers_.HasSubscribers();
}
}