blob: 0c8ce76230ddc70c9b7742987ab2f76cfb947710 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef OSP_IMPL_PRESENTATION_URL_AVAILABILITY_REQUESTER_H_
#define OSP_IMPL_PRESENTATION_URL_AVAILABILITY_REQUESTER_H_
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include "osp/msgs/osp_messages.h"
#include "osp/public/message_demuxer.h"
#include "osp/public/presentation/presentation_controller.h"
#include "osp/public/protocol_connection_client.h"
#include "osp/public/service_info.h"
#include "platform/api/time.h"
#include "platform/base/error.h"
namespace openscreen::osp {
// Handles Presentation API URL availability requests and persistent watches.
// It keeps track of the set of currently known receivers as well as all
// registered URLs and observers in order to query each receiver with all URLs.
// It uses the availability protocol message watch mechanism to stay informed of
// any availability changes as long as at least one observer is registered for a
// given URL.
class UrlAvailabilityRequester {
public:
explicit UrlAvailabilityRequester(ClockNowFunctionPtr now_function);
~UrlAvailabilityRequester();
// Adds a persistent availability request for |urls| to all known receivers.
// These URLs will also be queried for any receivers discovered in the future.
// |observer| will be called back once for the first known availability (which
// may be cached from previous requests) and when the availability of any of
// these URLs changes on any receiver.
void AddObserver(const std::vector<std::string>& urls,
ReceiverObserver* observer);
// Disassociates |observer| from all the URLs in |urls| so it will no longer
// receive availability updates for these URLs. Additionally, if |urls| is
// only a subset of the URL list it was originally added with, it will still
// be observing the URLs not included here.
void RemoveObserverUrls(const std::vector<std::string>& urls,
ReceiverObserver* observer);
// Disassociates |observer| from all the URLs it is observing. This
// guarantees that it is safe to delete |observer| after this call.
void RemoveObserver(ReceiverObserver* observer);
// Informs the UrlAvailabilityRequester of changes to the set of known
// receivers. New receivers are immediately queried for all currently
// observed URLs and removed receivers cause any URLs that were available on
// that receiver to become unavailable.
void AddReceiver(const ServiceInfo& info);
void ChangeReceiver(const ServiceInfo& info);
void RemoveReceiver(const ServiceInfo& info);
void RemoveAllReceivers();
// Ensures that all open availability watches (to all receivers) that are
// about to expire are refreshed by sending a new request with the same URLs.
// Returns the time point at which this should next be scheduled to run.
Clock::time_point RefreshWatches();
private:
// Handles Presentation API URL availability requests and watches for one
// particular receiver. When first constructed, it attempts to open a
// ProtocolConnection to the receiver, then it makes an availability request
// for all the observed URLs, then it continues to listen for update events
// during the following watch period. Before a watch will expire, it needs to
// send a new request to restart the watch, as long as there are active
// observers for a given URL.
class ReceiverRequester final
: public ProtocolConnectionClient::ConnectionRequestCallback,
public MessageDemuxer::MessageCallback {
public:
ReceiverRequester(UrlAvailabilityRequester& listener,
const std::string& service_id,
const IPEndpoint& endpoint);
~ReceiverRequester() override;
void GetOrRequestAvailabilities(
const std::vector<std::string>& requested_urls,
ReceiverObserver* observer);
void RequestUrlAvailabilities(std::vector<std::string> urls);
ErrorOr<uint64_t> SendRequest(uint64_t request_id,
const std::vector<std::string>& urls);
Clock::time_point RefreshWatches(Clock::time_point now);
Error::Code UpdateAvailabilities(
const std::vector<std::string>& urls,
const std::vector<msgs::UrlAvailability>& availabilities);
void RemoveUnobservedRequests(const std::set<std::string>& unobserved_urls);
void RemoveUnobservedWatches(const std::set<std::string>& unobserved_urls);
void RemoveReceiver();
// ProtocolConnectionClient::ConnectionRequestCallback overrides.
void OnConnectionOpened(
uint64_t request_id,
std::unique_ptr<ProtocolConnection> connection) override;
void OnConnectionFailed(uint64_t request_id) override;
// MessageDemuxer::MessageCallback overrides.
ErrorOr<size_t> OnStreamMessage(uint64_t endpoint_id,
uint64_t connection_id,
msgs::Type message_type,
const uint8_t* buffer,
size_t buffer_size,
Clock::time_point now) override;
std::map<std::string, msgs::UrlAvailability>& known_availability_by_url() {
return known_availability_by_url_;
}
private:
struct Request {
uint64_t watch_id = 0;
std::vector<std::string> urls;
};
struct Watch {
Clock::time_point deadline;
std::vector<std::string> urls;
};
UrlAvailabilityRequester& listener_;
uint64_t next_watch_id_ = 1;
const std::string service_id_;
uint64_t endpoint_id_{0};
ProtocolConnectionClient::ConnectRequest connect_request_;
// TODO(btolsch): Observe connection and restart all the things on close.
std::unique_ptr<ProtocolConnection> connection_;
MessageDemuxer::MessageWatch response_watch_;
std::map<uint64_t, Request> request_by_id_;
MessageDemuxer::MessageWatch event_watch_;
std::map<uint64_t, Watch> watch_by_id_;
std::map<std::string, msgs::UrlAvailability> known_availability_by_url_;
};
const ClockNowFunctionPtr now_function_;
std::map<std::string, std::vector<ReceiverObserver*>> observers_by_url_;
std::map<std::string, std::unique_ptr<ReceiverRequester>>
receiver_by_service_id_;
};
} // namespace openscreen::osp
#endif // OSP_IMPL_PRESENTATION_URL_AVAILABILITY_REQUESTER_H_