2021-01-08 01:15:34 +01:00
|
|
|
/**
|
|
|
|
|
* Copyright (c) Microsoft Corporation.
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
2021-04-24 05:39:09 +02:00
|
|
|
import fs from 'fs';
|
|
|
|
|
import path from 'path';
|
2021-02-24 22:39:51 +01:00
|
|
|
import * as trace from '../common/traceEvents';
|
2021-03-09 04:49:57 +01:00
|
|
|
import { ContextResources, ResourceSnapshot } from '../../snapshot/snapshotTypes';
|
2021-04-24 05:39:09 +02:00
|
|
|
import { BaseSnapshotStorage, SnapshotStorage } from '../../snapshot/snapshotStorage';
|
2021-02-24 22:39:51 +01:00
|
|
|
export * as trace from '../common/traceEvents';
|
2021-01-08 01:15:34 +01:00
|
|
|
|
2021-02-24 23:22:34 +01:00
|
|
|
export class TraceModel {
|
2021-04-24 05:39:09 +02:00
|
|
|
contextEntry: ContextEntry | undefined;
|
|
|
|
|
pageEntries = new Map<string, PageEntry>();
|
2021-02-25 03:38:04 +01:00
|
|
|
contextResources = new Map<string, ContextResources>();
|
2021-04-24 05:39:09 +02:00
|
|
|
private _snapshotStorage: PersistentSnapshotStorage;
|
|
|
|
|
|
|
|
|
|
constructor(snapshotStorage: PersistentSnapshotStorage) {
|
|
|
|
|
this._snapshotStorage = snapshotStorage;
|
|
|
|
|
}
|
2021-01-08 01:15:34 +01:00
|
|
|
|
2021-03-09 04:49:57 +01:00
|
|
|
appendEvents(events: trace.TraceEvent[], snapshotStorage: SnapshotStorage) {
|
2021-02-24 23:22:34 +01:00
|
|
|
for (const event of events)
|
|
|
|
|
this.appendEvent(event);
|
2021-03-09 04:49:57 +01:00
|
|
|
const actions: ActionEntry[] = [];
|
2021-04-24 05:39:09 +02:00
|
|
|
for (const page of this.contextEntry!.pages)
|
|
|
|
|
actions.push(...page.actions);
|
2021-03-09 04:49:57 +01:00
|
|
|
|
|
|
|
|
const resources = snapshotStorage.resources().reverse();
|
|
|
|
|
actions.reverse();
|
|
|
|
|
|
|
|
|
|
for (const action of actions) {
|
2021-03-10 20:43:26 +01:00
|
|
|
while (resources.length && resources[0].timestamp > action.timestamp)
|
2021-03-09 04:49:57 +01:00
|
|
|
action.resources.push(resources.shift()!);
|
|
|
|
|
action.resources.reverse();
|
|
|
|
|
}
|
2021-02-24 23:22:34 +01:00
|
|
|
}
|
2021-02-18 02:51:57 +01:00
|
|
|
|
2021-02-24 23:22:34 +01:00
|
|
|
appendEvent(event: trace.TraceEvent) {
|
2021-01-08 01:15:34 +01:00
|
|
|
switch (event.type) {
|
2021-04-24 05:39:09 +02:00
|
|
|
case 'context-metadata': {
|
|
|
|
|
this.contextEntry = {
|
2021-01-08 01:15:34 +01:00
|
|
|
startTime: Number.MAX_VALUE,
|
|
|
|
|
endTime: Number.MIN_VALUE,
|
|
|
|
|
created: event,
|
|
|
|
|
pages: [],
|
2021-04-24 05:39:09 +02:00
|
|
|
};
|
2021-01-08 01:15:34 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'page-created': {
|
|
|
|
|
const pageEntry: PageEntry = {
|
|
|
|
|
created: event,
|
|
|
|
|
destroyed: undefined as any,
|
|
|
|
|
actions: [],
|
2021-01-16 03:30:55 +01:00
|
|
|
interestingEvents: [],
|
2021-04-07 23:32:12 +02:00
|
|
|
screencastFrames: [],
|
2021-01-08 01:15:34 +01:00
|
|
|
};
|
2021-04-24 05:39:09 +02:00
|
|
|
this.pageEntries.set(event.pageId, pageEntry);
|
|
|
|
|
this.contextEntry!.pages.push(pageEntry);
|
2021-01-08 01:15:34 +01:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'page-destroyed': {
|
2021-04-24 05:39:09 +02:00
|
|
|
this.pageEntries.get(event.pageId)!.destroyed = event;
|
2021-01-08 01:15:34 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2021-04-07 23:32:12 +02:00
|
|
|
case 'page-screencast-frame': {
|
2021-04-24 05:39:09 +02:00
|
|
|
this.pageEntries.get(event.pageId)!.screencastFrames.push(event);
|
2021-04-07 23:32:12 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2021-01-08 01:15:34 +01:00
|
|
|
case 'action': {
|
2021-03-10 20:43:26 +01:00
|
|
|
const metadata = event.metadata;
|
2021-04-24 05:39:09 +02:00
|
|
|
const pageEntry = this.pageEntries.get(metadata.pageId!)!;
|
2021-01-08 01:15:34 +01:00
|
|
|
const action: ActionEntry = {
|
2021-04-23 18:28:18 +02:00
|
|
|
actionId: metadata.id,
|
2021-03-10 20:43:26 +01:00
|
|
|
resources: [],
|
|
|
|
|
...event,
|
2021-01-08 01:15:34 +01:00
|
|
|
};
|
|
|
|
|
pageEntry.actions.push(action);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-01-16 03:30:55 +01:00
|
|
|
case 'dialog-opened':
|
|
|
|
|
case 'dialog-closed':
|
|
|
|
|
case 'navigation':
|
|
|
|
|
case 'load': {
|
2021-04-24 05:39:09 +02:00
|
|
|
const pageEntry = this.pageEntries.get(event.pageId)!;
|
2021-01-16 03:30:55 +01:00
|
|
|
pageEntry.interestingEvents.push(event);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2021-04-24 05:39:09 +02:00
|
|
|
case 'resource-snapshot':
|
|
|
|
|
this._snapshotStorage.addResource(event.snapshot);
|
|
|
|
|
break;
|
|
|
|
|
case 'frame-snapshot':
|
|
|
|
|
this._snapshotStorage.addFrameSnapshot(event.snapshot);
|
|
|
|
|
break;
|
2021-01-08 01:15:34 +01:00
|
|
|
}
|
2021-04-24 05:39:09 +02:00
|
|
|
this.contextEntry!.startTime = Math.min(this.contextEntry!.startTime, event.timestamp);
|
|
|
|
|
this.contextEntry!.endTime = Math.max(this.contextEntry!.endTime, event.timestamp);
|
2021-01-08 01:15:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-02-24 23:22:34 +01:00
|
|
|
export type ContextEntry = {
|
|
|
|
|
startTime: number;
|
|
|
|
|
endTime: number;
|
|
|
|
|
created: trace.ContextCreatedTraceEvent;
|
|
|
|
|
pages: PageEntry[];
|
2021-01-08 01:15:34 +01:00
|
|
|
}
|
|
|
|
|
|
2021-02-24 23:22:34 +01:00
|
|
|
export type InterestingPageEvent = trace.DialogOpenedEvent | trace.DialogClosedEvent | trace.NavigationEvent | trace.LoadEvent;
|
|
|
|
|
|
|
|
|
|
export type PageEntry = {
|
|
|
|
|
created: trace.PageCreatedTraceEvent;
|
|
|
|
|
destroyed: trace.PageDestroyedTraceEvent;
|
|
|
|
|
actions: ActionEntry[];
|
|
|
|
|
interestingEvents: InterestingPageEvent[];
|
2021-04-08 16:59:05 +02:00
|
|
|
screencastFrames: {
|
|
|
|
|
sha1: string,
|
|
|
|
|
timestamp: number,
|
|
|
|
|
width: number,
|
|
|
|
|
height: number,
|
|
|
|
|
}[]
|
2021-01-08 01:15:34 +01:00
|
|
|
}
|
2021-02-24 23:22:34 +01:00
|
|
|
|
2021-03-10 20:43:26 +01:00
|
|
|
export type ActionEntry = trace.ActionTraceEvent & {
|
2021-02-24 23:22:34 +01:00
|
|
|
actionId: string;
|
2021-03-09 04:49:57 +01:00
|
|
|
resources: ResourceSnapshot[]
|
2021-02-24 23:22:34 +01:00
|
|
|
};
|
2021-04-24 05:39:09 +02:00
|
|
|
|
|
|
|
|
export class PersistentSnapshotStorage extends BaseSnapshotStorage {
|
|
|
|
|
private _resourcesDir: string;
|
|
|
|
|
|
|
|
|
|
constructor(resourcesDir: string) {
|
|
|
|
|
super();
|
|
|
|
|
this._resourcesDir = resourcesDir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
resourceContent(sha1: string): Buffer | undefined {
|
|
|
|
|
return fs.readFileSync(path.join(this._resourcesDir, sha1));
|
|
|
|
|
}
|
|
|
|
|
}
|