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 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_
|