File: info_card_tracker.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (170 lines) | stat: -rw-r--r-- 6,081 bytes parent folder | download | duplicates (3)
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
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/feed/core/v2/stream/info_card_tracker.h"

#include <algorithm>

#include "base/base64.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/feed/core/common/pref_names.h"
#include "components/feed/core/v2/config.h"
#include "components/feed/core/v2/feedstore_util.h"
#include "components/feed/core/v2/proto_util.h"
#include "components/feed/feed_feature_list.h"
#include "components/prefs/pref_service.h"

namespace feed {

using feedwire::InfoCardTrackingState;

namespace {

std::string InfoCardTypeToString(int info_card_type) {
  return base::NumberToString(info_card_type);
}

bool compareInfoCardTrackingState(const InfoCardTrackingState& i1,
                                  const InfoCardTrackingState& i2) {
  return (i1.type() < i2.type());
}

InfoCardTrackingState DecodeFromBase64SerializedString(
    const std::string& base64_serialized_state) {
  InfoCardTrackingState state;

  std::string serialized_state;
  if (!base::Base64Decode(base64_serialized_state, &serialized_state)) {
    DLOG(ERROR) << "Error decoding persisted state from base64";
    return state;
  }

  if (!state.ParseFromString(serialized_state))
    DLOG(ERROR) << "Error parsing InfoCardTrackingState message";

  return state;
}

int64_t GetAdjustedViewTimestamp(int64_t view_timestamp,
                                 int64_t server_timestamp,
                                 int64_t timestamp_adjustment) {
  view_timestamp += timestamp_adjustment;
  // Ensure that the view timestamp does not get earlier than the server.
  if (view_timestamp < server_timestamp)
    view_timestamp = server_timestamp;
  // Ensure that the view timestamp does not exceed the lifetime of the content.
  int64_t max_timestamp =
      server_timestamp +
      GetFeedConfig().content_expiration_threshold.InMilliseconds();
  if (view_timestamp > max_timestamp)
    view_timestamp = max_timestamp;
  return view_timestamp;
}

}  // namespace

InfoCardTracker::InfoCardTracker(PrefService* profile_prefs)
    : profile_prefs_(profile_prefs) {
  DCHECK(profile_prefs_);
}

InfoCardTracker::~InfoCardTracker() = default;

std::vector<InfoCardTrackingState> InfoCardTracker::GetAllStates(
    int64_t server_timestamp,
    int64_t client_timestamp) const {
  std::vector<InfoCardTrackingState> states;
  const base::Value& dict = profile_prefs_->GetValue(prefs::kInfoCardStates);
  if (dict.is_dict()) {
    int64_t timestamp_adjustment = server_timestamp - client_timestamp;
    for (const auto pair : dict.GetDict()) {
      int info_card_type = 0;
      if (!base::StringToInt(pair.first, &info_card_type))
        continue;
      if (!pair.second.is_string())
        continue;
      InfoCardTrackingState state =
          DecodeFromBase64SerializedString(pair.second.GetString());
      state.set_type(info_card_type);
      if (state.has_first_view_timestamp()) {
        state.set_first_view_timestamp(
            GetAdjustedViewTimestamp(state.first_view_timestamp(),
                                     server_timestamp, timestamp_adjustment));
      }
      if (state.has_last_view_timestamp()) {
        state.set_last_view_timestamp(
            GetAdjustedViewTimestamp(state.last_view_timestamp(),
                                     server_timestamp, timestamp_adjustment));
      }
      states.push_back(state);
    }
  }
  std::sort(states.begin(), states.end(), compareInfoCardTrackingState);
  return states;
}

void InfoCardTracker::OnViewed(int info_card_type,
                               int minimum_view_interval_seconds) {
  auto now = base::Time::Now();
  InfoCardTrackingState state = GetState(info_card_type);
  if (state.has_last_view_timestamp() &&
      now - feedstore::FromTimestampMillis(state.last_view_timestamp()) <
          base::Seconds(minimum_view_interval_seconds)) {
    return;
  }

  state.set_view_count(state.view_count() + 1);
  if (!state.has_first_view_timestamp())
    state.set_first_view_timestamp(feedstore::ToTimestampMillis(now));
  state.set_last_view_timestamp(feedstore::ToTimestampMillis(now));
  SetState(info_card_type, state);
}

void InfoCardTracker::OnClicked(int info_card_type) {
  InfoCardTrackingState state = GetState(info_card_type);
  state.set_click_count(state.click_count() + 1);
  SetState(info_card_type, state);
}

void InfoCardTracker::OnDismissed(int info_card_type) {
  InfoCardTrackingState state = GetState(info_card_type);
  state.set_explicitly_dismissed_count(state.explicitly_dismissed_count() + 1);
  SetState(info_card_type, state);
}

void InfoCardTracker::ResetState(int info_card_type) {
  InfoCardTrackingState state;
  SetState(info_card_type, state);
}

InfoCardTrackingState InfoCardTracker::GetState(int info_card_type) const {
  const base::Value::Dict& all_states =
      profile_prefs_->GetDict(prefs::kInfoCardStates);
  const std::string* base64_serialized_state =
      all_states.FindString(InfoCardTypeToString(info_card_type));
  if (!base64_serialized_state)
    return InfoCardTrackingState();
  return DecodeFromBase64SerializedString(*base64_serialized_state);
}

void InfoCardTracker::SetState(int info_card_type,
                               const InfoCardTrackingState& state) {
  // SerializeToString encodes the proto into a series of bytes that is not
  // going to be compatible with UTF-8 encoding. We need to convert them to
  // base64 before writing to the prefs store.
  std::string serialized_state;
  state.SerializeToString(&serialized_state);

  const base::Value::Dict& states =
      profile_prefs_->GetDict(prefs::kInfoCardStates);
  base::Value::Dict updated_states = states.Clone();
  updated_states.Set(InfoCardTypeToString(info_card_type),
                     base::Base64Encode(serialized_state));
  profile_prefs_->SetDict(prefs::kInfoCardStates, std::move(updated_states));
}

}  // namespace feed