| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "fuchsia_web/runners/cast/api_bindings_client.h" |
| |
| #include <utility> |
| |
| #include "base/fuchsia/fuchsia_logging.h" |
| #include "base/functional/bind.h" |
| #include "base/strings/string_piece.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "components/cast/message_port/fuchsia/message_port_fuchsia.h" |
| |
| namespace { |
| |
| uint64_t kBindingsIdStart = 0xFF0000; |
| |
| } // namespace |
| |
| ApiBindingsClient::ApiBindingsClient( |
| fidl::InterfaceHandle<chromium::cast::ApiBindings> bindings_service, |
| base::OnceClosure on_initialization_complete) |
| : bindings_service_(bindings_service.Bind()), |
| on_initialization_complete_(std::move(on_initialization_complete)) { |
| DCHECK(bindings_service_); |
| DCHECK(on_initialization_complete_); |
| |
| bindings_service_->GetAll( |
| fit::bind_member(this, &ApiBindingsClient::OnBindingsReceived)); |
| |
| bindings_service_.set_error_handler([this](zx_status_t status) { |
| ZX_LOG(ERROR, status) << "ApiBindings disconnected."; |
| std::move(on_initialization_complete_).Run(); |
| }); |
| } |
| |
| ApiBindingsClient::~ApiBindingsClient() { |
| if (connector_ && frame_) { |
| connector_->RegisterPortHandler({}); |
| |
| // Remove all injected scripts using their automatically enumerated IDs. |
| for (uint64_t i = 0; i < bindings_->size(); ++i) |
| frame_->RemoveBeforeLoadJavaScript(kBindingsIdStart + i); |
| } |
| } |
| |
| void ApiBindingsClient::AttachToFrame( |
| fuchsia::web::Frame* frame, |
| cast_api_bindings::NamedMessagePortConnector* connector, |
| base::OnceClosure on_error_callback) { |
| DCHECK(!frame_) << "AttachToFrame() was called twice."; |
| DCHECK(frame); |
| DCHECK(connector); |
| |
| if (!bindings_service_) { |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( |
| FROM_HERE, base::BindOnce(&ApiBindingsClient::CallOnErrorCallback, |
| weak_ptr_factory_.GetWeakPtr(), |
| std::move(on_error_callback))); |
| return; |
| } |
| |
| DCHECK(bindings_) |
| << "AttachToFrame() was called before bindings were received."; |
| |
| connector_ = connector; |
| frame_ = frame; |
| |
| bindings_service_.set_error_handler([on_error_callback = |
| std::move(on_error_callback)]( |
| zx_status_t status) mutable { |
| ZX_LOG_IF(ERROR, status != ZX_OK, status) << "ApiBindings disconnected."; |
| std::move(on_error_callback).Run(); |
| }); |
| |
| connector_->RegisterPortHandler(base::BindRepeating( |
| &ApiBindingsClient::OnPortConnected, base::Unretained(this))); |
| |
| // Enumerate and inject all scripts in |bindings|. |
| uint64_t bindings_id = kBindingsIdStart; |
| for (chromium::cast::ApiBinding& entry : *bindings_) { |
| frame_->AddBeforeLoadJavaScript( |
| bindings_id++, {"*"}, std::move(*entry.mutable_before_load_script()), |
| [](fuchsia::web::Frame_AddBeforeLoadJavaScript_Result result) { |
| CHECK(result.is_response()) << "JavaScript injection error: " |
| << static_cast<uint32_t>(result.err()); |
| }); |
| } |
| } |
| |
| void ApiBindingsClient::DetachFromFrame(fuchsia::web::Frame* frame) { |
| DCHECK_EQ(frame, frame_); |
| frame_ = nullptr; |
| bindings_service_.set_error_handler(nullptr); |
| } |
| |
| bool ApiBindingsClient::HasBindings() const { |
| return bindings_.has_value(); |
| } |
| |
| bool ApiBindingsClient::OnPortConnected( |
| base::StringPiece port_name, |
| std::unique_ptr<cast_api_bindings::MessagePort> port) { |
| if (!bindings_service_) |
| return false; |
| |
| bindings_service_->Connect( |
| std::string(port_name), |
| cast_api_bindings::MessagePortFuchsia::FromMessagePort(port.get()) |
| ->TakeClientHandle()); |
| return true; |
| } |
| |
| void ApiBindingsClient::OnBindingsReceived( |
| std::vector<chromium::cast::ApiBinding> bindings) { |
| bindings_ = std::move(bindings); |
| bindings_service_.set_error_handler(nullptr); |
| std::move(on_initialization_complete_).Run(); |
| } |
| |
| void ApiBindingsClient::CallOnErrorCallback( |
| base::OnceClosure on_error_callback) { |
| std::move(on_error_callback).Run(); |
| } |