let pageUpdateTime = {}; const CACHE_NAME = "fed-cache"; let util = { getPageName: function(url) { if (url.pathname === "/" || !url.pathname) { return "home" } else { let matches = url.pathname.match(/\/([^/] + )\/$/ ); if (!matches) console.log("get page name come across url: " + url); return matches ? matches[1] : "" } }, isHtmlPage: function(url) { return url.pathname === "/" || /^\/page\/\d+/.test(url.pathname) || /^\/\d{4}\/\d{2}\/\d{2}/.test(url.pathname) }, updateHtmlPage: async function(url, htmlRequest) { let pageName = util.getPageName(url); let jsonRequest = new Request("/html/service-worker/cache-json/" + pageName + ".sw.json"); fetch(jsonRequest).then(response => { if (response.status !== 200) { console.warn(`$ { response.status }: fetch $ { pageName }.sw.json failed`); return; } response.json().then(content => { if (pageUpdateTime[pageName] !== content.updateTime) { console.log("update page html"); util.fetchPut(htmlRequest, false, function() { util.postMessage({ type: 1, desc: "html found updated", url: url.href }) }); pageUpdateTime[pageName] = content.updateTime } }) }) }, updateHtmlTime: function(url) { let pageName = util.getPageName(url); let jsonRequest = new Request("/html/service-worker/cache-json/" + pageName + ".sw.json"); fetch(jsonRequest).then(response => { response.json().then(content => { pageUpdateTime[pageName] = content.updateTime }) }) }, putCache: function(request, resource) { if (request.method === "GET" && request.url.indexOf("wp-admin") < 0 && request.url.indexOf("preview_id") < 0 && request.url.indexOf("test=true") < 0 && request.url.indexOf("/category/") < 0 && request.url.indexOf("/author/") < 0 && request.url.indexOf("/html/") < 0) { caches.open(CACHE_NAME).then(cache => { cache.put(request.url, resource) }) } }, fetchPut: function(request, putCache = true, callback) { return fetch(request).then(response => { if (!response || response.status !== 200 || response.type !== "basic") { return response } util.putCache(request, response.clone()); typeof callback === "function" && callback(); return response }) }, delCache: function(url) { caches.open(CACHE_NAME).then(cache => { console.log("delete cache " + url); cache.delete(url, { ignoreVary: true }) }) }, postMessage: async function(msg) { const allClients = await clients.matchAll(); allClients.forEach(client => client.postMessage(msg)) } }; const messageProcess = { 1 : function(url) { util.delCache(url) } }; this.addEventListener("install", function(event) { this.skipWaiting(); console.log("install service worker"); caches.open(CACHE_NAME); let cacheResources = ["https://fed.renren.com/?launcher=true"]; event.waitUntil(caches.open(CACHE_NAME).then(cache => { cache.addAll(cacheResources) })) }); this.addEventListener("active", function(event) { clients.claims(); console.log("service worker is active") }); this.addEventListener("fetch", function(event) { event.respondWith(caches.match(event.request).then(response => { if (response) { if (response.headers.get("Content-Type").indexOf("text/html") >= 0) { console.log("update html"); let url = new URL(event.request.url); util.updateHtmlPage(url, event.request.clone(), event.clientId) } return response } let url = new URL(event.request.url); if (util.isHtmlPage(url)) { console.log("update html time"); util.updateHtmlTime(url) } let request = event.request.url.indexOf("http://fed.renren.com") >= 0 ? new Request(event.request.url.replace("http://", "https://")) : event.request.clone(); return util.fetchPut(request) })) }); this.addEventListener("message", function(event) { let msg = event.data; console.log(msg); if (typeof messageProcess[msg.type] === "function") { messageProcess[msg.type](msg.url) } }); this.addEventListener("push", function(event) { console.log("[Service Worker] Push Received."); console.log(` [Service Worker] Push had this data: "${event.data.text()}"`); let notificationData = event.data.json(); notificationData.requireInteraction = true; const title = notificationData.title; event.waitUntil(self.registration.showNotification(title, notificationData)) }); this.addEventListener("notificationclick", function(event) { console.log("[Service Worker] Notification click Received."); let notification = event.notification; notification.close(); event.waitUntil(clients.openWindow(notification.data.url)) }); this.addEventListener("notificationclose", function(event) { console.log("notification close"); console.log(JSON.stringify(event.notification)) });