privet_device_lister_impl.cc revision 58537e28ecd584eab876aee8be7156509866d23a
1// Copyright 2013 The Chromium 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 "chrome/browser/local_discovery/privet_device_lister_impl.h"
6
7#include <string>
8#include <utility>
9#include <vector>
10
11#include "base/bind.h"
12#include "base/strings/string_util.h"
13#include "base/strings/stringprintf.h"
14#include "chrome/browser/local_discovery/privet_constants.h"
15
16namespace local_discovery {
17
18PrivetDeviceListerImpl::PrivetDeviceListerImpl(
19    ServiceDiscoveryClient* service_discovery_client,
20    PrivetDeviceLister::Delegate* delegate)
21    : delegate_(delegate),
22      service_discovery_client_(service_discovery_client),
23      service_type_(kPrivetDefaultDeviceType) {
24}
25
26PrivetDeviceListerImpl::PrivetDeviceListerImpl(
27    ServiceDiscoveryClient* service_discovery_client,
28    PrivetDeviceLister::Delegate* delegate,
29    std::string subtype) : delegate_(delegate),
30                           service_discovery_client_(service_discovery_client),
31                           service_type_(
32                               base::StringPrintf(kPrivetSubtypeTemplate,
33                                                  subtype.c_str())) {
34}
35
36PrivetDeviceListerImpl::~PrivetDeviceListerImpl() {
37}
38
39void PrivetDeviceListerImpl::Start() {
40  CreateServiceWatcher();
41}
42
43void PrivetDeviceListerImpl::DiscoverNewDevices(bool force_update) {
44  service_watcher_->DiscoverNewServices(force_update);
45}
46
47void PrivetDeviceListerImpl::OnServiceUpdated(
48    ServiceWatcher::UpdateType update,
49    const std::string& service_name) {
50  if (update == ServiceWatcher::UPDATE_INVALIDATED) {
51    resolvers_.clear();
52    CreateServiceWatcher();
53
54    delegate_->DeviceCacheFlushed();
55    return;
56  }
57
58  if (update != ServiceWatcher::UPDATE_REMOVED) {
59    bool added = (update == ServiceWatcher::UPDATE_ADDED);
60    std::pair<ServiceResolverMap::iterator, bool> insert_result =
61        resolvers_.insert(make_pair(service_name,
62                                    linked_ptr<ServiceResolver>(NULL)));
63
64    // If there is already a resolver working on this service, don't add one.
65    if (insert_result.second) {
66      scoped_ptr<ServiceResolver> resolver =
67          service_discovery_client_->CreateServiceResolver(
68          service_name, base::Bind(
69              &PrivetDeviceListerImpl::OnResolveComplete,
70              base::Unretained(this),
71              added));
72
73      insert_result.first->second.reset(resolver.release());
74      insert_result.first->second->StartResolving();
75    }
76  } else {
77    delegate_->DeviceRemoved(service_name);
78  }
79}
80
81void PrivetDeviceListerImpl::OnResolveComplete(
82    bool added,
83    ServiceResolver::RequestStatus status,
84    const ServiceDescription& service_description) {
85  if (status != ServiceResolver::STATUS_SUCCESS) {
86    resolvers_.erase(service_description.service_name);
87
88    // TODO(noamsml): Add retry logic.
89    return;
90  }
91
92  DeviceDescription device_description;
93  FillDeviceDescription(service_description, &device_description);
94
95  std::string service_name = service_description.service_name;
96  resolvers_.erase(service_name);
97  delegate_->DeviceChanged(added, service_name, device_description);
98}
99
100void PrivetDeviceListerImpl::FillDeviceDescription(
101    const ServiceDescription& service_description,
102    DeviceDescription* device_description) {
103  device_description->address = service_description.address;
104  device_description->ip_address = service_description.ip_address;
105  device_description->last_seen = service_description.last_seen;
106
107  for (std::vector<std::string>::const_iterator i =
108           service_description.metadata.begin();
109       i < service_description.metadata.end();
110       i++) {
111    size_t equals_pos = i->find_first_of('=');
112    if (equals_pos == std::string::npos)
113      continue;  // We do not parse non key-value TXT records
114
115    std::string key = i->substr(0, equals_pos);
116    std::string value = i->substr(equals_pos + 1);
117
118    if (LowerCaseEqualsASCII(key, kPrivetTxtKeyName)) {
119      device_description->name = value;
120    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyDescription)) {
121      device_description->description = value;
122    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyURL)) {
123      device_description->url = value;
124    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyType)) {
125      device_description->type = value;
126    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyID)) {
127      device_description->id = value;
128    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyConnectionState)) {
129      device_description->connection_state = ConnectionStateFromString(value);
130    }
131  }
132}
133
134DeviceDescription::ConnectionState
135PrivetDeviceListerImpl::ConnectionStateFromString(const std::string& str) {
136  if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusOnline)) {
137    return DeviceDescription::ONLINE;
138  } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusOffline)) {
139    return DeviceDescription::OFFLINE;
140  } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusConnecting)) {
141    return DeviceDescription::CONNECTING;
142  } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusNotConfigured)) {
143    return DeviceDescription::NOT_CONFIGURED;
144  }
145
146  return DeviceDescription::UNKNOWN;
147}
148
149void PrivetDeviceListerImpl::CreateServiceWatcher() {
150  service_watcher_ =
151      service_discovery_client_->CreateServiceWatcher(
152          service_type_,
153          base::Bind(&PrivetDeviceListerImpl::OnServiceUpdated,
154                     base::Unretained(this)));
155  service_watcher_->Start();
156
157}
158
159}  // namespace local_discovery
160