File: ambient_topic_queue.h

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 (163 lines) | stat: -rw-r--r-- 6,845 bytes parent folder | download | duplicates (7)
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
// 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.

#ifndef ASH_AMBIENT_MODEL_AMBIENT_TOPIC_QUEUE_H_
#define ASH_AMBIENT_MODEL_AMBIENT_TOPIC_QUEUE_H_

#include <memory>
#include <queue>
#include <utility>
#include <vector>

#include "ash/ash_export.h"
#include "ash/public/cpp/ambient/ambient_backend_controller.h"
#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "net/base/backoff_entry.h"

namespace ash {

class AmbientBackendController;

// Maintains a queue of topics fetched from the IMAX server. Note "topic" in
// this class refers to the early stage in the pipeline where the topic only has
// a primary (and optional related) photo url. AmbientTopicQueue does not deal
// with downloading/decoding actual photos.
//
// The AmbientTopicQueue automatically fills itself. The caller only has a Pop()
// API. It fills itself with new topics from IMAX when:
// * The caller has popped all existing topics from the queue (it's empty).
// * The |topic_fetch_interval| provided in the constructor has elapsed since
//   the last topic fetch. This is done so that a sufficient amount of topics
//   are available in the queue regardless of how often the caller calls Pop().
//   (The access token required to fetch topics is only valid for a fixed period
//   after entering ambient mode).
//
// The AmbientTopicQueue stops filling itself when the total number of topics it
// has fetched exceeds the |topic_fetch_limit| provided in the constructor.
// When this limit has been reached, the queue remains empty even after the
// caller Pop()s everything from it.
class ASH_EXPORT AmbientTopicQueue {
 public:
  class Delegate {
   public:
    virtual ~Delegate() = default;

    // Returns a non-empty set of sizes that specify the desired size of the
    // topic photos returned by IMAX. This is invoked before each topic fetch,
    // so implementations may change the set of sizes they specify if desired.
    //
    // The AmbientTopicQueue will make a best effort to maintain a uniform
    // distribution of the specified topic sizes in its queue. Note that the
    // |topic_fetch_limit| is always honored though and is a global limit for
    // all topics in the queue irrespective of size.
    virtual std::vector<gfx::Size> GetTopicSizes() = 0;
  };

  // Starts automatically filling the queue on construction. Note this class
  // intentionally does not have a method to clear the queue/reset its state.
  // For this, it's cheap to just destroy and re-create the queue.
  //
  // |topic_fetch_limit|: See class-level comments above.
  // |topic_fetch_size|: Number of topics requested from IMAX in each individual
  //                     topic fetch.
  // |topic_fetch_interval|: See class-level comments above.
  // |should_split_topics|: See |AmbientPhotoConfig.should_split_topics|.
  AmbientTopicQueue(int topic_fetch_limit,
                    int topic_fetch_size,
                    base::TimeDelta topic_fetch_interval,
                    bool should_split_topics,
                    Delegate* delegate,
                    AmbientBackendController* backend_controller);
  AmbientTopicQueue(const AmbientTopicQueue&) = delete;
  AmbientTopicQueue& operator=(const AmbientTopicQueue&) = delete;
  ~AmbientTopicQueue();

  // Invokes the |wait_cb| when the queue has topics in it (i.e. the queue is
  // not empty). If the queue already has topics in it, the |wait_cb| is invoked
  // immediately and synchronously.
  enum class WaitResult {
    // IsEmpty() is guaranteed to be false.
    kTopicsAvailable,
    // IsEmpty() will be true for the following:
    //
    // The most recent topic fetch failed, and the queue is currently backing
    // off, waiting for the IMAX server to recover. This result is returned
    // immediately so that the caller can implement any fallback logic it
    // has (ex: reading photos from an on-disc cache) rather than getting stuck
    // waiting for long periods of time.
    kTopicFetchBackingOff,
    // The |topic_fetch_limit| has been reached, so the queue will not be filled
    // with any more topics for the rest of its lifetime.
    kTopicFetchLimitReached,
  };
  using WaitCallback = base::OnceCallback<void(WaitResult)>;
  void WaitForTopicsAvailable(WaitCallback wait_cb);

  // Pops() the topic from the front of the queue. Fails with a fatal error if
  // IsEmpty().
  AmbientModeTopic Pop();

  // Whether or not there are any topics in the queue currently.
  bool IsEmpty() const;

 private:
  bool HasReachedTopicFetchLimit() const;

  void FetchTopics();
  void OnScreenUpdateInfoFetched(const base::RepeatingClosure& barrier_closure,
                                 const gfx::Size& requested_topic_size,
                                 const ash::ScreenUpdate& screen_update);
  void OnAllScreenUpdateInfoFetched();
  void ScheduleFetchTopics(bool backoff);
  void Push(AmbientModeTopic topic);
  void RunPendingWaitCallbacks(WaitResult wait_result);

  const int topic_fetch_limit_;
  const int topic_fetch_size_;
  const base::TimeDelta topic_fetch_interval_;
  const bool should_split_topics_;
  const raw_ptr<Delegate> delegate_;
  const raw_ptr<AmbientBackendController> backend_controller_;

  std::queue<AmbientModeTopic> available_topics_;
  int total_topics_fetched_ = 0;

  // Whether a topic fetch is current in progress (waiting for IMAX to respond).
  // For simplicity, there should only be one topic fetch active at any given
  // time.
  bool topic_fetch_in_progress_ = false;

  // For topic fetches scheduled in the future (either a regularly scheduled one
  // or one from backoff).
  base::OneShotTimer fetch_topic_timer_;

  // Backoff for fetch topics retries.
  net::BackoffEntry fetch_topic_retry_backoff_;

  // Accumulation of WaitForTopicsAvailable() calls made while a topic fetch
  // is currently in progress. These are flushed/run when the topic fetch
  // completes.
  std::vector<WaitCallback> pending_wait_cbs_;

  // Transient storage for the IMAX responses returned from each topic fetch.
  // There is one entry per topic size requested since there is also one network
  // request made per topic size.
  //
  // The key contains the requested topic size's width/height. Using a map
  // ensures a *deterministic* ordering of the topic sizes when processing this
  // map after each fetch, but the order itself is irrelevant.
  base::flat_map<std::pair<int, int>, std::vector<AmbientModeTopic>>
      pending_topic_batches_;

  base::WeakPtrFactory<AmbientTopicQueue> weak_factory_{this};
};

}  // namespace ash

#endif  // ASH_AMBIENT_MODEL_AMBIENT_TOPIC_QUEUE_H_