mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-15 07:06:11 -04:00
724 lines
28 KiB
C++
724 lines
28 KiB
C++
// Copyright 2021 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.
|
|
|
|
#include "connections/implementation/service_controller_router.h"
|
|
|
|
#include <cstddef>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "absl/memory/memory.h"
|
|
#include "connections/discovery_options.h"
|
|
#include "connections/implementation/client_proxy.h"
|
|
#include "connections/implementation/offline_service_controller.h"
|
|
#include "connections/listeners.h"
|
|
#include "connections/params.h"
|
|
#include "connections/payload.h"
|
|
#include "connections/v3/bandwidth_info.h"
|
|
#include "connections/v3/connection_result.h"
|
|
#include "connections/v3/connections_device.h"
|
|
#include "connections/v3/listening_result.h"
|
|
#include "internal/platform/logging.h"
|
|
|
|
// TODO(b/285657711): Add tests for uncovered logic, even if trivial.
|
|
namespace nearby {
|
|
namespace connections {
|
|
namespace {
|
|
// Length of a MAC address, which consists of 6 bytes uniquely identifying a
|
|
// hardware interface.
|
|
const std::size_t kMacAddressLength = 6u;
|
|
|
|
// Length used for an endpoint ID, which identifies a device discovery and
|
|
// associated connection request.
|
|
const std::size_t kEndpointIdLength = 4u;
|
|
|
|
// Maximum length for information describing an endpoint; this information is
|
|
// advertised by one device and can be used by the other device to identify the
|
|
// advertiser.
|
|
const std::size_t kMaxEndpointInfoLength = 131u;
|
|
|
|
bool ClientHasConnectionToAtLeastOneEndpoint(
|
|
ClientProxy* client, const std::vector<std::string>& remote_endpoint_ids) {
|
|
for (auto& endpoint_id : remote_endpoint_ids) {
|
|
if (client->IsConnectedToEndpoint(endpoint_id)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
} // namespace
|
|
|
|
v3::Quality ServiceControllerRouter::GetMediumQuality(Medium medium) {
|
|
switch (medium) {
|
|
case location::nearby::proto::connections::USB:
|
|
case location::nearby::proto::connections::UNKNOWN_MEDIUM:
|
|
return v3::Quality::kUnknown;
|
|
case location::nearby::proto::connections::BLE:
|
|
case location::nearby::proto::connections::NFC:
|
|
return v3::Quality::kLow;
|
|
case location::nearby::proto::connections::BLUETOOTH:
|
|
case location::nearby::proto::connections::BLE_L2CAP:
|
|
return v3::Quality::kMedium;
|
|
case location::nearby::proto::connections::WIFI_HOTSPOT:
|
|
case location::nearby::proto::connections::WIFI_LAN:
|
|
case location::nearby::proto::connections::WIFI_AWARE:
|
|
case location::nearby::proto::connections::WIFI_DIRECT:
|
|
case location::nearby::proto::connections::WEB_RTC:
|
|
return v3::Quality::kHigh;
|
|
default:
|
|
return v3::Quality::kUnknown;
|
|
}
|
|
}
|
|
|
|
ServiceControllerRouter::ServiceControllerRouter() {
|
|
NEARBY_LOGS(INFO) << "ServiceControllerRouter going up.";
|
|
}
|
|
|
|
ServiceControllerRouter::~ServiceControllerRouter() {
|
|
NEARBY_LOGS(INFO) << "ServiceControllerRouter going down.";
|
|
|
|
if (service_controller_) {
|
|
service_controller_->Stop();
|
|
}
|
|
// And make sure that cleanup is the last thing we do.
|
|
serializer_.Shutdown();
|
|
}
|
|
|
|
void ServiceControllerRouter::StartAdvertising(
|
|
ClientProxy* client, absl::string_view service_id,
|
|
const AdvertisingOptions& advertising_options,
|
|
const ConnectionRequestInfo& info, ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-start-advertising",
|
|
[this, client, service_id = std::string(service_id), advertising_options,
|
|
info, callback = std::move(callback)]() mutable {
|
|
if (client->IsAdvertising()) {
|
|
callback({Status::kAlreadyAdvertising});
|
|
return;
|
|
}
|
|
|
|
callback(GetServiceController()->StartAdvertising(
|
|
client, service_id, advertising_options, info));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::StopAdvertising(ClientProxy* client,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-stop-advertising",
|
|
[this, client, callback = std::move(callback)]() mutable {
|
|
if (client->IsAdvertising()) {
|
|
GetServiceController()->StopAdvertising(client);
|
|
}
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::StartDiscovery(
|
|
ClientProxy* client, absl::string_view service_id,
|
|
const DiscoveryOptions& discovery_options, DiscoveryListener listener,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-start-discovery",
|
|
[this, client, service_id = std::string(service_id), discovery_options,
|
|
listener = std::move(listener),
|
|
callback = std::move(callback)]() mutable {
|
|
if (client->IsDiscovering()) {
|
|
callback({Status::kAlreadyDiscovering});
|
|
return;
|
|
}
|
|
|
|
callback(GetServiceController()->StartDiscovery(
|
|
client, service_id, discovery_options, std::move(listener)));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::StopDiscovery(ClientProxy* client,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-stop-discovery",
|
|
[this, client, callback = std::move(callback)]() mutable {
|
|
if (client->IsDiscovering()) {
|
|
GetServiceController()->StopDiscovery(client);
|
|
}
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::InjectEndpoint(
|
|
ClientProxy* client, absl::string_view service_id,
|
|
const OutOfBandConnectionMetadata& metadata, ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-inject-endpoint",
|
|
[this, client, service_id = std::string(service_id), metadata,
|
|
callback = std::move(callback)]() mutable {
|
|
// Currently, Bluetooth is the only supported medium for endpoint
|
|
// injection.
|
|
if (metadata.medium != Medium::BLUETOOTH ||
|
|
metadata.remote_bluetooth_mac_address.size() != kMacAddressLength) {
|
|
callback({Status::kError});
|
|
return;
|
|
}
|
|
|
|
if (metadata.endpoint_id.size() != kEndpointIdLength) {
|
|
callback({Status::kError});
|
|
return;
|
|
}
|
|
|
|
if (metadata.endpoint_info.Empty() ||
|
|
metadata.endpoint_info.size() > kMaxEndpointInfoLength) {
|
|
callback({Status::kError});
|
|
return;
|
|
}
|
|
|
|
if (!client->IsDiscovering()) {
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
GetServiceController()->InjectEndpoint(client, service_id, metadata);
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::RequestConnection(
|
|
ClientProxy* client, absl::string_view endpoint_id,
|
|
const ConnectionRequestInfo& info,
|
|
const ConnectionOptions& connection_options, ResultCallback callback) {
|
|
// Cancellations can be fired from clients anytime, need to add the
|
|
// CancellationListener as soon as possible.
|
|
client->AddCancellationFlag(std::string(endpoint_id));
|
|
|
|
RouteToServiceController(
|
|
"scr-request-connection",
|
|
[this, client, endpoint_id = std::string(endpoint_id), info,
|
|
connection_options, callback = std::move(callback)]() mutable {
|
|
if (client->HasPendingConnectionToEndpoint(endpoint_id) ||
|
|
client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kAlreadyConnectedToEndpoint});
|
|
return;
|
|
}
|
|
|
|
Status status = GetServiceController()->RequestConnection(
|
|
client, endpoint_id, info, connection_options);
|
|
if (!status.Ok()) {
|
|
client->CancelEndpoint(endpoint_id);
|
|
}
|
|
callback(status);
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::AcceptConnection(ClientProxy* client,
|
|
absl::string_view endpoint_id,
|
|
PayloadListener listener,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-accept-connection",
|
|
[this, client, endpoint_id = std::string(endpoint_id),
|
|
listener = std::move(listener),
|
|
callback = std::move(callback)]() mutable {
|
|
if (client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kAlreadyConnectedToEndpoint});
|
|
return;
|
|
}
|
|
|
|
if (client->HasLocalEndpointResponded(endpoint_id)) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Client " << client->GetClientId()
|
|
<< " invoked acceptConnectionRequest() after having already "
|
|
"accepted/rejected the connection to endpoint(id="
|
|
<< endpoint_id << ")";
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
callback(GetServiceController()->AcceptConnection(client, endpoint_id,
|
|
std::move(listener)));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::RejectConnection(ClientProxy* client,
|
|
absl::string_view endpoint_id,
|
|
ResultCallback callback) {
|
|
client->CancelEndpoint(std::string(endpoint_id));
|
|
|
|
RouteToServiceController(
|
|
"scr-reject-connection",
|
|
[this, client, endpoint_id = std::string(endpoint_id),
|
|
callback = std::move(callback)]() mutable {
|
|
if (client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kAlreadyConnectedToEndpoint});
|
|
return;
|
|
}
|
|
|
|
if (client->HasLocalEndpointResponded(endpoint_id)) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Client " << client->GetClientId()
|
|
<< " invoked rejectConnectionRequest() after having already "
|
|
"accepted/rejected the connection to endpoint(id="
|
|
<< endpoint_id << ")";
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
callback(GetServiceController()->RejectConnection(client, endpoint_id));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::InitiateBandwidthUpgrade(
|
|
ClientProxy* client, absl::string_view endpoint_id,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-init-bwu", [this, client, endpoint_id = std::string(endpoint_id),
|
|
callback = std::move(callback)]() mutable {
|
|
if (!client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
GetServiceController()->InitiateBandwidthUpgrade(client, endpoint_id);
|
|
|
|
// Operation is triggered; the caller can listen to
|
|
// ConnectionListener::OnBandwidthChanged() to determine its success.
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::SendPayload(
|
|
ClientProxy* client, absl::Span<const std::string> endpoint_ids,
|
|
Payload payload, ResultCallback callback) {
|
|
const std::vector<std::string> endpoints =
|
|
std::vector<std::string>(endpoint_ids.begin(), endpoint_ids.end());
|
|
|
|
RouteToServiceController(
|
|
"scr-send-payload",
|
|
[this, client, payload = std::move(payload), endpoints,
|
|
callback = std::move(callback)]() mutable {
|
|
if (!ClientHasConnectionToAtLeastOneEndpoint(client, endpoints)) {
|
|
callback({Status::kEndpointUnknown});
|
|
return;
|
|
}
|
|
|
|
GetServiceController()->SendPayload(client, endpoints,
|
|
std::move(payload));
|
|
|
|
// At this point, we've queued up the send Payload request with the
|
|
// ServiceController; any further failures (e.g. one of the endpoints is
|
|
// unknown, goes away, or otherwise fails) will be returned to the
|
|
// client as a PayloadTransferUpdate.
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::CancelPayload(ClientProxy* client,
|
|
std::uint64_t payload_id,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-cancel-payload",
|
|
[this, client, payload_id, callback = std::move(callback)]() mutable {
|
|
callback(GetServiceController()->CancelPayload(client, payload_id));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::DisconnectFromEndpoint(
|
|
ClientProxy* client, absl::string_view endpoint_id,
|
|
ResultCallback callback) {
|
|
// Client can emit the cancellation at anytime, we need to execute the request
|
|
// without further posting it.
|
|
client->CancelEndpoint(std::string(endpoint_id));
|
|
|
|
RouteToServiceController(
|
|
"scr-disconnect-endpoint",
|
|
[this, client, endpoint_id = std::string(endpoint_id),
|
|
callback = std::move(callback)]() mutable {
|
|
if (!client->IsConnectedToEndpoint(endpoint_id) &&
|
|
!client->HasPendingConnectionToEndpoint(endpoint_id)) {
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
GetServiceController()->DisconnectFromEndpoint(client, endpoint_id);
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::StartListeningForIncomingConnectionsV3(
|
|
ClientProxy* client, absl::string_view service_id,
|
|
v3::ConnectionListener listener,
|
|
const v3::ConnectionListeningOptions& options,
|
|
v3::ListeningResultListener callback) {
|
|
RouteToServiceController(
|
|
"scr-start-listening-for-incoming-connections",
|
|
[this, client, callback = std::move(callback), service_id,
|
|
listener = std::move(listener), options]() mutable {
|
|
if (client->IsListeningForIncomingConnections()) {
|
|
callback({{Status::kAlreadyListening},
|
|
{
|
|
.endpoint_id = client->GetLocalEndpointId(),
|
|
.connection_info = {},
|
|
}});
|
|
return;
|
|
}
|
|
auto pair =
|
|
GetServiceController()->StartListeningForIncomingConnections(
|
|
client, service_id, std::move(listener), options);
|
|
v3::ListeningResult result = {
|
|
.endpoint_id = client->GetLocalEndpointId(),
|
|
.connection_info = pair.second,
|
|
};
|
|
callback(std::make_pair(pair.first, result));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::StopListeningForIncomingConnectionsV3(
|
|
ClientProxy* client) {
|
|
RouteToServiceController(
|
|
"scr-stop-listening-for-incoming-connections", [this, client]() {
|
|
if (!client->IsListeningForIncomingConnections()) {
|
|
return;
|
|
}
|
|
GetServiceController()->StopListeningForIncomingConnections(client);
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::RequestConnectionV3(
|
|
ClientProxy* client, const NearbyDevice& remote_device,
|
|
v3::ConnectionRequestInfo info, const ConnectionOptions& connection_options,
|
|
ResultCallback callback) {
|
|
// Cancellations can be fired from clients anytime, need to add the
|
|
// CancellationListener as soon as possible.
|
|
client->AddCancellationFlag(remote_device.GetEndpointId());
|
|
|
|
RouteToServiceController(
|
|
"scr-request-connection-v3",
|
|
[this, client, &remote_device, v3_info = std::move(info),
|
|
connection_options, callback = std::move(callback)]() mutable {
|
|
std::string endpoint_id = remote_device.GetEndpointId();
|
|
if (client->HasPendingConnectionToEndpoint(endpoint_id) ||
|
|
client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kAlreadyConnectedToEndpoint});
|
|
return;
|
|
}
|
|
|
|
std::string endpoint_info;
|
|
if (v3_info.local_device.GetType() ==
|
|
NearbyDevice::Type::kConnectionsDevice) {
|
|
endpoint_info =
|
|
reinterpret_cast<v3::ConnectionsDevice&>(v3_info.local_device)
|
|
.GetEndpointInfo();
|
|
}
|
|
|
|
ConnectionListener listener = {
|
|
.initiated_cb =
|
|
[&v3_info, &remote_device](
|
|
const std::string& endpoint_id,
|
|
const ConnectionResponseInfo& response_info) mutable {
|
|
v3::InitialConnectionInfo new_info = {
|
|
.authentication_digits =
|
|
response_info.authentication_token,
|
|
.raw_authentication_token =
|
|
response_info.raw_authentication_token.string_data(),
|
|
.is_incoming_connection =
|
|
response_info.is_incoming_connection,
|
|
};
|
|
v3_info.listener.initiated_cb(remote_device, new_info);
|
|
},
|
|
.accepted_cb =
|
|
[result_cb = v3_info.listener.result_cb](
|
|
const std::string& endpoint_id) {
|
|
v3::ConnectionResult result = {
|
|
.status = {Status::kSuccess},
|
|
};
|
|
result_cb(v3::ConnectionsDevice(endpoint_id, "", {}), result);
|
|
},
|
|
.rejected_cb =
|
|
[result_cb = v3_info.listener.result_cb](
|
|
const std::string& endpoint_id, Status status) {
|
|
v3::ConnectionResult result = {
|
|
.status = status,
|
|
};
|
|
result_cb(v3::ConnectionsDevice(endpoint_id, "", {}), result);
|
|
},
|
|
.disconnected_cb =
|
|
[&v3_info](const std::string& endpoint_id) mutable {
|
|
auto device = v3::ConnectionsDevice(endpoint_id, "", {});
|
|
v3_info.listener.disconnected_cb(device);
|
|
},
|
|
.bandwidth_changed_cb =
|
|
[this, &v3_info](const std::string& endpoint_id,
|
|
Medium medium) mutable {
|
|
v3::BandwidthInfo bandwidth_info = {
|
|
.quality = GetMediumQuality(medium),
|
|
.medium = medium,
|
|
};
|
|
v3_info.listener.bandwidth_changed_cb(
|
|
v3::ConnectionsDevice(endpoint_id, "", {}),
|
|
bandwidth_info);
|
|
},
|
|
};
|
|
ConnectionRequestInfo old_info = {
|
|
.endpoint_info = ByteArray(endpoint_info),
|
|
.listener = std::move(listener),
|
|
};
|
|
Status status = GetServiceController()->RequestConnectionV3(
|
|
client, remote_device, std::move(old_info), connection_options);
|
|
if (!status.Ok()) {
|
|
NEARBY_LOGS(WARNING) << "Unable to request connection to endpoint "
|
|
<< endpoint_id << ": " << status.ToString();
|
|
client->CancelEndpoint(endpoint_id);
|
|
}
|
|
callback(status);
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::AcceptConnectionV3(
|
|
ClientProxy* client, const NearbyDevice& remote_device,
|
|
v3::PayloadListener listener, ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-accept-connection",
|
|
[this, client, endpoint_id = remote_device.GetEndpointId(),
|
|
v3_listener = std::move(listener),
|
|
callback = std::move(callback)]() mutable {
|
|
if (client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kAlreadyConnectedToEndpoint});
|
|
return;
|
|
}
|
|
|
|
if (client->HasLocalEndpointResponded(endpoint_id)) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Client " << client->GetClientId()
|
|
<< " invoked acceptConnectionRequest() after having already "
|
|
"accepted/rejected the connection to endpoint(id="
|
|
<< endpoint_id << ")";
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
PayloadListener old_listener = {
|
|
.payload_cb =
|
|
[v3_received = std::move(v3_listener.payload_received_cb)](
|
|
absl::string_view endpoint_id, Payload payload) {
|
|
v3_received(v3::ConnectionsDevice(endpoint_id, "", {}),
|
|
std::move(payload));
|
|
},
|
|
.payload_progress_cb =
|
|
[v3_cb = std::move(v3_listener.payload_progress_cb)](
|
|
absl::string_view endpoint_id,
|
|
const PayloadProgressInfo& info) mutable {
|
|
v3_cb(v3::ConnectionsDevice(endpoint_id, "", {}), info);
|
|
}};
|
|
|
|
callback(GetServiceController()->AcceptConnection(
|
|
client, endpoint_id, std::move(old_listener)));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::RejectConnectionV3(
|
|
ClientProxy* client, const NearbyDevice& remote_device,
|
|
ResultCallback callback) {
|
|
client->CancelEndpoint(remote_device.GetEndpointId());
|
|
|
|
RouteToServiceController(
|
|
"scr-reject-connection",
|
|
[this, client, endpoint_id = remote_device.GetEndpointId(),
|
|
callback = std::move(callback)]() mutable {
|
|
if (client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kAlreadyConnectedToEndpoint});
|
|
return;
|
|
}
|
|
|
|
if (client->HasLocalEndpointResponded(endpoint_id)) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Client " << client->GetClientId()
|
|
<< " invoked rejectConnectionRequest() after having already "
|
|
"accepted/rejected the connection to endpoint(id="
|
|
<< endpoint_id << ")";
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
callback(GetServiceController()->RejectConnection(client, endpoint_id));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::InitiateBandwidthUpgradeV3(
|
|
ClientProxy* client, const NearbyDevice& remote_device,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-init-bwu",
|
|
[this, client, endpoint_id = remote_device.GetEndpointId(),
|
|
callback = std::move(callback)]() mutable {
|
|
if (!client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
GetServiceController()->InitiateBandwidthUpgrade(client, endpoint_id);
|
|
|
|
// Operation is triggered; the caller can listen to
|
|
// ConnectionListener::OnBandwidthChanged() to determine its success.
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::SendPayloadV3(
|
|
ClientProxy* client, const NearbyDevice& recipient_device, Payload payload,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-send-payload", [this, client, payload = std::move(payload),
|
|
endpoint_id = recipient_device.GetEndpointId(),
|
|
callback = std::move(callback)]() mutable {
|
|
if (!client->IsConnectedToEndpoint(endpoint_id)) {
|
|
callback({Status::kEndpointUnknown});
|
|
return;
|
|
}
|
|
|
|
GetServiceController()->SendPayload(
|
|
client, std::vector<std::string>{endpoint_id}, std::move(payload));
|
|
|
|
// At this point, we've queued up the send Payload request with the
|
|
// ServiceController; any further failures (e.g. one of the endpoints is
|
|
// unknown, goes away, or otherwise fails) will be returned to the
|
|
// client as a PayloadTransferUpdate.
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::CancelPayloadV3(
|
|
ClientProxy* client, const NearbyDevice& recipient_device,
|
|
uint64_t payload_id, ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-cancel-payload",
|
|
[this, client, payload_id, callback = std::move(callback)]() mutable {
|
|
callback(GetServiceController()->CancelPayload(client, payload_id));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::DisconnectFromDeviceV3(
|
|
ClientProxy* client, const NearbyDevice& remote_device,
|
|
ResultCallback callback) {
|
|
// Client can emit the cancellation at anytime, we need to execute the request
|
|
// without further posting it.
|
|
client->CancelEndpoint(remote_device.GetEndpointId());
|
|
|
|
RouteToServiceController(
|
|
"scr-disconnect-endpoint",
|
|
[this, client, endpoint_id = remote_device.GetEndpointId(),
|
|
callback = std::move(callback)]() mutable {
|
|
if (!client->IsConnectedToEndpoint(endpoint_id) &&
|
|
!client->HasPendingConnectionToEndpoint(endpoint_id)) {
|
|
callback({Status::kOutOfOrderApiCall});
|
|
return;
|
|
}
|
|
|
|
GetServiceController()->DisconnectFromEndpoint(client, endpoint_id);
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::UpdateAdvertisingOptionsV3(
|
|
ClientProxy* client, absl::string_view service_id,
|
|
const AdvertisingOptions& options, ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-update-advertising-options",
|
|
[this, client, options, callback = std::move(callback),
|
|
service_id]() mutable {
|
|
callback(GetServiceController()->UpdateAdvertisingOptions(
|
|
client, service_id, options));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::UpdateDiscoveryOptionsV3(
|
|
ClientProxy* client, absl::string_view service_id,
|
|
const DiscoveryOptions& options, ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-update-discovery-options",
|
|
[this, client, options, callback = std::move(callback),
|
|
service_id]() mutable {
|
|
callback(GetServiceController()->UpdateDiscoveryOptions(
|
|
client, service_id, options));
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::StopAllEndpoints(ClientProxy* client,
|
|
ResultCallback callback) {
|
|
// Client can emit the cancellation at anytime, we need to execute the request
|
|
// without further posting it.
|
|
client->CancelAllEndpoints();
|
|
|
|
RouteToServiceController(
|
|
"scr-stop-all-endpoints",
|
|
[this, client, callback = std::move(callback)]() mutable {
|
|
NEARBY_LOGS(INFO) << "Client " << client->GetClientId()
|
|
<< " has requested us to stop all endpoints. We will "
|
|
"now reset the client.";
|
|
FinishClientSession(client);
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::SetCustomSavePath(ClientProxy* client,
|
|
absl::string_view path,
|
|
ResultCallback callback) {
|
|
RouteToServiceController(
|
|
"scr-set-custom-save-path", [this, client, path = std::string(path),
|
|
callback = std::move(callback)]() mutable {
|
|
NEARBY_LOGS(INFO) << "Client " << client->GetClientId()
|
|
<< " has requested us to set custom save path to "
|
|
<< path;
|
|
GetServiceController()->SetCustomSavePath(client, path);
|
|
callback({Status::kSuccess});
|
|
});
|
|
}
|
|
|
|
void ServiceControllerRouter::SetServiceControllerForTesting(
|
|
std::unique_ptr<ServiceController> service_controller) {
|
|
service_controller_ = std::move(service_controller);
|
|
}
|
|
|
|
ServiceController* ServiceControllerRouter::GetServiceController() {
|
|
if (!service_controller_) {
|
|
service_controller_ = std::make_unique<OfflineServiceController>();
|
|
}
|
|
return service_controller_.get();
|
|
}
|
|
|
|
void ServiceControllerRouter::FinishClientSession(ClientProxy* client) {
|
|
// Disconnect from all the connected endpoints tied to this clientProxy.
|
|
for (auto& endpoint_id : client->GetPendingConnectedEndpoints()) {
|
|
GetServiceController()->DisconnectFromEndpoint(client, endpoint_id);
|
|
}
|
|
|
|
for (auto& endpoint_id : client->GetConnectedEndpoints()) {
|
|
GetServiceController()->DisconnectFromEndpoint(client, endpoint_id);
|
|
}
|
|
|
|
// Stop any advertising and discovery that may be underway due to this client.
|
|
GetServiceController()->StopAdvertising(client);
|
|
GetServiceController()->StopDiscovery(client);
|
|
GetServiceController()->ShutdownBwuManagerExecutors();
|
|
|
|
// Finally, clear all state maintained by this client.
|
|
client->Reset();
|
|
}
|
|
|
|
void ServiceControllerRouter::RouteToServiceController(const std::string& name,
|
|
Runnable runnable) {
|
|
serializer_.Execute(name, std::move(runnable));
|
|
}
|
|
|
|
} // namespace connections
|
|
} // namespace nearby
|