chromium/chromeos/ash/services/secure_channel/channel_impl.cc

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/services/secure_channel/channel_impl.h"

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "chromeos/ash/services/secure_channel/file_transfer_update_callback.h"
#include "chromeos/ash/services/secure_channel/public/mojom/secure_channel_types.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/remote_set.h"

namespace ash::secure_channel {

namespace {

const char kReasonForDisconnection[] = "Remote device disconnected.";

}  // namespace

ChannelImpl::ChannelImpl(Delegate* delegate) : delegate_(delegate) {}

ChannelImpl::~ChannelImpl() = default;

mojo::PendingRemote<mojom::Channel> ChannelImpl::GenerateRemote() {
  // Only one PendingRemote should be generated from this instance.
  DCHECK(!receiver_.is_bound());

  mojo::PendingRemote<mojom::Channel> interface_remote =
      receiver_.BindNewPipeAndPassRemote();

  receiver_.set_disconnect_handler(base::BindOnce(
      &ChannelImpl::OnBindingDisconnected, base::Unretained(this)));

  return interface_remote;
}

void ChannelImpl::HandleRemoteDeviceDisconnection() {
  DCHECK(receiver_.is_bound());

  // If the RemoteDevice disconnected, alert clients by providing them a
  // reason specific to this event.
  receiver_.ResetWithReason(mojom::Channel::kConnectionDroppedReason,
                            kReasonForDisconnection);

  file_payload_listener_remotes_.Clear();
}

void ChannelImpl::SendMessage(const std::string& message,
                              SendMessageCallback callback) {
  delegate_->OnSendMessageRequested(message, std::move(callback));
}

void ChannelImpl::RegisterPayloadFile(
    int64_t payload_id,
    mojom::PayloadFilesPtr payload_files,
    mojo::PendingRemote<mojom::FilePayloadListener> listener,
    RegisterPayloadFileCallback callback) {
  mojo::RemoteSetElementId remote_id =
      file_payload_listener_remotes_.Add(std::move(listener));

  delegate_->RegisterPayloadFile(
      payload_id, std::move(payload_files),
      base::BindRepeating(&ChannelImpl::NotifyFileTransferUpdate,
                          weak_ptr_factory_.GetWeakPtr(), remote_id),
      base::BindOnce(&ChannelImpl::OnRegisterPayloadFileResult,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback),
                     remote_id));
}

void ChannelImpl::OnRegisterPayloadFileResult(
    RegisterPayloadFileCallback callback,
    mojo::RemoteSetElementId listener_remote_id,
    bool success) {
  if (!success) {
    file_payload_listener_remotes_.Remove(listener_remote_id);
  }
  std::move(callback).Run(success);
}

void ChannelImpl::NotifyFileTransferUpdate(
    mojo::RemoteSetElementId listener_remote_id,
    mojom::FileTransferUpdatePtr update) {
  bool is_transfer_complete =
      update->status != mojom::FileTransferStatus::kInProgress;
  file_payload_listener_remotes_.Get(listener_remote_id)
      ->OnFileTransferUpdate(std::move(update));

  if (is_transfer_complete) {
    file_payload_listener_remotes_.Remove(listener_remote_id);
  }
}

void ChannelImpl::GetConnectionMetadata(
    GetConnectionMetadataCallback callback) {
  delegate_->GetConnectionMetadata(
      base::BindOnce(&ChannelImpl::OnConnectionMetadataFetchedFromDelegate,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void ChannelImpl::OnConnectionMetadataFetchedFromDelegate(
    GetConnectionMetadataCallback callback,
    mojom::ConnectionMetadataPtr connection_metadata_from_delegate) {
  std::move(callback).Run(std::move(connection_metadata_from_delegate));
}

void ChannelImpl::OnBindingDisconnected() {
  delegate_->OnClientDisconnected();
}

}  // namespace ash::secure_channel