chromium/chromecast/mojo/remote_interfaces.h

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

#ifndef CHROMECAST_MOJO_REMOTE_INTERFACES_H_
#define CHROMECAST_MOJO_REMOTE_INTERFACES_H_

#include "base/sequence_checker.h"
#include "chromecast/mojo/mojom/remote_interfaces.mojom.h"
#include "mojo/public/cpp/bindings/generic_pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/remote.h"

namespace chromecast {

// Client helper object which wraps a mojo::Remote<mojom::RemoteInterfaces> and
// provides convenience methods for binding local Remote stubs.
//
// =============================================================================
// Example Usage
// =============================================================================
//
// From a service, create a pending RemoteInterfaces, such as from
// InterfaceBundle:
//
//   InterfaceBundle bundle;
//   bundle.AddInterface<mojom::Foo>(GetFooImpl());
//   bundle.AddInterface<mojom::Bar>(GetBarImpl());
//   mojo::PendingRemote<mojom::RemoteInterfaces> pending_provider =
//       bundle.CreateRemote();
//
// In a different service, we can use RemoteInterfaces to wrap
// |pending_provider| and access the interfaces that were added:
//
//   RemoteService::InjectInterfaces(
//       mojo::PendingRemote<mojom::RemoteInterfaces> pending_provider) {
//     RemoteInterfaces provider(std::move(pending_provider));
//     mojo::Remote<mojom::Bar> bar = bundle.GetRemote<mojom::Bar>();
//     bar->DoBarStuff();
//   }
class RemoteInterfaces {
 public:
  RemoteInterfaces();
  explicit RemoteInterfaces(
      mojo::PendingRemote<mojom::RemoteInterfaces> provider);
  ~RemoteInterfaces();

  RemoteInterfaces(const RemoteInterfaces&) = delete;
  RemoteInterfaces& operator=(const RemoteInterfaces&) = delete;

  // Late-binds a provider if one was not injected on creation.
  void SetProvider(mojo::PendingRemote<mojom::RemoteInterfaces> provider);

  // Exposes interfaces to a remote provider.
  mojo::PendingRemote<mojom::RemoteInterfaces> Forward();

  // Gets the currently unbound receiver to pass to a remote provider. There
  // must not already be a receiver bound to this class.
  mojo::PendingReceiver<mojom::RemoteInterfaces> GetReceiver();

  // ===========================================================================
  // Interface binding methods: After binding, the Remotes/PendingRemotes which
  // are bound are guaranteed to be bound and connected (i.e. remote.is_bound()
  // and remote.is_connected() will return true immediately). Clients can safely
  // start issuing method calls at this point. However, if the remote provider
  // does not fulfill the request, then the Remote/PendingRemote will become
  // disconnected (remote.is_connected() == false), but still be bound.
  // ===========================================================================

  // Binds a generic receiver to an implementation in the remote provider.
  void Bind(mojo::GenericPendingReceiver receiver);

  // Binds an <Interface> implementation in the remote provider.
  template <typename Interface>
  void Bind(mojo::PendingReceiver<Interface> receiver) {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    remote_provider_->BindInterface(Interface::Name_, receiver.PassPipe());
  }

  // Binds a new message pipe to |remote|, and passes the request to the remote
  // provider.
  template <typename Interface>
  void BindNewPipe(mojo::Remote<Interface>* remote) {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    auto pending_receiver = remote->BindNewPipeAndPassReceiver();
    Bind(std::move(pending_receiver));
  }

  // Dispenses a mojo::Remote<Interface> which is bound by the remote provider.
  template <typename Interface>
  mojo::Remote<Interface> CreateRemote() {
    DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
    mojo::Remote<Interface> remote;
    BindNewPipe(&remote);
    return remote;
  }

 private:
  void Init();

  mojo::Remote<mojom::RemoteInterfaces> remote_provider_;

  // Temporary pending receiver which allows the client to immediately
  // start acquiring remote interfaces while we wait for an implementation
  // to be provided.
  mojo::PendingReceiver<mojom::RemoteInterfaces> waiting_receiver_;

  SEQUENCE_CHECKER(sequence_checker_);
};

}  // namespace chromecast

#endif  // CHROMECAST_MOJO_REMOTE_INTERFACES_H_