| Index: components/enhanced_bookmarks/bookmark_server_cluster_service.cc
|
| diff --git a/components/enhanced_bookmarks/bookmark_server_cluster_service.cc b/components/enhanced_bookmarks/bookmark_server_cluster_service.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..ca38c1c145d2650c42d5ddf116ae7fbae5867503
|
| --- /dev/null
|
| +++ b/components/enhanced_bookmarks/bookmark_server_cluster_service.cc
|
| @@ -0,0 +1,315 @@
|
| +// Copyright 2014 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 "components/enhanced_bookmarks/bookmark_server_cluster_service.h"
|
| +
|
| +#include "base/json/json_reader.h"
|
| +#include "base/json/json_writer.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/prefs/pref_service.h"
|
| +#include "base/values.h"
|
| +#include "components/bookmarks/browser/bookmark_model.h"
|
| +#include "components/enhanced_bookmarks/enhanced_bookmark_model.h"
|
| +#include "components/enhanced_bookmarks/enhanced_bookmark_utils.h"
|
| +#include "components/enhanced_bookmarks/pref_names.h"
|
| +#include "components/enhanced_bookmarks/proto/cluster.pb.h"
|
| +#include "components/pref_registry/pref_registry_syncable.h"
|
| +#include "components/signin/core/browser/signin_manager.h"
|
| +#include "net/base/url_util.h"
|
| +#include "net/url_request/url_fetcher.h"
|
| +#include "net/url_request/url_request_context_getter.h"
|
| +
|
| +namespace {
|
| +const char kClusterUrl[] = "https://www.google.com/stars/cluster";
|
| +const int kPrefServiceVersion = 1;
|
| +const char kPrefServiceVersionKey[] = "version";
|
| +const char kPrefServiceDataKey[] = "data";
|
| +const char kAuthIdKey[] = "auth_id";
|
| +} // namespace
|
| +
|
| +namespace enhanced_bookmarks {
|
| +
|
| +BookmarkServerClusterService::BookmarkServerClusterService(
|
| + const std::string& application_language_code,
|
| + scoped_refptr<net::URLRequestContextGetter> request_context_getter,
|
| + ProfileOAuth2TokenService* token_service,
|
| + SigninManagerBase* signin_manager,
|
| + enhanced_bookmarks::EnhancedBookmarkModel* enhanced_bookmark_model,
|
| + PrefService* pref_service)
|
| + : BookmarkServerService(request_context_getter,
|
| + token_service,
|
| + signin_manager,
|
| + enhanced_bookmark_model),
|
| + application_language_code_(application_language_code),
|
| + pref_service_(pref_service) {
|
| + LoadModel();
|
| +
|
| + if (model_->loaded())
|
| + TriggerTokenRequest(false);
|
| +
|
| + GetSigninManager()->AddObserver(this);
|
| +}
|
| +
|
| +BookmarkServerClusterService::~BookmarkServerClusterService() {
|
| + GetSigninManager()->RemoveObserver(this);
|
| +}
|
| +
|
| +const std::vector<const BookmarkNode*>
|
| +BookmarkServerClusterService::BookmarksForClusterNamed(
|
| + const std::string& cluster_name) const {
|
| + std::vector<const BookmarkNode*> results;
|
| +
|
| + ClusterMap::const_iterator cluster_it = cluster_data_.find(cluster_name);
|
| + if (cluster_it == cluster_data_.end())
|
| + return results;
|
| +
|
| + for (auto& star_id : cluster_it->second) {
|
| + const BookmarkNode* bookmark = BookmarkForRemoteId(star_id);
|
| + if (bookmark)
|
| + results.push_back(bookmark);
|
| + }
|
| + return results;
|
| +}
|
| +
|
| +const std::vector<std::string>
|
| +BookmarkServerClusterService::ClustersForBookmark(
|
| + const BookmarkNode* bookmark) const {
|
| + const std::string& star_id = RemoteIDForBookmark(bookmark);
|
| +
|
| + // TODO(noyau): if this turns out to be a perf bottleneck this may be improved
|
| + // by storing a reverse map from id to cluster.
|
| + std::vector<std::string> clusters;
|
| + for (auto& pair : cluster_data_) {
|
| + const std::vector<std::string>& stars_ids = pair.second;
|
| + if (std::find(stars_ids.begin(), stars_ids.end(), star_id) !=
|
| + stars_ids.end())
|
| + clusters.push_back(pair.first);
|
| + }
|
| + return clusters;
|
| +}
|
| +
|
| +const std::vector<std::string> BookmarkServerClusterService::GetClusters()
|
| + const {
|
| + std::vector<std::string> cluster_names;
|
| +
|
| + for (auto& pair : cluster_data_)
|
| + cluster_names.push_back(pair.first);
|
| +
|
| + return cluster_names;
|
| +}
|
| +
|
| +// static
|
| +void BookmarkServerClusterService::RegisterPrefs(
|
| + user_prefs::PrefRegistrySyncable* registry) {
|
| + registry->RegisterDictionaryPref(
|
| + prefs::kBookmarkClusters,
|
| + user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
|
| +}
|
| +
|
| +scoped_ptr<net::URLFetcher> BookmarkServerClusterService::CreateFetcher() {
|
| + // Add the necessary arguments to the URI.
|
| + GURL url(kClusterUrl);
|
| + url = net::AppendQueryParameter(url, "output", "proto");
|
| +
|
| + // Append language.
|
| + if (!application_language_code_.empty())
|
| + url = net::AppendQueryParameter(url, "hl", application_language_code_);
|
| +
|
| + url = net::AppendQueryParameter(url, "v", model_->GetVersionString());
|
| +
|
| + // Build the URLFetcher to perform the request.
|
| + scoped_ptr<net::URLFetcher> url_fetcher(
|
| + net::URLFetcher::Create(url, net::URLFetcher::POST, this));
|
| +
|
| + // Binary encode a basic request proto.
|
| + image_collections::ClusterRequest request_proto;
|
| + request_proto.set_cluster_all(true);
|
| +
|
| + std::string proto_output;
|
| + bool result = request_proto.SerializePartialToString(&proto_output);
|
| + DCHECK(result);
|
| +
|
| + url_fetcher->SetUploadData("application/octet-stream", proto_output);
|
| + return url_fetcher;
|
| +}
|
| +
|
| +bool BookmarkServerClusterService::ProcessResponse(const std::string& response,
|
| + bool* should_notify) {
|
| + DCHECK(*should_notify);
|
| + image_collections::ClusterResponse response_proto;
|
| + bool result = response_proto.ParseFromString(response);
|
| + if (!result)
|
| + return false; // Not formatted properly.
|
| +
|
| + ClusterMap new_cluster_data;
|
| + for (const auto& cluster : response_proto.clusters()) {
|
| + const std::string& title = cluster.title();
|
| + if (title.empty())
|
| + continue;
|
| + std::vector<std::string> stars_ids;
|
| + for (auto& doc : cluster.docs()) {
|
| + if (!doc.empty())
|
| + stars_ids.push_back(doc);
|
| + }
|
| + if (stars_ids.size())
|
| + new_cluster_data[title] = stars_ids;
|
| + }
|
| +
|
| + if (new_cluster_data.size() == cluster_data_.size() &&
|
| + std::equal(new_cluster_data.begin(),
|
| + new_cluster_data.end(),
|
| + cluster_data_.begin())) {
|
| + *should_notify = false;
|
| + } else {
|
| + SwapModel(&new_cluster_data);
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +void BookmarkServerClusterService::CleanAfterFailure() {
|
| + if (cluster_data_.empty())
|
| + return;
|
| +
|
| + ClusterMap empty;
|
| + SwapModel(&empty);
|
| +}
|
| +
|
| +void BookmarkServerClusterService::EnhancedBookmarkModelLoaded() {
|
| + TriggerTokenRequest(false);
|
| +}
|
| +
|
| +void BookmarkServerClusterService::EnhancedBookmarkAdded(
|
| + const BookmarkNode* node) {
|
| + // Nothing to do.
|
| +}
|
| +
|
| +void BookmarkServerClusterService::EnhancedBookmarkRemoved(
|
| + const BookmarkNode* node) {
|
| + // It is possible to remove the entries from the map here, but as those are
|
| + // filtered in ClustersForBookmark() this is not strictly necessary.
|
| +}
|
| +
|
| +void BookmarkServerClusterService::EnhancedBookmarkAllUserNodesRemoved() {
|
| + if (!cluster_data_.empty()) {
|
| + ClusterMap empty;
|
| + SwapModel(&empty);
|
| + }
|
| +}
|
| +
|
| +void BookmarkServerClusterService::EnhancedBookmarkRemoteIdChanged(
|
| + const BookmarkNode* node,
|
| + const std::string& old_remote_id,
|
| + const std::string& remote_id) {
|
| + std::vector<std::string> clusters;
|
| + for (auto& pair : cluster_data_) {
|
| + std::vector<std::string>& stars_ids = pair.second;
|
| + std::replace(stars_ids.begin(), stars_ids.end(), old_remote_id, remote_id);
|
| + }
|
| +}
|
| +
|
| +void BookmarkServerClusterService::GoogleSignedOut(
|
| + const std::string& account_id,
|
| + const std::string& username) {
|
| + if (!cluster_data_.empty()) {
|
| + ClusterMap empty;
|
| + SwapModel(&empty);
|
| + }
|
| +}
|
| +
|
| +void BookmarkServerClusterService::SwapModel(ClusterMap* cluster_map) {
|
| + cluster_data_.swap(*cluster_map);
|
| + const std::string& auth_id = GetSigninManager()->GetAuthenticatedAccountId();
|
| + scoped_ptr<base::DictionaryValue> dictionary(
|
| + Serialize(cluster_data_, auth_id));
|
| + pref_service_->Set(prefs::kBookmarkClusters, *dictionary);
|
| +}
|
| +
|
| +void BookmarkServerClusterService::LoadModel() {
|
| + const base::DictionaryValue* dictionary =
|
| + pref_service_->GetDictionary(prefs::kBookmarkClusters);
|
| + const std::string& auth_id = GetSigninManager()->GetAuthenticatedAccountId();
|
| +
|
| + ClusterMap loaded_data;
|
| + bool result = BookmarkServerClusterService::Deserialize(
|
| + *dictionary, auth_id, &loaded_data);
|
| + if (result)
|
| + cluster_data_.swap(loaded_data);
|
| +}
|
| +
|
| +//
|
| +// Serialization.
|
| +//
|
| +// static
|
| +scoped_ptr<base::DictionaryValue> BookmarkServerClusterService::Serialize(
|
| + const ClusterMap& cluster_map,
|
| + const std::string& auth_id) {
|
| + // Create a list of all clusters. For each cluster, make another list. The
|
| + // first element in the list is the key (cluster name). All subsequent
|
| + // elements are stars ids.
|
| + scoped_ptr<base::ListValue> all_clusters(new base::ListValue);
|
| + for (auto& pair : cluster_map) {
|
| + scoped_ptr<base::ListValue> cluster(new base::ListValue);
|
| + cluster->AppendString(pair.first);
|
| + cluster->AppendStrings(pair.second);
|
| + all_clusters->Append(cluster.release());
|
| + }
|
| +
|
| + // The dictionary that will be serialized has two fields: a version field and
|
| + // a data field.
|
| + scoped_ptr<base::DictionaryValue> data(new base::DictionaryValue);
|
| + data->SetInteger(kPrefServiceVersionKey, kPrefServiceVersion);
|
| + data->Set(kPrefServiceDataKey, all_clusters.release());
|
| + data->SetString(kAuthIdKey, auth_id);
|
| +
|
| + return data.Pass();
|
| +}
|
| +
|
| +// static
|
| +bool BookmarkServerClusterService::Deserialize(
|
| + const base::DictionaryValue& value,
|
| + const std::string& auth_id,
|
| + ClusterMap* out_map) {
|
| + ClusterMap output;
|
| +
|
| + // Check version.
|
| + int version;
|
| + if (!value.GetInteger(kPrefServiceVersionKey, &version))
|
| + return false;
|
| + if (version != kPrefServiceVersion)
|
| + return false;
|
| +
|
| + // Check auth id.
|
| + std::string id;
|
| + if (!value.GetString(kAuthIdKey, &id))
|
| + return false;
|
| + if (id != auth_id)
|
| + return false;
|
| +
|
| + const base::ListValue* all_clusters = NULL;
|
| + if (!value.GetList(kPrefServiceDataKey, &all_clusters))
|
| + return false;
|
| +
|
| + for (size_t index = 0; index < all_clusters->GetSize(); ++index) {
|
| + const base::ListValue* cluster = NULL;
|
| + if (!all_clusters->GetList(index, &cluster))
|
| + return false;
|
| + if (cluster->GetSize() < 1)
|
| + return false;
|
| + std::string key;
|
| + if (!cluster->GetString(0, &key))
|
| + return false;
|
| + std::vector<std::string> stars_ids;
|
| + for (size_t index = 1; index < cluster->GetSize(); ++index) {
|
| + std::string stars_id;
|
| + if (!cluster->GetString(index, &stars_id))
|
| + return false;
|
| + stars_ids.push_back(stars_id);
|
| + }
|
| + output.insert(std::make_pair(key, stars_ids));
|
| + }
|
| + out_map->swap(output);
|
| + return true;
|
| +}
|
| +
|
| +} // namespace enhanced_bookmarks
|
|
|