blob: 7aaa29145c7c0c16db5a24e7853462cd6349476d [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/content_index/content_index_database.h"
#include <string>
#include "base/time/time.h"
#include "content/browser/content_index/content_index.pb.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace {
constexpr char kEntryPrefix[] = "content_index:entry_";
std::string EntryKey(const std::string& id) {
return kEntryPrefix + id;
}
std::string CreateSerializedContentEntry(
const blink::mojom::ContentDescription& description,
base::Time entry_time) {
// Convert description.
proto::ContentDescription description_proto;
description_proto.set_id(std::move(description.id));
description_proto.set_title(std::move(description.title));
description_proto.set_description(std::move(description.description));
description_proto.set_category(static_cast<int>(description.category));
description_proto.set_icon_url(description.icon_url.spec());
description_proto.set_launch_url(description.launch_url.spec());
// Create entry.
proto::ContentEntry entry;
*entry.mutable_description() = std::move(description_proto);
entry.set_timestamp(entry_time.ToDeltaSinceWindowsEpoch().InMicroseconds());
return entry.SerializeAsString();
}
blink::mojom::ContentDescriptionPtr DescriptionFromProto(
const proto::ContentDescription& description) {
// Validate.
if (description.category() <
static_cast<int>(blink::mojom::ContentCategory::kMinValue) ||
description.category() >
static_cast<int>(blink::mojom::ContentCategory::kMaxValue)) {
return nullptr;
}
// Convert.
auto result = blink::mojom::ContentDescription::New();
result->id = description.id();
result->title = description.title();
result->description = description.description();
result->category =
static_cast<blink::mojom::ContentCategory>(description.category());
result->icon_url = GURL(description.icon_url());
result->launch_url = GURL(description.launch_url());
return result;
}
} // namespace
ContentIndexDatabase::ContentIndexDatabase(
BrowserContext* browser_context,
scoped_refptr<ServiceWorkerContextWrapper> service_worker_context)
: browser_context_(browser_context),
service_worker_context_(std::move(service_worker_context)),
weak_ptr_factory_(this) {}
ContentIndexDatabase::~ContentIndexDatabase() = default;
void ContentIndexDatabase::AddEntry(
int64_t service_worker_registration_id,
const url::Origin& origin,
blink::mojom::ContentDescriptionPtr description,
const SkBitmap& icon,
blink::mojom::ContentIndexService::AddCallback callback) {
base::Time entry_time = base::Time::Now();
std::string key = EntryKey(description->id);
std::string value = CreateSerializedContentEntry(*description, entry_time);
DCHECK(!value.empty());
// Entry to pass over to the provider.
ContentIndexEntry entry(service_worker_registration_id,
std::move(description), entry_time);
// TODO(crbug.com/973844): Serialize and store icon.
service_worker_context_->StoreRegistrationUserData(
service_worker_registration_id, origin.GetURL(),
{{std::move(key), std::move(value)}},
base::BindOnce(&ContentIndexDatabase::DidAddEntry,
weak_ptr_factory_.GetWeakPtr(), std::move(callback),
std::move(entry)));
}
void ContentIndexDatabase::DidAddEntry(
blink::mojom::ContentIndexService::AddCallback callback,
ContentIndexEntry entry,
blink::ServiceWorkerStatusCode status) {
if (status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
return;
}
std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
if (auto* provider = browser_context_->GetContentIndexProvider())
provider->OnContentAdded(std::move(entry), weak_ptr_factory_.GetWeakPtr());
}
void ContentIndexDatabase::DeleteEntry(
int64_t service_worker_registration_id,
const std::string& entry_id,
blink::mojom::ContentIndexService::DeleteCallback callback) {
service_worker_context_->ClearRegistrationUserData(
service_worker_registration_id, {EntryKey(entry_id)},
base::BindOnce(
&ContentIndexDatabase::DidDeleteEntry, weak_ptr_factory_.GetWeakPtr(),
service_worker_registration_id, entry_id, std::move(callback)));
}
void ContentIndexDatabase::DidDeleteEntry(
int64_t service_worker_registration_id,
const std::string& entry_id,
blink::mojom::ContentIndexService::DeleteCallback callback,
blink::ServiceWorkerStatusCode status) {
if (status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR);
return;
}
std::move(callback).Run(blink::mojom::ContentIndexError::NONE);
if (auto* provider = browser_context_->GetContentIndexProvider())
provider->OnContentDeleted(service_worker_registration_id, entry_id);
}
void ContentIndexDatabase::GetDescriptions(
int64_t service_worker_registration_id,
blink::mojom::ContentIndexService::GetDescriptionsCallback callback) {
service_worker_context_->GetRegistrationUserDataByKeyPrefix(
service_worker_registration_id, kEntryPrefix,
base::BindOnce(&ContentIndexDatabase::DidGetDescriptions,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void ContentIndexDatabase::DidGetDescriptions(
blink::mojom::ContentIndexService::GetDescriptionsCallback callback,
const std::vector<std::string>& data,
blink::ServiceWorkerStatusCode status) {
if (status == blink::ServiceWorkerStatusCode::kErrorNotFound) {
std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
/* descriptions= */ {});
return;
} else if (status != blink::ServiceWorkerStatusCode::kOk) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
/* descriptions= */ {});
return;
}
std::vector<blink::mojom::ContentDescriptionPtr> descriptions;
descriptions.reserve(data.size());
// TODO(crbug.com/973844): Clear the storage if there is data corruption.
for (const auto& serialized_entry : data) {
proto::ContentEntry entry;
if (!entry.ParseFromString(serialized_entry)) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
/* descriptions= */ {});
return;
}
auto description = DescriptionFromProto(entry.description());
if (!description) {
std::move(callback).Run(blink::mojom::ContentIndexError::STORAGE_ERROR,
/* descriptions= */ {});
return;
}
descriptions.push_back(std::move(description));
}
std::move(callback).Run(blink::mojom::ContentIndexError::NONE,
std::move(descriptions));
}
void ContentIndexDatabase::GetIcon(
int64_t service_worker_registration_id,
const std::string& description_id,
base::OnceCallback<void(SkBitmap)> icon_callback) {
// TODO(crbug.com/973844): Implement this after icon is fetched & persisted.
std::move(icon_callback).Run(SkBitmap());
}
} // namespace content