chrome-devtools-frontend
Version:
Chrome DevTools UI
205 lines (165 loc) • 7.79 kB
text/typescript
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type * as ProtocolProxyApi from '../../generated/protocol-proxy-api.js';
import type * as Protocol from '../../generated/protocol.js';
import type * as Common from '../common/common.js';
import {SDKModel} from './SDKModel.js';
import {Events as StorageKeyManagerEvents, StorageKeyManager} from './StorageKeyManager.js';
import {Capability, type Target} from './Target.js';
export class StorageBucketsModel extends SDKModel<EventTypes> implements ProtocolProxyApi.StorageDispatcher {
private enabled = false;
readonly storageAgent: ProtocolProxyApi.StorageApi;
private readonly storageKeyManager: StorageKeyManager|null;
private bucketsById = new Map<string, Protocol.Storage.StorageBucketInfo>();
private trackedStorageKeys = new Set<string>();
constructor(target: Target) {
super(target);
target.registerStorageDispatcher(this);
this.storageAgent = target.storageAgent();
this.storageKeyManager = target.model(StorageKeyManager);
}
getBuckets(): Set<Protocol.Storage.StorageBucketInfo> {
return new Set(this.bucketsById.values());
}
getBucketsForStorageKey(storageKey: string): Set<Protocol.Storage.StorageBucketInfo> {
const buckets = [...this.bucketsById.values()];
return new Set(buckets.filter(({bucket}) => bucket.storageKey === storageKey));
}
getDefaultBucketForStorageKey(storageKey: string): Protocol.Storage.StorageBucketInfo|null {
const buckets = [...this.bucketsById.values()];
return buckets.find(({bucket}) => bucket.storageKey === storageKey && bucket.name === undefined) ?? null;
}
getBucketById(bucketId: string): Protocol.Storage.StorageBucketInfo|null {
return this.bucketsById.get(bucketId) ?? null;
}
getBucketByName(storageKey: string, bucketName?: string): Protocol.Storage.StorageBucketInfo|null {
if (!bucketName) {
return this.getDefaultBucketForStorageKey(storageKey);
}
const buckets = [...this.bucketsById.values()];
return buckets.find(({bucket}) => bucket.storageKey === storageKey && bucket.name === bucketName) ?? null;
}
deleteBucket(bucket: Protocol.Storage.StorageBucket): void {
void this.storageAgent.invoke_deleteStorageBucket({bucket});
}
enable(): void {
if (this.enabled) {
return;
}
if (this.storageKeyManager) {
this.storageKeyManager.addEventListener(StorageKeyManagerEvents.STORAGE_KEY_ADDED, this.storageKeyAdded, this);
this.storageKeyManager.addEventListener(
StorageKeyManagerEvents.STORAGE_KEY_REMOVED, this.storageKeyRemoved, this);
for (const storageKey of this.storageKeyManager.storageKeys()) {
this.addStorageKey(storageKey);
}
}
this.enabled = true;
}
private storageKeyAdded(event: Common.EventTarget.EventTargetEvent<string>): void {
this.addStorageKey(event.data);
}
private storageKeyRemoved(event: Common.EventTarget.EventTargetEvent<string>): void {
this.removeStorageKey(event.data);
}
private addStorageKey(storageKey: string): void {
if (this.trackedStorageKeys.has(storageKey)) {
throw new Error('Can\'t call addStorageKey for a storage key if it has already been added.');
}
this.trackedStorageKeys.add(storageKey);
void this.storageAgent.invoke_setStorageBucketTracking({storageKey, enable: true});
}
private removeStorageKey(storageKey: string): void {
if (!this.trackedStorageKeys.has(storageKey)) {
throw new Error('Can\'t call removeStorageKey for a storage key if it hasn\'t already been added.');
}
const bucketsForStorageKey = this.getBucketsForStorageKey(storageKey);
for (const bucket of bucketsForStorageKey) {
this.bucketRemoved(bucket);
}
this.trackedStorageKeys.delete(storageKey);
void this.storageAgent.invoke_setStorageBucketTracking({storageKey, enable: false});
}
private bucketAdded(bucketInfo: Protocol.Storage.StorageBucketInfo): void {
this.bucketsById.set(bucketInfo.id, bucketInfo);
this.dispatchEventToListeners(Events.BUCKET_ADDED, {model: this, bucketInfo});
}
private bucketRemoved(bucketInfo: Protocol.Storage.StorageBucketInfo): void {
this.bucketsById.delete(bucketInfo.id);
this.dispatchEventToListeners(Events.BUCKET_REMOVED, {model: this, bucketInfo});
}
private bucketChanged(bucketInfo: Protocol.Storage.StorageBucketInfo): void {
this.dispatchEventToListeners(Events.BUCKET_CHANGED, {model: this, bucketInfo});
}
private bucketInfosAreEqual(
bucketInfo1: Protocol.Storage.StorageBucketInfo, bucketInfo2: Protocol.Storage.StorageBucketInfo): boolean {
return bucketInfo1.bucket.storageKey === bucketInfo2.bucket.storageKey && bucketInfo1.id === bucketInfo2.id &&
bucketInfo1.bucket.name === bucketInfo2.bucket.name && bucketInfo1.expiration === bucketInfo2.expiration &&
bucketInfo1.quota === bucketInfo2.quota && bucketInfo1.persistent === bucketInfo2.persistent &&
bucketInfo1.durability === bucketInfo2.durability;
}
storageBucketCreatedOrUpdated({bucketInfo}: Protocol.Storage.StorageBucketCreatedOrUpdatedEvent): void {
const curBucket = this.getBucketById(bucketInfo.id);
if (curBucket) {
if (!this.bucketInfosAreEqual(curBucket, bucketInfo)) {
this.bucketChanged(bucketInfo);
}
} else {
this.bucketAdded(bucketInfo);
}
}
storageBucketDeleted({bucketId}: Protocol.Storage.StorageBucketDeletedEvent): void {
const curBucket = this.getBucketById(bucketId);
if (curBucket) {
this.bucketRemoved(curBucket);
} else {
throw new Error(
`Received an event that Storage Bucket '${bucketId}' was deleted, but it wasn't in the StorageBucketsModel.`);
}
}
attributionReportingTriggerRegistered(_event: Protocol.Storage.AttributionReportingTriggerRegisteredEvent): void {
}
interestGroupAccessed(_event: Protocol.Storage.InterestGroupAccessedEvent): void {
}
interestGroupAuctionEventOccurred(_event: Protocol.Storage.InterestGroupAuctionEventOccurredEvent): void {
}
interestGroupAuctionNetworkRequestCreated(_event: Protocol.Storage.InterestGroupAuctionNetworkRequestCreatedEvent):
void {
}
indexedDBListUpdated(_event: Protocol.Storage.IndexedDBListUpdatedEvent): void {
}
indexedDBContentUpdated(_event: Protocol.Storage.IndexedDBContentUpdatedEvent): void {
}
cacheStorageListUpdated(_event: Protocol.Storage.CacheStorageListUpdatedEvent): void {
}
cacheStorageContentUpdated(_event: Protocol.Storage.CacheStorageContentUpdatedEvent): void {
}
sharedStorageAccessed(_event: Protocol.Storage.SharedStorageAccessedEvent): void {
}
sharedStorageWorkletOperationExecutionFinished(
_event: Protocol.Storage.SharedStorageWorkletOperationExecutionFinishedEvent): void {
}
attributionReportingSourceRegistered(_event: Protocol.Storage.AttributionReportingSourceRegisteredEvent): void {
}
attributionReportingReportSent(_event: Protocol.Storage.AttributionReportingReportSentEvent): void {
}
attributionReportingVerboseDebugReportSent(_event: Protocol.Storage.AttributionReportingVerboseDebugReportSentEvent):
void {
}
}
SDKModel.register(StorageBucketsModel, {capabilities: Capability.STORAGE, autostart: false});
export const enum Events {
BUCKET_ADDED = 'BucketAdded',
BUCKET_REMOVED = 'BucketRemoved',
BUCKET_CHANGED = 'BucketChanged',
}
export interface BucketEvent {
model: StorageBucketsModel;
bucketInfo: Protocol.Storage.StorageBucketInfo;
}
export interface EventTypes {
[Events.BUCKET_ADDED]: BucketEvent;
[Events.BUCKET_REMOVED]: BucketEvent;
[Events.BUCKET_CHANGED]: BucketEvent;
}