-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
251 additions
and
9 deletions.
There are no files selected for viewing
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/** | ||
* Service Worker functionality controller. | ||
* Use this object on the front to communicate with Service Worker. | ||
*/ | ||
export default class Sw_Control_Front_Model_Sw_Control { | ||
constructor(spec) { | ||
// EXTRACT DEPS | ||
/** @type {typeof Sw_Control_Front_Model_Sw_Message_Type} */ | ||
const MSG = spec['Sw_Control_Front_Model_Sw_Message_Type$']; | ||
/** @type {typeof Sw_Control_Front_Model_Sw_Message_Dto} */ | ||
const Dto = spec['Sw_Control_Front_Model_Sw_Message_Dto#']; | ||
|
||
// DEFINE WORKING VARS / PROPS | ||
/** | ||
* Registry for outgoing messages been sent to SW and theirs callbacks. | ||
* @type {Object<string, function>} | ||
* @private | ||
*/ | ||
const _queue = {}; | ||
|
||
// DEFINE INNER FUNCTIONS | ||
const generateMsgId = () => `${(new Date()).getTime()}`; | ||
|
||
/** | ||
* Return SW response (payload) to consumer using callback function from queue. | ||
* @param {MessageEvent} event | ||
*/ | ||
function onMessage(event) { | ||
/** @type {Message} */ | ||
const msg = event.data; | ||
console.log(`[Control]: backward message from SW, type '${msg.type}'.`); | ||
if (typeof _queue[msg.id] === 'function') _queue[msg.id](msg.payload); | ||
} | ||
|
||
// DEFINE INSTANCE METHODS | ||
/** | ||
* Get state of the service worker. | ||
* 'true' - 'cat' URL is selected as secondary image, 'false' - 'dog' URL. | ||
* @return {Promise<boolean>} | ||
*/ | ||
this.getState = function () { | ||
// generate ID to register data parsing callback | ||
const id = generateMsgId(); | ||
// create and return new promise | ||
return new Promise(async (resolve) => { | ||
// create and register callback to process SW backward message. | ||
_queue[id] = function (payload) { | ||
// return 'boolean' result to caller (see SW code) | ||
console.log(`[Control]: payload is returned to caller: ${JSON.stringify(payload)}`); | ||
resolve(payload); | ||
}; | ||
// create new DTO to send data to SW | ||
const msg = new Dto(); | ||
msg.id = id; | ||
msg.type = MSG.GET_STATE; | ||
// send message to SW | ||
console.log(`[Control]: send message to SW to get current state.`); | ||
const sw = await navigator.serviceWorker.ready; | ||
if (sw.active) sw.active.postMessage(msg); | ||
}); | ||
}; | ||
|
||
this.setState = function (replaceWithCat = true) { | ||
const id = generateMsgId(); | ||
return new Promise(async (resolve) => { | ||
// create and register callback to process SW backward message. | ||
_queue[id] = function (payload) { | ||
// return 'boolean' result to caller (see SW code) | ||
console.log(`[Control]: payload is returned to caller: ${JSON.stringify(payload)}.`); | ||
resolve(payload); | ||
}; | ||
// create new DTO to send data to SW | ||
const msg = new Dto(); | ||
msg.id = id; | ||
msg.type = MSG.SET_STATE; | ||
msg.payload = replaceWithCat; | ||
// send message to SW | ||
const logState = (replaceWithCat) ? 'cat' : 'dog'; | ||
console.log(`[Control]: send message to SW to set state: ${logState}.`); | ||
const sw = await navigator.serviceWorker.ready; | ||
sw.active.postMessage(msg); | ||
}); | ||
}; | ||
|
||
// MAIN FUNCTIONALITY | ||
self.navigator.serviceWorker.addEventListener('message', onMessage); | ||
} | ||
|
||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
/** | ||
* Service worker message structure. | ||
*/ | ||
export default class Sw_Control_Front_Model_Sw_Message_Dto { | ||
/** @type {string} */ | ||
id; | ||
/** @type {*} */ | ||
payload; | ||
/** @type {typeof Sw_Control_Front_Model_Sw_Message_Type} */ | ||
type; | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* Enumeration for Service Worker messages. | ||
*/ | ||
const Sw_Control_Front_Model_Sw_Message_Type = { | ||
GET_STATE: 'get_state', | ||
SET_STATE: 'set_state', | ||
} | ||
Object.freeze(Sw_Control_Front_Model_Sw_Message_Type); | ||
export default Sw_Control_Front_Model_Sw_Message_Type; |
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
File renamed without changes
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
// DEFINE WORKING VARS / PROPS | ||
const CACHE_STATIC = 'sw-static-cache-v1'; | ||
const URL_CAT = '/img/cat.svg'; | ||
const URL_DOG = '/img/dog.svg'; | ||
const URL_PRIMARY = '/img/primary.svg'; | ||
const URL_SECONDARY = '/img/secondary.svg'; // this is virtual URL that is mapped to real URL (dog or cat) | ||
|
||
let _useCat = true; // SW state to replace virtual URL | ||
|
||
// DEFINE INNER FUNCTIONS | ||
|
||
/** | ||
* Send message to `index.html` to start bootstrap process after installation process been completed. | ||
*/ | ||
function onActivate() { | ||
self.clients.claim(); | ||
} | ||
|
||
/** | ||
* Replace secondary URL with 'cat' or 'dog' URL. | ||
* @param event | ||
*/ | ||
function onFetch(event) { | ||
const url = new URL(event.request.url); | ||
if (url.origin === location.origin && url.pathname === URL_SECONDARY) { | ||
if (_useCat) { | ||
event.respondWith(caches.match(URL_CAT)); | ||
} else { | ||
event.respondWith(caches.match(URL_DOG)); | ||
} | ||
|
||
} | ||
} | ||
|
||
/** | ||
* Load images to the cache storage. | ||
* @param event | ||
*/ | ||
function onInstall(event) { | ||
// DEFINE INNER FUNCTIONS | ||
async function cacheStatics() { | ||
try { | ||
const files = [URL_CAT, URL_DOG, URL_PRIMARY]; | ||
const cacheStat = await caches.open(CACHE_STATIC); | ||
await cacheStat.addAll(files); | ||
} catch (e) { | ||
console.log('[SW] install error: '); | ||
console.dir(e); | ||
} | ||
} | ||
|
||
// MAIN FUNCTIONALITY | ||
event.waitUntil(cacheStatics()); | ||
} | ||
|
||
/** | ||
* Get messages from app and change internal state. | ||
* @param {MessageEvent} event | ||
*/ | ||
function onMessage(event) { | ||
// get incoming data | ||
/** @type {Sw_Control_Front_Model_Sw_Message_Dto} */ | ||
const msg = event.data; | ||
console.log(`[SW]: new message is received, type: ${msg.type}`); | ||
// create outgoing data | ||
/** @type {Sw_Control_Front_Model_Sw_Message_Dto} */ | ||
const res = {}; | ||
res.id = msg.id; | ||
res.type = msg.type; | ||
// analyze type of the message, perform requested operation and set outgoing data | ||
if (msg.type === 'get_state') { | ||
res.payload = _useCat; | ||
} else if (msg.type === 'set_state') { | ||
const useCat = msg.payload; | ||
if (useCat !== _useCat) { | ||
// change state | ||
_useCat = useCat; | ||
res.payload = true; | ||
} else { | ||
// we don't change anything | ||
res.payload = false; | ||
} | ||
} | ||
console.log(`[SW]: send backward message, type: ${msg.type}`); | ||
event.source.postMessage(res); | ||
} | ||
|
||
// MAIN FUNCTIONALITY | ||
self.addEventListener('activate', onActivate); | ||
self.addEventListener('fetch', onFetch); | ||
self.addEventListener('install', onInstall); | ||
self.addEventListener('message', onMessage); |