privet_device_lister_impl.cc revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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  service_watcher_ =
41      service_discovery_client_->CreateServiceWatcher(
42          service_type_,
43          base::Bind(&PrivetDeviceListerImpl::OnServiceUpdated,
44                     base::Unretained(this)));
45  service_watcher_->Start();
46}
47
48void PrivetDeviceListerImpl::DiscoverNewDevices(bool force_update) {
49  service_watcher_->DiscoverNewServices(force_update);
50}
51
52void PrivetDeviceListerImpl::OnServiceUpdated(
53    ServiceWatcher::UpdateType update,
54    const std::string& service_name) {
55  if (update != ServiceWatcher::UPDATE_REMOVED) {
56    bool added = (update == ServiceWatcher::UPDATE_ADDED);
57    std::pair<ServiceResolverMap::iterator, bool> insert_result =
58        resolvers_.insert(make_pair(service_name,
59                                    linked_ptr<ServiceResolver>(NULL)));
60
61    // If there is already a resolver working on this service, don't add one.
62    if (insert_result.second) {
63      scoped_ptr<ServiceResolver> resolver =
64          service_discovery_client_->CreateServiceResolver(
65          service_name, base::Bind(
66              &PrivetDeviceListerImpl::OnResolveComplete,
67              base::Unretained(this),
68              added));
69
70      insert_result.first->second.reset(resolver.release());
71      insert_result.first->second->StartResolving();
72    }
73  } else {
74    delegate_->DeviceRemoved(service_name);
75  }
76}
77
78void PrivetDeviceListerImpl::OnResolveComplete(
79    bool added,
80    ServiceResolver::RequestStatus status,
81    const ServiceDescription& service_description) {
82  if (status != ServiceResolver::STATUS_SUCCESS) {
83    resolvers_.erase(service_description.service_name);
84
85    // TODO(noamsml): Add retry logic.
86    return;
87  }
88
89  DeviceDescription device_description;
90  FillDeviceDescription(service_description, &device_description);
91
92  std::string service_name = service_description.service_name;
93  resolvers_.erase(service_name);
94  delegate_->DeviceChanged(added, service_name, device_description);
95}
96
97void PrivetDeviceListerImpl::FillDeviceDescription(
98    const ServiceDescription& service_description,
99    DeviceDescription* device_description) {
100  device_description->address = service_description.address;
101  device_description->ip_address = service_description.ip_address;
102  device_description->last_seen = service_description.last_seen;
103
104  for (std::vector<std::string>::const_iterator i =
105           service_description.metadata.begin();
106       i < service_description.metadata.end();
107       i++) {
108    size_t equals_pos = i->find_first_of('=');
109    if (equals_pos == std::string::npos)
110      continue;  // We do not parse non key-value TXT records
111
112    std::string key = i->substr(0, equals_pos);
113    std::string value = i->substr(equals_pos + 1);
114
115    if (LowerCaseEqualsASCII(key, kPrivetTxtKeyName)) {
116      device_description->name = value;
117    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyDescription)) {
118      device_description->description = value;
119    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyURL)) {
120      device_description->url = value;
121    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyType)) {
122      device_description->type = value;
123    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyID)) {
124      device_description->id = value;
125    } else if (LowerCaseEqualsASCII(key, kPrivetTxtKeyConnectionState)) {
126      device_description->connection_state = ConnectionStateFromString(value);
127    }
128  }
129}
130
131DeviceDescription::ConnectionState
132PrivetDeviceListerImpl::ConnectionStateFromString(const std::string& str) {
133  if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusOnline)) {
134    return DeviceDescription::ONLINE;
135  } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusOffline)) {
136    return DeviceDescription::OFFLINE;
137  } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusConnecting)) {
138    return DeviceDescription::CONNECTING;
139  } else if (LowerCaseEqualsASCII(str, kPrivetConnectionStatusNotConfigured)) {
140    return DeviceDescription::NOT_CONFIGURED;
141  }
142
143  return DeviceDescription::UNKNOWN;
144}
145
146}  // namespace local_discovery
147