mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-11-04 05:27:04 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			163 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
const CACHE_NAME = 'v0.3';
 | 
						|
const DELAY_BEFORE_SENDING_CACHE = 2000;
 | 
						|
 | 
						|
/*
 | 
						|
 * Control everything going through the wire, applying different
 | 
						|
 * strategy for caching, fetching resources
 | 
						|
 */
 | 
						|
self.addEventListener('fetch', function(event){
 | 
						|
    if(is_a_ressource(event.request)){
 | 
						|
        return event.respondWith(smartCacheStrategy(event.request));
 | 
						|
    }else if(is_an_api_call(event.request)){
 | 
						|
        return event;
 | 
						|
    }else if(is_an_index(event.request)){
 | 
						|
        return event.respondWith(smartCacheStrategy(event.request))
 | 
						|
    }else{
 | 
						|
        return event;
 | 
						|
    }
 | 
						|
});
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * When a new service worker is coming in, we need to do a bit of
 | 
						|
 * cleanup to get rid of the rotten cache
 | 
						|
 */
 | 
						|
self.addEventListener('activate', function(event){
 | 
						|
    vacuum(event);
 | 
						|
});
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * When a newly installed service worker is coming in, we want to use it
 | 
						|
 * straight away (make it active). By default it would be in a "waiting state"
 | 
						|
 */
 | 
						|
self.addEventListener('install', function(event){
 | 
						|
    if (self.skipWaiting) { self.skipWaiting(); }
 | 
						|
});
 | 
						|
 | 
						|
 | 
						|
 | 
						|
////////////////////////////////////////
 | 
						|
// Test if what's the request is about
 | 
						|
////////////////////////////////////////
 | 
						|
 | 
						|
function is_a_ressource(request){
 | 
						|
    return ['css', 'js', 'img', 'logo', 'manifest.json', 'favicon.ico'].indexOf(_pathname(request)[0]) >= 0 ? true : false;
 | 
						|
}
 | 
						|
 | 
						|
function is_an_api_call(request){
 | 
						|
    return _pathname(request)[0] === 'api' ? true : false;
 | 
						|
}
 | 
						|
function is_an_index(request){
 | 
						|
    return ['login', 'files', 'view', 'logout'].indexOf(_pathname(request)[0]) >= 0? true : false;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
////////////////////////////////////////
 | 
						|
// HELPERS
 | 
						|
////////////////////////////////////////
 | 
						|
 | 
						|
function vacuum(event){
 | 
						|
    return event.waitUntil(
 | 
						|
        caches.keys().then(function(cachesName){
 | 
						|
            return Promise.all(cachesName.map(function(cacheName){
 | 
						|
                if(cacheName !== CACHE_NAME){
 | 
						|
                    return caches.delete(cacheName);
 | 
						|
                }
 | 
						|
            }));
 | 
						|
        })
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
function _pathname(request){
 | 
						|
    return request.url.replace(/^http[s]?:\/\/[^\/]*\//, '').split('/')
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Loading Strategy:
 | 
						|
 * use what's in cache first to make things faster but refresh it as we receive a response
 | 
						|
 */
 | 
						|
function smartCacheStrategy(request){
 | 
						|
    return caches.open(CACHE_NAME).then(function(cache){
 | 
						|
        return cache.match(request)
 | 
						|
            .then(function(response){
 | 
						|
                if(response && response.status === 200){
 | 
						|
                    fetchAndCache(request).catch(nil);
 | 
						|
                    response.headers.append('Content-Stale', 'yes');
 | 
						|
                    return response;
 | 
						|
                }else{
 | 
						|
                    return Promise.reject("OUPS");
 | 
						|
                }
 | 
						|
            })
 | 
						|
            .catch(function(err){
 | 
						|
                return fetchAndCache(request);
 | 
						|
            });
 | 
						|
    }).catch(() => request);
 | 
						|
 | 
						|
 | 
						|
    function fetchAndCache(_request){
 | 
						|
        // A request is a stream and can only be consumed once. Since we are consuming this
 | 
						|
        // once by cache and once by the browser for fetch, we need to clone the response as
 | 
						|
        // seen on https://developers.google.com/web/fundamentals/getting-started/primers/service-workers
 | 
						|
        return fetch(_request.clone && _request.clone() || _request)
 | 
						|
            .then(function(response){
 | 
						|
                if(!response || response.status !== 200){ return response; }
 | 
						|
 | 
						|
                // A response is a stream and can only because we want the browser to consume the
 | 
						|
                // response as well as the cache consuming the response, we need to clone it
 | 
						|
                const responseClone = response.clone();
 | 
						|
                caches.open(CACHE_NAME).then(function(cache){
 | 
						|
                    cache.put(_request, responseClone);
 | 
						|
                });
 | 
						|
                return response;
 | 
						|
            }).catch(() => _request);
 | 
						|
    }
 | 
						|
    function nil(e){}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
// Broken as I didn't understood the Promise.race behavior correctly first ...
 | 
						|
// if nothing in cache it just brakes
 | 
						|
function networkFirstStrategy(request){
 | 
						|
    return new Promise(function(done, error){
 | 
						|
        cache(request.clone && request.clone() || request).then(function(response){
 | 
						|
            if(!response || !response.headers) return;
 | 
						|
            response.headers.append('Content-Stale', 'yes');
 | 
						|
            done(response);
 | 
						|
        });
 | 
						|
        network(request.clone && request.clone() || request)
 | 
						|
            .then(done)
 | 
						|
            .catch(error);
 | 
						|
    }).catch(() => request);
 | 
						|
 | 
						|
    function network(request){
 | 
						|
        return fetch(request)
 | 
						|
            .then(function(response){
 | 
						|
                if(!response || response.status !== 200) return Promise.reject(response);
 | 
						|
 | 
						|
                const responseClone = response.clone();
 | 
						|
                caches.open(CACHE_NAME).then(function(cache){
 | 
						|
                    cache.put(request, responseClone);
 | 
						|
                });
 | 
						|
                return Promise.resolve(response);
 | 
						|
            })
 | 
						|
            .catch(function(){
 | 
						|
                return cache(request.clone && request.clone() || request)
 | 
						|
            });
 | 
						|
    }
 | 
						|
 | 
						|
    function cache(_request){
 | 
						|
        return timeout()
 | 
						|
            .then(function(){ return caches.open(CACHE_NAME); })
 | 
						|
            .then(function(_cache){ return _cache.match(_request); });
 | 
						|
 | 
						|
        function timeout(){
 | 
						|
            return new Promise(function(done) {
 | 
						|
                setTimeout(function() {
 | 
						|
                    done();
 | 
						|
                }, DELAY_BEFORE_SENDING_CACHE);
 | 
						|
            });
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |