Last active
March 9, 2021 17:58
-
-
Save freelancing-solutions/8891501dbad18d85568380781d3c50f1 to your computer and use it in GitHub Desktop.
writing a custom service worker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Incrementing OFFLINE_VERSION will kick off the install event and force | |
// previously cached resources to be updated from the network. | |
const OFFLINE_VERSION = 1; | |
const CACHE_NAME = 'FREELANCE-PROFILESS'; | |
const website_base_url = 'http://localhost'; | |
// Customize this with your URL. | |
// TODO- use Flask Assets to bundle some of the adminLTE css files and js files togather, | |
// TODO- also bundle adminLTE Files with flask bundler... | |
// NOTE- Never Cache URLS that require Authorization | |
// Load all other URLS in this array, you have to manually insert them here one by one or use bundlers | |
// for your static assets that way you can preload them easily here... | |
const CACHE_URLS = [ '/' ]; | |
// ***********************************************************************************************// | |
// Global Variable to hold the value of the authorization token | |
let auth_token = ""; | |
let cache = self.caches; | |
// NOTE: Installing Service worker | |
self.addEventListener('install', (event) => { | |
event.waitUntil((async () => { | |
// ON Service worker installation is where i load to cache | |
await cache.open(CACHE_NAME).then(cache => cache.addAll(CACHE_URLS)); | |
})()); | |
}); | |
// Activating Worker | |
self.addEventListener('activate', (event) => { | |
event.waitUntil((async () => { | |
// Enable navigation preload if it's supported. | |
// See https://developers.google.com/web/updates/2017/02/navigation-preload | |
if ('navigationPreload' in self.registration) { | |
await self.registration.navigationPreload.enable(); | |
} | |
})()); | |
// Claiming Control of page | |
self.clients.claim(); | |
}); | |
// Listening to fetch events to handle requests and Authorization | |
// TODO- consider using the fetch event handler to dispatch messages back to the page triggering the events | |
self.addEventListener('fetch', (event) => { | |
// Checks if the request is included in our cache if yes returns the cached request | |
let check_cache_hit = async event => { | |
let matched_response = cache.match(event.request); | |
if (matched_response){return matched_response}else{await cache.add(event.request); return false} | |
} | |
// handling fetch events | |
request_url = String(event.request.url); | |
// console.log('request url', request_url); | |
if (event.request.method == "POST"){ | |
// NOTE- This handles adding auth headers to request | |
return event.respondWith( (async () => await fetch(event.request))()) | |
} | |
if (event.request.method == "DELETE"){ | |
// NOTE- This handles adding auth headers to request | |
return event.respondWith( (async () => await fetch(event.request))()) | |
} | |
if (event.request.method == "PUT"){ | |
// NOTE- This handles adding auth headers to request | |
return event.respondWith( (async () => await fetch(event.request))()) | |
} | |
// if its service worker request fetch a fresh copy | |
if ((event.request.method == "GET") && (request_url.includes('sw.js'))) { | |
return event.respondWith( (async () => await fetch(event.request))()) | |
} | |
// if its for static assets fetch first from cache if failed fetch fresh copy | |
if ((event.request.method == "GET") && (request_url.includes('static'))){ | |
return event.respondWith((async () => {return await event.preloadResponse || await check_cache_hit(event) || await fetch(event.request)})()) | |
} | |
// if its a GET request to another domain fetch a fresh copy | |
// if its service worker request fetch a fresh copy | |
if ((event.request.method == "GET") && (!request_url.includes(website_base_url))){ | |
return event.respondWith( (async () => await fetch(event.request))()) | |
} | |
// all other requests fetch securely from backend | |
return event.respondWith((async () => {return await handle_auth_headers(event)})()) | |
}); | |
// NOTE: This is where i actually insert auth headers | |
let handle_auth_headers = async event => { | |
let headers = new Headers(); | |
event.request.headers.forEach((val, key) => { | |
headers.append(key, val); | |
}); | |
// Add ID token to header. | |
headers.append("x-access-token", auth_token); | |
console.log("Auth-Token Inserted on Headers : ", auth_token); | |
// always user cors in order to enable headers modification | |
let request = new Request(event.request.url, { | |
method: event.request.method, | |
headers: headers, | |
mode: "cors", | |
credentials: event.request.credentials, | |
cache: event.request.cache, | |
redirect:event.request.redirect, | |
referrer: event.request.referrer, | |
body: event.request.body, | |
bodyUsed: event.request.bodyUsed, | |
context: event.request.context | |
}); | |
console.log("fetching this request securely", request.url); | |
return await fetch(request); | |
} | |
//********************************************************************************************* */ | |
// Message Dispatcher | |
let messaging = { | |
// This handler should handle all communication from the app to the | |
// service worker -> from the service worker to the outside world | |
messages_handler : function(e){ | |
this.dispatch_message_to_sender = function(e, message){e.source.postMessage(message)}; | |
if (e.data && e.data.type === "auth-token"){ | |
// console.log("setting token", e.data.token); | |
auth_token = e.data.token; | |
if ((auth_token !== "") && (auth_token !== "undefined")){ | |
this.dispatch_message_to_sender(e,{type: "auth-token",message: "Token-Received"}) | |
}else{ | |
auth_token = ""; | |
this.dispatch_message_to_sender(e,{type: "auth-token",message: "Not-Logged-IN"}) | |
} | |
} | |
console.log("Service Worker Receiving this message : ", e.data); | |
}, | |
//********************************************************************************************* *// | |
// PUSH Messages Handler | |
push_handler : function(e){ | |
console.log("push dispatching here"); | |
// let json_message = e.data.json(); | |
// let blob_data = e.data.blob(); | |
let text_message = e.data.text(); | |
// console.log("json", json_message); | |
// console.log("blob", blob_data); | |
console.log('text message', text_message); | |
}, | |
// TODO- dispatch PUSH Messages to App.js push message handler | |
// The handler should decipher the message and decide as to where its destined | |
//********************************************************************************************* */ | |
// Sync messages handlers | |
sync_handler : function(e){ | |
console.log("SYNC DISPATCHER", e); | |
}, | |
init : function(){ | |
self.addEventListener('message', this.messages_handler); | |
self.addEventListener('sync', this.sync_handler); | |
self.addEventListener('push', this.push_handler) | |
} | |
} | |
messaging.init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Custom Cache First Service Worker With Planned Support for Push and Messaging
The service worker is built with integrated authentication based on JWT Authentication and supports message based communication
between Document API and Service Worker , to pass around authentication details.
Authentication is supported by passing header information
by modifying request headers of requests that may need authentication:
The Function handle_auth_headers above takes care of inserting header information
to authenticate calls to the back-end server.
In order for header modification to succeed however the request **mode needs to be set as "cors" ** any other mode will
mean that request headers can not be modified and you will be unable to insert authentication tokens from the service worker.
hence this is why every request mode is set to cors and all other options are left as is.