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.
5 #include "chrome/browser/local_discovery/service_discovery_device_lister.h"
10 #include "base/bind.h"
11 #include "base/message_loop/message_loop.h"
13 namespace local_discovery {
16 #if defined(OS_MACOSX)
17 const int kMacServiceResolvingIntervalSecs = 60;
21 ServiceDiscoveryDeviceLister::ServiceDiscoveryDeviceLister(
23 ServiceDiscoveryClient* service_discovery_client,
24 const std::string& service_type)
25 : delegate_(delegate),
26 service_discovery_client_(service_discovery_client),
27 service_type_(service_type),
31 ServiceDiscoveryDeviceLister::~ServiceDiscoveryDeviceLister() {
34 void ServiceDiscoveryDeviceLister::Start() {
35 VLOG(1) << "DeviceListerStart: service_type: " << service_type_;
36 CreateServiceWatcher();
39 void ServiceDiscoveryDeviceLister::DiscoverNewDevices(bool force_update) {
40 VLOG(1) << "DiscoverNewDevices: service_type: " << service_type_;
41 service_watcher_->DiscoverNewServices(force_update);
44 void ServiceDiscoveryDeviceLister::OnServiceUpdated(
45 ServiceWatcher::UpdateType update,
46 const std::string& service_name) {
47 VLOG(1) << "OnServiceUpdated: service_type: " << service_type_
48 << ", service_name: " << service_name
49 << ", update: " << update;
50 if (update == ServiceWatcher::UPDATE_INVALIDATED) {
52 CreateServiceWatcher();
54 delegate_->OnDeviceCacheFlushed();
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)));
64 // If there is already a resolver working on this service, don't add one.
65 if (insert_result.second) {
66 VLOG(1) << "Adding resolver for service_name: " << service_name;
67 scoped_ptr<ServiceResolver> resolver =
68 service_discovery_client_->CreateServiceResolver(
69 service_name, base::Bind(
70 &ServiceDiscoveryDeviceLister::OnResolveComplete,
71 weak_factory_.GetWeakPtr(),
75 insert_result.first->second.reset(resolver.release());
76 insert_result.first->second->StartResolving();
78 VLOG(1) << "Resolver already exists, service_name: " << service_name;
81 delegate_->OnDeviceRemoved(service_name);
85 // TODO(noamsml): Update ServiceDiscoveryClient interface to match this.
86 void ServiceDiscoveryDeviceLister::OnResolveComplete(
88 std::string service_name,
89 ServiceResolver::RequestStatus status,
90 const ServiceDescription& service_description) {
91 VLOG(1) << "OnResolveComplete: service_type: " << service_type_
92 << ", service_name: " << service_name
93 << ", status: " << status;
94 if (status == ServiceResolver::STATUS_SUCCESS) {
95 delegate_->OnDeviceChanged(added, service_description);
97 #if defined(OS_MACOSX)
98 // On Mac, the Bonjour service does not seem to ever evict a service if a
99 // device is unplugged, so we need to continuously try to resolve the
100 // service to detect non-graceful shutdowns.
101 base::MessageLoop::current()->PostDelayedTask(
103 base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
104 weak_factory_.GetWeakPtr(),
105 ServiceWatcher::UPDATE_CHANGED,
106 service_description.service_name),
107 base::TimeDelta::FromSeconds(kMacServiceResolvingIntervalSecs));
110 // TODO(noamsml): Add retry logic.
112 resolvers_.erase(service_name);
115 void ServiceDiscoveryDeviceLister::CreateServiceWatcher() {
117 service_discovery_client_->CreateServiceWatcher(
119 base::Bind(&ServiceDiscoveryDeviceLister::OnServiceUpdated,
120 weak_factory_.GetWeakPtr()));
121 service_watcher_->Start();
124 } // namespace local_discovery