1// Copyright 2015 The Weave Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/privet/publisher.h"
6
7#include <map>
8
9#include <weave/error.h>
10#include <weave/provider/dns_service_discovery.h>
11
12#include "src/privet/cloud_delegate.h"
13#include "src/privet/device_delegate.h"
14#include "src/privet/device_ui_kind.h"
15#include "src/privet/wifi_bootstrap_manager.h"
16#include "src/privet/wifi_ssid_generator.h"
17#include "src/string_utils.h"
18
19namespace weave {
20namespace privet {
21
22namespace {
23
24// The service type we'll expose via DNS-SD.
25const char kPrivetServiceType[] = "_privet._tcp";
26
27}  // namespace
28
29Publisher::Publisher(const DeviceDelegate* device,
30                     const CloudDelegate* cloud,
31                     const WifiDelegate* wifi,
32                     provider::DnsServiceDiscovery* dns_sd)
33    : dns_sd_{dns_sd}, device_{device}, cloud_{cloud}, wifi_{wifi} {
34  CHECK(device_);
35  CHECK(cloud_);
36  CHECK(dns_sd_);
37  Update();
38}
39
40Publisher::~Publisher() {
41  RemoveService();
42}
43
44void Publisher::Update() {
45  if (device_->GetHttpEnpoint().first == 0)
46    return RemoveService();
47  ExposeService();
48}
49
50void Publisher::ExposeService() {
51  std::string name{cloud_->GetName()};
52  std::string model_id{cloud_->GetModelId()};
53  DCHECK_EQ(model_id.size(), 5U);
54
55  VLOG(2) << "DNS-SD update requested";
56  const uint16_t port = device_->GetHttpEnpoint().first;
57  DCHECK_NE(port, 0);
58
59  std::vector<std::string> txt_record{
60      {"txtvers=3"},
61      {"ty=" + name},
62      {"services=" + GetDeviceUiKind(model_id)},
63      {"id=" + cloud_->GetDeviceId()},
64      {"mmid=" + model_id},
65      {"flags=" + WifiSsidGenerator{cloud_, wifi_}.GenerateFlags()},
66  };
67
68  if (!cloud_->GetCloudId().empty())
69    txt_record.emplace_back("gcd_id=" + cloud_->GetCloudId());
70
71  if (!cloud_->GetDescription().empty())
72    txt_record.emplace_back("note=" + cloud_->GetDescription());
73
74  auto new_data = std::make_pair(port, txt_record);
75  if (published_ == new_data)
76    return;
77
78  VLOG(1) << "Updating service using DNS-SD, port: " << port;
79  published_ = new_data;
80  dns_sd_->PublishService(kPrivetServiceType, port, txt_record);
81}
82
83void Publisher::RemoveService() {
84  if (!published_.first)
85    return;
86  published_ = {};
87  VLOG(1) << "Stopping service publishing";
88  dns_sd_->StopPublishing(kPrivetServiceType);
89}
90
91}  // namespace privet
92}  // namespace weave
93