• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 "osp/impl/service_listener_impl.h"
6 
7 #include <algorithm>
8 
9 #include "platform/base/error.h"
10 #include "util/osp_logging.h"
11 
12 namespace openscreen {
13 namespace osp {
14 namespace {
15 
IsTransitionValid(ServiceListener::State from,ServiceListener::State to)16 bool IsTransitionValid(ServiceListener::State from, ServiceListener::State to) {
17   switch (from) {
18     case ServiceListener::State::kStopped:
19       return to == ServiceListener::State::kStarting ||
20              to == ServiceListener::State::kStopping;
21     case ServiceListener::State::kStarting:
22       return to == ServiceListener::State::kRunning ||
23              to == ServiceListener::State::kStopping ||
24              to == ServiceListener::State::kSuspended;
25     case ServiceListener::State::kRunning:
26       return to == ServiceListener::State::kSuspended ||
27              to == ServiceListener::State::kSearching ||
28              to == ServiceListener::State::kStopping;
29     case ServiceListener::State::kStopping:
30       return to == ServiceListener::State::kStopped;
31     case ServiceListener::State::kSearching:
32       return to == ServiceListener::State::kRunning ||
33              to == ServiceListener::State::kSuspended ||
34              to == ServiceListener::State::kStopping;
35     case ServiceListener::State::kSuspended:
36       return to == ServiceListener::State::kRunning ||
37              to == ServiceListener::State::kSearching ||
38              to == ServiceListener::State::kStopping;
39     default:
40       OSP_DCHECK(false) << "unknown ServiceListener::State value: "
41                         << static_cast<int>(from);
42       break;
43   }
44   return false;
45 }
46 
47 }  // namespace
48 
49 ServiceListenerImpl::Delegate::Delegate() = default;
50 ServiceListenerImpl::Delegate::~Delegate() = default;
51 
SetListenerImpl(ServiceListenerImpl * listener)52 void ServiceListenerImpl::Delegate::SetListenerImpl(
53     ServiceListenerImpl* listener) {
54   OSP_DCHECK(!listener_);
55   listener_ = listener;
56 }
57 
ServiceListenerImpl(Delegate * delegate)58 ServiceListenerImpl::ServiceListenerImpl(Delegate* delegate)
59     : delegate_(delegate) {
60   delegate_->SetListenerImpl(this);
61 }
62 
63 ServiceListenerImpl::~ServiceListenerImpl() = default;
64 
OnReceiverAdded(const ServiceInfo & info)65 void ServiceListenerImpl::OnReceiverAdded(const ServiceInfo& info) {
66   receiver_list_.OnReceiverAdded(info);
67   for (auto* observer : observers_) {
68     observer->OnReceiverAdded(info);
69   }
70 }
71 
OnReceiverChanged(const ServiceInfo & info)72 void ServiceListenerImpl::OnReceiverChanged(const ServiceInfo& info) {
73   const Error changed_error = receiver_list_.OnReceiverChanged(info);
74   if (changed_error.ok()) {
75     for (auto* observer : observers_) {
76       observer->OnReceiverChanged(info);
77     }
78   }
79 }
80 
OnReceiverRemoved(const ServiceInfo & info)81 void ServiceListenerImpl::OnReceiverRemoved(const ServiceInfo& info) {
82   const Error removed_error = receiver_list_.OnReceiverRemoved(info);
83   if (removed_error.ok()) {
84     for (auto* observer : observers_) {
85       observer->OnReceiverRemoved(info);
86     }
87   }
88 }
89 
OnAllReceiversRemoved()90 void ServiceListenerImpl::OnAllReceiversRemoved() {
91   const Error removed_all_error = receiver_list_.OnAllReceiversRemoved();
92   if (removed_all_error.ok()) {
93     for (auto* observer : observers_) {
94       observer->OnAllReceiversRemoved();
95     }
96   }
97 }
98 
OnError(ServiceListenerError error)99 void ServiceListenerImpl::OnError(ServiceListenerError error) {
100   last_error_ = error;
101   for (auto* observer : observers_) {
102     observer->OnError(error);
103   }
104 }
105 
Start()106 bool ServiceListenerImpl::Start() {
107   if (state_ != State::kStopped)
108     return false;
109   state_ = State::kStarting;
110   delegate_->StartListener();
111   return true;
112 }
113 
StartAndSuspend()114 bool ServiceListenerImpl::StartAndSuspend() {
115   if (state_ != State::kStopped)
116     return false;
117   state_ = State::kStarting;
118   delegate_->StartAndSuspendListener();
119   return true;
120 }
121 
Stop()122 bool ServiceListenerImpl::Stop() {
123   if (state_ == State::kStopped || state_ == State::kStopping)
124     return false;
125 
126   state_ = State::kStopping;
127   delegate_->StopListener();
128   return true;
129 }
130 
Suspend()131 bool ServiceListenerImpl::Suspend() {
132   if (state_ != State::kRunning && state_ != State::kSearching &&
133       state_ != State::kStarting) {
134     return false;
135   }
136   delegate_->SuspendListener();
137   return true;
138 }
139 
Resume()140 bool ServiceListenerImpl::Resume() {
141   if (state_ != State::kSuspended && state_ != State::kSearching)
142     return false;
143 
144   delegate_->ResumeListener();
145   return true;
146 }
147 
SearchNow()148 bool ServiceListenerImpl::SearchNow() {
149   if (state_ != State::kRunning && state_ != State::kSuspended)
150     return false;
151 
152   delegate_->SearchNow(state_);
153   return true;
154 }
155 
AddObserver(Observer * observer)156 void ServiceListenerImpl::AddObserver(Observer* observer) {
157   OSP_DCHECK(observer);
158   observers_.push_back(observer);
159 }
160 
RemoveObserver(Observer * observer)161 void ServiceListenerImpl::RemoveObserver(Observer* observer) {
162   // TODO(btolsch): Consider writing an ObserverList in base/ for things like
163   // CHECK()ing that the list is empty on destruction.
164   observers_.erase(std::remove(observers_.begin(), observers_.end(), observer),
165                    observers_.end());
166 }
167 
GetReceivers() const168 const std::vector<ServiceInfo>& ServiceListenerImpl::GetReceivers() const {
169   return receiver_list_.receivers();
170 }
171 
SetState(State state)172 void ServiceListenerImpl::SetState(State state) {
173   OSP_DCHECK(IsTransitionValid(state_, state));
174   state_ = state;
175   if (!observers_.empty()) {
176     MaybeNotifyObservers();
177   }
178 }
179 
MaybeNotifyObservers()180 void ServiceListenerImpl::MaybeNotifyObservers() {
181   OSP_DCHECK(!observers_.empty());
182   switch (state_) {
183     case State::kRunning:
184       for (auto* observer : observers_) {
185         observer->OnStarted();
186       }
187       break;
188     case State::kStopped:
189       for (auto* observer : observers_) {
190         observer->OnStopped();
191       }
192       break;
193     case State::kSuspended:
194       for (auto* observer : observers_) {
195         observer->OnSuspended();
196       }
197       break;
198     case State::kSearching:
199       for (auto* observer : observers_) {
200         observer->OnSearching();
201       }
202       break;
203     default:
204       break;
205   }
206 }
207 
208 }  // namespace osp
209 }  // namespace openscreen
210