import*as Common from'../common/common.js';import{ConsoleMessage,MessageLevel,MessageSource}from'./ConsoleModel.js';import{Events as NetworkManagerEvents,NetworkManager}from'./NetworkManager.js';import{Events as NetworkRequestEvents,InitiatorType,NetworkRequest}from'./NetworkRequest.js';import{Events as ResourceTreeModelEvents,ResourceTreeFrame,ResourceTreeModel}from'./ResourceTreeModel.js';import{RuntimeModel}from'./RuntimeModel.js';import{SDKModelObserver}from'./SDKModel.js';export class NetworkLog extends Common.ObjectWrapper.ObjectWrapper{constructor(){super();this._requests=[];this._requestsSet=new Set();this._pageLoadForManager=new Map();this._isRecording=true;self.SDK.targetManager.observeModels(NetworkManager,this);}
modelAdded(networkManager){const eventListeners=[];eventListeners.push(networkManager.addEventListener(NetworkManagerEvents.RequestStarted,this._onRequestStarted,this));eventListeners.push(networkManager.addEventListener(NetworkManagerEvents.RequestUpdated,this._onRequestUpdated,this));eventListeners.push(networkManager.addEventListener(NetworkManagerEvents.RequestRedirected,this._onRequestRedirect,this));eventListeners.push(networkManager.addEventListener(NetworkManagerEvents.RequestFinished,this._onRequestUpdated,this));eventListeners.push(networkManager.addEventListener(NetworkManagerEvents.MessageGenerated,this._networkMessageGenerated.bind(this,networkManager)));const resourceTreeModel=networkManager.target().model(ResourceTreeModel);if(resourceTreeModel){eventListeners.push(resourceTreeModel.addEventListener(ResourceTreeModelEvents.WillReloadPage,this._willReloadPage,this));eventListeners.push(resourceTreeModel.addEventListener(ResourceTreeModelEvents.MainFrameNavigated,this._onMainFrameNavigated,this));eventListeners.push(resourceTreeModel.addEventListener(ResourceTreeModelEvents.Load,this._onLoad,this));eventListeners.push(resourceTreeModel.addEventListener(ResourceTreeModelEvents.DOMContentLoaded,this._onDOMContentLoaded.bind(this,resourceTreeModel)));}
networkManager[_events]=eventListeners;}
modelRemoved(networkManager){this._removeNetworkManagerListeners(networkManager);}
_removeNetworkManagerListeners(networkManager){Common.EventTarget.EventTarget.removeEventListeners(networkManager[_events]);}
setIsRecording(enabled){if(this._isRecording===enabled){return;}
this._isRecording=enabled;if(enabled){self.SDK.targetManager.observeModels(NetworkManager,this);}else{self.SDK.targetManager.unobserveModels(NetworkManager,this);self.SDK.targetManager.models(NetworkManager).forEach(this._removeNetworkManagerListeners.bind(this));}}
requestForURL(url){return this._requests.find(request=>request.url()===url)||null;}
requests(){return this._requests;}
requestByManagerAndId(networkManager,requestId){for(let i=this._requests.length-1;i>=0;i--){const request=this._requests[i];if(requestId===request.requestId()&&networkManager===NetworkManager.forRequest(request)){return request;}}
return null;}
_requestByManagerAndURL(networkManager,url){for(const request of this._requests){if(url===request.url()&&networkManager===NetworkManager.forRequest(request)){return request;}}
return null;}
_initializeInitiatorSymbolIfNeeded(request){if(!request[_initiatorDataSymbol]){request[_initiatorDataSymbol]={info:null,chain:null,request:undefined,};}}
initiatorInfoForRequest(request){this._initializeInitiatorSymbolIfNeeded(request);if(request[_initiatorDataSymbol].info){return request[_initiatorDataSymbol].info;}
let type=InitiatorType.Other;let url='';let lineNumber=-Infinity;let columnNumber=-Infinity;let scriptId=null;let initiatorStack=null;const initiator=request.initiator();const redirectSource=request.redirectSource();if(redirectSource){type=InitiatorType.Redirect;url=redirectSource.url();}else if(initiator){if(initiator.type===Protocol.Network.InitiatorType.Parser){type=InitiatorType.Parser;url=initiator.url?initiator.url:url;lineNumber=initiator.lineNumber?initiator.lineNumber:lineNumber;}else if(initiator.type===Protocol.Network.InitiatorType.Script){for(let stack=initiator.stack;stack;stack=stack.parent){const topFrame=stack.callFrames.length?stack.callFrames[0]:null;if(!topFrame){continue;}
type=InitiatorType.Script;url=topFrame.url||Common.UIString.UIString('<anonymous>');lineNumber=topFrame.lineNumber;columnNumber=topFrame.columnNumber;scriptId=topFrame.scriptId;break;}
if(!initiator.stack&&initiator.url){type=InitiatorType.Script;url=initiator.url;lineNumber=initiator.lineNumber||0;}
if(initiator.stack&&initiator.stack.callFrames&&initiator.stack.callFrames.length){initiatorStack=initiator.stack||null;}}else if(initiator.type===Protocol.Network.InitiatorType.Preload){type=InitiatorType.Preload;}else if(initiator.type===Protocol.Network.InitiatorType.SignedExchange){type=InitiatorType.SignedExchange;url=initiator.url;}}
request[_initiatorDataSymbol].info={type:type,url:url,lineNumber:lineNumber,columnNumber:columnNumber,scriptId:scriptId,stack:initiatorStack};return request[_initiatorDataSymbol].info;}
initiatorGraphForRequest(request){const initiated=new Map();const networkManager=NetworkManager.forRequest(request);for(const otherRequest of this._requests){const otherRequestManager=NetworkManager.forRequest(otherRequest);if(networkManager===otherRequestManager&&this._initiatorChain(otherRequest).has(request)){initiated.set(otherRequest,this._initiatorRequest(otherRequest));}}
return{initiators:this._initiatorChain(request),initiated:initiated};}
_initiatorChain(request){this._initializeInitiatorSymbolIfNeeded(request);let initiatorChainCache=(request[_initiatorDataSymbol].chain);if(initiatorChainCache){return initiatorChainCache;}
initiatorChainCache=new Set();let checkRequest=request;do{this._initializeInitiatorSymbolIfNeeded(checkRequest);if(checkRequest[_initiatorDataSymbol].chain){initiatorChainCache.addAll(checkRequest[_initiatorDataSymbol].chain);break;}
if(initiatorChainCache.has(checkRequest)){break;}
initiatorChainCache.add(checkRequest);checkRequest=this._initiatorRequest(checkRequest);}while(checkRequest);request[_initiatorDataSymbol].chain=initiatorChainCache;return initiatorChainCache;}
_initiatorRequest(request){this._initializeInitiatorSymbolIfNeeded(request);if(request[_initiatorDataSymbol].request!==undefined){return request[_initiatorDataSymbol].request;}
const url=this.initiatorInfoForRequest(request).url;const networkManager=NetworkManager.forRequest(request);request[_initiatorDataSymbol].request=networkManager?this._requestByManagerAndURL(networkManager,url):null;return request[_initiatorDataSymbol].request;}
_willReloadPage(){if(!self.Common.settings.moduleSetting('network_log.preserve-log').get()){this.reset();}}
_onMainFrameNavigated(event){const mainFrame=(event.data);const manager=mainFrame.resourceTreeModel().target().model(NetworkManager);if(!manager||mainFrame.resourceTreeModel().target().parentTarget()){return;}
const oldRequests=this._requests;const oldManagerRequests=this._requests.filter(request=>NetworkManager.forRequest(request)===manager);const oldRequestsSet=this._requestsSet;this._requests=[];this._requestsSet=new Set();this.dispatchEventToListeners(Events.Reset);let currentPageLoad=null;const requestsToAdd=[];for(const request of oldManagerRequests){if(request.loaderId!==mainFrame.loaderId){continue;}
if(!currentPageLoad){currentPageLoad=new PageLoad(request);let redirectSource=request.redirectSource();while(redirectSource){requestsToAdd.push(redirectSource);redirectSource=redirectSource.redirectSource();}}
requestsToAdd.push(request);}
const serviceWorkerRequestsToAdd=[];for(const swRequest of oldRequests){if(!swRequest.initiatedByServiceWorker()){continue;}
const keepRequest=requestsToAdd.some(request=>request.url()===swRequest.url()&&request.issueTime()<=swRequest.issueTime());if(keepRequest){serviceWorkerRequestsToAdd.push(swRequest);}}
requestsToAdd.push(...serviceWorkerRequestsToAdd);for(const request of requestsToAdd){oldRequestsSet.delete(request);this._requests.push(request);this._requestsSet.add(request);currentPageLoad.bindRequest(request);this.dispatchEventToListeners(Events.RequestAdded,request);}
if(self.Common.settings.moduleSetting('network_log.preserve-log').get()){for(const request of oldRequestsSet){this._requests.push(request);this._requestsSet.add(request);this.dispatchEventToListeners(Events.RequestAdded,request);}}
if(currentPageLoad){this._pageLoadForManager.set(manager,currentPageLoad);}}
importRequests(requests){this.reset();this._requests=[];this._requestsSet.clear();for(const request of requests){this._requests.push(request);this._requestsSet.add(request);this.dispatchEventToListeners(Events.RequestAdded,request);}}
_onRequestStarted(event){const request=(event.data);this._requests.push(request);this._requestsSet.add(request);const manager=NetworkManager.forRequest(request);const pageLoad=manager?this._pageLoadForManager.get(manager):null;if(pageLoad){pageLoad.bindRequest(request);}
this.dispatchEventToListeners(Events.RequestAdded,request);}
_onRequestUpdated(event){const request=(event.data);if(!this._requestsSet.has(request)){return;}
this.dispatchEventToListeners(Events.RequestUpdated,request);}
_onRequestRedirect(event){const request=(event.data);delete request[_initiatorDataSymbol];}
_onDOMContentLoaded(resourceTreeModel,event){const networkManager=resourceTreeModel.target().model(NetworkManager);const pageLoad=networkManager?this._pageLoadForManager.get(networkManager):null;if(pageLoad){pageLoad.contentLoadTime=(event.data);}}
_onLoad(event){const networkManager=event.data.resourceTreeModel.target().model(NetworkManager);const pageLoad=networkManager?this._pageLoadForManager.get(networkManager):null;if(pageLoad){pageLoad.loadTime=(event.data.loadTime);}}
reset(){this._requests=[];this._requestsSet.clear();const managers=new Set(self.SDK.targetManager.models(NetworkManager));for(const manager of this._pageLoadForManager.keys()){if(!managers.has(manager)){this._pageLoadForManager.delete(manager);}}
this.dispatchEventToListeners(Events.Reset);}
_networkMessageGenerated(networkManager,event){const message=(event.data);const consoleMessage=new ConsoleMessage(networkManager.target().model(RuntimeModel),MessageSource.Network,message.warning?MessageLevel.Warning:MessageLevel.Info,message.message);this.associateConsoleMessageWithRequest(consoleMessage,message.requestId);self.SDK.consoleModel.addMessage(consoleMessage);}
associateConsoleMessageWithRequest(consoleMessage,requestId){const target=consoleMessage.target();const networkManager=target?target.model(NetworkManager):null;if(!networkManager){return;}
const request=this.requestByManagerAndId(networkManager,requestId);if(!request){return;}
consoleMessage[_requestSymbol]=request;const initiator=request.initiator();if(initiator){consoleMessage.stackTrace=initiator.stack||undefined;if(initiator.url){consoleMessage.url=initiator.url;consoleMessage.line=initiator.lineNumber||0;}}}
static requestForConsoleMessage(consoleMessage){return consoleMessage[_requestSymbol]||null;}}
export class PageLoad{constructor(mainRequest){this.id=++PageLoad._lastIdentifier;this.url=mainRequest.url();this.startTime=mainRequest.startTime;this.loadTime;this.contentLoadTime;this.mainRequest=mainRequest;this._showDataSaverWarningIfNeeded();}
async _showDataSaverWarningIfNeeded(){const manager=NetworkManager.forRequest(this.mainRequest);if(!manager){return;}
if(!this.mainRequest.finished){await this.mainRequest.once(NetworkRequestEvents.FinishedLoading);}
const saveDataHeader=this.mainRequest.requestHeaderValue('Save-Data');if(!PageLoad._dataSaverMessageWasShown&&saveDataHeader&&saveDataHeader==='on'){const message=Common.UIString.UIString('Consider disabling %s while debugging. For more info see: %s',Common.UIString.UIString('Chrome Data Saver'),'https://support.google.com/chrome/?p=datasaver');manager.dispatchEventToListeners(NetworkManagerEvents.MessageGenerated,{message:message,requestId:this.mainRequest.requestId(),warning:true});PageLoad._dataSaverMessageWasShown=true;}}
static forRequest(request){return request[PageLoad._pageLoadForRequestSymbol]||null;}
bindRequest(request){request[PageLoad._pageLoadForRequestSymbol]=this;}}
PageLoad._lastIdentifier=0;PageLoad._pageLoadForRequestSymbol=Symbol('PageLoadForRequest');PageLoad._dataSaverMessageWasShown=false;const _requestSymbol=Symbol('_request');export const Events={Reset:Symbol('Reset'),RequestAdded:Symbol('RequestAdded'),RequestUpdated:Symbol('RequestUpdated')};const _initiatorDataSymbol=Symbol('InitiatorData');const _events=Symbol('SDK.NetworkLog.events');export let InitiatorGraph;