| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/host/chromeos/file_session_storage.h" |
| |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/callback.h" |
| #include "base/functional/callback_forward.h" |
| #include "base/json/json_reader.h" |
| #include "base/json/json_writer.h" |
| #include "base/logging.h" |
| #include "base/path_service.h" |
| #include "base/task/thread_pool.h" |
| #include "base/values.h" |
| #include "chrome/common/chrome_paths.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| namespace remoting { |
| |
| namespace { |
| |
| constexpr char kStoredSessionFileName[] = "session"; |
| |
| template <class T> |
| absl::optional<T> make_nullopt() { |
| return absl::nullopt; |
| } |
| |
| base::TaskTraits GetFileTaskTraits() { |
| return {base::MayBlock(), base::TaskPriority::BEST_EFFORT}; |
| } |
| |
| void WriteFileAsync(const base::FilePath& file, |
| std::string content, |
| base::OnceCallback<void(bool)> on_done) { |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, GetFileTaskTraits(), |
| base::BindOnce( |
| [](base::FilePath file, std::string content) { |
| return base::WriteFile(file, content); |
| }, |
| file, std::move(content)), |
| std::move(on_done)); |
| } |
| |
| void DeleteFileAsync(const base::FilePath& file, |
| base::OnceCallback<void(bool)> on_done) { |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, GetFileTaskTraits(), base::BindOnce(&base::DeleteFile, file), |
| std::move(on_done)); |
| } |
| |
| void FileExistsAsync(const base::FilePath& file, |
| base::OnceCallback<void(bool)> on_done) { |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, GetFileTaskTraits(), base::BindOnce(&base::PathExists, file), |
| std::move(on_done)); |
| } |
| |
| // Wrapper around base::ReadFileToString that returns the result as an optional |
| // string. |
| absl::optional<std::string> ReadFileToString(const base::FilePath& file) { |
| std::string result; |
| bool success = base::ReadFileToString(file, &result); |
| if (success) { |
| return result; |
| } else { |
| return absl::nullopt; |
| } |
| } |
| |
| void ReadFileAsync( |
| const base::FilePath& file, |
| base::OnceCallback<void(absl::optional<std::string>)> on_done) { |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, GetFileTaskTraits(), base::BindOnce(&ReadFileToString, file), |
| std::move(on_done)); |
| } |
| |
| base::FilePath GetDefaultDirectory() { |
| base::FilePath result; |
| base::PathService::Get(chrome::DIR_CHROMEOS_CRD_DATA, &result); |
| return result; |
| } |
| |
| } // namespace |
| |
| FileSessionStorage::FileSessionStorage() |
| : FileSessionStorage(GetDefaultDirectory()) {} |
| |
| FileSessionStorage::FileSessionStorage(const base::FilePath& storage_directory) |
| : storage_directory_(storage_directory) {} |
| |
| void FileSessionStorage::StoreSession(const base::Value::Dict& information, |
| base::OnceClosure on_done) { |
| WriteFileAsync(session_file(), base::WriteJson(information).value(), |
| base::BindOnce([](bool success) { |
| LOG_IF(ERROR, !success) |
| << "Failed to create CRD session information file"; |
| }).Then(std::move(on_done))); |
| } |
| |
| void FileSessionStorage::DeleteSession(base::OnceClosure on_done) { |
| DeleteFileAsync(session_file(), |
| base::BindOnce([](bool success) { |
| LOG_IF(ERROR, !success) |
| << "Failed to remove CRD session information file"; |
| }).Then(std::move(on_done))); |
| } |
| |
| void FileSessionStorage::RetrieveSession( |
| base::OnceCallback<void(absl::optional<base::Value::Dict>)> on_done) { |
| ReadFileAsync(session_file(), |
| base::BindOnce([](absl::optional<std::string> content) { |
| if (!content.has_value()) { |
| LOG(ERROR) << "Failed to read CRD session information file"; |
| return make_nullopt<base::Value::Dict>(); |
| } |
| |
| auto dict_optional = |
| base::JSONReader::ReadDict(content.value()); |
| LOG_IF(ERROR, !dict_optional.has_value()) |
| << "Failed to parse stored CRD session information"; |
| return dict_optional; |
| }).Then(std::move(on_done))); |
| } |
| |
| void FileSessionStorage::HasSession( |
| base::OnceCallback<void(bool)> on_done) const { |
| FileExistsAsync(session_file(), std::move(on_done)); |
| } |
| |
| void FileSessionStorage::SetStorageDirectoryForTesting( |
| const base::FilePath& dir) { |
| storage_directory_ = dir; |
| } |
| |
| base::FilePath FileSessionStorage::session_file() const { |
| return storage_directory_.AppendASCII(kStoredSessionFileName); |
| } |
| |
| } // namespace remoting |