Files
grin-web-wallet/scripts/service_worker_installer.js
2024-12-20 18:08:44 -08:00

524 lines
15 KiB
JavaScript
Executable File

// Use strict
"use strict";
// Classes
// Service worker installer class
class ServiceWorkerInstaller {
// Public
// Constructor
constructor(version) {
// Set version
this.version = version;
// Set service worker to no service worker
this.serviceWorker = ServiceWorkerInstaller.NO_SERVICE_WORKER;
// Set allow updates
this.allowUpdates = false;
// Check if not an extension and not loading from file
if(Common.isExtension() === false && location["protocol"] !== Common.FILE_PROTOCOL) {
// Check if service workers are supported
if(typeof navigator === "object" && navigator !== null && "serviceWorker" in navigator === true) {
// Set installation status to installing
this.installationStatus = ServiceWorkerInstaller.INSTALLING_STATUS;
// Check if document is complete
if(document["readyState"] === "complete")
// Register
this.register();
// Otherwise
else {
// Set self
var self = this;
// Window load event
$(window).on("load", function() {
// Register
self.register();
});
}
}
// Otherwise
else {
// Set installation status to unsupported
this.installationStatus = ServiceWorkerInstaller.UNSUPPORTED_STATUS;
}
}
// Otherwise
else {
// Set installation status to unsupported
this.installationStatus = ServiceWorkerInstaller.UNSUPPORTED_STATUS;
}
}
// Get installation status
getInstallationStatus() {
// Return installation status
return this.installationStatus;
}
// Installing status
static get INSTALLING_STATUS() {
// Return installing status
return 0;
}
// Unsupported status
static get UNSUPPORTED_STATUS() {
// Return unsupported status
return ServiceWorkerInstaller.INSTALLING_STATUS + 1;
}
// Installed status
static get INSTALLED_STATUS() {
// Return installed status
return ServiceWorkerInstaller.UNSUPPORTED_STATUS + 1;
}
// Failed status
static get FAILED_STATUS() {
// Return failed status
return ServiceWorkerInstaller.INSTALLED_STATUS + 1;
}
// Install succeeded event
static get INSTALL_SUCCEEDED_EVENT() {
// Return install succeeded event
return "ServiceWorkerInstallerInstallSucceededEvent";
}
// Install failed event
static get INSTALL_FAILED_EVENT() {
// Return install failed event
return "ServiceWorkerInstallerInstallFailedEvent";
}
// Update available event
static get UPDATE_AVAILABLE_EVENT() {
// Return update available event
return "ServiceWorkerInstallerUpdateAvailableEvent";
}
// Private
// Register
register() {
// Set self
var self = this;
// Register service worker
navigator["serviceWorker"].register(getResource(ServiceWorkerInstaller.FILE_LOCATION), {
// Scope
"scope": ServiceWorkerInstaller.SCOPE
// Check if registration was successful
}).then(function(registration) {
// Set service worker to registration
self.serviceWorker = registration;
// Try
try {
// Save last update timestamp in local storage
localStorage.setItem(ServiceWorkerInstaller.SERVICE_WORKER_LAST_UPDATE_TIMESTAMP_LOCAL_STORAGE_NAME, Common.getCurrentTimestamp().toFixed());
}
// Catch errors
catch(error) {
// Trigger a fatal error
new FatalError(FatalError.LOCAL_STORAGE_ERROR);
// Return
return;
}
// Get active service worker
var activeServiceWorker = self.serviceWorker["active"];
// Check if there is no existing active service worker
if(activeServiceWorker === ServiceWorkerInstaller.NO_ACTIVE_SERVICE_WORKER) {
// Get installing service worker
var installingServiceWorker = self.serviceWorker["installing"];
// Check if a service worker is installing
if(installingServiceWorker !== ServiceWorkerInstaller.NO_INSTALLING_SERVICE_WORKER) {
// Save initial state change function
var initialStateChangeFunction = installingServiceWorker["onstatechange"];
// Installing service worker state change event
installingServiceWorker["onstatechange"] = function(event) {
// Check if installing service worker's state is activated
if(event["target"]["state"] === ServiceWorkerInstaller.ACTIVATED_STATE) {
// Restore initial state change function
installingServiceWorker["onstatechange"] = initialStateChangeFunction;
// Set installation status to installed
self.installationStatus = ServiceWorkerInstaller.INSTALLED_STATUS;
// Trigger install succeeded event
$(self).trigger(ServiceWorkerInstaller.INSTALL_SUCCEEDED_EVENT);
// Service worker update found event
self.serviceWorker["onupdatefound"] = function() {
// Get installing service worker
installingServiceWorker = self.serviceWorker["installing"];
// Check if a service worker is installing
if(installingServiceWorker !== ServiceWorkerInstaller.NO_INSTALLING_SERVICE_WORKER) {
// Save initial state change function
initialStateChangeFunction = installingServiceWorker["onstatechange"];
// Installing service worker state change event
installingServiceWorker["onstatechange"] = function(event) {
// Check if installing service worker's state is activated
if(event["target"]["state"] === ServiceWorkerInstaller.ACTIVATED_STATE) {
// Restore initial state change function
installingServiceWorker["onstatechange"] = initialStateChangeFunction;
// Trigger update available event
$(self).trigger(ServiceWorkerInstaller.UPDATE_AVAILABLE_EVENT);
}
};
}
};
// Set allow updates
self.allowUpdates = true;
}
// Otherwise check if service worker's state is redundant
else if(event["target"]["state"] === ServiceWorkerInstaller.REDUNDANT_STATE) {
// Restore initial state change function
installingServiceWorker["onstatechange"] = initialStateChangeFunction;
// Set installation status to failed
self.installationStatus = ServiceWorkerInstaller.FAILED_STATUS;
// Trigger install failed event
$(self).trigger(ServiceWorkerInstaller.INSTALL_FAILED_EVENT);
}
};
}
// Otherwise
else {
// Set installation status to failed
self.installationStatus = ServiceWorkerInstaller.FAILED_STATUS;
// Trigger install failed event
$(self).trigger(ServiceWorkerInstaller.INSTALL_FAILED_EVENT);
}
}
// Otherwise
else {
// Service worker message event
navigator["serviceWorker"]["onmessage"] = function(event) {
// Check if active service worker is the current version
if(event["data"] === self.version.getVersion()) {
// Set installation status to installed
self.installationStatus = ServiceWorkerInstaller.INSTALLED_STATUS;
// Trigger install succeeded event
$(self).trigger(ServiceWorkerInstaller.INSTALL_SUCCEEDED_EVENT);
// Service worker update found event
self.serviceWorker["onupdatefound"] = function() {
// Get installing service worker
installingServiceWorker = self.serviceWorker["installing"];
// Check if a service worker is installing
if(installingServiceWorker !== ServiceWorkerInstaller.NO_INSTALLING_SERVICE_WORKER) {
// Save initial state change function
initialStateChangeFunction = installingServiceWorker["onstatechange"];
// Installing service worker state change event
installingServiceWorker["onstatechange"] = function(event) {
// Check if installing service worker's state is activated
if(event["target"]["state"] === ServiceWorkerInstaller.ACTIVATED_STATE) {
// Restore initial state change function
installingServiceWorker["onstatechange"] = initialStateChangeFunction;
// Trigger update available event
$(self).trigger(ServiceWorkerInstaller.UPDATE_AVAILABLE_EVENT);
}
};
}
};
// Set allow updates
self.allowUpdates = true;
}
// Otherwise
else {
// Service worker update found event
self.serviceWorker["onupdatefound"] = function() {
// Get installing service worker
var installingServiceWorker = self.serviceWorker["installing"];
// Check if a service worker is installing
if(installingServiceWorker !== ServiceWorkerInstaller.NO_INSTALLING_SERVICE_WORKER) {
// Save initial state change function
var initialStateChangeFunction = installingServiceWorker["onstatechange"];
// Installing service worker state change event
installingServiceWorker["onstatechange"] = function(event) {
// Check if installing service worker's state is activated
if(event["target"]["state"] === ServiceWorkerInstaller.ACTIVATED_STATE) {
// Restore initial state change function
installingServiceWorker["onstatechange"] = initialStateChangeFunction;
// Set installation status to installed
self.installationStatus = ServiceWorkerInstaller.INSTALLED_STATUS;
// Trigger install succeeded event
$(self).trigger(ServiceWorkerInstaller.INSTALL_SUCCEEDED_EVENT);
// Service worker update found event
self.serviceWorker["onupdatefound"] = function() {
// Get installing service worker
installingServiceWorker = self.serviceWorker["installing"];
// Check if a service worker is installing
if(installingServiceWorker !== ServiceWorkerInstaller.NO_INSTALLING_SERVICE_WORKER) {
// Save initial state change function
initialStateChangeFunction = installingServiceWorker["onstatechange"];
// Installing service worker state change event
installingServiceWorker["onstatechange"] = function(event) {
// Check if installing service worker's state is activated
if(event["target"]["state"] === ServiceWorkerInstaller.ACTIVATED_STATE) {
// Restore initial state change function
installingServiceWorker["onstatechange"] = initialStateChangeFunction;
// Trigger update available event
$(self).trigger(ServiceWorkerInstaller.UPDATE_AVAILABLE_EVENT);
}
};
}
};
// Set allow updates
self.allowUpdates = true;
}
// Otherwise check if service worker's state is redundant
else if(event["target"]["state"] === ServiceWorkerInstaller.REDUNDANT_STATE) {
// Restore initial state change function
installingServiceWorker["onstatechange"] = initialStateChangeFunction;
// Set installation status to failed
self.installationStatus = ServiceWorkerInstaller.FAILED_STATUS;
// Trigger install failed event
$(self).trigger(ServiceWorkerInstaller.INSTALL_FAILED_EVENT);
}
};
}
// Otherwise
else {
// Set installation status to failed
self.installationStatus = ServiceWorkerInstaller.FAILED_STATUS;
// Trigger install failed event
$(self).trigger(ServiceWorkerInstaller.INSTALL_FAILED_EVENT);
}
};
}
};
// Request version from active service worker
activeServiceWorker.postMessage("");
}
// Set interval
setInterval(function() {
// Check for updates
self.checkForUpdates();
}, ServiceWorkerInstaller.CHECK_FOR_UPDATES_INTERVAL_SECONDS * Common.MILLISECONDS_IN_A_SECOND);
// Catch errors
}).catch(function(error) {
// Set installation status to failed
self.installationStatus = ServiceWorkerInstaller.FAILED_STATUS;
// Trigger install failed event
$(self).trigger(ServiceWorkerInstaller.INSTALL_FAILED_EVENT);
});
}
// Check for updates
checkForUpdates() {
// Get last update timestamp from local storage
var lastUpdateTimestamp = localStorage.getItem(ServiceWorkerInstaller.SERVICE_WORKER_LAST_UPDATE_TIMESTAMP_LOCAL_STORAGE_NAME);
// Check if time to check for an update
if(lastUpdateTimestamp === Common.INVALID_LOCAL_STORAGE_ITEM || parseInt(lastUpdateTimestamp, Common.DECIMAL_NUMBER_BASE) <= Common.getCurrentTimestamp() - ServiceWorkerInstaller.UPDATE_EXPIRATION_SECONDS) {
// Try
try {
// Save last update timestamp in local storage
localStorage.setItem(ServiceWorkerInstaller.SERVICE_WORKER_LAST_UPDATE_TIMESTAMP_LOCAL_STORAGE_NAME, Common.getCurrentTimestamp().toFixed());
}
// Catch errors
catch(error) {
// Trigger a fatal error
new FatalError(FatalError.LOCAL_STORAGE_ERROR);
// Return
return;
}
// Check if service worker exists and updates are allowed
if(this.serviceWorker !== ServiceWorkerInstaller.NO_SERVICE_WORKER && this.allowUpdates === true) {
// Update service worker and catch errors
this.serviceWorker.update().catch(function(error) {
});
}
}
}
// No service worker
static get NO_SERVICE_WORKER() {
// Return no service worker
return null;
}
// File location
static get FILE_LOCATION() {
// Return file location
return "./scripts/service_worker.js";
}
// Scope
static get SCOPE() {
// Return scope
return "./";
}
// Service worker Last update timestamp local storage name
static get SERVICE_WORKER_LAST_UPDATE_TIMESTAMP_LOCAL_STORAGE_NAME() {
// Return service worker last update timestamp local storage name
return "Service Worker Last Update Timestamp";
}
// Check for updates interval seconds
static get CHECK_FOR_UPDATES_INTERVAL_SECONDS() {
// Return check for updates interval seconds
return 2 * Common.MINUTES_IN_AN_HOUR * Common.SECONDS_IN_A_MINUTE;
}
// Update expiration seconds
static get UPDATE_EXPIRATION_SECONDS() {
// Return update expiration seconds
return 1 * Common.HOURS_IN_A_DAY * Common.MINUTES_IN_AN_HOUR * Common.SECONDS_IN_A_MINUTE;
}
// Activated state
static get ACTIVATED_STATE() {
// Return activated state
return "activated";
}
// Redundant state
static get REDUNDANT_STATE() {
// Return redundant state
return "redundant";
}
// No active service worker
static get NO_ACTIVE_SERVICE_WORKER() {
// Return no active service worker
return null;
}
// No installing service worker
static get NO_INSTALLING_SERVICE_WORKER() {
// Return no installing service worker
return ServiceWorkerInstaller.NO_ACTIVE_SERVICE_WORKER;
}
}
// Main function
// Set global object's service worker installer
globalThis["ServiceWorkerInstaller"] = ServiceWorkerInstaller;