blob: 4565f245f7b731d19a3e9430007338a17bd09346 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bus.h"
#include <zircon/assert.h>
namespace netemul {
class BusBinding : public fuchsia::netemul::bus::Bus {
public:
using FBus = fuchsia::netemul::bus::Bus;
using FEvent = fuchsia::netemul::bus::Event;
BusBinding(std::string name, ::netemul::Bus* parent,
async_dispatcher_t* dispatcher,
fidl::InterfaceRequest<FBus> request)
: client_name_(std::move(name)),
parent_(parent),
binding_(this, std::move(request), dispatcher) {}
void Publish(FEvent data) override {
parent_->Publish(std::move(data), client_name_);
}
void EnsurePublish(FEvent data,
FBus::EnsurePublishCallback callback) override {
parent_->Publish(std::move(data), client_name_);
callback();
}
void GetClients(GetClientsCallback callback) override {
std::vector<std::string> data;
const auto& clients = parent_->clients();
data.reserve(clients.size());
for (const auto& x : clients) {
data.push_back(x.first);
}
callback(std::move(data));
}
void OnBusData(const std::string& from, FEvent event) {
if (from != client_name_) {
binding_.events().OnBusData(std::move(event));
}
}
void OnClientAttached(const std::string& client) {
if (client != client_name_) {
binding_.events().OnClientAttached(client);
}
}
void OnClientDetached(const std::string& client) {
if (client != client_name_) {
binding_.events().OnClientDetached(client);
}
}
void SetErrorHandler(fit::function<void(zx_status_t)> handler) {
binding_.set_error_handler(std::move(handler));
}
private:
const std::string client_name_;
// Pointer to parent bus. Not owned.
::netemul::Bus* parent_;
fidl::Binding<FBus> binding_;
};
Bus::Bus(async_dispatcher_t* dispatcher) : dispatcher_(dispatcher) {}
void Bus::Subscribe(const std::string& clientName,
fidl::InterfaceRequest<Bus::FBus> request) {
// reject if clientName is already in clients
if (clients_.find(clientName) != clients_.end()) {
return;
}
auto binding = std::make_unique<BusBinding>(clientName, this, dispatcher_,
std::move(request));
binding->SetErrorHandler([this, clientName](zx_status_t err) {
// notify other clients this client is gone
NotifyClientDetached(clientName);
clients_.erase(clientName);
});
// notify other clients of new client
NotifyClientAttached(clientName);
clients_.insert(
std::pair<std::string, ClientBinding>(clientName, std::move(binding)));
}
void Bus::NotifyClientAttached(const std::string& client) {
for (const auto& cli : clients_) {
cli.second->OnClientAttached(client);
}
}
void Bus::NotifyClientDetached(const std::string& client) {
for (const auto& cli : clients_) {
cli.second->OnClientDetached(client);
}
}
const std::unordered_map<std::string, Bus::ClientBinding>& Bus::clients() {
return clients_;
}
void Bus::Publish(Bus::FEvent data, const std::string& from) {
for (const auto& cli : clients_) {
Bus::FEvent clone;
ZX_ASSERT(data.Clone(&clone) == ZX_OK);
cli.second->OnBusData(from, std::move(clone));
}
}
Bus::~Bus() = default;
} // namespace netemul