[go: nahoru, domu]

blob: ccf62130d23f8fc57938d4343ad1811183ab4a28 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BATCH_ELEMENT_CHECKER_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BATCH_ELEMENT_CHECKER_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/callback.h"
#include "base/callback_forward.h"
#include "base/callback_helpers.h"
#include "base/containers/flat_map.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "components/autofill_assistant/browser/client_status.h"
#include "components/autofill_assistant/browser/selector.h"
#include "components/autofill_assistant/browser/service.pb.h"
#include "components/autofill_assistant/browser/web/element.h"
#include "components/autofill_assistant/browser/web/element_finder.h"
#include "components/autofill_assistant/browser/web/selector_observer.h"
namespace autofill_assistant {
class WebController;
// Helper for checking a set of elements at the same time. It avoids duplicate
// checks.
class BatchElementChecker {
public:
explicit BatchElementChecker();
BatchElementChecker(const BatchElementChecker&) = delete;
BatchElementChecker& operator=(const BatchElementChecker&) = delete;
virtual ~BatchElementChecker();
// Callback for AddFieldValueCheck. Argument is true is the element exists.
// The string contains the field value, or an empty string if accessing the
// value failed.
//
// An ElementCheckCallback must not delete its calling BatchElementChecker.
using GetFieldValueCallback =
base::OnceCallback<void(const ClientStatus&, const std::string&)>;
// Callback for AddElementConditionCheck. Arguments are a client status
// (Element Resolution Failed if couldn't find element), a vector of payloads,
// and a map of client_id's to the resulting elements.
//
// An ElementConditionCheckCallback must not delete its calling
// BatchElementChecker.
using ElementConditionCheckCallback = base::OnceCallback<void(
const ClientStatus&,
const std::vector<std::string>& payloads,
const std::vector<std::string>& tags,
const base::flat_map<std::string, DomObjectFrameStack>&)>;
// Returns true if element condition is empty.
static bool IsElementConditionEmpty(const ElementConditionProto& proto);
// Checks an element precondition
//
// New element precondition checks cannot be added once Run has been called.
void AddElementConditionCheck(const ElementConditionProto& selector,
ElementConditionCheckCallback callback);
// Gets the value of |selector| and return the result through |callback|. The
// returned value will be the empty string in case of error or empty value.
//
// New field checks cannot be added once Run has been called.
void AddFieldValueCheck(const Selector& selector,
GetFieldValueCallback callback);
// A callback to call once all the elements have been checked. These callbacks
// are guaranteed to be called in order.
//
// These callback are allowed to delete the current instance.
void AddAllDoneCallback(base::OnceCallback<void()> all_done);
// Returns true if all there are no checks to run.
bool empty() const;
// Turns on observer mode. When BatchElementChecker runs in observer mode, it
// waits until any element condition checks or element checks become true.
void EnableObserver(base::TimeDelta max_wait_time,
base::TimeDelta periodic_check_interval,
base::TimeDelta extra_timeout);
// Runs the checks. Once all checks are done, calls the callbacks registered
// to AddAllDoneCallback().
void Run(WebController* web_controller);
private:
// Not using absl::optional because it's hard to see what "if (var)" means.
struct MatchResult {
bool checked = false;
bool match_result = false;
bool matches() { return checked && match_result; }
};
// Results of one independent |Selector| within one |ElementCondition|.
struct Result {
Result();
~Result();
Result(const Result&);
// Selector checked.
Selector selector;
// Result of checking that selector.
MatchResult match{/* checked= */ false, /* match_result= */ false};
// The identifier given to this result through the script. This identifier
// can be used to later find the element in the |ElementStore|.
absl::optional<std::string> client_id;
// Whether the matching should be done strict or not.
bool strict = false;
// Used in SelectorObserver runs, element_id to retrieve result from
// SelectorObserver.
int element_id = -1;
};
struct ElementConditionCheck {
ElementConditionCheck();
~ElementConditionCheck();
ElementConditionCheck(ElementConditionCheck&&);
// Result of individual |Selector|s within the |ElementCondition|.
std::vector<Result> results;
// Callback called with the result after the check is done (if observer
// mode is enabled) or after one condition matches (if observer mode
// is disabled).
ElementConditionCheckCallback callback;
// |ElementConditionProto| to check.
ElementConditionProto proto;
// Resulting found elements. Key is the |client_id| in the |Match|
// |ElementCondition|s (used to refer to this element in the scripts), value
// is the found element.
base::flat_map<std::string, DomObjectFrameStack> elements;
};
void RunWithObserver(WebController* web_controller);
// Gets called for each Selector checked.
void OnSelectorChecked(
std::vector<std::pair</* element_condition_index */ size_t,
/* result_index */ size_t>>* results,
const ClientStatus& element_status,
std::unique_ptr<ElementFinder::Result> element_result);
void OnElementPreconditionChecked(
std::vector<ElementConditionCheckCallback>* callbacks,
const ClientStatus& element_status);
// Gets called for each FieldValueCheck.
void OnFieldValueChecked(std::vector<GetFieldValueCallback>* callbacks,
const ClientStatus& status,
const std::string& value);
void CheckDone();
void FinishedCallbacks();
void CallAllCallbacksWithError(const ClientStatus& status);
// Add selectors from |proto| to |results_|, doing a depth-first search.
void AddElementConditionResults(const ElementConditionProto& proto,
size_t element_condition_index);
MatchResult EvaluateElementPrecondition(const ElementConditionProto& proto,
const std::vector<Result>& results,
size_t* results_iter,
std::vector<std::string>* payloads,
std::vector<std::string>* tags);
void CheckElementConditions();
void OnResultsUpdated(const ClientStatus& status,
const std::vector<SelectorObserver::Update>& updates,
SelectorObserver* selector_observer);
void OnGetElementsDone(const ClientStatus& status,
const base::flat_map<SelectorObserver::SelectorId,
DomObjectFrameStack>& elements);
// A way to find unique selectors and what |Result|'s are affected by them.
//
// Must not be modified after |Run()| is called because it's referenced by
// index.
base::flat_map<std::pair<Selector, /* strict */ bool>,
std::vector<std::pair</* element_condition_index */ size_t,
/* result_index */ size_t>>>
unique_selectors_;
// Must not be modified after |Run()| is called because it's referenced by
// index.
std::vector<ElementConditionCheck> element_condition_checks_;
// A map of GetFieldValue arguments (selector) to callbacks that take the
// field value.
base::flat_map<Selector, std::vector<GetFieldValueCallback>>
get_field_value_callbacks_;
int pending_checks_count_ = 0;
// Run() was called. Checking elements might or might not have finished yet.
bool started_ = false;
// Whether to wait until one of the conditions becomes true.
bool use_observers_ = false;
base::TimeDelta observer_max_wait_time_;
base::TimeDelta observer_periodic_check_interval_;
base::TimeDelta observer_extra_timeout_;
std::vector<base::OnceCallback<void()>> all_done_;
base::WeakPtrFactory<BatchElementChecker> weak_ptr_factory_{this};
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_BATCH_ELEMENT_CHECKER_H_