Bug 1943650 - Command-line --help output misformatted after --dbus-service. r=emilio
[gecko.git] / toolkit / components / antitracking / bouncetrackingprotection / BTPRemoteExceptionList.sys.mjs
bloba61bc4ae0af5b49266ab7c74382c03d4cb33fe98
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 const lazy = {};
7 ChromeUtils.defineESModuleGetters(lazy, {
8   RemoteSettings: "resource://services-settings/remote-settings.sys.mjs",
9 });
11 // Name of the RemoteSettings collection containing the rules.
12 const COLLECTION_NAME = "bounce-tracking-protection-exceptions";
14 export class BTPRemoteExceptionList {
15   classId = Components.ID("{06F13674-FB28-4DFC-BF25-342C83705B2F}");
16   QueryInterface = ChromeUtils.generateQI(["nsIBTPRemoteExceptionList"]);
18   #rs = null;
19   // Stores the this-wrapped on-sync callback so it can be unregistered on
20   // shutdown.
21   #onSyncCallback = null;
23   // Weak reference to nsIBounceTrackingProtection.
24   #btp = null;
26   constructor() {
27     this.#rs = lazy.RemoteSettings(COLLECTION_NAME);
28   }
30   async init(bounceTrackingProtection) {
31     if (!bounceTrackingProtection) {
32       throw new Error("Missing required argument bounceTrackingProtection");
33     }
34     // Get a weak ref to BounceTrackingProtection to avoid a reference cycle.
35     this.#btp = Cu.getWeakReference(bounceTrackingProtection);
37     await this.importAllExceptions();
39     // Register callback for collection changes.
40     // Only register if not already registered.
41     if (!this.#onSyncCallback) {
42       this.#onSyncCallback = this.onSync.bind(this);
43       this.#rs.on("sync", this.#onSyncCallback);
44     }
45   }
47   shutdown() {
48     // Unregister callback for collection changes.
49     if (this.#onSyncCallback) {
50       this.#rs.off("sync", this.#onSyncCallback);
51       this.#onSyncCallback = null;
52     }
53   }
55   /**
56    * Called for remote settings "sync" events.
57    */
58   onSync({ data: { created = [], updated = [], deleted = [] } }) {
59     // Check if feature is still active before attempting to send updates.
60     let btp = this.#btp?.get();
61     if (!btp) {
62       return;
63     }
65     let siteHostsToRemove = deleted.map(ex => ex.siteHost);
66     let siteHostsToAdd = created.map(ex => ex.siteHost);
68     updated.forEach(ex => {
69       // We only care about site host changes.
70       if (ex.old.siteHost == ex.new.siteHost) {
71         return;
72       }
73       siteHostsToRemove.push(ex.old.siteHost);
74       siteHostsToAdd.push(ex.new.siteHost);
75     });
77     if (siteHostsToRemove.length) {
78       btp.removeSiteHostExceptions(siteHostsToRemove);
79     }
80     if (siteHostsToAdd.length) {
81       btp.addSiteHostExceptions(siteHostsToAdd);
82     }
83   }
85   async importAllExceptions() {
86     try {
87       let exceptions = await this.#rs.get();
88       if (!exceptions.length) {
89         return;
90       }
91       this.onSync({ data: { created: exceptions } });
92     } catch (error) {
93       console.error(
94         "Error while importing BTP exceptions from RemoteSettings",
95         error
96       );
97     }
98   }