ServiceWorkerManager.js 12 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. export default class ServiceWorkerManager extends SDK.SDKModel{constructor(target){super(target);target.registerServiceWorkerDispatcher(new ServiceWorkerDispatcher(this));this._lastAnonymousTargetId=0;this._agent=target.serviceWorkerAgent();this._registrations=new Map();this.enable();this._forceUpdateSetting=Common.settings.createSetting('serviceWorkerUpdateOnReload',false);if(this._forceUpdateSetting.get()){this._forceUpdateSettingChanged();}
  2. this._forceUpdateSetting.addChangeListener(this._forceUpdateSettingChanged,this);new ServiceWorkerContextNamer(target,this);}
  3. enable(){if(this._enabled){return;}
  4. this._enabled=true;this._agent.enable();}
  5. disable(){if(!this._enabled){return;}
  6. this._enabled=false;this._registrations.clear();this._agent.disable();}
  7. registrations(){return this._registrations;}
  8. hasRegistrationForURLs(urls){for(const registration of this._registrations.values()){if(urls.filter(url=>url&&url.startsWith(registration.scopeURL)).length===urls.length){return true;}}
  9. return false;}
  10. findVersion(versionId){for(const registration of this.registrations().values()){const version=registration.versions.get(versionId);if(version){return version;}}
  11. return null;}
  12. deleteRegistration(registrationId){const registration=this._registrations.get(registrationId);if(!registration){return;}
  13. if(registration._isRedundant()){this._registrations.delete(registrationId);this.dispatchEventToListeners(Events.RegistrationDeleted,registration);return;}
  14. registration._deleting=true;for(const version of registration.versions.values()){this.stopWorker(version.id);}
  15. this._unregister(registration.scopeURL);}
  16. updateRegistration(registrationId){const registration=this._registrations.get(registrationId);if(!registration){return;}
  17. this._agent.updateRegistration(registration.scopeURL);}
  18. deliverPushMessage(registrationId,data){const registration=this._registrations.get(registrationId);if(!registration){return;}
  19. const origin=Common.ParsedURL.extractOrigin(registration.scopeURL);this._agent.deliverPushMessage(origin,registrationId,data);}
  20. dispatchSyncEvent(registrationId,tag,lastChance){const registration=this._registrations.get(registrationId);if(!registration){return;}
  21. const origin=Common.ParsedURL.extractOrigin(registration.scopeURL);this._agent.dispatchSyncEvent(origin,registrationId,tag,lastChance);}
  22. dispatchPeriodicSyncEvent(registrationId,tag){const registration=this._registrations.get(registrationId);if(!registration){return;}
  23. const origin=Common.ParsedURL.extractOrigin(registration.scopeURL);this._agent.dispatchPeriodicSyncEvent(origin,registrationId,tag);}
  24. _unregister(scope){this._agent.unregister(scope);}
  25. startWorker(scope){this._agent.startWorker(scope);}
  26. skipWaiting(scope){this._agent.skipWaiting(scope);}
  27. stopWorker(versionId){this._agent.stopWorker(versionId);}
  28. inspectWorker(versionId){this._agent.inspectWorker(versionId);}
  29. _workerRegistrationUpdated(registrations){for(const payload of registrations){let registration=this._registrations.get(payload.registrationId);if(!registration){registration=new ServiceWorkerRegistration(payload);this._registrations.set(payload.registrationId,registration);this.dispatchEventToListeners(Events.RegistrationUpdated,registration);continue;}
  30. registration._update(payload);if(registration._shouldBeRemoved()){this._registrations.delete(registration.id);this.dispatchEventToListeners(Events.RegistrationDeleted,registration);}else{this.dispatchEventToListeners(Events.RegistrationUpdated,registration);}}}
  31. _workerVersionUpdated(versions){const registrations=new Set();for(const payload of versions){const registration=this._registrations.get(payload.registrationId);if(!registration){continue;}
  32. registration._updateVersion(payload);registrations.add(registration);}
  33. for(const registration of registrations){if(registration._shouldBeRemoved()){this._registrations.delete(registration.id);this.dispatchEventToListeners(Events.RegistrationDeleted,registration);}else{this.dispatchEventToListeners(Events.RegistrationUpdated,registration);}}}
  34. _workerErrorReported(payload){const registration=this._registrations.get(payload.registrationId);if(!registration){return;}
  35. registration.errors.push(payload);this.dispatchEventToListeners(Events.RegistrationErrorAdded,{registration:registration,error:payload});}
  36. forceUpdateOnReloadSetting(){return this._forceUpdateSetting;}
  37. _forceUpdateSettingChanged(){this._agent.setForceUpdateOnPageLoad(this._forceUpdateSetting.get());}}
  38. export const Events={RegistrationUpdated:Symbol('RegistrationUpdated'),RegistrationErrorAdded:Symbol('RegistrationErrorAdded'),RegistrationDeleted:Symbol('RegistrationDeleted')};class ServiceWorkerDispatcher{constructor(manager){this._manager=manager;}
  39. workerRegistrationUpdated(registrations){this._manager._workerRegistrationUpdated(registrations);}
  40. workerVersionUpdated(versions){this._manager._workerVersionUpdated(versions);}
  41. workerErrorReported(errorMessage){this._manager._workerErrorReported(errorMessage);}}
  42. export class ServiceWorkerVersion{constructor(registration,payload){this.registration=registration;this._update(payload);}
  43. _update(payload){this.id=payload.versionId;this.scriptURL=payload.scriptURL;const parsedURL=new Common.ParsedURL(payload.scriptURL);this.securityOrigin=parsedURL.securityOrigin();this.runningStatus=payload.runningStatus;this.status=payload.status;this.scriptLastModified=payload.scriptLastModified;this.scriptResponseTime=payload.scriptResponseTime;this.controlledClients=[];for(let i=0;i<payload.controlledClients.length;++i){this.controlledClients.push(payload.controlledClients[i]);}
  44. this.targetId=payload.targetId||null;}
  45. isStartable(){return!this.registration.isDeleted&&this.isActivated()&&this.isStopped();}
  46. isStoppedAndRedundant(){return this.runningStatus===Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Stopped&&this.status===Protocol.ServiceWorker.ServiceWorkerVersionStatus.Redundant;}
  47. isStopped(){return this.runningStatus===Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Stopped;}
  48. isStarting(){return this.runningStatus===Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Starting;}
  49. isRunning(){return this.runningStatus===Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Running;}
  50. isStopping(){return this.runningStatus===Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Stopping;}
  51. isNew(){return this.status===Protocol.ServiceWorker.ServiceWorkerVersionStatus.New;}
  52. isInstalling(){return this.status===Protocol.ServiceWorker.ServiceWorkerVersionStatus.Installing;}
  53. isInstalled(){return this.status===Protocol.ServiceWorker.ServiceWorkerVersionStatus.Installed;}
  54. isActivating(){return this.status===Protocol.ServiceWorker.ServiceWorkerVersionStatus.Activating;}
  55. isActivated(){return this.status===Protocol.ServiceWorker.ServiceWorkerVersionStatus.Activated;}
  56. isRedundant(){return this.status===Protocol.ServiceWorker.ServiceWorkerVersionStatus.Redundant;}
  57. mode(){if(this.isNew()||this.isInstalling()){return ServiceWorkerVersion.Modes.Installing;}else if(this.isInstalled()){return ServiceWorkerVersion.Modes.Waiting;}else if(this.isActivating()||this.isActivated()){return ServiceWorkerVersion.Modes.Active;}
  58. return ServiceWorkerVersion.Modes.Redundant;}}
  59. ServiceWorkerVersion.RunningStatus={[Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Running]:ls`running`,[Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Starting]:ls`starting`,[Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Stopped]:ls`stopped`,[Protocol.ServiceWorker.ServiceWorkerVersionRunningStatus.Stopping]:ls`stopping`,};ServiceWorkerVersion.Status={[Protocol.ServiceWorker.ServiceWorkerVersionStatus.Activated]:ls`activated`,[Protocol.ServiceWorker.ServiceWorkerVersionStatus.Activating]:ls`activating`,[Protocol.ServiceWorker.ServiceWorkerVersionStatus.Installed]:ls`installed`,[Protocol.ServiceWorker.ServiceWorkerVersionStatus.Installing]:ls`installing`,[Protocol.ServiceWorker.ServiceWorkerVersionStatus.New]:ls`new`,[Protocol.ServiceWorker.ServiceWorkerVersionStatus.Redundant]:ls`redundant`,};ServiceWorkerVersion.Modes={Installing:'installing',Waiting:'waiting',Active:'active',Redundant:'redundant'};export class ServiceWorkerRegistration{constructor(payload){this._update(payload);this.versions=new Map();this._deleting=false;this.errors=[];}
  60. _update(payload){this._fingerprint=Symbol('fingerprint');this.id=payload.registrationId;this.scopeURL=payload.scopeURL;const parsedURL=new Common.ParsedURL(payload.scopeURL);this.securityOrigin=parsedURL.securityOrigin();this.isDeleted=payload.isDeleted;this.forceUpdateOnPageLoad=payload.forceUpdateOnPageLoad;}
  61. fingerprint(){return this._fingerprint;}
  62. versionsByMode(){const result=new Map();for(const version of this.versions.values()){result.set(version.mode(),version);}
  63. return result;}
  64. _updateVersion(payload){this._fingerprint=Symbol('fingerprint');let version=this.versions.get(payload.versionId);if(!version){version=new ServiceWorkerVersion(this,payload);this.versions.set(payload.versionId,version);return version;}
  65. version._update(payload);return version;}
  66. _isRedundant(){for(const version of this.versions.values()){if(!version.isStoppedAndRedundant()){return false;}}
  67. return true;}
  68. _shouldBeRemoved(){return this._isRedundant()&&(!this.errors.length||this._deleting);}
  69. canBeRemoved(){return this.isDeleted||this._deleting;}
  70. clearErrors(){this._fingerprint=Symbol('fingerprint');this.errors=[];}}
  71. class ServiceWorkerContextNamer{constructor(target,serviceWorkerManager){this._target=target;this._serviceWorkerManager=serviceWorkerManager;this._versionByTargetId=new Map();serviceWorkerManager.addEventListener(Events.RegistrationUpdated,this._registrationsUpdated,this);serviceWorkerManager.addEventListener(Events.RegistrationDeleted,this._registrationsUpdated,this);SDK.targetManager.addModelListener(SDK.RuntimeModel,SDK.RuntimeModel.Events.ExecutionContextCreated,this._executionContextCreated,this);}
  72. _registrationsUpdated(event){this._versionByTargetId.clear();const registrations=this._serviceWorkerManager.registrations().valuesArray();for(const registration of registrations){const versions=registration.versions.valuesArray();for(const version of versions){if(version.targetId){this._versionByTargetId.set(version.targetId,version);}}}
  73. this._updateAllContextLabels();}
  74. _executionContextCreated(event){const executionContext=(event.data);const serviceWorkerTargetId=this._serviceWorkerTargetId(executionContext.target());if(!serviceWorkerTargetId){return;}
  75. this._updateContextLabel(executionContext,this._versionByTargetId.get(serviceWorkerTargetId)||null);}
  76. _serviceWorkerTargetId(target){if(target.parentTarget()!==this._target||target.type()!==SDK.Target.Type.ServiceWorker){return null;}
  77. return target.id();}
  78. _updateAllContextLabels(){for(const target of SDK.targetManager.targets()){const serviceWorkerTargetId=this._serviceWorkerTargetId(target);if(!serviceWorkerTargetId){continue;}
  79. const version=this._versionByTargetId.get(serviceWorkerTargetId)||null;const runtimeModel=target.model(SDK.RuntimeModel);const executionContexts=runtimeModel?runtimeModel.executionContexts():[];for(const context of executionContexts){this._updateContextLabel(context,version);}}}
  80. _updateContextLabel(context,version){if(!version){context.setLabel('');return;}
  81. const parsedUrl=context.origin.asParsedURL();const label=parsedUrl?parsedUrl.lastPathComponentWithFragment():context.name;const localizedStatus=ServiceWorkerVersion.Status[version.status];context.setLabel(ls`${label} #${version.id} (${localizedStatus})`);}}
  82. self.SDK=self.SDK||{};SDK=SDK||{};SDK.ServiceWorkerManager=ServiceWorkerManager;SDK.ServiceWorkerManager.Events=Events;SDK.ServiceWorkerVersion=ServiceWorkerVersion;SDK.ServiceWorkerRegistration=ServiceWorkerRegistration;SDK.SDKModel.register(ServiceWorkerManager,SDK.Target.Capability.ServiceWorker,true);