Files
nearby/cpp/core_v2/internal/client_proxy.h
T
Alexey Polyudov 7e19ffbab7 Release based on cl/313536507.
Signed-off-by: Alexey Polyudov <apolyudov@google.com>
Change-Id: I83ec7dee1a7ef6f4bdfd47482c94d03910525b7e
2020-06-04 10:06:31 -07:00

232 lines
9.5 KiB
C++

// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef CORE_V2_INTERNAL_CLIENT_PROXY_H_
#define CORE_V2_INTERNAL_CLIENT_PROXY_H_
#include <cstdint>
#include <string>
#include <vector>
#include "core_v2/listeners.h"
#include "core_v2/status.h"
#include "core_v2/strategy.h"
#include "platform_v2/base/byte_array.h"
#include "platform_v2/public/mutex.h"
#include "proto/connections_enums.pb.h"
// Prefer using absl:: versions of a set and a map; they tend to be more
// efficient: implementation is using open-addressing hash tables.
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/types/span.h"
namespace location {
namespace nearby {
namespace connections {
// CLientProxy is tracking state of client's connection, and serves as
// a proxy for notifications sent to this client.
class ClientProxy final {
public:
static constexpr int kEndpointIdLength = 4;
ClientProxy();
~ClientProxy();
ClientProxy(ClientProxy&&) = default;
ClientProxy& operator=(ClientProxy&&) = default;
std::int64_t GetClientId() const;
std::string GenerateLocalEndpointId();
// Clears all the runtime state of this client.
void Reset();
// Marks this client as advertising with the given callbacks.
void StartedAdvertising(
const std::string& service_id, Strategy strategy,
const ConnectionListener& connection_lifecycle_listener,
absl::Span<proto::connections::Medium> mediums);
// Marks this client as not advertising.
void StoppedAdvertising();
bool IsAdvertising() const;
std::string GetAdvertisingServiceId() const;
// Marks this client as discovering with the given callback.
void StartedDiscovery(
const std::string& service_id, Strategy strategy,
const DiscoveryListener& discovery_listener,
absl::Span<proto::connections::Medium> mediums);
// Marks this client as not discovering at all.
void StoppedDiscovery();
bool IsDiscoveringServiceId(const std::string& service_id) const;
bool IsDiscovering() const;
std::string GetDiscoveryServiceId() const;
// Proxies to the client's DiscoveryListener::OnEndpointFound() callback.
void OnEndpointFound(const std::string& service_id,
const std::string& endpoint_id,
const std::string& endpoint_name,
proto::connections::Medium medium);
// Proxies to the client's DiscoveryListener::OnEndpointLost() callback.
void OnEndpointLost(const std::string& service_id,
const std::string& endpoint_id);
// Proxies to the client's ConnectionListener::OnInitiated() callback.
void OnConnectionInitiated(const std::string& endpoint_id,
const ConnectionResponseInfo& info,
const ConnectionListener& listener);
// Proxies to the client's ConnectionListener::OnAccepted() callback.
void OnConnectionAccepted(const std::string& endpoint_id);
// Proxies to the client's ConnectionListener::OnRejected() callback.
void OnConnectionRejected(const std::string& endpoint_id,
const Status& status);
void OnBandwidthChanged(const std::string& endpoint_id, std::int32_t quality);
// Removes the endpoint from this client's list of connected endpoints. If
// notify is true, also calls the client's
// ConnectionListener.disconnected_cb() callback.
void OnDisconnected(const std::string& endpoint_id, bool notify);
// Returns true if it's safe to send payloads to this endpoint.
bool IsConnectedToEndpoint(const std::string& endpoint_id) const;
// Returns all endpoints that can safely be sent payloads.
std::vector<std::string> GetConnectedEndpoints() const;
// Returns all endpoints that are still awaiting acceptance.
std::vector<std::string> GetPendingConnectedEndpoints() const;
// Returns the number of endpoints that are connected and outgoing.
std::int32_t GetNumOutgoingConnections() const;
// Returns the number of endpoints that are connected and incoming.
std::int32_t GetNumIncomingConnections() const;
// If true, then we're in the process of approving (or rejecting) a
// connection. No payloads should be sent until isConnectedToEndpoint()
// returns true.
bool HasPendingConnectionToEndpoint(const std::string& endpoint_id) const;
// Returns true if the local endpoint has already marked itself as
// accepted/rejected.
bool HasLocalEndpointResponded(const std::string& endpoint_id) const;
// Returns true if the remote endpoint has already marked themselves as
// accepted/rejected.
bool HasRemoteEndpointResponded(const std::string& endpoint_id) const;
// Marks the local endpoint as having accepted the connection.
void LocalEndpointAcceptedConnection(const std::string& endpoint_id,
const PayloadListener& listener);
// Marks the local endpoint as having rejected the connection.
void LocalEndpointRejectedConnection(const std::string& endpoint_id);
// Marks the remote endpoint as having accepted the connection.
void RemoteEndpointAcceptedConnection(const std::string& endpoint_id);
// Marks the remote endpoint as having rejected the connection.
void RemoteEndpointRejectedConnection(const std::string& endpoint_id);
// Returns true if both the local endpoint and the remote endpoint have
// accepted the connection.
bool IsConnectionAccepted(const std::string& endpoint_id) const;
// Returns true if either the local endpoint or the remote endpoint has
// rejected the connection.
bool IsConnectionRejected(const std::string& endpoint_id) const;
// Proxies to the client's PayloadListener::OnPayload() callback.
void OnPayload(const std::string& endpoint_id, Payload payload);
// Proxies to the client's PayloadListener::OnPayloadProgress() callback.
void OnPayloadProgress(const std::string& endpoint_id,
const PayloadProgressInfo& info);
bool LocalConnectionIsAccepted(std::string endpoint_id) const;
bool RemoteConnectionIsAccepted(std::string endpoint_id) const;
private:
struct Connection {
// Status: may be either:
// Connection::PENDING, or combination of
// Connection::LOCAL_ENDPOINT_ACCEPTED:
// Connection::LOCAL_ENDPOINT_REJECTED and
// Connection::REMOTE_ENDPOINT_ACCEPTED:
// Connection::REMOTE_ENDPOINT_REJECTED, or
// Connection::CONNECTED.
// Only when this is set to CONNECTED should you allow payload transfers.
//
// We want this enum to be implicitly convertible to int, because
// we perform bit operations on it.
enum Status : uint8_t {
kPending = 0,
kLocalEndpointAccepted = 1 << 0,
kLocalEndpointRejected = 1 << 1,
kRemoteEndpointAccepted = 1 << 2,
kRemoteEndpointRejected = 1 << 3,
kConnected = 1 << 4,
};
bool is_incoming{false};
Status status{kPending};
ConnectionListener connection_listener;
PayloadListener payload_listener;
};
struct AdvertisingInfo {
std::string service_id;
ConnectionListener listener;
void Clear() { service_id.clear(); }
bool IsEmpty() const { return service_id.empty(); }
};
struct DiscoveryInfo {
std::string service_id;
DiscoveryListener listener;
void Clear() { service_id.clear(); }
bool IsEmpty() const { return service_id.empty(); }
};
void RemoveAllEndpoints();
bool ConnectionStatusesContains(const std::string& endpoint_id,
Connection::Status status_to_match) const;
void AppendConnectionStatus(const std::string& endpoint_id,
Connection::Status status_to_append);
const Connection* LookupConnection(const std::string& endpoint_id) const;
Connection* LookupConnection(const std::string& endpoint_id);
bool ConnectionStatusMatches(const std::string& endpoint_id,
Connection::Status status) const;
std::vector<std::string> GetMatchingEndpoints(
std::function<bool(const Connection&)> pred) const;
mutable RecursiveMutex mutex_;
std::int64_t client_id_;
// If not empty, we are currently advertising and accepting connection
// requests for the given service_id.
AdvertisingInfo advertising_info_;
// If not empty, we are currently discovering for the given service_id.
DiscoveryInfo discovery_info_;
// Maps endpoint_id to endpoint connection state.
absl::flat_hash_map<std::string, Connection> connections_;
// A cache of endpoint ids that we've already notified the discoverer of. We
// check this cache before calling onEndpointFound() so that we don't notify
// the client multiple times for the same endpoint. This would otherwise
// happen because some mediums (like Bluetooth) repeatedly give us the same
// endpoints after each scan.
absl::flat_hash_set<std::string> discovered_endpoint_ids_;
};
// Operator overloads when comparing Ptr<ClientProxy>.
bool operator==(const ClientProxy& lhs, const ClientProxy& rhs);
bool operator<(const ClientProxy& lhs, const ClientProxy& rhs);
} // namespace connections
} // namespace nearby
} // namespace location
#endif // CORE_V2_INTERNAL_CLIENT_PROXY_H_