ppd_metadata_manager.cc 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "chromeos/printing/ppd_metadata_manager.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include "base/containers/flat_map.h"
  11. #include "base/containers/queue.h"
  12. #include "base/containers/span.h"
  13. #include "base/json/json_reader.h"
  14. #include "base/logging.h"
  15. #include "base/memory/raw_ptr.h"
  16. #include "base/sequence_checker.h"
  17. #include "base/strings/strcat.h"
  18. #include "base/strings/string_piece.h"
  19. #include "base/strings/string_split.h"
  20. #include "base/strings/string_util.h"
  21. #include "base/strings/stringprintf.h"
  22. #include "base/time/clock.h"
  23. #include "base/time/time.h"
  24. #include "base/values.h"
  25. #include "chromeos/printing/ppd_metadata_parser.h"
  26. #include "chromeos/printing/ppd_provider.h"
  27. #include "chromeos/printing/printer_config_cache.h"
  28. #include "third_party/abseil-cpp/absl/types/optional.h"
  29. namespace chromeos {
  30. namespace {
  31. // Defines the containing directory of all metadata in the serving root.
  32. const char kMetadataParentDirectory[] = "metadata_v3";
  33. // Defines the number of shards of sharded metadata.
  34. constexpr int kNumShards = 20;
  35. // Defines the magic maximal number for USB vendor IDs and product IDs
  36. // (restricted to 16 bits).
  37. constexpr int kSixteenBitsMaximum = 0xffff;
  38. // Convenience struct containing parsed metadata of type T.
  39. template <typename T>
  40. struct ParsedMetadataWithTimestamp {
  41. base::Time time_of_parse;
  42. T value;
  43. };
  44. // Tracks the progress of a single call to
  45. // PpdMetadataManager::FindAllEmmsAvailableInIndex().
  46. class ForwardIndexSearchContext {
  47. public:
  48. ForwardIndexSearchContext(
  49. const std::vector<std::string>& emms,
  50. base::Time max_age,
  51. PpdMetadataManager::FindAllEmmsAvailableInIndexCallback cb)
  52. : emms_(emms), current_index_(), max_age_(max_age), cb_(std::move(cb)) {}
  53. ~ForwardIndexSearchContext() = default;
  54. ForwardIndexSearchContext(const ForwardIndexSearchContext&) = delete;
  55. ForwardIndexSearchContext& operator=(const ForwardIndexSearchContext&) =
  56. delete;
  57. ForwardIndexSearchContext(ForwardIndexSearchContext&&) = default;
  58. // The effective-make-and-model string currently being sought in the
  59. // forward index search tracked by this struct.
  60. base::StringPiece CurrentEmm() const {
  61. DCHECK_LT(current_index_, emms_.size());
  62. return emms_[current_index_];
  63. }
  64. // Returns whether the CurrentEmm() is the last one in |this|
  65. // that needs searching.
  66. bool CurrentEmmIsLast() const {
  67. DCHECK_LT(current_index_, emms_.size());
  68. return current_index_ + 1 == emms_.size();
  69. }
  70. void AdvanceToNextEmm() {
  71. DCHECK_LT(current_index_, emms_.size());
  72. current_index_++;
  73. }
  74. // Called when the PpdMetadataManager has searched all appropriate
  75. // forward index metadata for all |emms_|.
  76. void PostCallback() {
  77. DCHECK(CurrentEmmIsLast());
  78. base::SequencedTaskRunnerHandle::Get()->PostTask(
  79. FROM_HERE, base::BindOnce(std::move(cb_), cb_arg_));
  80. }
  81. // Called when the PpdMetadataManager successfully maps the
  82. // CurrentEmm() to a ParsedIndexValues struct.
  83. void AddDataFromForwardIndexForCurrentEmm(const ParsedIndexValues& value) {
  84. cb_arg_.insert_or_assign(CurrentEmm(), value);
  85. }
  86. base::Time MaxAge() const { return max_age_; }
  87. private:
  88. // List of all effective-make-and-model strings that caller gave to
  89. // PpdMetadataManager::FindAllEmmsAvailableInIndex().
  90. std::vector<std::string> emms_;
  91. // Index into |emms| that marks the effective-make-and-model string
  92. // currently being searched.
  93. size_t current_index_;
  94. // Freshness requirement for forward indices that this search reads.
  95. base::Time max_age_;
  96. // Callback that caller gave to
  97. // PpdMetadataManager::FindAllEmmsAvailableInIndex().
  98. PpdMetadataManager::FindAllEmmsAvailableInIndexCallback cb_;
  99. // Accrues data to pass to |cb|.
  100. base::flat_map<std::string, ParsedIndexValues> cb_arg_;
  101. };
  102. // Enqueues calls to PpdMetadataManager::FindAllEmmsAvailableInIndex().
  103. class ForwardIndexSearchQueue {
  104. public:
  105. ForwardIndexSearchQueue() = default;
  106. ~ForwardIndexSearchQueue() = default;
  107. ForwardIndexSearchQueue(const ForwardIndexSearchQueue&) = delete;
  108. ForwardIndexSearchQueue& operator=(const ForwardIndexSearchQueue&) = delete;
  109. void Enqueue(ForwardIndexSearchContext context) {
  110. contexts_.push(std::move(context));
  111. }
  112. bool IsIdle() const { return contexts_.empty(); }
  113. ForwardIndexSearchContext& CurrentContext() {
  114. DCHECK(!IsIdle());
  115. return contexts_.front();
  116. }
  117. // Progresses the frontmost search context, advancing it to its
  118. // next effective-make-and-model string to find in forward index
  119. // metadata.
  120. //
  121. // If the frontmost search context has no more
  122. // effective-make-and-model strings to search, then
  123. // 1. its callback is posted from here and
  124. // 2. it is popped off the |contexts| queue.
  125. void AdvanceToNextEmm() {
  126. DCHECK(!IsIdle());
  127. if (CurrentContext().CurrentEmmIsLast()) {
  128. CurrentContext().PostCallback();
  129. contexts_.pop();
  130. } else {
  131. CurrentContext().AdvanceToNextEmm();
  132. }
  133. }
  134. private:
  135. base::queue<ForwardIndexSearchContext> contexts_;
  136. };
  137. // Maps parsed metadata by name to parsed contents.
  138. //
  139. // Implementation note: the keys (metadata names) used here are
  140. // basenames attached to their containing directory - e.g.
  141. // * "metadata_v3/index-00.json"
  142. // * "metadata_v3/locales.json"
  143. // This is done to match up with the PrinterConfigCache class and
  144. // with the folder layout of the Chrome OS Printing serving root.
  145. template <typename T>
  146. using CachedParsedMetadataMap =
  147. base::flat_map<std::string, ParsedMetadataWithTimestamp<T>>;
  148. // Returns whether |map| has a value for |key| fresher than
  149. // |expiration|.
  150. template <typename T>
  151. bool MapHasValueFresherThan(const CachedParsedMetadataMap<T>& metadata_map,
  152. base::StringPiece key,
  153. base::Time expiration) {
  154. if (!metadata_map.contains(key)) {
  155. return false;
  156. }
  157. const auto& value = metadata_map.at(key);
  158. return value.time_of_parse > expiration;
  159. }
  160. // Calculates the shard number of |key| inside sharded metadata.
  161. int IndexShard(base::StringPiece key) {
  162. unsigned int hash = 5381;
  163. for (char c : key) {
  164. hash = hash * 33 + c;
  165. }
  166. return hash % kNumShards;
  167. }
  168. // Helper class used by PpdMetadataManagerImpl::SetMetadataLocale().
  169. // Sifts through the list of locales advertised by the Chrome OS
  170. // Printing serving root and selects the best match for a
  171. // particular browser locale.
  172. //
  173. // This class must not outlive any data it is fed.
  174. // This class is neither copyable nor movable.
  175. class MetadataLocaleFinder {
  176. public:
  177. explicit MetadataLocaleFinder(const std::string& browser_locale)
  178. : browser_locale_(browser_locale),
  179. browser_locale_pieces_(base::SplitStringPiece(browser_locale,
  180. "-",
  181. base::KEEP_WHITESPACE,
  182. base::SPLIT_WANT_ALL)),
  183. is_english_available_(false) {}
  184. ~MetadataLocaleFinder() = default;
  185. MetadataLocaleFinder(const MetadataLocaleFinder&) = delete;
  186. MetadataLocaleFinder& operator=(const MetadataLocaleFinder&) = delete;
  187. // Finds and returns the best-fit metadata locale from |locales|.
  188. // Returns the empty string if no best candidate was found.
  189. base::StringPiece BestCandidate(base::span<const std::string> locales) {
  190. AnalyzeCandidates(locales);
  191. if (!best_parent_locale_.empty()) {
  192. return best_parent_locale_;
  193. } else if (!best_distant_relative_locale_.empty()) {
  194. return best_distant_relative_locale_;
  195. } else if (is_english_available_) {
  196. return "en";
  197. }
  198. return base::StringPiece();
  199. }
  200. private:
  201. // Returns whether or not |locale| appears to be a parent of our
  202. // |browser_locale_|. For example, "en-GB" is a parent of "en-GB-foo."
  203. bool IsParentOfBrowserLocale(base::StringPiece locale) const {
  204. const std::string locale_with_trailing_hyphen = base::StrCat({locale, "-"});
  205. return base::StartsWith(browser_locale_, locale_with_trailing_hyphen);
  206. }
  207. // Updates our |best_distant_relative_locale_| to |locale| if we find
  208. // that it's a better match.
  209. //
  210. // The best distant relative locale is the one that
  211. // * has the longest piecewise match with |browser_locale_| but
  212. // * has the shortest piecewise length.
  213. // So given a |browser_locale_| "es," the better distant relative
  214. // locale between "es-GB" and "es-GB-foo" is "es-GB."
  215. void AnalyzeCandidateAsDistantRelative(base::StringPiece locale) {
  216. const std::vector<base::StringPiece> locale_pieces = base::SplitStringPiece(
  217. locale, "-", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL);
  218. const size_t locale_piecewise_length = locale_pieces.size();
  219. const size_t iter_limit =
  220. std::min(browser_locale_pieces_.size(), locale_piecewise_length);
  221. size_t locale_piecewise_match_length = 0;
  222. for (; locale_piecewise_match_length < iter_limit;
  223. locale_piecewise_match_length++) {
  224. if (locale_pieces[locale_piecewise_match_length] !=
  225. browser_locale_pieces_[locale_piecewise_match_length]) {
  226. break;
  227. }
  228. }
  229. if (locale_piecewise_match_length == 0) {
  230. return;
  231. } else if (locale_piecewise_match_length >
  232. best_distant_relative_locale_piecewise_match_length_ ||
  233. (locale_piecewise_match_length ==
  234. best_distant_relative_locale_piecewise_match_length_ &&
  235. locale_piecewise_length <
  236. best_distant_relative_locale_piecewise_length_)) {
  237. best_distant_relative_locale_ = std::string(locale);
  238. best_distant_relative_locale_piecewise_match_length_ =
  239. locale_piecewise_match_length;
  240. best_distant_relative_locale_piecewise_length_ = locale_piecewise_length;
  241. }
  242. }
  243. // Reads |locale| and updates our members as necessary.
  244. // For example, |locale| could reveal support for the "en" locale.
  245. void AnalyzeCandidate(base::StringPiece locale) {
  246. if (locale == "en") {
  247. is_english_available_ = true;
  248. }
  249. if (IsParentOfBrowserLocale(locale) &&
  250. locale.size() > best_parent_locale_.size()) {
  251. best_parent_locale_ = std::string(locale);
  252. } else if (best_parent_locale_.empty()) {
  253. // We need only track distant relative locales if we don't have a
  254. // |best_parent_locale_|, which is always a better choice.
  255. AnalyzeCandidateAsDistantRelative(locale);
  256. }
  257. }
  258. // Analyzes all candidate locales in |locales|, updating our
  259. // private members with best-fit locale(s).
  260. void AnalyzeCandidates(base::span<const std::string> locales) {
  261. for (base::StringPiece locale : locales) {
  262. // The serving root indicates direct support for our browser
  263. // locale; there's no need to analyze anything else, since this
  264. // is definitely the best match we're going to get.
  265. if (locale == browser_locale_) {
  266. best_parent_locale_ = std::string(browser_locale_);
  267. return;
  268. }
  269. AnalyzeCandidate(locale);
  270. }
  271. }
  272. const base::StringPiece browser_locale_;
  273. const std::vector<base::StringPiece> browser_locale_pieces_;
  274. // See IsParentOfBrowserLocale().
  275. std::string best_parent_locale_;
  276. // See AnalyzeCandidateAsDistantRelative().
  277. std::string best_distant_relative_locale_;
  278. size_t best_distant_relative_locale_piecewise_match_length_;
  279. size_t best_distant_relative_locale_piecewise_length_;
  280. // Denotes whether or not the Chrome OS Printing serving root serves
  281. // metadata for the "en" locale - our final fallback.
  282. bool is_english_available_;
  283. };
  284. // Represents the basename and containing directory of a piece of PPD
  285. // metadata. Does not own any strings given to its setter methods and
  286. // must not outlive them.
  287. class PpdMetadataPathSpecifier {
  288. public:
  289. enum class Type {
  290. kLocales,
  291. kManufacturers, // locale-sensitive
  292. kPrinters, // locale-sensitive
  293. kForwardIndex, // sharded
  294. kReverseIndex, // locale-sensitive; sharded
  295. kUsbIndex,
  296. kUsbVendorIds,
  297. };
  298. explicit PpdMetadataPathSpecifier(Type type)
  299. : type_(type),
  300. printers_basename_(nullptr),
  301. metadata_locale_(nullptr),
  302. shard_(0),
  303. usb_vendor_id_(0) {}
  304. ~PpdMetadataPathSpecifier() = default;
  305. // PpdMetadataPathSpecifier is neither copyable nor movable.
  306. PpdMetadataPathSpecifier(const PpdMetadataPathSpecifier&) = delete;
  307. PpdMetadataPathSpecifier& operator=(const PpdMetadataPathSpecifier&) = delete;
  308. void SetPrintersBasename(const char* const basename) {
  309. DCHECK_EQ(type_, Type::kPrinters);
  310. printers_basename_ = basename;
  311. }
  312. void SetMetadataLocale(const char* const locale) {
  313. DCHECK(type_ == Type::kManufacturers || type_ == Type::kReverseIndex);
  314. metadata_locale_ = locale;
  315. }
  316. void SetUsbVendorId(const int vendor_id) {
  317. DCHECK_EQ(type_, Type::kUsbIndex);
  318. usb_vendor_id_ = vendor_id;
  319. }
  320. void SetShard(const int shard) {
  321. DCHECK(type_ == Type::kForwardIndex || type_ == Type::kReverseIndex);
  322. shard_ = shard;
  323. }
  324. std::string AsString() const {
  325. switch (type_) {
  326. case Type::kLocales:
  327. return base::StringPrintf("%s/locales.json", kMetadataParentDirectory);
  328. case Type::kManufacturers:
  329. DCHECK(metadata_locale_);
  330. DCHECK(!base::StringPiece(metadata_locale_).empty());
  331. return base::StringPrintf("%s/manufacturers-%s.json",
  332. kMetadataParentDirectory, metadata_locale_);
  333. case Type::kPrinters:
  334. DCHECK(printers_basename_);
  335. DCHECK(!base::StringPiece(printers_basename_).empty());
  336. return base::StringPrintf("%s/%s", kMetadataParentDirectory,
  337. printers_basename_);
  338. case Type::kForwardIndex:
  339. DCHECK(shard_ >= 0 && shard_ < kNumShards);
  340. return base::StringPrintf("%s/index-%02d.json",
  341. kMetadataParentDirectory, shard_);
  342. case Type::kReverseIndex:
  343. DCHECK(metadata_locale_);
  344. DCHECK(!base::StringPiece(metadata_locale_).empty());
  345. DCHECK(shard_ >= 0 && shard_ < kNumShards);
  346. return base::StringPrintf("%s/reverse_index-%s-%02d.json",
  347. kMetadataParentDirectory, metadata_locale_,
  348. shard_);
  349. case Type::kUsbIndex:
  350. DCHECK(usb_vendor_id_ >= 0 && usb_vendor_id_ <= kSixteenBitsMaximum);
  351. return base::StringPrintf("%s/usb-%04x.json", kMetadataParentDirectory,
  352. usb_vendor_id_);
  353. case Type::kUsbVendorIds:
  354. return base::StringPrintf("%s/usb_vendor_ids.json",
  355. kMetadataParentDirectory);
  356. }
  357. // This function cannot fail except by maintainer error.
  358. NOTREACHED();
  359. return std::string();
  360. }
  361. // Private const char* members are const char* for compatibility with
  362. // base::StringPrintf().
  363. private:
  364. Type type_;
  365. // Populated only when |type_| == kPrinters.
  366. // Contains the basename of the target printers metadata file.
  367. const char* printers_basename_;
  368. // Populated only when |type_| is locale-sensitive and != kPrinters.
  369. // Contains the metadata locale for which we intend to fetch metadata.
  370. const char* metadata_locale_;
  371. // Populated only when |type_| is sharded.
  372. int shard_;
  373. // Populated only when |type_| == kUsbIndex.
  374. int usb_vendor_id_;
  375. };
  376. // Note: generally, each Get*() method is segmented into three parts:
  377. // 1. check if query can be answered immediately,
  378. // 2. fetch appropriate metadata if it can't [defer to On*Fetched()],
  379. // and (time passes)
  380. // 3. answer query with appropriate metadata [call On*Available()].
  381. class PpdMetadataManagerImpl : public PpdMetadataManager {
  382. public:
  383. PpdMetadataManagerImpl(base::StringPiece browser_locale,
  384. base::Clock* clock,
  385. std::unique_ptr<PrinterConfigCache> config_cache)
  386. : browser_locale_(browser_locale),
  387. clock_(clock),
  388. config_cache_(std::move(config_cache)),
  389. weak_factory_(this) {}
  390. ~PpdMetadataManagerImpl() override {
  391. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  392. }
  393. void GetLocale(GetLocaleCallback cb) override {
  394. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  395. // Per header comment: if a best-fit metadata locale is already set,
  396. // we don't refresh it; we just immediately declare success.
  397. //
  398. // Side effect: classes composing |this| can call
  399. // SetLocaleForTesting() before composition and get this cop-out
  400. // for free.
  401. if (!metadata_locale_.empty()) {
  402. base::SequencedTaskRunnerHandle::Get()->PostTask(
  403. FROM_HERE, base::BindOnce(std::move(cb), true));
  404. return;
  405. }
  406. PpdMetadataPathSpecifier path(PpdMetadataPathSpecifier::Type::kLocales);
  407. const std::string metadata_name = path.AsString();
  408. PrinterConfigCache::FetchCallback fetch_cb =
  409. base::BindOnce(&PpdMetadataManagerImpl::OnLocalesFetched,
  410. weak_factory_.GetWeakPtr(), std::move(cb));
  411. // We call Fetch() with a default-constructed TimeDelta(): "give
  412. // me the freshest possible locales metadata."
  413. config_cache_->Fetch(metadata_name, base::TimeDelta(), std::move(fetch_cb));
  414. }
  415. void GetManufacturers(base::TimeDelta age,
  416. PpdProvider::ResolveManufacturersCallback cb) override {
  417. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  418. DCHECK(!metadata_locale_.empty());
  419. PpdMetadataPathSpecifier path(
  420. PpdMetadataPathSpecifier::Type::kManufacturers);
  421. path.SetMetadataLocale(metadata_locale_.c_str());
  422. const std::string metadata_name = path.AsString();
  423. if (MapHasValueFresherThan(cached_manufacturers_, metadata_name,
  424. clock_->Now() - age)) {
  425. OnManufacturersAvailable(metadata_name, std::move(cb));
  426. return;
  427. }
  428. PrinterConfigCache::FetchCallback fetch_cb =
  429. base::BindOnce(&PpdMetadataManagerImpl::OnManufacturersFetched,
  430. weak_factory_.GetWeakPtr(), std::move(cb));
  431. config_cache_->Fetch(metadata_name, age, std::move(fetch_cb));
  432. }
  433. void GetPrinters(base::StringPiece manufacturer,
  434. base::TimeDelta age,
  435. GetPrintersCallback cb) override {
  436. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  437. DCHECK(!metadata_locale_.empty());
  438. const auto metadata_name = GetPrintersMetadataName(manufacturer);
  439. if (!metadata_name.has_value()) {
  440. base::SequencedTaskRunnerHandle::Get()->PostTask(
  441. FROM_HERE, base::BindOnce(std::move(cb), false, ParsedPrinters{}));
  442. return;
  443. }
  444. if (MapHasValueFresherThan(cached_printers_, metadata_name.value(),
  445. clock_->Now() - age)) {
  446. OnPrintersAvailable(metadata_name.value(), std::move(cb));
  447. return;
  448. }
  449. PrinterConfigCache::FetchCallback fetch_cb =
  450. base::BindOnce(&PpdMetadataManagerImpl::OnPrintersFetched,
  451. weak_factory_.GetWeakPtr(), std::move(cb));
  452. config_cache_->Fetch(metadata_name.value(), age, std::move(fetch_cb));
  453. }
  454. void FindAllEmmsAvailableInIndex(
  455. const std::vector<std::string>& emms,
  456. base::TimeDelta age,
  457. FindAllEmmsAvailableInIndexCallback cb) override {
  458. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  459. ForwardIndexSearchContext context(emms, clock_->Now() - age, std::move(cb));
  460. bool queue_was_idle = forward_index_search_queue_.IsIdle();
  461. forward_index_search_queue_.Enqueue(std::move(context));
  462. // If we are the prime movers, then we need to set the forward
  463. // index search in motion.
  464. if (queue_was_idle) {
  465. ContinueSearchingForwardIndices();
  466. }
  467. // If we're not the prime movers, then a search is already ongoing
  468. // and we need not provide extra impetus.
  469. }
  470. void FindDeviceInUsbIndex(int vendor_id,
  471. int product_id,
  472. base::TimeDelta age,
  473. FindDeviceInUsbIndexCallback cb) override {
  474. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  475. // Fails the |cb| immediately if the |vendor_id| or |product_id| are
  476. // obviously out of range.
  477. if (vendor_id < 0 || vendor_id > kSixteenBitsMaximum || product_id < 0 ||
  478. product_id > kSixteenBitsMaximum) {
  479. base::SequencedTaskRunnerHandle::Get()->PostTask(
  480. FROM_HERE, base::BindOnce(std::move(cb), std::string()));
  481. return;
  482. }
  483. PpdMetadataPathSpecifier path(PpdMetadataPathSpecifier::Type::kUsbIndex);
  484. path.SetUsbVendorId(vendor_id);
  485. const std::string metadata_name = path.AsString();
  486. if (MapHasValueFresherThan(cached_usb_indices_, metadata_name,
  487. clock_->Now() - age)) {
  488. OnUsbIndexAvailable(metadata_name, product_id, std::move(cb));
  489. return;
  490. }
  491. auto callback = base::BindOnce(&PpdMetadataManagerImpl::OnUsbIndexFetched,
  492. weak_factory_.GetWeakPtr(), metadata_name,
  493. product_id, std::move(cb));
  494. config_cache_->Fetch(metadata_name, age, std::move(callback));
  495. }
  496. void GetUsbManufacturerName(int vendor_id,
  497. base::TimeDelta age,
  498. GetUsbManufacturerNameCallback cb) override {
  499. PpdMetadataPathSpecifier path(
  500. PpdMetadataPathSpecifier::Type::kUsbVendorIds);
  501. const std::string metadata_name = path.AsString();
  502. if (MapHasValueFresherThan(cached_usb_vendor_id_map_, metadata_name,
  503. clock_->Now() - age)) {
  504. OnUsbVendorIdMapAvailable(metadata_name, vendor_id, std::move(cb));
  505. return;
  506. }
  507. auto fetch_cb =
  508. base::BindOnce(&PpdMetadataManagerImpl::OnUsbVendorIdMapFetched,
  509. weak_factory_.GetWeakPtr(), vendor_id, std::move(cb));
  510. config_cache_->Fetch(metadata_name, age, std::move(fetch_cb));
  511. }
  512. void SplitMakeAndModel(base::StringPiece effective_make_and_model,
  513. base::TimeDelta age,
  514. PpdProvider::ReverseLookupCallback cb) override {
  515. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  516. DCHECK(!metadata_locale_.empty());
  517. PpdMetadataPathSpecifier path(
  518. PpdMetadataPathSpecifier::Type::kReverseIndex);
  519. path.SetMetadataLocale(metadata_locale_.c_str());
  520. path.SetShard(IndexShard(effective_make_and_model));
  521. const std::string metadata_name = path.AsString();
  522. if (MapHasValueFresherThan(cached_reverse_indices_, metadata_name,
  523. clock_->Now() - age)) {
  524. OnReverseIndexAvailable(metadata_name, effective_make_and_model,
  525. std::move(cb));
  526. return;
  527. }
  528. PrinterConfigCache::FetchCallback fetch_cb =
  529. base::BindOnce(&PpdMetadataManagerImpl::OnReverseIndexFetched,
  530. weak_factory_.GetWeakPtr(),
  531. std::string(effective_make_and_model), std::move(cb));
  532. config_cache_->Fetch(metadata_name, age, std::move(fetch_cb));
  533. }
  534. PrinterConfigCache* GetPrinterConfigCacheForTesting() const override {
  535. return config_cache_.get();
  536. }
  537. void SetLocaleForTesting(base::StringPiece locale) override {
  538. metadata_locale_ = std::string(locale);
  539. }
  540. // This method should read much the same as OnManufacturersFetched().
  541. bool SetManufacturersForTesting(
  542. base::StringPiece manufacturers_json) override {
  543. DCHECK(!metadata_locale_.empty());
  544. const auto parsed = ParseManufacturers(manufacturers_json);
  545. if (!parsed.has_value()) {
  546. return false;
  547. }
  548. // We need to name the manufacturers metadata manually to store it.
  549. PpdMetadataPathSpecifier path(
  550. PpdMetadataPathSpecifier::Type::kManufacturers);
  551. path.SetMetadataLocale(metadata_locale_.c_str());
  552. const std::string manufacturers_name = path.AsString();
  553. ParsedMetadataWithTimestamp<ParsedManufacturers> value = {clock_->Now(),
  554. parsed.value()};
  555. cached_manufacturers_.insert_or_assign(manufacturers_name, value);
  556. return true;
  557. }
  558. base::StringPiece ExposeMetadataLocaleForTesting() const override {
  559. return metadata_locale_;
  560. }
  561. private:
  562. // Denotes the status of an ongoing forward index search - see
  563. // FindAllEmmsAvailableInIndex().
  564. enum class ForwardIndexSearchStatus {
  565. // We called |config_cache_|::Fetch(). We provided a bound
  566. // callback that will resume the forward index search for us when
  567. // the fetch completes.
  568. kWillResumeOnFetchCompletion,
  569. // We did not call |config_cache_|::Fetch(), so |this| still has
  570. // control of the progression of the forward index search.
  571. kCanContinue,
  572. };
  573. // Called by OnLocalesFetched().
  574. // Continues a prior call to GetLocale().
  575. //
  576. // Attempts to set |metadata_locale_| given the advertised
  577. // |locales_list|. Returns true if successful and false if not.
  578. bool SetMetadataLocale(const std::vector<std::string>& locales_list) {
  579. // This class helps track all the locales that _could_ be good fits
  580. // given our |browser_locale_| but which are not exact matches.
  581. MetadataLocaleFinder locale_finder(browser_locale_);
  582. metadata_locale_ = std::string(locale_finder.BestCandidate(locales_list));
  583. return !metadata_locale_.empty();
  584. }
  585. // Called back by |config_cache_|.Fetch().
  586. // Continues a prior call to GetLocale().
  587. //
  588. // On successful |result|, parses and sets the |metadata_locale_|.
  589. // Calls |cb| with the |result|.
  590. void OnLocalesFetched(GetLocaleCallback cb,
  591. const PrinterConfigCache::FetchResult& result) {
  592. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  593. if (!result.succeeded) {
  594. base::SequencedTaskRunnerHandle::Get()->PostTask(
  595. FROM_HERE, base::BindOnce(std::move(cb), false));
  596. return;
  597. }
  598. const auto parsed = ParseLocales(result.contents);
  599. if (!parsed.has_value()) {
  600. base::SequencedTaskRunnerHandle::Get()->PostTask(
  601. FROM_HERE, base::BindOnce(std::move(cb), false));
  602. return;
  603. }
  604. // SetMetadataLocale() _can_ fail, but that would be an
  605. // extraordinarily bad thing - i.e. that the Chrome OS Printing
  606. // serving root is itself in an invalid state.
  607. base::SequencedTaskRunnerHandle::Get()->PostTask(
  608. FROM_HERE,
  609. base::BindOnce(std::move(cb), SetMetadataLocale(parsed.value())));
  610. }
  611. // Called by one of
  612. // * GetManufacturers() or
  613. // * OnManufacturersFetched().
  614. // Continues a prior call to GetManufacturers().
  615. //
  616. // Invokes |cb| with success, providing it with a list of
  617. // manufacturers.
  618. void OnManufacturersAvailable(base::StringPiece metadata_name,
  619. PpdProvider::ResolveManufacturersCallback cb) {
  620. const auto& parsed_manufacturers = cached_manufacturers_.at(metadata_name);
  621. std::vector<std::string> manufacturers_for_cb;
  622. for (const auto& iter : parsed_manufacturers.value) {
  623. manufacturers_for_cb.push_back(iter.first);
  624. }
  625. std::sort(manufacturers_for_cb.begin(), manufacturers_for_cb.end());
  626. base::SequencedTaskRunnerHandle::Get()->PostTask(
  627. FROM_HERE,
  628. base::BindOnce(std::move(cb), PpdProvider::CallbackResultCode::SUCCESS,
  629. manufacturers_for_cb));
  630. }
  631. // Called by |config_cache_|.Fetch().
  632. // Continues a prior call to GetManufacturers().
  633. //
  634. // Parses and updates our cached map of manufacturers if |result|
  635. // indicates a successful fetch. Calls |cb| accordingly.
  636. void OnManufacturersFetched(PpdProvider::ResolveManufacturersCallback cb,
  637. const PrinterConfigCache::FetchResult& result) {
  638. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  639. if (!result.succeeded) {
  640. base::SequencedTaskRunnerHandle::Get()->PostTask(
  641. FROM_HERE,
  642. base::BindOnce(std::move(cb),
  643. PpdProvider::CallbackResultCode::SERVER_ERROR,
  644. std::vector<std::string>{}));
  645. return;
  646. }
  647. const auto parsed = ParseManufacturers(result.contents);
  648. if (!parsed.has_value()) {
  649. base::SequencedTaskRunnerHandle::Get()->PostTask(
  650. FROM_HERE,
  651. base::BindOnce(std::move(cb),
  652. PpdProvider::CallbackResultCode::INTERNAL_ERROR,
  653. std::vector<std::string>{}));
  654. return;
  655. }
  656. ParsedMetadataWithTimestamp<ParsedManufacturers> value = {clock_->Now(),
  657. parsed.value()};
  658. cached_manufacturers_.insert_or_assign(result.key, value);
  659. OnManufacturersAvailable(result.key, std::move(cb));
  660. }
  661. // Called by GetPrinters().
  662. // Returns the known name for the Printers metadata named by
  663. // |manufacturer|.
  664. absl::optional<std::string> GetPrintersMetadataName(
  665. base::StringPiece manufacturer) {
  666. PpdMetadataPathSpecifier manufacturers_path(
  667. PpdMetadataPathSpecifier::Type::kManufacturers);
  668. manufacturers_path.SetMetadataLocale(metadata_locale_.c_str());
  669. const std::string manufacturers_metadata_name =
  670. manufacturers_path.AsString();
  671. if (!cached_manufacturers_.contains(manufacturers_metadata_name)) {
  672. // This is likely a bug: we don't have the expected manufacturers
  673. // metadata.
  674. return absl::nullopt;
  675. }
  676. const ParsedMetadataWithTimestamp<ParsedManufacturers>& manufacturers =
  677. cached_manufacturers_.at(manufacturers_metadata_name);
  678. if (!manufacturers.value.contains(manufacturer)) {
  679. // This is likely a bug: we don't know about this manufacturer.
  680. return absl::nullopt;
  681. }
  682. PpdMetadataPathSpecifier printers_path(
  683. PpdMetadataPathSpecifier::Type::kPrinters);
  684. printers_path.SetPrintersBasename(
  685. manufacturers.value.at(manufacturer).c_str());
  686. return printers_path.AsString();
  687. }
  688. // Called by one of
  689. // * GetPrinters() or
  690. // * OnPrintersFetched().
  691. // Continues a prior call to GetPrinters().
  692. //
  693. // Invokes |cb| with success, providing it a map of printers.
  694. void OnPrintersAvailable(base::StringPiece metadata_name,
  695. GetPrintersCallback cb) {
  696. const auto& parsed_printers = cached_printers_.at(metadata_name);
  697. base::SequencedTaskRunnerHandle::Get()->PostTask(
  698. FROM_HERE, base::BindOnce(std::move(cb), true, parsed_printers.value));
  699. }
  700. // Called by |config_cache_|.Fetch().
  701. // Continues a prior call to GetPrinters().
  702. //
  703. // Parses and updates our cached map of printers if |result| indicates
  704. // a successful fetch. Calls |cb| accordingly.
  705. void OnPrintersFetched(GetPrintersCallback cb,
  706. const PrinterConfigCache::FetchResult& result) {
  707. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  708. if (!result.succeeded) {
  709. base::SequencedTaskRunnerHandle::Get()->PostTask(
  710. FROM_HERE, base::BindOnce(std::move(cb), false, ParsedPrinters{}));
  711. return;
  712. }
  713. const auto parsed = ParsePrinters(result.contents);
  714. if (!parsed.has_value()) {
  715. base::SequencedTaskRunnerHandle::Get()->PostTask(
  716. FROM_HERE, base::BindOnce(std::move(cb), false, ParsedPrinters{}));
  717. return;
  718. }
  719. ParsedMetadataWithTimestamp<ParsedPrinters> value = {clock_->Now(),
  720. parsed.value()};
  721. cached_printers_.insert_or_assign(result.key, value);
  722. OnPrintersAvailable(result.key, std::move(cb));
  723. }
  724. // Called when one unit of sufficiently fresh forward index metadata
  725. // is available. Seeks out the current effective-make-and-model string
  726. // in said metadata.
  727. void FindEmmInForwardIndex(base::StringPiece metadata_name) {
  728. // Caller must have verified that this index is already present (and
  729. // sufficiently fresh) before entering this method.
  730. DCHECK(cached_forward_indices_.contains(metadata_name));
  731. ForwardIndexSearchContext& context =
  732. forward_index_search_queue_.CurrentContext();
  733. const ParsedIndex& index = cached_forward_indices_.at(metadata_name).value;
  734. const auto& iter = index.find(context.CurrentEmm());
  735. if (iter != index.end()) {
  736. context.AddDataFromForwardIndexForCurrentEmm(iter->second);
  737. }
  738. forward_index_search_queue_.AdvanceToNextEmm();
  739. }
  740. // Called by |config_cache_|.Fetch().
  741. // Continues a prior call to FindAllEmmsAvailableInForwardIndex().
  742. //
  743. // Parses and updates our cached map of forward indices if |result|
  744. // indicates a successful fetch. Continues the action that
  745. // necessitated fetching the present forward index.
  746. void OnForwardIndexFetched(const PrinterConfigCache::FetchResult& result) {
  747. if (!result.succeeded) {
  748. // We failed to fetch the forward index containing the current
  749. // effective-make-and-model string. There's nothing we can do but
  750. // carry on, e.g. by moving to deal with the next emm.
  751. forward_index_search_queue_.AdvanceToNextEmm();
  752. ContinueSearchingForwardIndices();
  753. return;
  754. }
  755. const auto parsed = ParseForwardIndex(result.contents);
  756. if (!parsed.has_value()) {
  757. // Same drill as fetch failure above.
  758. forward_index_search_queue_.AdvanceToNextEmm();
  759. ContinueSearchingForwardIndices();
  760. return;
  761. }
  762. ParsedMetadataWithTimestamp<ParsedIndex> value = {clock_->Now(),
  763. parsed.value()};
  764. cached_forward_indices_.insert_or_assign(result.key, value);
  765. ContinueSearchingForwardIndices();
  766. }
  767. // Works on searching the forward index for the current
  768. // effective-make-and-model string in the frontmost entry in the
  769. // forward index search queue.
  770. //
  771. // One invocation of this method ultimately processes exactly one
  772. // effective-make-and-model string: either we find it in some forward
  773. // index metadata or we don't.
  774. ForwardIndexSearchStatus SearchForwardIndicesForOneEmm() {
  775. const ForwardIndexSearchContext& context =
  776. forward_index_search_queue_.CurrentContext();
  777. PpdMetadataPathSpecifier path(
  778. PpdMetadataPathSpecifier::Type::kForwardIndex);
  779. path.SetShard(IndexShard(context.CurrentEmm()));
  780. const std::string forward_index_name = path.AsString();
  781. if (MapHasValueFresherThan(cached_forward_indices_, forward_index_name,
  782. context.MaxAge())) {
  783. // We have the appropriate forward index metadata and it's fresh
  784. // enough to make a determination: is the current
  785. // effective-make-and-model string present in this metadata?
  786. FindEmmInForwardIndex(forward_index_name);
  787. return ForwardIndexSearchStatus::kCanContinue;
  788. }
  789. // We don't have the appropriate forward index metadata. We need to
  790. // get it before we can determine if the current
  791. // effective-make-and-model string is present in it.
  792. //
  793. // PrinterConfigCache::Fetch() accepts a TimeDelta expressing the
  794. // maximum permissible age of the cached response; to simulate the
  795. // original TimeDelta that caller gave to
  796. // FindAllEmmsAvailableInIndex(), we find the delta between Now()
  797. // and the absolute time ceiling recorded in the
  798. // ForwardIndexSearchContext.
  799. auto callback =
  800. base::BindOnce(&PpdMetadataManagerImpl::OnForwardIndexFetched,
  801. weak_factory_.GetWeakPtr());
  802. config_cache_->Fetch(forward_index_name, clock_->Now() - context.MaxAge(),
  803. std::move(callback));
  804. return ForwardIndexSearchStatus::kWillResumeOnFetchCompletion;
  805. }
  806. // Continues working on the forward index search queue.
  807. void ContinueSearchingForwardIndices() {
  808. while (!forward_index_search_queue_.IsIdle()) {
  809. ForwardIndexSearchStatus status = SearchForwardIndicesForOneEmm();
  810. // If we invoked |config_cache_|::Fetch(), then control has passed
  811. // out of this class for now. It will resume from
  812. // OnForwardIndexFetched().
  813. if (status == ForwardIndexSearchStatus::kWillResumeOnFetchCompletion) {
  814. break;
  815. }
  816. }
  817. }
  818. // Called by one of
  819. // * FindDeviceInUsbIndex() or
  820. // * OnUsbIndexFetched().
  821. // Searches the now-available USB index metadata with |metadata_name|
  822. // for a device with given |product_id|, calling |cb| appropriately.
  823. void OnUsbIndexAvailable(base::StringPiece metadata_name,
  824. int product_id,
  825. FindDeviceInUsbIndexCallback cb) {
  826. DCHECK(cached_usb_indices_.contains(metadata_name));
  827. const ParsedUsbIndex& usb_index =
  828. cached_usb_indices_.at(metadata_name).value;
  829. const auto& iter = usb_index.find(product_id);
  830. std::string effective_make_and_model;
  831. if (iter != usb_index.end()) {
  832. effective_make_and_model = iter->second;
  833. }
  834. base::SequencedTaskRunnerHandle::Get()->PostTask(
  835. FROM_HERE,
  836. base::BindOnce(std::move(cb), std::move(effective_make_and_model)));
  837. }
  838. // Called by |config_cache_|.Fetch().
  839. // Continues a prior call to FindDeviceInUsbIndex().
  840. //
  841. // Parses and updates our cached map of USB index metadata if |result|
  842. // indicates a successful fetch.
  843. void OnUsbIndexFetched(std::string metadata_name,
  844. int product_id,
  845. FindDeviceInUsbIndexCallback cb,
  846. const PrinterConfigCache::FetchResult& fetch_result) {
  847. if (!fetch_result.succeeded) {
  848. base::SequencedTaskRunnerHandle::Get()->PostTask(
  849. FROM_HERE, base::BindOnce(std::move(cb), std::string()));
  850. return;
  851. }
  852. absl::optional<ParsedUsbIndex> parsed =
  853. ParseUsbIndex(fetch_result.contents);
  854. if (!parsed.has_value()) {
  855. base::SequencedTaskRunnerHandle::Get()->PostTask(
  856. FROM_HERE, base::BindOnce(std::move(cb), std::string()));
  857. return;
  858. }
  859. DCHECK(fetch_result.key == metadata_name);
  860. ParsedMetadataWithTimestamp<ParsedUsbIndex> value = {clock_->Now(),
  861. parsed.value()};
  862. cached_usb_indices_.insert_or_assign(fetch_result.key, value);
  863. OnUsbIndexAvailable(fetch_result.key, product_id, std::move(cb));
  864. }
  865. // Called by one of
  866. // * GetUsbManufacturerName() or
  867. // * OnUsbVendorIdMapFetched().
  868. //
  869. // Searches the available USB vendor ID map (named by |metadata_name|)
  870. // for |vendor_id| and invokes |cb| accordingly.
  871. void OnUsbVendorIdMapAvailable(base::StringPiece metadata_name,
  872. int vendor_id,
  873. GetUsbManufacturerNameCallback cb) {
  874. DCHECK(cached_usb_vendor_id_map_.contains(metadata_name));
  875. ParsedUsbVendorIdMap usb_vendor_id_map =
  876. cached_usb_vendor_id_map_.at(metadata_name).value;
  877. std::string manufacturer_name;
  878. const auto& iter = usb_vendor_id_map.find(vendor_id);
  879. if (iter != usb_vendor_id_map.end()) {
  880. manufacturer_name = iter->second;
  881. }
  882. base::SequencedTaskRunnerHandle::Get()->PostTask(
  883. FROM_HERE, base::BindOnce(std::move(cb), manufacturer_name));
  884. }
  885. // Called by |config_cache_|->Fetch().
  886. // Continues a prior call to GetUsbManufacturerName.
  887. //
  888. // Parses and updates our cached map of USB vendor IDs if |result|
  889. // indicates a successful fetch.
  890. //
  891. // If we're haggling over bits, it is wasteful to have a map that
  892. // only ever has at most one key-value pair. We willfully accept this
  893. // inefficiency to maintain consistency with other metadata
  894. // operations.
  895. void OnUsbVendorIdMapFetched(
  896. int vendor_id,
  897. GetUsbManufacturerNameCallback cb,
  898. const PrinterConfigCache::FetchResult& fetch_result) {
  899. if (!fetch_result.succeeded) {
  900. base::SequencedTaskRunnerHandle::Get()->PostTask(
  901. FROM_HERE, base::BindOnce(std::move(cb), std::string()));
  902. return;
  903. }
  904. const absl::optional<ParsedUsbVendorIdMap> parsed =
  905. ParseUsbVendorIdMap(fetch_result.contents);
  906. if (!parsed.has_value()) {
  907. base::SequencedTaskRunnerHandle::Get()->PostTask(
  908. FROM_HERE, base::BindOnce(std::move(cb), std::string()));
  909. return;
  910. }
  911. ParsedMetadataWithTimestamp<ParsedUsbVendorIdMap> value = {clock_->Now(),
  912. parsed.value()};
  913. cached_usb_vendor_id_map_.insert_or_assign(fetch_result.key, value);
  914. OnUsbVendorIdMapAvailable(fetch_result.key, vendor_id, std::move(cb));
  915. }
  916. // Called by one of
  917. // * SplitMakeAndModel() or
  918. // * OnReverseIndexFetched().
  919. // Continues a prior call to SplitMakeAndModel().
  920. //
  921. // Looks for |effective_make_and_model| in the reverse index named by
  922. // |metadata_name|, and tries to invoke |cb| with the split make and
  923. // model.
  924. void OnReverseIndexAvailable(base::StringPiece metadata_name,
  925. base::StringPiece effective_make_and_model,
  926. PpdProvider::ReverseLookupCallback cb) {
  927. const auto& parsed_reverse_index =
  928. cached_reverse_indices_.at(metadata_name);
  929. // We expect this reverse index shard to contain the decomposition
  930. // for |effective_make_and_model|.
  931. if (!parsed_reverse_index.value.contains(effective_make_and_model)) {
  932. base::SequencedTaskRunnerHandle::Get()->PostTask(
  933. FROM_HERE,
  934. base::BindOnce(std::move(cb),
  935. PpdProvider::CallbackResultCode::NOT_FOUND, "", ""));
  936. return;
  937. }
  938. const ReverseIndexLeaf& leaf =
  939. parsed_reverse_index.value.at(effective_make_and_model);
  940. base::SequencedTaskRunnerHandle::Get()->PostTask(
  941. FROM_HERE,
  942. base::BindOnce(std::move(cb), PpdProvider::CallbackResultCode::SUCCESS,
  943. leaf.manufacturer, leaf.model));
  944. }
  945. // Called by |config_cache_|.Fetch().
  946. // Continues a prior call to SplitMakeAndModel().
  947. //
  948. // Parses and updates our cached map of reverse indices if |result|
  949. // indicates a successful fetch. Calls |cb| accordingly.
  950. void OnReverseIndexFetched(std::string effective_make_and_model,
  951. PpdProvider::ReverseLookupCallback cb,
  952. const PrinterConfigCache::FetchResult& result) {
  953. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  954. if (!result.succeeded) {
  955. base::SequencedTaskRunnerHandle::Get()->PostTask(
  956. FROM_HERE,
  957. base::BindOnce(std::move(cb),
  958. PpdProvider::CallbackResultCode::SERVER_ERROR, "",
  959. ""));
  960. return;
  961. }
  962. const auto parsed = ParseReverseIndex(result.contents);
  963. if (!parsed.has_value()) {
  964. base::SequencedTaskRunnerHandle::Get()->PostTask(
  965. FROM_HERE,
  966. base::BindOnce(std::move(cb),
  967. PpdProvider::CallbackResultCode::INTERNAL_ERROR, "",
  968. ""));
  969. return;
  970. }
  971. ParsedMetadataWithTimestamp<ParsedReverseIndex> value = {clock_->Now(),
  972. parsed.value()};
  973. cached_reverse_indices_.insert_or_assign(result.key, value);
  974. OnReverseIndexAvailable(result.key, effective_make_and_model,
  975. std::move(cb));
  976. }
  977. const std::string browser_locale_;
  978. raw_ptr<const base::Clock> clock_;
  979. // The closest match to |browser_locale_| for which the serving root
  980. // claims to serve metadata.
  981. std::string metadata_locale_;
  982. std::unique_ptr<PrinterConfigCache> config_cache_;
  983. CachedParsedMetadataMap<ParsedManufacturers> cached_manufacturers_;
  984. CachedParsedMetadataMap<ParsedPrinters> cached_printers_;
  985. CachedParsedMetadataMap<ParsedIndex> cached_forward_indices_;
  986. CachedParsedMetadataMap<ParsedUsbIndex> cached_usb_indices_;
  987. CachedParsedMetadataMap<ParsedUsbVendorIdMap> cached_usb_vendor_id_map_;
  988. CachedParsedMetadataMap<ParsedReverseIndex> cached_reverse_indices_;
  989. // Processing queue for FindAllEmmsAvailableInIndex().
  990. ForwardIndexSearchQueue forward_index_search_queue_;
  991. SEQUENCE_CHECKER(sequence_checker_);
  992. // Dispenses weak pointers to the |config_cache_|. This is necessary
  993. // because |this| could be deleted while the |config_cache_| is
  994. // processing something off-sequence.
  995. base::WeakPtrFactory<PpdMetadataManagerImpl> weak_factory_;
  996. };
  997. } // namespace
  998. // static
  999. std::unique_ptr<PpdMetadataManager> PpdMetadataManager::Create(
  1000. base::StringPiece browser_locale,
  1001. base::Clock* clock,
  1002. std::unique_ptr<PrinterConfigCache> config_cache) {
  1003. return std::make_unique<PpdMetadataManagerImpl>(browser_locale, clock,
  1004. std::move(config_cache));
  1005. }
  1006. } // namespace chromeos