123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- "use strict";
- const {ActivityStreamMessageChannel} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamMessageChannel.jsm");
- const {ActivityStreamStorage} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamStorage.jsm");
- const {Prefs} = ChromeUtils.import("resource://activity-stream/lib/ActivityStreamPrefs.jsm");
- const {reducers} = ChromeUtils.import("resource://activity-stream/common/Reducers.jsm");
- const {redux} = ChromeUtils.import("resource://activity-stream/vendor/Redux.jsm");
- /**
- * Store - This has a similar structure to a redux store, but includes some extra
- * functionality to allow for routing of actions between the Main processes
- * and child processes via a ActivityStreamMessageChannel.
- * It also accepts an array of "Feeds" on inititalization, which
- * can listen for any action that is dispatched through the store.
- */
- this.Store = class Store {
- /**
- * constructor - The redux store and message manager are created here,
- * but no listeners are added until "init" is called.
- */
- constructor() {
- this._middleware = this._middleware.bind(this);
- // Bind each redux method so we can call it directly from the Store. E.g.,
- // store.dispatch() will call store._store.dispatch();
- for (const method of ["dispatch", "getState", "subscribe"]) {
- this[method] = (...args) => this._store[method](...args);
- }
- this.feeds = new Map();
- this._prefs = new Prefs();
- this._messageChannel = new ActivityStreamMessageChannel({dispatch: this.dispatch});
- this._store = redux.createStore(
- redux.combineReducers(reducers),
- redux.applyMiddleware(this._middleware, this._messageChannel.middleware)
- );
- this.storage = null;
- }
- /**
- * _middleware - This is redux middleware consumed by redux.createStore.
- * it calls each feed's .onAction method, if one
- * is defined.
- */
- _middleware() {
- return next => action => {
- next(action);
- for (const store of this.feeds.values()) {
- if (store.onAction) {
- store.onAction(action);
- }
- }
- };
- }
- /**
- * initFeed - Initializes a feed by calling its constructor function
- *
- * @param {string} feedName The name of a feed, as defined in the object
- * passed to Store.init
- * @param {Action} initAction An optional action to initialize the feed
- */
- initFeed(feedName, initAction) {
- const feed = this._feedFactories.get(feedName)();
- feed.store = this;
- this.feeds.set(feedName, feed);
- if (initAction && feed.onAction) {
- feed.onAction(initAction);
- }
- }
- /**
- * uninitFeed - Removes a feed and calls its uninit function if defined
- *
- * @param {string} feedName The name of a feed, as defined in the object
- * passed to Store.init
- * @param {Action} uninitAction An optional action to uninitialize the feed
- */
- uninitFeed(feedName, uninitAction) {
- const feed = this.feeds.get(feedName);
- if (!feed) {
- return;
- }
- if (uninitAction && feed.onAction) {
- feed.onAction(uninitAction);
- }
- this.feeds.delete(feedName);
- }
- /**
- * onPrefChanged - Listener for handling feed changes.
- */
- onPrefChanged(name, value) {
- if (this._feedFactories.has(name)) {
- if (value) {
- this.initFeed(name, this._initAction);
- } else {
- this.uninitFeed(name, this._uninitAction);
- }
- }
- }
- /**
- * init - Initializes the ActivityStreamMessageChannel channel, and adds feeds.
- *
- * Note that it intentionally initializes the TelemetryFeed first so that the
- * addon is able to report the init errors from other feeds.
- *
- * @param {Map} feedFactories A Map of feeds with the name of the pref for
- * the feed as the key and a function that
- * constructs an instance of the feed.
- * @param {Action} initAction An optional action that will be dispatched
- * to feeds when they're created.
- * @param {Action} uninitAction An optional action for when feeds uninit.
- */
- async init(feedFactories, initAction, uninitAction) {
- this._feedFactories = feedFactories;
- this._initAction = initAction;
- this._uninitAction = uninitAction;
- const telemetryKey = "feeds.telemetry";
- if (feedFactories.has(telemetryKey) && this._prefs.get(telemetryKey)) {
- this.initFeed(telemetryKey);
- }
- await this._initIndexedDB(telemetryKey);
- for (const pref of feedFactories.keys()) {
- if (pref !== telemetryKey && this._prefs.get(pref)) {
- this.initFeed(pref);
- }
- }
- this._prefs.observeBranch(this);
- this._messageChannel.createChannel();
- // Dispatch an initial action after all enabled feeds are ready
- if (initAction) {
- this.dispatch(initAction);
- }
- // Dispatch NEW_TAB_INIT/NEW_TAB_LOAD events after INIT event.
- this._messageChannel.simulateMessagesForExistingTabs();
- }
- async _initIndexedDB(telemetryKey) {
- this.dbStorage = new ActivityStreamStorage({
- storeNames: ["sectionPrefs", "snippets"],
- telemetry: this.feeds.get(telemetryKey),
- });
- // Accessing the db causes the object stores to be created / migrated.
- // This needs to happen before other instances try to access the db, which
- // would update only a subset of the stores to the latest version.
- try {
- await this.dbStorage.db; // eslint-disable-line no-unused-expressions
- } catch (e) {
- this.dbStorage.telemetry = null;
- }
- }
- /**
- * uninit - Uninitalizes each feed, clears them, and destroys the message
- * manager channel.
- *
- * @return {type} description
- */
- uninit() {
- if (this._uninitAction) {
- this.dispatch(this._uninitAction);
- }
- this._prefs.ignoreBranch(this);
- this.feeds.clear();
- this._feedFactories = null;
- this._messageChannel.destroyChannel();
- }
- };
- const EXPORTED_SYMBOLS = ["Store"];
|