Created
March 13, 2017 17:32
-
-
Save Rebolon/2d0c848e202faca4a1c69432d6dc5f8a to your computer and use it in GitHub Desktop.
Revisions
-
Rebolon created this gist
Mar 13, 2017 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,177 @@ /** * allow to cache response and/or to listen on newRequest event * * for cache system, it's freely adapted from https://github.com/pagekit/vue-resource/issues/252 @airtonix sample */ export class HttpInterceptors { _cache constructor (Vue, ttlInHours) { if (Vue.http === undefined) { throw new Error('you have to add the vue-resource plugin') } if (!Vue.DI || !Vue.DI.Bus) { throw new Error('you have to add the Vue.DI.Bus system') } this.vueJS = Vue this.ttlInHours = ttlInHours } /** * * @param IBus {$emit: function} * @returns {HttpInterceptors} */ addNewRequestListener (bus) { if (typeof bus.$emit !== 'function') { throw new Error('bus must have an $emit method') } this.vueJS.http.interceptors.push((request, next) => { bus.$emit('newRequest', request) // continue to next interceptor next() }) return this } /** * @params ICache {get: function, put: function, remove: function} * @returns {HttpInterceptors} */ addHttpCache (cache) { ['get', 'put', 'remove'].forEach(method => { if (typeof cache[method] !== 'function') { throw new Error(`cache must have an ${method} method`) } }) // this is to be able to test the doCache method lonely this._cache = cache this.vueJS.http.interceptors.push(this._doCache.bind(this)) return this } /** * * @param request * @param next * @private */ _doCache (request, next) { if (!this._cache) { throw new Error(`you forgot the cache system`) } let id = this._getId(request) if (request.method.toLowerCase() === 'get') { this._cache.get(this._getId(request)) .then(doc => { if (this._checkTTL(doc)) { console.log('cache hit', id) next(request.respondWith(doc.body, {status: 200, statusText: 'Ok'})) } else { console.log(doc.ttl, this._getTTL(), this._checkTTL(doc)) this._cache.remove(doc) throw Object.create({code: 1000}) } }) .catch(err => { if (err.status === 404) { console.info('cache miss, not in db (catch)', id) next((response) => { let {status, statusText, body} = response if (status === 200 && request.method.toLowerCase() === 'get') { response._id = id response.ttl = this._getTTL() // if Conflict we have to get the current object, merge the response with the object Object.assign(docFound, response) and then put it in db this._cache .put(response) .catch(err => { if (err.status === 409) { console.warn('Conflict error in insert') return } console.error('error during put db', err, response) }) } request.respondWith(body, {status, statusText}) }) return } else if (err.code === 1000) { console.info('cache miss, ttl delayed (catch)', id) next() return } console.error('error during get db', err) }) } else { next() } } /** * * @param request * @returns {string} */ _getId (request) { let qs = [] Object.keys(request.params).forEach(key => { if (key === 'apikey') return qs.push(`${key}=${request.params[key]}`) }) if (qs.length) { qs = `?${qs.join('&')}` } const id = `CACHE_${request.url}${qs}` return id } /** * */ _getTTL () { const now = new Date() return now.setHours(now.getHours() + this.ttlInHours) } /** * * @param data * @returns {boolean} */ _checkTTL (data) { return data.ttl > new Date() } } /** * to use it with a 60 minutes of TTL on each http call: * * import Vue from 'vue' * import PouchDB from 'pouchdb' * import { HttpInterceptors } from './interceptors' * const VueResource = require('vue-resource') * * Vue.use(VueResource) * const interceptors = new HttpInterceptors(Vue, 1) * interceptors * .addNewRequestListener(new Vue) * .addHttpCache(new PouchDB('your-channel')) */