summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/push_messaging/budget_database.h
blob: 0ae20374262b12b3a4779157afcf38b3fdbc693a (plain)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
// Copyright 2016 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.

#ifndef CHROME_BROWSER_PUSH_MESSAGING_BUDGET_DATABASE_H_
#define CHROME_BROWSER_PUSH_MESSAGING_BUDGET_DATABASE_H_

#include <list>
#include <map>
#include <memory>

#include "base/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/leveldb_proto/public/proto_database.h"

namespace base {
class Clock;
class Time;
}  // namespace base

namespace budget_service {
class Budget;
}

namespace url {
class Origin;
}

class Profile;

// Structure representing the budget at points in time in the future.
struct BudgetState {
  BudgetState();
  BudgetState(const BudgetState& other);
  ~BudgetState();

  BudgetState& operator=(const BudgetState& other);

  // Amount of budget that will be available. This should be the lower bound of
  // the budget between this time and the previous time.
  double budget_at = 0;

  // Time at which the budget is available, in milliseconds since 00:00:00 UTC
  // on 1 January 1970, at which the budget_at will be valid.
  double time = 0;
};

// A class used to asynchronously read and write details of the budget
// assigned to an origin. The class uses an underlying LevelDB.
class BudgetDatabase {
 public:
  // The default amount of budget that should be spent.
  static constexpr double kDefaultAmount = 2.0;

  // Callback for getting a list of all budget chunks.
  using GetBudgetCallback = base::OnceCallback<void(std::vector<BudgetState>)>;

  // This is invoked only after the spend has been written to the database.
  using SpendBudgetCallback = base::OnceCallback<void(bool success)>;

  // The database_dir specifies the location of the budget information on disk.
  explicit BudgetDatabase(Profile* profile);

  BudgetDatabase(const BudgetDatabase&) = delete;
  BudgetDatabase& operator=(const BudgetDatabase&) = delete;

  ~BudgetDatabase();

  // Get the full budget expectation for the origin. This will return a
  // sequence of time points and the expected budget at those times.
  void GetBudgetDetails(const url::Origin& origin, GetBudgetCallback callback);

  // Spend a fixed (2.0) amount of budget for an origin. The callback indicates
  // whether the budget could be spent for the given |origin|.
  void SpendBudget(const url::Origin& origin,
                   SpendBudgetCallback callback,
                   double amount = kDefaultAmount);

 private:
  FRIEND_TEST_ALL_PREFIXES(BudgetDatabaseTest,
                           DefaultSiteEngagementInIncognitoProfile);
  friend class BudgetDatabaseTest;

  // Used to allow tests to change time for testing.
  void SetClockForTesting(std::unique_ptr<base::Clock> clock);

  // Holds information about individual pieces of awarded budget. There is a
  // one-to-one mapping of these to the chunks in the underlying database.
  struct BudgetChunk {
    BudgetChunk(double amount, base::Time expiration)
        : amount(amount), expiration(expiration) {}
    BudgetChunk(const BudgetChunk&) = default;
    BudgetChunk& operator=(const BudgetChunk&) = default;

    double amount;
    base::Time expiration;
  };

  // Data structure for caching budget information.
  using BudgetChunks = std::list<BudgetChunk>;

  // Holds information about the overall budget for a site. This includes the
  // time the budget was last incremented, as well as a list of budget chunks
  // which have been awarded.
  struct BudgetInfo {
    BudgetInfo();

    BudgetInfo(const BudgetInfo&) = delete;
    BudgetInfo& operator=(const BudgetInfo&) = delete;

    BudgetInfo(const BudgetInfo&& other);

    ~BudgetInfo();

    base::Time last_engagement_award;
    BudgetChunks chunks;
  };

  // Callback for writing budget values to the database.
  using StoreBudgetCallback = base::OnceCallback<void(bool success)>;

  using CacheCallback = base::OnceCallback<void(bool success)>;

  void OnDatabaseInit(leveldb_proto::Enums::InitStatus status);

  bool IsCached(const url::Origin& origin) const;

  double GetBudget(const url::Origin& origin) const;

  void AddToCache(const url::Origin& origin,
                  CacheCallback callback,
                  bool success,
                  std::unique_ptr<budget_service::Budget> budget);

  void GetBudgetAfterSync(const url::Origin& origin,
                          GetBudgetCallback callback,
                          bool success);

  void SpendBudgetAfterSync(const url::Origin& origin,
                            double amount,
                            SpendBudgetCallback callback,
                            bool success);

  void SpendBudgetAfterWrite(SpendBudgetCallback callback, bool success);

  void WriteCachedValuesToDatabase(const url::Origin& origin,
                                   StoreBudgetCallback callback);

  void SyncCache(const url::Origin& origin, CacheCallback callback);
  void SyncLoadedCache(const url::Origin& origin,
                       CacheCallback callback,
                       bool success);

  // Add budget based on engagement with an origin. The method queries for the
  // engagement score of the origin, and then calculates when engagement budget
  // was last awarded and awards a portion of the score based on that.
  // This only writes budget to the cache.
  void AddEngagementBudget(const url::Origin& origin);

  bool CleanupExpiredBudget(const url::Origin& origin);

  // Gets the current Site Engagement Score for |origin|. Will return a fixed
  // score of zero when |profile_| is off the record.
  double GetSiteEngagementScoreForOrigin(const url::Origin& origin) const;

  raw_ptr<Profile> profile_;

  // The database for storing budget information.
  std::unique_ptr<leveldb_proto::ProtoDatabase<budget_service::Budget>> db_;

  // Cached data for the origins which have been loaded.
  std::map<url::Origin, BudgetInfo> budget_map_;

  // The clock used to vend times.
  std::unique_ptr<base::Clock> clock_;

  base::WeakPtrFactory<BudgetDatabase> weak_ptr_factory_{this};
};

#endif  // CHROME_BROWSER_PUSH_MESSAGING_BUDGET_DATABASE_H_