зеркало из https://github.com/mozilla/gecko-dev.git
219 строки
5.8 KiB
JavaScript
219 строки
5.8 KiB
JavaScript
/* 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/. */
|
|
|
|
const lazy = {};
|
|
|
|
ChromeUtils.defineESModuleGetters(lazy, {
|
|
CommonNames: "resource:///modules/CommonNames.sys.mjs",
|
|
SnapshotGroups: "resource:///modules/SnapshotGroups.sys.mjs",
|
|
});
|
|
|
|
/**
|
|
* A builder for snapshot groups based on domains.
|
|
*/
|
|
export const DomainGroupBuilder = new (class DomainGroupBuilder {
|
|
/**
|
|
* @type {Map<string, object>}
|
|
* A map of domains to snapshot group data for groups that are currently in
|
|
* the database.
|
|
*/
|
|
#currentGroups = null;
|
|
|
|
/**
|
|
* @type {string}
|
|
* The name of the builder recorded in the groups.
|
|
*/
|
|
name = "domain";
|
|
|
|
/**
|
|
* @type {boolean}
|
|
* This will cause the minimum snapshot size check to be enforced.
|
|
*/
|
|
skipMinimumSize = false;
|
|
|
|
/**
|
|
* Rebuilds the domain groups from the complete list of snapshots.
|
|
*
|
|
* @param {Snapshot[]} snapshots
|
|
* The current array of snapshots in the database.
|
|
*/
|
|
async rebuild(snapshots) {
|
|
// Clear the current groups and rebuild.
|
|
this.#currentGroups = null;
|
|
await this.#maybeLoadGroups();
|
|
|
|
let untouchedDomains = new Set(this.#currentGroups.keys());
|
|
let changedDomains = new Set();
|
|
|
|
for (let snapshot of snapshots) {
|
|
let domain = this.#getDomain(snapshot.url);
|
|
if (!domain) {
|
|
continue;
|
|
}
|
|
|
|
untouchedDomains.delete(domain);
|
|
|
|
let group = this.#currentGroups.get(domain);
|
|
if (!group) {
|
|
this.#currentGroups.set(
|
|
domain,
|
|
this.#generateDomainData(domain, snapshot.url)
|
|
);
|
|
changedDomains.add(domain);
|
|
} else if (!group.urls.has(snapshot.url)) {
|
|
group.urls.add(snapshot.url);
|
|
changedDomains.add(domain);
|
|
}
|
|
}
|
|
|
|
// Untouched domains are ones which have no-urls, and therefore should
|
|
// be deleted.
|
|
for (let domain of [...untouchedDomains.values()]) {
|
|
let group = this.#currentGroups.get(domain);
|
|
await lazy.SnapshotGroups.delete(group.id);
|
|
this.#currentGroups.delete(domain);
|
|
}
|
|
|
|
for (let domain of [...changedDomains.values()]) {
|
|
await this.#checkDomain(domain);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Updates the domain snapshot groups based on the added and removed urls.
|
|
*
|
|
* @param {object} options
|
|
* @param {Set<object>} options.addedItems
|
|
* The added items (url, userPersisted) to handle in this update.
|
|
* @param {Set<string>} options.removedUrls
|
|
* The removed urls to handle in this update.
|
|
*/
|
|
async update({ addedItems, removedUrls }) {
|
|
await this.#maybeLoadGroups();
|
|
// Update the groups with the changes, and keep a note of the changed
|
|
// domains.
|
|
let changedDomains = new Set();
|
|
for (let { url } of addedItems.values()) {
|
|
let domain = this.#getDomain(url);
|
|
if (!domain) {
|
|
continue;
|
|
}
|
|
|
|
let group = this.#currentGroups.get(domain);
|
|
if (!group) {
|
|
this.#currentGroups.set(domain, this.#generateDomainData(domain, url));
|
|
changedDomains.add(domain);
|
|
} else if (!group.urls.has(url)) {
|
|
group.urls.add(url);
|
|
changedDomains.add(domain);
|
|
}
|
|
}
|
|
|
|
for (let url of removedUrls.values()) {
|
|
let domain = this.#getDomain(url);
|
|
if (!domain) {
|
|
continue;
|
|
}
|
|
|
|
let group = this.#currentGroups.get(domain);
|
|
if (group?.urls.has(url)) {
|
|
group.urls.delete(url);
|
|
changedDomains.add(domain);
|
|
}
|
|
}
|
|
|
|
// Check the saved groups are up to date.
|
|
for (let domain of changedDomains.values()) {
|
|
await this.#checkDomain(domain);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles checking a domain to see if it now should be added, updated
|
|
* or deleted in the snapshot groups in the database.
|
|
*
|
|
* @param {string} domain
|
|
* The domain that is being checked.
|
|
* @param {Set<string>} urls
|
|
* The updated set of urls for the domain.
|
|
*/
|
|
async #checkDomain(domain, urls) {
|
|
let group = this.#currentGroups.get(domain);
|
|
if (group.urls.size > 0) {
|
|
// If the group has an id, then it is already in the database.
|
|
if (group.id) {
|
|
await lazy.SnapshotGroups.updateUrls(group.id, [
|
|
...group.urls.values(),
|
|
]);
|
|
} else {
|
|
// This is a new group.
|
|
let id = await lazy.SnapshotGroups.add(group, [...group.urls.values()]);
|
|
group.id = id;
|
|
}
|
|
} else {
|
|
// This group no longer has entries, and needs to be removed.
|
|
await lazy.SnapshotGroups.delete(group.id);
|
|
this.#currentGroups.delete(domain);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Loads the current domain snapshot groups and all the snapshot urls from
|
|
* the database, and inserts them into #currentGroups.
|
|
*/
|
|
async #maybeLoadGroups() {
|
|
if (this.#currentGroups) {
|
|
return;
|
|
}
|
|
this.#currentGroups = new Map();
|
|
|
|
let groups = await lazy.SnapshotGroups.query({
|
|
builder: this.name,
|
|
limit: -1,
|
|
skipMinimum: true,
|
|
});
|
|
|
|
for (let group of groups) {
|
|
this.#currentGroups.set(group.builderMetadata.domain, group);
|
|
group.urls = new Set(
|
|
await lazy.SnapshotGroups.getUrls({ id: group.id, hidden: true })
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates the group information for a domain.
|
|
*
|
|
* @param {string} domain
|
|
* The domain of the group.
|
|
* @param {string} url
|
|
* The initial url being added to the group.
|
|
* @returns {SnapshotGroup}
|
|
*/
|
|
#generateDomainData(domain, url) {
|
|
return {
|
|
title: lazy.CommonNames.getURLName(new URL(url)),
|
|
builder: this.name,
|
|
builderMetadata: {
|
|
domain,
|
|
},
|
|
urls: new Set([url]),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Gets the domain of a URL.
|
|
*
|
|
* @param {string} url
|
|
* @returns {string}
|
|
*/
|
|
#getDomain(url) {
|
|
try {
|
|
return new URL(url).hostname;
|
|
} catch (ex) {
|
|
return null;
|
|
}
|
|
}
|
|
})();
|