| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef EXTENSIONS_RENDERER_BINDINGS_API_EVENT_HANDLER_H_ |
| #define EXTENSIONS_RENDERER_BINDINGS_API_EVENT_HANDLER_H_ |
| |
| #include <string> |
| |
| #include "base/functional/callback.h" |
| #include "base/memory/raw_ptr.h" |
| #include "extensions/common/mojom/event_dispatcher.mojom-forward.h" |
| #include "extensions/renderer/bindings/api_binding_types.h" |
| #include "extensions/renderer/bindings/api_event_listeners.h" |
| #include "extensions/renderer/bindings/event_emitter.h" |
| #include "extensions/renderer/bindings/listener_tracker.h" |
| #include "v8/include/v8.h" |
| |
| namespace extensions { |
| class APIResponseValidator; |
| class ExceptionHandler; |
| |
| // The object to handle API events. This includes vending v8::Objects for the |
| // event; handling adding, removing, and querying listeners; and firing events |
| // to subscribed listeners. Designed to be used across JS contexts, but on a |
| // single thread. |
| class APIEventHandler { |
| public: |
| // A callback to retrieve the owner of the context's identity. This allows us |
| // to associate multiple listeners from different v8::Contexts with the same |
| // owner (e.g., extension). |
| using ContextOwnerIdGetter = |
| base::RepeatingCallback<std::string(v8::Local<v8::Context>)>; |
| |
| APIEventHandler(const APIEventListeners::ListenersUpdated& listeners_changed, |
| const ContextOwnerIdGetter& context_owner_id_getter, |
| ExceptionHandler* exception_handler); |
| |
| APIEventHandler(const APIEventHandler&) = delete; |
| APIEventHandler& operator=(const APIEventHandler&) = delete; |
| |
| ~APIEventHandler(); |
| |
| // Sets the response validator to be used in verifying event arguments. |
| void SetResponseValidator(std::unique_ptr<APIResponseValidator> validator); |
| |
| // Returns a new v8::Object for an event with the given `event_name`. If |
| // `notify_on_change` is true, notifies whenever listeners state is changed. |
| // TODO(devlin): Maybe worth creating a Params struct to hold the event |
| // information? |
| v8::Local<v8::Object> CreateEventInstance(const std::string& event_name, |
| bool supports_filters, |
| bool supports_lazy_listeners, |
| int max_listeners, |
| bool notify_on_change, |
| v8::Local<v8::Context> context); |
| |
| // Creates a new event without any name. This is used by custom bindings when |
| // the entirety of the logic for the event is contained in the renderer. These |
| // events do not notify of new/removed listeners or allow for dispatching |
| // through FireEventInContext(). |
| v8::Local<v8::Object> CreateAnonymousEventInstance( |
| v8::Local<v8::Context> context); |
| |
| // Invalidates the given `event`. |
| void InvalidateCustomEvent(v8::Local<v8::Context> context, |
| v8::Local<v8::Object> event); |
| |
| // Notifies all listeners of the event with the given `event_name` in the |
| // specified `context`, sending the included `arguments`. |
| // `on_dispatched_callback` allows the caller to specify a `v8::Function` to |
| // be called with the results of the listener event dispatch. |
| // `listener_error_callback` is an optional callback that is invoked |
| // immediately when a listener throws an exception. The exception is passed as |
| // the single argument to the callback. |
| // Warning: This runs arbitrary JS code, so the `context` may be invalidated |
| // after this! |
| void FireEventInContext(const std::string& event_name, |
| v8::Local<v8::Context> context, |
| const base::Value::List& arguments, |
| mojom::EventFilteringInfoPtr filter); |
| void FireEventInContext(const std::string& event_name, |
| v8::Local<v8::Context> context, |
| v8::LocalVector<v8::Value>* arguments, |
| mojom::EventFilteringInfoPtr filter, |
| v8::Local<v8::Function> on_dispatched_callback, |
| v8::Local<v8::Function> listener_error_callback); |
| |
| // Registers a `function` to serve as an "argument massager" for the given |
| // `event_name`, mutating the original arguments. |
| // The function is called with two arguments: the array of original arguments |
| // being dispatched to the event, and the function to dispatch the event to |
| // listeners. |
| void RegisterArgumentMassager(v8::Local<v8::Context> context, |
| const std::string& event_name, |
| v8::Local<v8::Function> function); |
| |
| // Returns true if there is a listener for the given `event_name` in the |
| // given `context`. |
| bool HasListenerForEvent(const std::string& event_name, |
| v8::Local<v8::Context> context); |
| |
| // Invalidates listeners for the given `context`. It's a shame we have to |
| // have this separately (as opposed to hooking into e.g. a PerContextData |
| // destructor), but we need to do this before the context is fully removed |
| // (because the associated extension ScriptContext needs to be valid). |
| void InvalidateContext(v8::Local<v8::Context> context); |
| |
| // Returns the number of event listeners for a given `event_name` and |
| // `context`. |
| size_t GetNumEventListenersForTesting(const std::string& event_name, |
| v8::Local<v8::Context> context); |
| |
| private: |
| APIEventListeners::ListenersUpdated listeners_changed_; |
| |
| ContextOwnerIdGetter context_owner_id_getter_; |
| |
| // The shared ListenerTracker for all listeners in the system. |
| ListenerTracker listener_tracker_; |
| |
| // The exception handler associated with the bindings system; guaranteed to |
| // outlive this object. |
| const raw_ptr<ExceptionHandler> exception_handler_; |
| |
| // The response validator used to verify event arguments. Only non-null if |
| // validation is enabled. |
| std::unique_ptr<APIResponseValidator> api_response_validator_; |
| }; |
| |
| } // namespace extensions |
| |
| #endif // EXTENSIONS_RENDERER_BINDINGS_API_EVENT_HANDLER_H_ |