1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SHARE_SHARE_RANKING_H_
#define CHROME_BROWSER_SHARE_SHARE_RANKING_H_
#include <optional>
#include "base/callback_list.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "base/supports_user_data.h"
#include "build/build_config.h"
#include "chrome/browser/share/proto/share_ranking_message.pb.h"
#include "chrome/browser/share/share_history.h"
#include "components/leveldb_proto/public/proto_database.h"
class Profile;
namespace sharing {
class ShareHistory;
class ShareRanking : public base::SupportsUserData::Data {
public:
using Ranking = std::vector<std::string>;
using BackingDb = leveldb_proto::ProtoDatabase<proto::ShareRanking>;
using GetRankingCallback =
base::OnceCallback<void(std::optional<Ranking> result)>;
static ShareRanking* Get(Profile* profile);
explicit ShareRanking(Profile* profile,
std::unique_ptr<BackingDb> backing_db = nullptr);
~ShareRanking() override;
void UpdateRanking(const std::string& type, Ranking ranking);
void GetRanking(const std::string& type, GetRankingCallback callback);
// This method:
// 1. Fetches the existing rankings and histories for |type| from the provided
// databases
// 2. Runs the ranking algorithm (see below).
// 3. If |persist_update|, writes the new ranking back to |ranking|
// 4. Returns the display ranking to use for this specific share
void Rank(ShareHistory* history,
const std::string& type,
const std::vector<std::string>& available_on_system,
size_t fold,
size_t length,
bool persist_update,
GetRankingCallback callback);
void Clear(const base::Time& start = base::Time(),
const base::Time& end = base::Time());
// The core of the ranking algorithm, exposed as a pure function for ease of
// testing and reasoning about the code. This function takes the existing
// share history and ranking for this type, a set of all targets available on
// the current system, and a length, and computes the new display ranking and
// the new persistent ranking.
//
// TODO(ellyjones): Document (publicly) how this works and why.
static void ComputeRanking(
const std::map<std::string, int>& all_share_history,
const std::map<std::string, int>& recent_share_history,
const Ranking& old_ranking,
const std::vector<std::string>& available_on_system,
size_t fold,
size_t length,
Ranking* display_ranking,
Ranking* persisted_ranking);
static const char* const kMoreTarget;
void set_initial_ranking_for_test(Ranking ranking) {
initial_ranking_for_test_ = ranking;
}
private:
// A PendingRankCall represents a call to Rank() that is in progress; an
// object of this type is threaded through the async calls used by Rank() to
// pass state from one step to the next.
struct PendingRankCall {
PendingRankCall();
~PendingRankCall();
// These members mirror the parameters passed in to Rank().
std::string type;
std::vector<std::string> available_on_system;
size_t fold;
size_t length;
bool persist_update;
GetRankingCallback callback;
// This is the ShareHistory passed into Rank(), held as a WeakPtr in case
// the Rank() call is pending across profile teardown.
base::WeakPtr<ShareHistory> history_db;
// These are intermediate results generated by async steps of Rank(),
// accumulated into the PendingRankCall for later use.
std::vector<ShareHistory::Target> all_history;
std::vector<ShareHistory::Target> recent_history;
};
void Init();
void OnInitDone(leveldb_proto::Enums::InitStatus status);
void OnBackingGetDone(std::string key,
GetRankingCallback callback,
bool ok,
std::unique_ptr<proto::ShareRanking> ranking);
void FlushToBackingDb(const std::string& key);
// Steps of the state machine for Rank() - in order, that method:
// 1. Fetches all history for the given type
// 2. Fetches recent history for the given type
// 3. Fetches the existing ranking for the given type
// Each of these steps is asynchronous and the On*Done methods are used for
// their completion callbacks.
void OnRankGetAllDone(std::unique_ptr<PendingRankCall> pending,
std::vector<ShareHistory::Target> history);
void OnRankGetRecentDone(std::unique_ptr<PendingRankCall> pending,
std::vector<ShareHistory::Target> history);
void OnRankGetOldRankingDone(std::unique_ptr<PendingRankCall> pending,
std::optional<Ranking> ranking);
// Return the default initial ranking, which depends on the current locale.
Ranking GetDefaultInitialRankingForType(const std::string& type);
bool init_finished_ = false;
leveldb_proto::Enums::InitStatus db_init_status_;
base::OnceClosureList post_init_callbacks_;
std::unique_ptr<BackingDb> db_;
// Cached ranking values, which are used when populated; otherwise they are
// fetched from the backing database. Updates to this are written back to the
// backing database by FlushToBackingDb().
base::flat_map<std::string, Ranking> ranking_;
std::optional<Ranking> initial_ranking_for_test_;
base::WeakPtrFactory<ShareRanking> weak_factory_{this};
};
} // namespace sharing
#endif // CHROME_BROWSER_SHARE_SHARE_RANKING_H_
|