mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Migrate PreferencesRepository from location/nearby to third_party/nearby
PiperOrigin-RevId: 524185819
This commit is contained in:
committed by
Copybara-Service
parent
b023a666b9
commit
00bba36219
@@ -31,6 +31,7 @@ cc_library(
|
||||
"log_message.h",
|
||||
"mutex.h",
|
||||
"output_file.h",
|
||||
"preferences_repository.h",
|
||||
"scheduled_executor.h",
|
||||
"settable_future.h",
|
||||
"submittable_executor.h",
|
||||
@@ -53,6 +54,7 @@ cc_library(
|
||||
"@com_google_absl//absl/functional:any_invocable",
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"@nlohmann_json//:json",
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ objc_library(
|
||||
"log_message.mm",
|
||||
"multi_thread_executor.mm",
|
||||
"platform.mm",
|
||||
"preferences_repository.mm",
|
||||
"scheduled_executor.mm",
|
||||
"timer.mm",
|
||||
"utils.mm",
|
||||
@@ -40,6 +41,7 @@ objc_library(
|
||||
"device_info.h",
|
||||
"log_message.h",
|
||||
"multi_thread_executor.h",
|
||||
"preferences_repository.h",
|
||||
"scheduled_executor.h",
|
||||
"single_thread_executor.h",
|
||||
"timer.h",
|
||||
@@ -67,6 +69,7 @@ objc_library(
|
||||
"@com_google_absl//absl/strings",
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_absl//absl/types:optional",
|
||||
"@nlohmann_json//:json",
|
||||
] + select({
|
||||
"//tools/cc_target_os:platform_ios": [
|
||||
"//third_party/apple_frameworks:UIKit",
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2023 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 PLATFORM_IMPLEMENTATION_APPLE_PREFERENCES_REPOSITORY_H_
|
||||
#define PLATFORM_IMPLEMENTATION_APPLE_PREFERENCES_REPOSITORY_H_
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
#include "internal/platform/implementation/preferences_repository.h"
|
||||
|
||||
namespace nearby::apple {
|
||||
|
||||
class PreferencesRepository : public api::PreferencesRepository {
|
||||
public:
|
||||
explicit PreferencesRepository(absl::string_view path)
|
||||
: api::PreferencesRepository(path) {}
|
||||
|
||||
nlohmann::json LoadPreferences() override ABSL_LOCKS_EXCLUDED(&mutex_);
|
||||
bool SavePreferences(nlohmann::json preferences) override
|
||||
ABSL_LOCKS_EXCLUDED(&mutex_);
|
||||
|
||||
private:
|
||||
absl::Mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace nearby::apple
|
||||
|
||||
#endif // PLATFORM_IMPLEMENTATION_APPLE_PREFERENCES_REPOSITORY_H_
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2023 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.
|
||||
|
||||
#import "internal/platform/implementation/apple/preferences_repository.h"
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace nearby::apple {
|
||||
|
||||
nlohmann::json PreferencesRepository::LoadPreferences() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return nlohmann::json::object();
|
||||
}
|
||||
|
||||
bool PreferencesRepository::SavePreferences(nlohmann::json preferences) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace nearby::apple
|
||||
@@ -18,6 +18,7 @@ cc_library(
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"log_message.cc",
|
||||
"preferences_repository.cc",
|
||||
"scheduled_executor.cc",
|
||||
"system_clock.cc",
|
||||
],
|
||||
@@ -30,11 +31,12 @@ cc_library(
|
||||
"multi_thread_executor.h",
|
||||
"mutex.h",
|
||||
"pipe.h",
|
||||
"preferences_repository.h",
|
||||
"scheduled_executor.h",
|
||||
"single_thread_executor.h",
|
||||
"timer.h",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
visibility = ["//location/nearby/cpp:__subpackages__"],
|
||||
deps = [
|
||||
"//internal/platform:base",
|
||||
"//internal/platform:logging",
|
||||
@@ -52,6 +54,7 @@ cc_library(
|
||||
"@com_google_absl//absl/time",
|
||||
"@com_google_glog//:glog",
|
||||
"@com_google_nisaba//nisaba/port:thread_pool",
|
||||
"@nlohmann_json//:json",
|
||||
],
|
||||
alwayslink = 1,
|
||||
)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
// 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 "internal/platform/implementation/g3/preferences_repository.h"
|
||||
|
||||
#include <filesystem> // NOLINT(build/c++17)
|
||||
#include <fstream>
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
namespace {
|
||||
using json = nlohmann::json;
|
||||
} // namespace
|
||||
|
||||
json PreferencesRepository::LoadPreferences() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
// Emulate Windows implementation
|
||||
try {
|
||||
// settings.json is used for testing, but we should look at having
|
||||
// an implementation override for G3 in PreferencesManager to override
|
||||
// the path for testing.
|
||||
std::filesystem::path path =
|
||||
std::filesystem::temp_directory_path() / "settings.json";
|
||||
if (!std::filesystem::exists(path)) {
|
||||
return value_;
|
||||
}
|
||||
|
||||
std::ifstream preferences_file(path.c_str());
|
||||
if (!preferences_file.good()) {
|
||||
return value_;
|
||||
}
|
||||
json preferences = json::parse(preferences_file, nullptr, false);
|
||||
preferences_file.close();
|
||||
|
||||
if (preferences.is_discarded()) {
|
||||
return value_;
|
||||
}
|
||||
|
||||
value_ = preferences;
|
||||
} catch (...) {
|
||||
return value_;
|
||||
}
|
||||
|
||||
return value_;
|
||||
}
|
||||
|
||||
bool PreferencesRepository::SavePreferences(json preferences) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
value_ = preferences;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,47 @@
|
||||
// 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.
|
||||
|
||||
#ifndef PLATFORM_IMPLEMENTATION_G3_PREFERENCES_REPOSITORY_H_
|
||||
#define PLATFORM_IMPLEMENTATION_G3_PREFERENCES_REPOSITORY_H_
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
#include "internal/platform/implementation/preferences_repository.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace g3 {
|
||||
|
||||
class PreferencesRepository : public api::PreferencesRepository {
|
||||
public:
|
||||
explicit PreferencesRepository(absl::string_view path)
|
||||
: api::PreferencesRepository(path) {}
|
||||
|
||||
nlohmann::json LoadPreferences() override ABSL_LOCKS_EXCLUDED(&mutex_);
|
||||
bool SavePreferences(nlohmann::json preferences) override
|
||||
ABSL_LOCKS_EXCLUDED(&mutex_);
|
||||
|
||||
private:
|
||||
// Avoid to write in google3, just create a memory value to simulate a
|
||||
// preferences storage
|
||||
nlohmann::json value_ = nlohmann::json::object();
|
||||
absl::Mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace g3
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPLEMENTATION_G3_PREFERENCES_REPOSITORY_H_
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2023 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 "internal/platform/implementation/g3/preferences_repository.h"
|
||||
|
||||
#include <filesystem> // NOLINT(build/c++17)
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
|
||||
namespace nearby {
|
||||
namespace platform {
|
||||
namespace g3 {
|
||||
namespace {
|
||||
using json = ::nlohmann::json;
|
||||
} // namespace
|
||||
|
||||
TEST(Preferences, TestSaveAndGetPreferences) {
|
||||
PreferencesRepository preferences_repository{
|
||||
std::filesystem::temp_directory_path().string()};
|
||||
std::string string_key = "string_value";
|
||||
std::string string_value = "hello world";
|
||||
std::string int_key = "int_value";
|
||||
json prefs = {{int_key, 345}, {string_key, string_value}};
|
||||
|
||||
EXPECT_TRUE(preferences_repository.SavePreferences(prefs));
|
||||
|
||||
auto result = preferences_repository.LoadPreferences();
|
||||
EXPECT_EQ(result[string_key].get<std::string>(), string_value);
|
||||
EXPECT_EQ(result[int_key].get<int>(), 345);
|
||||
}
|
||||
|
||||
TEST(Preferences, TestMultipleSaveAndGetPreferences) {
|
||||
PreferencesRepository preferences_repository{
|
||||
std::filesystem::temp_directory_path().string()};
|
||||
std::string string_key = "string_value";
|
||||
std::string string_value = "hello world";
|
||||
std::string string_new_value = "again";
|
||||
std::string int_key = "int_value";
|
||||
json prefs = {{int_key, 345}, {string_key, string_value}};
|
||||
EXPECT_TRUE(preferences_repository.SavePreferences(prefs));
|
||||
|
||||
json result = preferences_repository.LoadPreferences();
|
||||
EXPECT_EQ(result[string_key].get<std::string>(), string_value);
|
||||
prefs[string_key] = string_new_value;
|
||||
prefs[int_key] = 456;
|
||||
EXPECT_TRUE(preferences_repository.SavePreferences(prefs));
|
||||
result = preferences_repository.LoadPreferences();
|
||||
EXPECT_EQ(result[string_key].get<std::string>(), string_new_value);
|
||||
EXPECT_EQ(result[int_key].get<int>(), 456);
|
||||
}
|
||||
|
||||
} // namespace g3
|
||||
} // namespace platform
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,47 @@
|
||||
// Copyright 2023 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 PLATFORM_IMPLEMENTATION_PREFERENCE_REPOSITORY_H_
|
||||
#define PLATFORM_IMPLEMENTATION_PREFERENCE_REPOSITORY_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
|
||||
namespace nearby {
|
||||
namespace api {
|
||||
|
||||
// A repository for preferences. The implementations are different on different
|
||||
// platforms.
|
||||
//
|
||||
// The data in preferences has multiple types, such as int, bool, string and
|
||||
// dictionary. Using proto to describe it is a little complicated. In the
|
||||
// repository, we use json as the parser for now.
|
||||
class PreferencesRepository {
|
||||
public:
|
||||
explicit PreferencesRepository(absl::string_view path) : path_(path) {}
|
||||
virtual ~PreferencesRepository() = default;
|
||||
|
||||
virtual nlohmann::json LoadPreferences() = 0;
|
||||
virtual bool SavePreferences(nlohmann::json preferences) = 0;
|
||||
|
||||
protected:
|
||||
std::string path_;
|
||||
};
|
||||
|
||||
} // namespace api
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPLEMENTATION_PREFERENCE_REPOSITORY_H_
|
||||
@@ -33,6 +33,7 @@ cc_library(
|
||||
"log_message.h",
|
||||
"mutex.h",
|
||||
"output_file.h",
|
||||
"preferences_repository.h",
|
||||
"scheduled_executor.h",
|
||||
"settable_future.h",
|
||||
"submittable_executor.h",
|
||||
@@ -148,6 +149,7 @@ cc_library(
|
||||
"file_path.cc",
|
||||
"http_loader.cc",
|
||||
"platform.cc",
|
||||
"preferences_repository.cc",
|
||||
"scheduled_executor.cc",
|
||||
"submittable_executor.cc",
|
||||
"system_clock.cc",
|
||||
@@ -239,6 +241,7 @@ cc_test(
|
||||
"executor_test.cc",
|
||||
"file_path_test.cc",
|
||||
"http_loader_test.cc",
|
||||
"preferences_repository_test.cc",
|
||||
"scheduled_executor_test.cc",
|
||||
"submittable_executor_test.cc",
|
||||
"thread_pool_test.cc",
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
// Copyright 2023 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 "internal/platform/implementation/windows/preferences_repository.h"
|
||||
|
||||
#include <exception>
|
||||
#include <filesystem> // NOLINT(build/c++17)
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
namespace {
|
||||
using json = ::nlohmann::json;
|
||||
|
||||
constexpr char kPreferencesFileName[] = "preferences.json";
|
||||
constexpr char kPreferencesBackupFileName[] = "preferences_bak.json";
|
||||
|
||||
} // namespace
|
||||
|
||||
json PreferencesRepository::LoadPreferences() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
std::optional<json> preferences = AttemptLoad();
|
||||
if (preferences.has_value()) {
|
||||
return preferences.value();
|
||||
}
|
||||
|
||||
NEARBY_LOGS(ERROR) << "Could not load preferences file, trying backup.";
|
||||
|
||||
// In the future we should switch to using a transaction log or another
|
||||
// stable method which doesn't pose a risk of losing settings
|
||||
preferences = RestoreFromBackup();
|
||||
if (preferences.has_value()) {
|
||||
NEARBY_LOGS(ERROR) << "Successfully recovered from backup.";
|
||||
return preferences.value();
|
||||
}
|
||||
|
||||
NEARBY_LOGS(ERROR) << "Failed to load preferences file from back up.";
|
||||
|
||||
return json::object();
|
||||
}
|
||||
|
||||
bool PreferencesRepository::SavePreferences(json preferences) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
try {
|
||||
std::filesystem::path path = path_;
|
||||
if (!std::filesystem::exists(path) &&
|
||||
!std::filesystem::create_directories(path)) {
|
||||
NEARBY_LOGS(ERROR) << "Failed to create preferences path.";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::filesystem::path full_name = path / kPreferencesFileName;
|
||||
std::filesystem::path full_name_backup = path / kPreferencesBackupFileName;
|
||||
|
||||
// Create a backup without moving the bytes on disk
|
||||
if (std::filesystem::exists(full_name)) {
|
||||
NEARBY_LOGS(INFO) << "Making backup of preferences file.";
|
||||
std::filesystem::rename(full_name, full_name_backup);
|
||||
}
|
||||
|
||||
std::ofstream preferences_file(full_name.c_str());
|
||||
preferences_file << preferences;
|
||||
preferences_file.close();
|
||||
|
||||
// Make sure the file wasn't saved in a corrupted state
|
||||
if (!AttemptLoad().has_value()) {
|
||||
NEARBY_LOGS(ERROR) << "Preferences saved to disk in corrupted state. "
|
||||
"Restoring from backup.";
|
||||
|
||||
if (!RestoreFromBackup().has_value()) {
|
||||
NEARBY_LOGS(ERROR) << "Failed to restore preferences file.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
NEARBY_LOGS(ERROR) << "Failed to save preferences file: " << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::optional<json> PreferencesRepository::AttemptLoad() {
|
||||
std::filesystem::path path = path_;
|
||||
std::filesystem::path full_name = path / kPreferencesFileName;
|
||||
if (!std::filesystem::exists(path) || !std::filesystem::exists(full_name)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
try {
|
||||
std::ifstream preferences_file(full_name.c_str());
|
||||
if (!preferences_file.good()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
json preferences = json::parse(preferences_file, nullptr, false);
|
||||
preferences_file.close();
|
||||
|
||||
if (preferences.is_discarded()) {
|
||||
NEARBY_LOGS(ERROR) << "Preferences file corrupted.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return preferences;
|
||||
} catch (const std::exception& e) {
|
||||
NEARBY_LOGS(ERROR) << "Exception while loading preferences: " << e.what();
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<json> PreferencesRepository::RestoreFromBackup() {
|
||||
std::filesystem::path path = path_;
|
||||
std::filesystem::path full_name = path / kPreferencesFileName;
|
||||
std::filesystem::path full_name_backup = path / kPreferencesBackupFileName;
|
||||
|
||||
if (!std::filesystem::exists(full_name_backup)) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "Backup requested but no backup preferences file found.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::filesystem::rename(full_name_backup, full_name);
|
||||
|
||||
NEARBY_LOGS(INFO) << "Attempting load from backup preferences.";
|
||||
return AttemptLoad();
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
@@ -0,0 +1,48 @@
|
||||
// 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.
|
||||
|
||||
#ifndef PLATFORM_IMPLEMENTATION_WINDOWS_PREFERENCES_REPOSITORY_H_
|
||||
#define PLATFORM_IMPLEMENTATION_WINDOWS_PREFERENCES_REPOSITORY_H_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
#include "internal/platform/implementation/preferences_repository.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
class PreferencesRepository : public api::PreferencesRepository {
|
||||
public:
|
||||
explicit PreferencesRepository(absl::string_view path)
|
||||
: api::PreferencesRepository(path) {}
|
||||
|
||||
nlohmann::json LoadPreferences() override ABSL_LOCKS_EXCLUDED(&mutex_);
|
||||
bool SavePreferences(nlohmann::json preferences) override
|
||||
ABSL_LOCKS_EXCLUDED(&mutex_);
|
||||
|
||||
std::optional<nlohmann::json> AttemptLoad();
|
||||
std::optional<nlohmann::json> RestoreFromBackup();
|
||||
|
||||
private:
|
||||
absl::Mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
|
||||
#endif // PLATFORM_IMPLEMENTATION_WINDOWS_PREFERENCES_REPOSITORY_H_
|
||||
@@ -0,0 +1,142 @@
|
||||
// Copyright 2023 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 "internal/platform/implementation/windows/preferences_repository.h"
|
||||
|
||||
#include <filesystem> // NOLINT(build/c++17)
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "nlohmann/json_fwd.hpp"
|
||||
#include "internal/platform/implementation/device_info.h"
|
||||
#include "internal/platform/implementation/platform.h"
|
||||
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
namespace {
|
||||
|
||||
using json = ::nlohmann::json;
|
||||
|
||||
constexpr char kPreferencesFileName[] = "preferences.json";
|
||||
constexpr char kPreferencesBackupFileName[] = "preferences_bak.json";
|
||||
constexpr char kPreferencesPath[] = "Google/Nearby/Sharing";
|
||||
|
||||
TEST(PreferencesRepository, LoadWithBadPath) {
|
||||
PreferencesRepository preferences_repository{"c:\\users\\a\\b\\c\\d\\e\\f"};
|
||||
json result = preferences_repository.LoadPreferences();
|
||||
EXPECT_TRUE(result.empty());
|
||||
}
|
||||
|
||||
TEST(PreferencesRepository, SaveAndLoadPreferences) {
|
||||
std::optional<std::filesystem::path> app_data_path =
|
||||
api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath();
|
||||
ASSERT_TRUE(app_data_path.has_value());
|
||||
std::filesystem::path full_path = *app_data_path / kPreferencesPath;
|
||||
std::filesystem::path full_name = full_path / kPreferencesFileName;
|
||||
|
||||
if (std::filesystem::exists(full_name)) {
|
||||
std::filesystem::remove(full_name);
|
||||
}
|
||||
|
||||
PreferencesRepository preferences_repository{full_path.string()};
|
||||
json data;
|
||||
data["key1"] = "value1";
|
||||
data["key2"] = "value2";
|
||||
EXPECT_TRUE(preferences_repository.SavePreferences(data));
|
||||
json result = preferences_repository.LoadPreferences();
|
||||
EXPECT_EQ(result.size(), 2);
|
||||
EXPECT_EQ(result["key1"], "value1");
|
||||
EXPECT_EQ(result["key2"], "value2");
|
||||
std::filesystem::remove(full_name);
|
||||
}
|
||||
|
||||
TEST(PreferencesRepository, LoadFromBackup) {
|
||||
std::optional<std::filesystem::path> app_data_path =
|
||||
api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath();
|
||||
ASSERT_TRUE(app_data_path.has_value());
|
||||
std::filesystem::path full_path = *app_data_path / kPreferencesPath;
|
||||
std::filesystem::path full_name = full_path / kPreferencesFileName;
|
||||
std::filesystem::path full_name_backup =
|
||||
full_path / kPreferencesBackupFileName;
|
||||
|
||||
if (std::filesystem::exists(full_name)) {
|
||||
std::filesystem::remove(full_name);
|
||||
}
|
||||
|
||||
if (std::filesystem::exists(full_name_backup)) {
|
||||
std::filesystem::remove(full_name_backup);
|
||||
}
|
||||
|
||||
PreferencesRepository preferences_repository{full_path.string()};
|
||||
json data;
|
||||
data["key1"] = "value1";
|
||||
data["key2"] = "value2";
|
||||
|
||||
std::ofstream backup_file(full_name_backup.c_str());
|
||||
backup_file << data;
|
||||
backup_file.close();
|
||||
|
||||
std::optional<json> result;
|
||||
result = preferences_repository.AttemptLoad();
|
||||
EXPECT_FALSE(result.has_value());
|
||||
result = preferences_repository.RestoreFromBackup();
|
||||
EXPECT_TRUE(result.has_value());
|
||||
EXPECT_EQ(result.value()["key1"], "value1");
|
||||
EXPECT_EQ(result.value()["key2"], "value2");
|
||||
std::filesystem::remove(full_name);
|
||||
EXPECT_FALSE(std::filesystem::exists(full_name_backup));
|
||||
}
|
||||
|
||||
TEST(PreferencesRepository, RecoverFromCorruption) {
|
||||
std::optional<std::filesystem::path> app_data_path =
|
||||
api::ImplementationPlatform::CreateDeviceInfo()->GetLocalAppDataPath();
|
||||
ASSERT_TRUE(app_data_path.has_value());
|
||||
std::filesystem::path full_path = *app_data_path / kPreferencesPath;
|
||||
std::filesystem::path full_name = full_path / kPreferencesFileName;
|
||||
std::filesystem::path full_name_backup =
|
||||
full_path / kPreferencesBackupFileName;
|
||||
|
||||
if (std::filesystem::exists(full_name)) {
|
||||
std::filesystem::remove(full_name);
|
||||
}
|
||||
|
||||
if (std::filesystem::exists(full_name_backup)) {
|
||||
std::filesystem::remove(full_name_backup);
|
||||
}
|
||||
|
||||
PreferencesRepository preferences_repository{full_path.string()};
|
||||
json data;
|
||||
data["key1"] = "value1";
|
||||
data["key2"] = "value2";
|
||||
|
||||
std::ofstream preferences_file(full_name_backup.c_str());
|
||||
preferences_file << data;
|
||||
preferences_file.close();
|
||||
|
||||
std::ofstream backup_file(full_name.c_str());
|
||||
backup_file << "[BAD JSON FILE]";
|
||||
backup_file.close();
|
||||
|
||||
std::optional<json> result = preferences_repository.LoadPreferences();
|
||||
EXPECT_EQ(result.value()["key1"], "value1");
|
||||
EXPECT_EQ(result.value()["key2"], "value2");
|
||||
std::filesystem::remove(full_name);
|
||||
EXPECT_FALSE(std::filesystem::exists(full_name_backup));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
Reference in New Issue
Block a user