Files
Max Karolinskiy 0ed24eed95 [cr149] CommandStorageBackend c'tor signature changed.
Chromium change:
https://source.chromium.org/chromium/chromium/src/+/d345c21d2c52cb8754e1e3d896c57756ba74d3a8

commit d345c21d2c52cb8754e1e3d896c57756ba74d3a8
Author: Rusty Sammon <sammon@google.com>
Date:   Wed Apr 8 05:58:28 2026 -0700

    Change CommandStorageBackend.encyptor_ type to be std::unique_ptr

    In https://crrev.com/c/7634060, I thought that std::optional would make it clearer that the Encryptor might be missing. However, I now see that std::unique_ptr is better for situations like this.  It support polymorphism better for TestEncryptor and makes it simpler to pass the Encryptor to SessionFileReader.

    See also comment chain
    https://chromium-review.git.corp.google.com/c/chromium/src/+/7684434/comment/b29aa46f_08ba9d5c/

    BUG=479420496
2026-05-22 16:57:45 -04:00

142 lines
5.1 KiB
C++

/* Copyright (c) 2026 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/. */
#include "brave/browser/workspaces/workspace_service.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/hash/hash.h"
#include "base/logging.h"
#include "base/task/bind_post_task.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/time/time.h"
#include "brave/browser/workspaces/workspace_session_utils.h"
#include "brave/browser/workspaces/workspace_utils.h"
#include "chrome/browser/profiles/profile.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
#include "components/sessions/core/session_id.h"
#include "third_party/abseil-cpp/absl/strings/str_format.h"
namespace {
std::string ComputeKey(const std::string& name) {
return absl::StrFormat("%08x", base::PersistentHash(name));
}
} // namespace
WorkspaceService::WorkspaceService(Profile& profile)
: profile_(profile),
workspaces_path_(profile.GetPath().AppendASCII("workspaces")),
pref_service_(*profile.GetPrefs()),
io_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN})) {}
WorkspaceService::~WorkspaceService() = default;
std::vector<WorkspaceMetadata> WorkspaceService::ListWorkspaces() const {
return ListWorkspacesFromDict(
pref_service_->GetDict(kWorkspacesMetadataPref));
}
void WorkspaceService::SaveWorkspaceMetadata(const WorkspaceMetadata& meta) {
ScopedDictPrefUpdate updated(*pref_service_, kWorkspacesMetadataPref);
updated->Set(ComputeKey(meta.name), WorkspaceMetadataToDictEntry(meta));
}
void WorkspaceService::RemoveWorkspaceMetadata(const std::string& name) {
ScopedDictPrefUpdate updated(*pref_service_, kWorkspacesMetadataPref);
updated->Remove(ComputeKey(name));
}
base::FilePath WorkspaceService::GetWorkspacePathForName(
const std::string& name) const {
return workspaces_path_.AppendASCII(ComputeKey(name));
}
void WorkspaceService::SaveWorkspace(const std::string& name) {
if (name.empty()) {
return;
}
// Collect session commands on the UI thread, then write to disk on a
// background task (WriteWorkspaceToDisk does blocking file I/O).
WorkspaceMetadata workspace{.name = name, .modified_at = base::Time::Now()};
std::vector<std::unique_ptr<sessions::SessionCommand>> commands =
GenerateBrowserSessionCommandsForWorkspace(base::to_address(profile_),
workspace);
base::FilePath workspace_path = GetWorkspacePathForName(name);
auto backend = base::MakeRefCounted<sessions::CommandStorageBackend>(
io_task_runner_, workspace_path, kWorkspaceSessionType,
/*encryptor=*/nullptr);
// Save metadata optimistically now; roll it back if the write fails.
// BindPostTask ensures on_error always runs on the UI thread whether it is
// invoked by AppendCommands or directly by WriteWorkspaceToDisk on a
// directory-creation failure.
SaveWorkspaceMetadata(workspace);
// "Rolling back" is just removing the metadata from the dictionary.
auto on_error = base::BindPostTask(
base::SequencedTaskRunner::GetCurrentDefault(),
base::BindOnce(&WorkspaceService::RemoveWorkspaceMetadata, GetWeakPtr(),
name));
io_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&WriteWorkspaceToDisk, std::move(commands),
std::move(workspace_path), std::move(backend),
std::move(on_error)));
}
void WorkspaceService::RestoreWorkspace(const std::string& name) {
base::FilePath path = GetWorkspacePathForName(name);
auto backend = base::MakeRefCounted<sessions::CommandStorageBackend>(
io_task_runner_, path, kWorkspaceSessionType,
/*encryptor=*/nullptr);
io_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&ReadWorkspaceFromDisk, std::move(path),
std::move(backend)),
base::BindOnce(&WorkspaceService::DoRestoreWorkspace, GetWeakPtr()));
}
void WorkspaceService::ShowSaveWorkspaceDialog() {
// TODO(https://github.com/brave/brave-browser/issues/55108)
SaveWorkspace("example-workspace");
}
void WorkspaceService::ShowOpenWorkspaceDialog() {
// TODO(https://github.com/brave/brave-browser/issues/55108)
RestoreWorkspace("example-workspace");
}
void WorkspaceService::DoRestoreWorkspace(
std::vector<std::unique_ptr<sessions::SessionCommand>> commands) {
if (commands.empty()) {
DVLOG(1) << "Could not load workspace: no commands";
return;
}
RestoreBrowserSessionCommandsForWorkspace(base::to_address(profile_),
std::move(commands));
}
base::WeakPtr<WorkspaceService> WorkspaceService::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void WorkspaceService::Shutdown() {
weak_ptr_factory_.InvalidateWeakPtrs();
}