blob: 6938713a135460375492a5877535fa5d9202ae07 [file] [log] [blame]
// Copyright 2017 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 "peridot/bin/sessionmgr/device_map_impl.h"
#include <limits.h>
#include <unistd.h>
#include <lib/fidl/cpp/binding_set.h>
#include <lib/fidl/cpp/interface_ptr.h>
#include <lib/fidl/cpp/optional.h>
#include <lib/fxl/time/time_point.h>
#include "peridot/bin/sessionmgr/storage/constants_and_utils.h"
#include "peridot/lib/fidl/json_xdr.h"
#include "peridot/lib/ledger_client/operations.h"
namespace modular {
namespace {
using ReadDeviceDataCall = ReadDataCall<fuchsia::modular::DeviceMapEntry>;
using ReadAllDeviceDataCall = ReadAllDataCall<fuchsia::modular::DeviceMapEntry>;
using WriteDeviceDataCall = WriteDataCall<fuchsia::modular::DeviceMapEntry>;
// Reads old versions of device data, which are missing a timestamp.
void XdrDeviceMapEntry_v1(XdrContext* const xdr,
fuchsia::modular::DeviceMapEntry* const data) {
xdr->Field("name", &data->name);
xdr->Field("device_id", &data->device_id);
xdr->Field("profile", &data->profile);
xdr->Field("hostname", &data->hostname);
// The time below is 26 Sep 2017 17:44:40 GMT, just to mark the entry as old.
// Since this filter is not the latest, it is only ever used FROM_JSON, never
// TO_JSON.
data->last_change_timestamp = 1506447879;
}
void XdrDeviceMapEntry_v2(XdrContext* const xdr,
fuchsia::modular::DeviceMapEntry* const data) {
xdr->Field("name", &data->name);
xdr->Field("device_id", &data->device_id);
xdr->Field("profile", &data->profile);
xdr->Field("hostname", &data->hostname);
xdr->Field("last_change_timestamp", &data->last_change_timestamp);
}
void XdrDeviceMapEntry_v3(XdrContext* const xdr,
fuchsia::modular::DeviceMapEntry* const data) {
if (!xdr->Version(3)) {
return;
}
xdr->Field("name", &data->name);
xdr->Field("device_id", &data->device_id);
xdr->Field("profile", &data->profile);
xdr->Field("hostname", &data->hostname);
xdr->Field("last_change_timestamp", &data->last_change_timestamp);
}
constexpr XdrFilterType<fuchsia::modular::DeviceMapEntry> XdrDeviceMapEntry[] =
{
XdrDeviceMapEntry_v3,
XdrDeviceMapEntry_v2,
XdrDeviceMapEntry_v1,
nullptr,
};
std::string LoadHostname() {
char host_name_buffer[HOST_NAME_MAX + 1];
int result = gethostname(host_name_buffer, sizeof(host_name_buffer));
if (result < 0) {
FXL_LOG(ERROR) << "unable to get hostname. errno " << errno;
return "fuchsia";
}
return host_name_buffer;
}
} // namespace
DeviceMapImpl::DeviceMapImpl(const std::string& device_name,
const std::string& device_id,
const std::string& device_profile,
LedgerClient* const ledger_client,
LedgerPageId page_id)
: PageClient("DeviceMapImpl", ledger_client, std::move(page_id),
kDeviceKeyPrefix) {
current_device_id_ = device_id;
// TODO(jimbe) Load the fuchsia::modular::DeviceMapEntry for the current
// device from the Ledger.
fuchsia::modular::DeviceMapEntry device;
device.name = device_name;
device.device_id = device_id;
device.profile = device_profile;
device.hostname = LoadHostname();
devices_[device_id] = std::move(device);
SaveCurrentDevice();
}
DeviceMapImpl::~DeviceMapImpl() = default;
void DeviceMapImpl::Connect(
fidl::InterfaceRequest<fuchsia::modular::DeviceMap> request) {
bindings_.AddBinding(this, std::move(request));
}
void DeviceMapImpl::Query(QueryCallback callback) {
operation_queue_.Add(new ReadAllDeviceDataCall(page(), kDeviceKeyPrefix,
XdrDeviceMapEntry, callback));
}
void DeviceMapImpl::GetCurrentDevice(GetCurrentDeviceCallback callback) {
callback(devices_[current_device_id_]);
}
void DeviceMapImpl::SetCurrentDeviceProfile(::std::string profile) {
devices_[current_device_id_].profile = profile;
Notify(current_device_id_);
SaveCurrentDevice();
}
void DeviceMapImpl::SaveCurrentDevice() {
auto& device = devices_[current_device_id_];
device.last_change_timestamp = time(nullptr);
operation_queue_.Add(new WriteDeviceDataCall(
page(), MakeDeviceKey(current_device_id_), XdrDeviceMapEntry,
fidl::MakeOptional(device), [] {}));
}
void DeviceMapImpl::WatchDeviceMap(
fidl::InterfaceHandle<fuchsia::modular::DeviceMapWatcher> watcher) {
auto watcher_ptr = watcher.Bind();
for (const auto& item : devices_) {
const auto& device = item.second;
watcher_ptr->OnDeviceMapChange(device);
}
change_watchers_.AddInterfacePtr(std::move(watcher_ptr));
}
void DeviceMapImpl::Notify(const std::string& device_id) {
const fuchsia::modular::DeviceMapEntry& device = devices_[current_device_id_];
for (auto& watcher : change_watchers_.ptrs()) {
(*watcher)->OnDeviceMapChange(device);
}
}
void DeviceMapImpl::OnPageChange(const std::string& key,
const std::string& value) {
FXL_LOG(INFO) << "Updated Device: " << key << " value=" << value;
fuchsia::modular::DeviceMapEntry device;
if (!XdrRead(value, &device, XdrDeviceMapEntry)) {
FXL_DCHECK(false);
return;
}
fidl::StringPtr device_id = device.device_id;
devices_[device_id] = std::move(device);
Notify(device_id);
}
void DeviceMapImpl::OnPageDelete(const std::string& key) {
// This shouldn't happen.
FXL_LOG(ERROR) << "Deleted Device: " << key;
}
} // namespace modular