Add SetCustomSavePath API to Nearby Connections

PiperOrigin-RevId: 492563503
This commit is contained in:
Aaron Yu
2022-12-02 14:38:55 -08:00
committed by Copybara-Service
parent 2273c87b57
commit 49af1a96b6
20 changed files with 193 additions and 82 deletions
+4 -2
View File
@@ -169,10 +169,12 @@ void Core::StopAllEndpoints(ResultCallback callback) {
router_->StopAllEndpoints(&client_, callback);
}
std::string Core::Dump() {
return client_.Dump();
void Core::SetCustomSavePath(absl::string_view path, ResultCallback callback) {
router_->SetCustomSavePath(&client_, path, callback);
}
std::string Core::Dump() { return client_.Dump(); }
} // namespace connections
} // namespace nearby
} // namespace location
+5
View File
@@ -237,6 +237,11 @@ class Core {
void InitiateBandwidthUpgrade(absl::string_view endpoint_id,
ResultCallback callback);
// Sets a custom save path. Defaults to the download path.
//
// path - The path where the received files will be saved to.
void SetCustomSavePath(absl::string_view path, ResultCallback callback);
// Gets the local endpoint generated by Nearby Connections.
std::string GetLocalEndpointId() { return client_.GetLocalEndpointId(); }
@@ -316,18 +316,26 @@ std::unique_ptr<InternalPayload> CreateOutgoingInternalPayload(
}
std::string make_path(std::string& parent_folder, std::string& file_name) {
if (!parent_folder.empty()) {
return std::string(api::ImplementationPlatform::GetCustomSavePath(
parent_folder, file_name));
}
return std::string(
api::ImplementationPlatform::GetDownloadPath(parent_folder, file_name));
}
std::string make_path(std::string& parent_folder, int64_t id) {
std::string file_name(std::to_string(id));
if (!parent_folder.empty()) {
return std::string(api::ImplementationPlatform::GetCustomSavePath(
parent_folder, file_name));
}
return std::string(
api::ImplementationPlatform::GetDownloadPath(parent_folder, file_name));
}
std::unique_ptr<InternalPayload> CreateIncomingInternalPayload(
const PayloadTransferFrame& frame) {
const PayloadTransferFrame& frame, const std::string& custom_save_path) {
if (frame.packet_type() != PayloadTransferFrame::DATA) {
return {};
}
@@ -351,7 +359,7 @@ std::unique_ptr<InternalPayload> CreateIncomingInternalPayload(
}
case PayloadTransferFrame::PayloadHeader::FILE: {
std::string parent_folder("");
std::string parent_folder(custom_save_path);
std::string file_name("");
std::string file_path("");
@@ -15,6 +15,10 @@
#ifndef CORE_INTERNAL_INTERNAL_PAYLOAD_FACTORY_H_
#define CORE_INTERNAL_INTERNAL_PAYLOAD_FACTORY_H_
#include <string>
#include <memory>
#include "connections/implementation/internal_payload.h"
#include "connections/payload.h"
@@ -28,7 +32,7 @@ std::unique_ptr<InternalPayload> CreateOutgoingInternalPayload(Payload payload);
// Creates an InternalPayload representing an incoming Payload from a remote
// endpoint.
std::unique_ptr<InternalPayload> CreateIncomingInternalPayload(
const PayloadTransferFrame& frame);
const PayloadTransferFrame& frame, const std::string& custom_save_path);
} // namespace connections
} // namespace nearby
@@ -71,6 +71,7 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromFilePayload) {
TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromByteMessage) {
PayloadTransferFrame frame;
std::string path = "C:\\Downloads";
frame.set_packet_type(PayloadTransferFrame::DATA);
std::int64_t payload_chunk_offset = 0;
ByteArray data(kText);
@@ -84,7 +85,7 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromByteMessage) {
header.set_total_size(512);
*frame.mutable_payload_chunk() = std::move(payload_chunk);
std::unique_ptr<InternalPayload> internal_payload =
CreateIncomingInternalPayload(frame);
CreateIncomingInternalPayload(frame, path);
EXPECT_NE(internal_payload, nullptr);
Payload payload = internal_payload->ReleasePayload();
EXPECT_EQ(payload.AsFile(), nullptr);
@@ -94,13 +95,14 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromByteMessage) {
TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromStreamMessage) {
PayloadTransferFrame frame;
std::string path = "C:\\Downloads";
frame.set_packet_type(PayloadTransferFrame::DATA);
auto& header = *frame.mutable_payload_header();
header.set_type(PayloadTransferFrame::PayloadHeader::STREAM);
header.set_id(12345);
header.set_total_size(0);
std::unique_ptr<InternalPayload> internal_payload =
CreateIncomingInternalPayload(frame);
CreateIncomingInternalPayload(frame, path);
EXPECT_NE(internal_payload, nullptr);
Payload payload = internal_payload->ReleasePayload();
EXPECT_EQ(payload.AsFile(), nullptr);
@@ -111,13 +113,14 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromStreamMessage) {
TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromFileMessage) {
PayloadTransferFrame frame;
std::string path = "C:\\Downloads";
frame.set_packet_type(PayloadTransferFrame::DATA);
auto& header = *frame.mutable_payload_header();
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
header.set_id(12345);
header.set_total_size(512);
std::unique_ptr<InternalPayload> internal_payload =
CreateIncomingInternalPayload(frame);
CreateIncomingInternalPayload(frame, path);
EXPECT_NE(internal_payload, nullptr);
Payload payload = internal_payload->ReleasePayload();
EXPECT_NE(payload.AsFile(), nullptr);
@@ -129,25 +132,27 @@ TEST(InternalPayloadFactoryTest, CanCreateInternalPayloadFromFileMessage) {
TEST(InternalPayloadFactoryTest,
InternalPayloadFromFileMessageWithoutIdReturnsNullptr) {
PayloadTransferFrame frame;
std::string path = "C:\\Downloads";
frame.set_packet_type(PayloadTransferFrame::DATA);
auto& header = *frame.mutable_payload_header();
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
header.set_total_size(512);
std::unique_ptr<InternalPayload> internal_payload =
CreateIncomingInternalPayload(frame);
CreateIncomingInternalPayload(frame, path);
EXPECT_EQ(internal_payload, nullptr);
}
TEST(InternalPayloadFactoryTest,
CanCreateInternalPayloadFromFileMessageWithFileNameNotSet) {
PayloadTransferFrame frame;
std::string path = "C:\\Downloads";
frame.set_packet_type(PayloadTransferFrame::DATA);
auto& header = *frame.mutable_payload_header();
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
header.set_id(12345);
header.set_total_size(512);
std::unique_ptr<InternalPayload> internal_payload =
CreateIncomingInternalPayload(frame);
CreateIncomingInternalPayload(frame, path);
EXPECT_NE(internal_payload, nullptr);
Payload payload = internal_payload->ReleasePayload();
EXPECT_EQ(payload.GetFileName(), "12345");
@@ -155,6 +160,7 @@ TEST(InternalPayloadFactoryTest,
TEST(InternalPayloadFactoryTest,
CanCreateInternalPayloadFromFileMessageWithFileNameSet) {
PayloadTransferFrame frame;
std::string path = "C:\\Downloads";
frame.set_packet_type(PayloadTransferFrame::DATA);
auto& header = *frame.mutable_payload_header();
header.set_type(PayloadTransferFrame::PayloadHeader::FILE);
@@ -162,7 +168,7 @@ TEST(InternalPayloadFactoryTest,
header.set_total_size(512);
header.set_file_name("test.file.name");
std::unique_ptr<InternalPayload> internal_payload =
CreateIncomingInternalPayload(frame);
CreateIncomingInternalPayload(frame, path);
EXPECT_NE(internal_payload, nullptr);
auto test = internal_payload->GetFileName();
Payload payload = internal_payload->ReleasePayload();
@@ -85,6 +85,9 @@ class MockServiceController : public ServiceController {
(override));
MOCK_METHOD(void, ShutdownBwuManagerExecutors, (), (override));
MOCK_METHOD(void, SetCustomSavePath,
(ClientProxy * client, const std::string& path), (override));
};
} // namespace connections
@@ -92,6 +92,11 @@ class MockServiceControllerRouter : public ServiceControllerRouter {
MOCK_METHOD(void, StopAllEndpoints,
(ClientProxy * client, const ResultCallback& callback),
(override));
MOCK_METHOD(void, SetCustomSavePath,
(ClientProxy * client, absl::string_view path,
const ResultCallback& callback),
(override));
};
} // namespace connections
@@ -15,6 +15,8 @@
#include "connections/implementation/offline_service_controller.h"
#include <string>
#include <utility>
#include <vector>
#include "absl/strings/str_join.h"
@@ -142,6 +144,14 @@ void OfflineServiceController::DisconnectFromEndpoint(
endpoint_manager_.UnregisterEndpoint(client, endpoint_id);
}
void OfflineServiceController::SetCustomSavePath(ClientProxy* client,
const std::string& path) {
if (stop_) return;
NEARBY_LOGS(INFO) << "Client " << client->GetClientId()
<< " requested to set custom save path: " << path;
payload_manager_.SetCustomSavePath(client, path);
}
void OfflineServiceController::ShutdownBwuManagerExecutors() {
bwu_manager_.ShutdownExecutors();
}
@@ -77,6 +77,8 @@ class OfflineServiceController : public ServiceController {
void Stop() override;
void SetCustomSavePath(ClientProxy* client, const std::string& path) override;
void ShutdownBwuManagerExecutors() override;
private:
@@ -282,6 +282,7 @@ Payload::Id PayloadManager::CreateOutgoingPayload(
PayloadManager::PayloadManager(EndpointManager& endpoint_manager)
: endpoint_manager_(&endpoint_manager) {
endpoint_manager_->RegisterFrameProcessor(V1Frame::PAYLOAD_TRANSFER, this);
custom_save_path_ = "";
}
void PayloadManager::CancelAllPayloads() {
@@ -676,7 +677,8 @@ PayloadTransferFrame::PayloadChunk PayloadManager::CreatePayloadChunk(
PayloadManager::PendingPayload* PayloadManager::CreateIncomingPayload(
const PayloadTransferFrame& frame, const std::string& endpoint_id) {
auto internal_payload = CreateIncomingInternalPayload(frame);
auto internal_payload =
CreateIncomingInternalPayload(frame, custom_save_path_);
if (!internal_payload) {
return nullptr;
}
@@ -1191,6 +1193,11 @@ PayloadType PayloadManager::FramePayloadTypeToPayloadType(
}
}
void PayloadManager::SetCustomSavePath(ClientProxy* client,
const std::string& path) {
custom_save_path_ = path;
}
///////////////////////////////// EndpointInfo /////////////////////////////////
PayloadManager::EndpointInfo::Status
@@ -71,6 +71,8 @@ class PayloadManager : public EndpointManager::FrameProcessor {
void DisconnectFromEndpointManager();
void SetCustomSavePath(ClientProxy* client, const std::string& path);
private:
// Information about an endpoint for a particular payload.
struct EndpointInfo {
@@ -310,6 +312,7 @@ class PayloadManager : public EndpointManager::FrameProcessor {
PayloadTransferFrame::PayloadHeader::PayloadType type);
mutable Mutex mutex_;
std::string custom_save_path_;
AtomicBoolean shutdown_{false};
std::unique_ptr<CountDownLatch> shutdown_barrier_;
int send_payload_count_ = 0;
@@ -99,6 +99,9 @@ class ServiceController {
virtual void DisconnectFromEndpoint(ClientProxy* client,
const std::string& endpoint_id) = 0;
virtual void SetCustomSavePath(ClientProxy* client,
const std::string& path) = 0;
};
} // namespace connections
@@ -343,6 +343,19 @@ void ServiceControllerRouter::StopAllEndpoints(ClientProxy* client,
});
}
void ServiceControllerRouter::SetCustomSavePath(
ClientProxy* client, absl::string_view path,
const ResultCallback& callback) {
RouteToServiceController(
"scr-set-custom-save-path", [this, client, path, callback]() {
NEARBY_LOGS(INFO) << "Client " << client->GetClientId()
<< " has requested us to set custom save path to "
<< path;
GetServiceController()->SetCustomSavePath(client, std::string(path));
callback.result_cb({Status::kSuccess});
});
}
void ServiceControllerRouter::SetServiceControllerForTesting(
std::unique_ptr<ServiceController> service_controller) {
service_controller_ = std::move(service_controller);
@@ -108,6 +108,9 @@ class ServiceControllerRouter {
virtual void StopAllEndpoints(ClientProxy* client,
const ResultCallback& callback);
virtual void SetCustomSavePath(ClientProxy* client, absl::string_view path,
const ResultCallback& callback);
void SetServiceControllerForTesting(
std::unique_ptr<ServiceController> service_controller);
@@ -63,8 +63,13 @@ namespace location {
namespace nearby {
namespace api {
std::string ImplementationPlatform::GetCustomSavePath(
const std::string& parent_folder, const std::string& file_name) {
return file::JoinPath(parent_folder, file_name);
}
std::string ImplementationPlatform::GetDownloadPath(
absl::string_view parent_folder, absl::string_view file_name) {
const std::string& parent_folder, const std::string& file_name) {
std::string fullPath("/tmp");
return file::JoinPath("/tmp", file_name);
@@ -122,7 +127,7 @@ std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
}
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
absl::string_view file_path, size_t size) {
const std::string& file_path, size_t size) {
return shared::IOFile::CreateInputFile(file_path, size);
}
@@ -137,7 +142,7 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
}
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
absl::string_view file_path) {
const std::string& file_path) {
return shared::IOFile::CreateOutputFile(file_path);
}
@@ -36,8 +36,20 @@ namespace location {
namespace nearby {
namespace api {
std::string ImplementationPlatform::GetDownloadPath(absl::string_view parent_folder,
absl::string_view file_name) {
std::string ImplementationPlatform::GetCustomSavePath(const std::string& parent_folder,
const std::string& file_name) {
// TODO(b/227535777): This needs to be done correctly, we now have a file name and parent folder,
// they should be combined with the custom save path
NSString* fileName = ObjCStringFromCppString(file_name);
// TODO(b/227535777): If file name matches an existing file, it will be overwritten. Append a
// number until a unique file name is reached 'foobar (2).png'.
return CppStringFromObjCString([NSTemporaryDirectory() stringByAppendingPathComponent:fileName]);
}
std::string ImplementationPlatform::GetDownloadPath(const std::string& parent_folder,
const std::string& file_name) {
// TODO(jfcarroll): This needs to be done correctly, we now have a file name and parent folder,
// they should be combined with the default download path
NSString* fileName = ObjCStringFromCppString(file_name);
@@ -84,7 +96,7 @@ std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(PayloadId pay
return nullptr;
}
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(absl::string_view file_path,
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(const std::string& file_path,
size_t size) {
return shared::IOFile::CreateInputFile(file_path, size);
}
@@ -94,7 +106,7 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(PayloadId p
return nullptr;
}
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(absl::string_view file_path) {
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(const std::string& file_path) {
return shared::IOFile::CreateOutputFile(file_path);
}
@@ -131,8 +143,8 @@ std::unique_ptr<BleMedium> ImplementationPlatform::CreateBleMedium(api::Bluetoot
return nullptr;
}
std::unique_ptr<ble_v2::BleMedium>
ImplementationPlatform::CreateBleV2Medium(api::BluetoothAdapter& adapter) {
std::unique_ptr<ble_v2::BleMedium> ImplementationPlatform::CreateBleV2Medium(
api::BluetoothAdapter& adapter) {
return std::make_unique<ios::BleMedium>(adapter);
}
+9 -6
View File
@@ -66,12 +66,15 @@ class ImplementationPlatform {
// - CountDownLatch : to ensure at least N threads are waiting.
// - file I/O
// - Logging
static std::string GetDownloadPath(absl::string_view parent_folder,
absl::string_view file_name);
static std::string GetCustomSavePath(const std::string& parent_folder,
const std::string& file_name);
static std::string GetDownloadPath(absl::string_view file_name);
static std::string GetDownloadPath(const std::string& parent_folder,
const std::string& file_name);
static std::string GetAppDataPath(absl::string_view file_name);
static std::string GetDownloadPath(const std::string& file_name);
static std::string GetAppDataPath(const std::string& file_name);
static OSName GetCurrentOS();
@@ -96,11 +99,11 @@ class ImplementationPlatform {
static std::unique_ptr<InputFile> CreateInputFile(PayloadId, std::int64_t);
static std::unique_ptr<InputFile> CreateInputFile(absl::string_view, size_t);
static std::unique_ptr<InputFile> CreateInputFile(const std::string&, size_t);
static std::unique_ptr<OutputFile> CreateOutputFile(PayloadId);
static std::unique_ptr<OutputFile> CreateOutputFile(absl::string_view);
static std::unique_ptr<OutputFile> CreateOutputFile(const std::string&);
static std::unique_ptr<LogMessage> CreateLogMessage(
const char* file, int line, LogMessage::Severity severity);
@@ -49,6 +49,13 @@ wchar_t const* kForbiddenPathNames[] = {
L"COM5", L"COM6", L"COM7", L"COM8", L"COM9", L"LPT1", L"LPT2", L"LPT3",
L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9"};
std::wstring FilePath::GetCustomSavePath(std::wstring parent_folder,
std::wstring file_name) {
std::wstring path;
path += parent_folder + kPathDelimiter + file_name;
return CreateOutputFileWithRename(path);
}
std::wstring FilePath::GetDownloadPath(std::wstring parent_folder,
std::wstring file_name) {
return CreateOutputFileWithRename(
@@ -1,49 +1,51 @@
// Copyright 2022 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 THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_
#include <string>
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace windows {
class FilePath {
public:
static std::wstring GetDownloadPath(std::wstring parent_folder,
std::wstring file_name);
private:
// If the file already exists we add " (x)", where x is an incrementing
// number, starting at 1, using the next non-existing number, to the
// file name, just before the first dot, or at the end if no dot. The
// absolute path is returned.
static std::wstring CreateOutputFileWithRename(std::wstring path);
static void ReplaceInvalidCharacters(std::wstring& path);
static void SanitizePath(std::wstring& path);
static std::wstring MutateForbiddenPathElements(std::wstring& str);
static std::wstring GetDownloadPathInternal(std::wstring parent_folder,
std::wstring file_name);
};
} // namespace windows
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_
// Copyright 2022 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 THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_
#include <string>
#include "absl/strings/string_view.h"
namespace location {
namespace nearby {
namespace windows {
class FilePath {
public:
static std::wstring GetCustomSavePath(std::wstring parent_folder,
std::wstring file_name);
static std::wstring GetDownloadPath(std::wstring parent_folder,
std::wstring file_name);
private:
// If the file already exists we add " (x)", where x is an incrementing
// number, starting at 1, using the next non-existing number, to the
// file name, just before the first dot, or at the end if no dot. The
// absolute path is returned.
static std::wstring CreateOutputFileWithRename(std::wstring path);
static void ReplaceInvalidCharacters(std::wstring& path);
static void SanitizePath(std::wstring& path);
static std::wstring MutateForbiddenPathElements(std::wstring& str);
static std::wstring GetDownloadPathInternal(std::wstring parent_folder,
std::wstring file_name);
};
} // namespace windows
} // namespace nearby
} // namespace location
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_FILE_PATH_H_
@@ -93,8 +93,17 @@ std::string GetApplicationName(DWORD pid) {
} // namespace
std::string ImplementationPlatform::GetCustomSavePath(
const std::string& parent_folder, const std::string& file_name) {
auto parent = windows::string_to_wstring(parent_folder);
auto file = windows::string_to_wstring(file_name);
return windows::wstring_to_string(
windows::FilePath::GetCustomSavePath(parent, file));
}
std::string ImplementationPlatform::GetDownloadPath(
absl::string_view parent_folder, absl::string_view file_name) {
const std::string& parent_folder, const std::string& file_name) {
auto parent = windows::string_to_wstring(std::string(parent_folder));
auto file = windows::string_to_wstring(std::string(file_name));
@@ -103,7 +112,7 @@ std::string ImplementationPlatform::GetDownloadPath(
}
std::string ImplementationPlatform::GetDownloadPath(
absl::string_view file_name) {
const std::string& file_name) {
std::wstring fake_parent_path;
auto file = windows::string_to_wstring(std::string(file_name));
@@ -112,7 +121,7 @@ std::string ImplementationPlatform::GetDownloadPath(
}
std::string ImplementationPlatform::GetAppDataPath(
absl::string_view file_name) {
const std::string& file_name) {
PWSTR basePath;
// Retrieves the full path of a known folder identified by the folder's
@@ -185,7 +194,7 @@ std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
}
std::unique_ptr<InputFile> ImplementationPlatform::CreateInputFile(
absl::string_view file_path, size_t size) {
const std::string& file_path, size_t size) {
return windows::IOFile::CreateInputFile(file_path, size);
}
@@ -199,8 +208,7 @@ std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
}
std::unique_ptr<OutputFile> ImplementationPlatform::CreateOutputFile(
absl::string_view file_path) {
// TODO(jfcarroll): the following code should probably be moved to FilePath
const std::string& file_path) {
std::string path(file_path);
std::string folder_path = path.substr(0, path.find_last_of('/'));