| 
									
										
										
										
											2023-05-05 15:12:18 -07: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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import type zip from '@zip.js/zip.js'; | 
					
						
							|  |  |  | // @ts-ignore
 | 
					
						
							| 
									
										
										
										
											2023-09-13 18:39:10 +02:00
										 |  |  | import * as zipImport from '@zip.js/zip.js/lib/zip-no-worker-inflate.js'; | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  | import type { TraceModelBackend } from './traceModel'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const zipjs = zipImport as typeof zip; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-13 18:39:10 +02:00
										 |  |  | type Progress = (done: number, total: number) => undefined; | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | export class ZipTraceModelBackend implements TraceModelBackend { | 
					
						
							| 
									
										
										
										
											2023-09-13 18:39:10 +02:00
										 |  |  |   private _zipReader: zip.ZipReader<unknown>; | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  |   private _entriesPromise: Promise<Map<string, zip.Entry>>; | 
					
						
							|  |  |  |   private _traceURL: string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(traceURL: string, progress: Progress) { | 
					
						
							|  |  |  |     this._traceURL = traceURL; | 
					
						
							| 
									
										
										
										
											2023-09-13 18:39:10 +02:00
										 |  |  |     zipjs.configure({ baseURL: self.location.href } as any); | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  |     this._zipReader = new zipjs.ZipReader( | 
					
						
							| 
									
										
										
										
											2024-01-17 10:40:58 -08:00
										 |  |  |         new zipjs.HttpReader(formatUrl(traceURL), { mode: 'cors', preventHeadRequest: true } as any), | 
					
						
							| 
									
										
										
										
											2023-09-13 18:39:10 +02:00
										 |  |  |         { useWebWorkers: false }); | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  |     this._entriesPromise = this._zipReader.getEntries({ onprogress: progress }).then(entries => { | 
					
						
							|  |  |  |       const map = new Map<string, zip.Entry>(); | 
					
						
							|  |  |  |       for (const entry of entries) | 
					
						
							|  |  |  |         map.set(entry.filename, entry); | 
					
						
							|  |  |  |       return map; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   isLive() { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   traceURL() { | 
					
						
							|  |  |  |     return this._traceURL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async entryNames(): Promise<string[]> { | 
					
						
							|  |  |  |     const entries = await this._entriesPromise; | 
					
						
							|  |  |  |     return [...entries.keys()]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async hasEntry(entryName: string): Promise<boolean> { | 
					
						
							|  |  |  |     const entries = await this._entriesPromise; | 
					
						
							|  |  |  |     return entries.has(entryName); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async readText(entryName: string): Promise<string | undefined> { | 
					
						
							|  |  |  |     const entries = await this._entriesPromise; | 
					
						
							|  |  |  |     const entry = entries.get(entryName); | 
					
						
							|  |  |  |     if (!entry) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     const writer = new zipjs.TextWriter(); | 
					
						
							|  |  |  |     await entry.getData?.(writer); | 
					
						
							|  |  |  |     return writer.getData(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async readBlob(entryName: string): Promise<Blob | undefined> { | 
					
						
							|  |  |  |     const entries = await this._entriesPromise; | 
					
						
							|  |  |  |     const entry = entries.get(entryName); | 
					
						
							|  |  |  |     if (!entry) | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     const writer = new zipjs.BlobWriter() as zip.BlobWriter; | 
					
						
							|  |  |  |     await entry.getData!(writer); | 
					
						
							|  |  |  |     return writer.getData(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export class FetchTraceModelBackend implements TraceModelBackend { | 
					
						
							|  |  |  |   private _entriesPromise: Promise<Map<string, string>>; | 
					
						
							|  |  |  |   private _traceURL: string; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   constructor(traceURL: string) { | 
					
						
							|  |  |  |     this._traceURL = traceURL; | 
					
						
							| 
									
										
										
										
											2023-06-26 18:13:40 +02:00
										 |  |  |     this._entriesPromise = fetch('/trace/file?path=' + encodeURIComponent(traceURL)).then(async response => { | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  |       const json = JSON.parse(await response.text()); | 
					
						
							|  |  |  |       const entries = new Map<string, string>(); | 
					
						
							|  |  |  |       for (const entry of json.entries) | 
					
						
							|  |  |  |         entries.set(entry.name, entry.path); | 
					
						
							|  |  |  |       return entries; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   isLive() { | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   traceURL(): string { | 
					
						
							|  |  |  |     return this._traceURL; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async entryNames(): Promise<string[]> { | 
					
						
							|  |  |  |     const entries = await this._entriesPromise; | 
					
						
							|  |  |  |     return [...entries.keys()]; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async hasEntry(entryName: string): Promise<boolean> { | 
					
						
							|  |  |  |     const entries = await this._entriesPromise; | 
					
						
							|  |  |  |     return entries.has(entryName); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async readText(entryName: string): Promise<string | undefined> { | 
					
						
							|  |  |  |     const response = await this._readEntry(entryName); | 
					
						
							|  |  |  |     return response?.text(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   async readBlob(entryName: string): Promise<Blob | undefined> { | 
					
						
							|  |  |  |     const response = await this._readEntry(entryName); | 
					
						
							| 
									
										
										
										
											2023-08-25 12:10:28 -07:00
										 |  |  |     return response?.status === 200 ? await response?.blob() : undefined; | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private async _readEntry(entryName: string): Promise<Response | undefined> { | 
					
						
							|  |  |  |     const entries = await this._entriesPromise; | 
					
						
							|  |  |  |     const fileName = entries.get(entryName); | 
					
						
							|  |  |  |     if (!fileName) | 
					
						
							|  |  |  |       return; | 
					
						
							| 
									
										
										
										
											2023-06-26 18:13:40 +02:00
										 |  |  |     return fetch('/trace/file?path=' + encodeURIComponent(fileName)); | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function formatUrl(trace: string) { | 
					
						
							| 
									
										
										
										
											2023-06-26 18:13:40 +02:00
										 |  |  |   let url = trace.startsWith('http') || trace.startsWith('blob') ? trace : `file?path=${encodeURIComponent(trace)}`; | 
					
						
							| 
									
										
										
										
											2023-05-05 15:12:18 -07:00
										 |  |  |   // Dropbox does not support cors.
 | 
					
						
							|  |  |  |   if (url.startsWith('https://www.dropbox.com/')) | 
					
						
							|  |  |  |     url = 'https://dl.dropboxusercontent.com/' + url.substring('https://www.dropbox.com/'.length); | 
					
						
							|  |  |  |   return url; | 
					
						
							|  |  |  | } |