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
ash / ambient / managed / screensaver_image_downloader.h [blame]
// Copyright 2023 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_MANAGED_SCREENSAVER_IMAGE_DOWNLOADER_H_
#define ASH_AMBIENT_MANAGED_SCREENSAVER_IMAGE_DOWNLOADER_H_
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "ash/ash_export.h"
#include "base/containers/flat_set.h"
#include "base/containers/queue.h"
#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/values.h"
#include "services/network/public/cpp/simple_url_loader.h"
namespace network {
class SharedURLLoaderFactory;
}
namespace ash {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class ScreensaverImageDownloadResult {
kSuccess = 0,
kNetworkError = 1,
kFileSaveError = 2,
kFileSystemWriteError = 3,
kCancelled = 4,
kMaxValue = kCancelled,
};
// Provides a cache service to download and store external image files that will
// be displayed in the managed screensaver feature. This cache will operate in a
// specific file directory, specified on instantiation.
//
// Each image will be downloaded and stored with a unique name based on its URL
// address. This cache assumes that the remote contents of the URL will not
// change, i.e. once downloaded, it will not attempt to refresh its content.
class ASH_EXPORT ScreensaverImageDownloader {
private:
// Expresses the state of the downloading queue. It has two states:
// * Waiting: No download is being executed and the queue is empty.
// * Downloading: A download is in progress, and additional requests may be
// in queue.
enum class QueueState {
kWaiting,
kDownloading,
};
public:
using ImageListUpdatedCallback =
base::RepeatingCallback<void(const std::vector<base::FilePath>& images)>;
ScreensaverImageDownloader() = delete;
ScreensaverImageDownloader(
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory,
const base::FilePath& download_directory,
ImageListUpdatedCallback image_list_updated_callback);
~ScreensaverImageDownloader();
ScreensaverImageDownloader(const ScreensaverImageDownloader&) = delete;
ScreensaverImageDownloader& operator=(const ScreensaverImageDownloader&) =
delete;
// Updates the list of images to be cached to `image_url_list`. Processing the
// new list can download new images and delete images that are no longer being
// referenced in the new list.
void UpdateImageUrlList(const base::Value::List& image_url_list);
std::vector<base::FilePath> GetScreensaverImages();
// Used for setting images in tests.
void SetImagesForTesting(const std::vector<base::FilePath>& images);
base::FilePath GetDowloadDirForTesting();
private:
friend class ScreensaverImageDownloaderTest;
// Called when unreferenced images have been deleted. Used for removing stale
// file references from the in-memory `downloaded_images_` cache.
void OnUnreferencedImagesDeleted(
std::vector<base::FilePath> file_paths_deleted);
// Downloads a new external image from `image_url` to the download folder as
// `file_name`. The async `callback` will pass the result, and the file path
// if the operation succeeded.
void QueueImageDownload(const std::string& image_url);
// Empties the downloading queue, and replies to pending requests to indicate
// that they have been cancelled.
void ClearRequestQueue();
// Clears out the download folder.
void DeleteDownloadedImages();
// Verifies that the download directory is present and writable, or attempts
// to create it otherwise. The result of this operation is passed along to
// `OnVerifyDownloadDirectoryCompleted`.
void StartImageDownload(const std::string& image_url);
// Starts a new download if the download folder is present and writable.
// Otherwise, it completes the request with an error result.
void OnVerifyDownloadDirectoryCompleted(const std::string& image_url,
bool can_download_to_dir);
// Resolves the download request if the file is already cached, otherwise
// triggers a new URL request to download the file.
void OnCheckIsFileIsInCache(const base::FilePath& file_path,
const std::string& image_url,
bool is_file_present);
// Moves the downloaded image to its desired path. To avoid reading
// errors, every image is initially downloaded to a temporary file. On
// network error, `callback` is invoked.
void OnUrlDownloadedToTempFile(
std::unique_ptr<network::SimpleURLLoader> simple_loader,
const std::string& image_url,
base::FilePath temp_path);
// Handles the final result of the image download process, and triggers the
// complete `callback`.
void OnUrlDownloadToFileComplete(const base::FilePath& path,
const std::string& image_url,
bool file_is_present);
// Completes a download by calling `result` with `result` and `path`. It will
// attempt to start the next download, if any.
void FinishImageDownload(const std::string& image_url,
ScreensaverImageDownloadResult result,
std::optional<base::FilePath> path);
QueueState queue_state_ = QueueState::kWaiting;
// To avoid multiple URL requests, only one download can be executed.
// Additional downloads will be queued, and executed sequentially.
base::queue<std::string> downloading_queue_;
base::flat_set<base::FilePath> downloaded_images_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory_;
base::FilePath download_directory_;
// Used to notify changes in the list of downloaded images.
ImageListUpdatedCallback image_list_updated_callback_;
base::WeakPtrFactory<ScreensaverImageDownloader> weak_ptr_factory_{this};
};
} // namespace ash
#endif // ASH_AMBIENT_MANAGED_SCREENSAVER_IMAGE_DOWNLOADER_H_