diff options
author | Thomas Steur <tsteur@users.noreply.github.com> | 2020-10-02 03:20:20 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-02 03:20:20 +0300 |
commit | 2807e94baaa9b545f27a55a7dd071ba187799491 (patch) | |
tree | 9fa5722fe414e7f1e664d4226b2620d215fd1987 /offline-service-worker.js | |
parent | 06d43857c48ada2fa7f1ad18a8309e8826c0e413 (diff) |
JS Offline tracking (#15970)
* JS Offline tracking
* minor tweaks
* add some tests
* add some tests
* apply review feedback
Diffstat (limited to 'offline-service-worker.js')
-rw-r--r-- | offline-service-worker.js | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/offline-service-worker.js b/offline-service-worker.js new file mode 100644 index 0000000000..a00fe1a906 --- /dev/null +++ b/offline-service-worker.js @@ -0,0 +1,175 @@ +var matomoAnalytics = {initialize: function (options) { + if ('object' !== typeof options) { + options = {}; + } + + var maxLimitQueue = options.queueLimit || 50; + var maxTimeLimit = options.timeLimit || (60 * 60 * 24); // in seconds... + // same as configured in in tracking_requests_require_authentication_when_custom_timestamp_newer_than + + function getQueue() + { + return new Promise(function(resolve, reject) { + // do a thing, possibly async, then... + + if (!indexedDB) { + reject(new Error('No support for IndexedDB')); + return; + } + var request = indexedDB.open("matomo", 1); + + request.onerror = function() { + console.error("Error", request.error); + reject(new Error(request.error)); + }; + request.onupgradeneeded = function(event) { + console.log('onupgradeneeded') + var db = event.target.result; + + if (!db.objectStoreNames.contains('requests')) { + db.createObjectStore('requests', {autoIncrement : true, keyPath: 'id'}); + } + + }; + request.onsuccess = function(event) { + var db = event.target.result; + let transaction = db.transaction("requests", "readwrite"); + let requests =transaction.objectStore("requests"); + resolve(requests); + + + }; + }); + } + + function syncQueue () { + // check something in indexdb + return getQueue().then(function (queue) { + queue.openCursor().onsuccess = function(event) { + var cursor = event.target.result; + if (cursor && navigator.onLine) { + cursor.continue(); + var queueId = cursor.value.id; + + var secondsQueuedAgo = ((Date.now() - cursor.value.created) / 1000); + secondsQueuedAgo = parseInt(secondsQueuedAgo, 10); + if (secondsQueuedAgo > maxTimeLimit) { + // too old + getQueue().then(function (queue) { + queue.delete(queueId); + }); + return; + } + + console.log("Cursor " + cursor.key); + + var init = { + headers: cursor.value.headers, + method: cursor.value.method, + } + if (cursor.value.body) { + init.body = cursor.value.body; + } + + if (cursor.value.url.includes('?')) { + cursor.value.url += '&cdo=' + secondsQueuedAgo; + } else if (init.body) { + // todo test if this actually works for bulk requests + init.body = init.body.replace('&idsite=', '&cdo=' + secondsQueuedAgo + '&idsite='); + } + + fetch(cursor.value.url, init).then(function (response) { + console.log('server response', response); + if (response.status < 400) { + getQueue().then(function (queue) { + queue.delete(queueId); + }); + } + }).catch(function (error) { + console.error('Send to Server failed:', error); + throw error + }) + } + else { + console.log("No more entries!"); + } + }; + }); + } + + function limitQueueIfNeeded(queue) + { + var countRequest = queue.count(); + countRequest.onsuccess = function(event) { + if (event.result > maxLimitQueue) { + // we delete only one at a time because of concurrency some other process might delete data too + queue.openCursor().onsuccess = function(event) { + var cursor = event.target.result; + if (cursor) { + queue.delete(cursor.value.id); + limitQueueIfNeeded(queue); + } + } + } + } + } + + self.addEventListener('sync', function(event) { + if (event.tag === 'matomoSync') { + syncQueue(); + } + }); + + self.addEventListener('fetch', function (event) { + let isOnline = navigator.onLine; + + let isTrackingRequest = (event.request.url.includes('/matomo.php') + || event.request.url.includes('/piwik.php')); + let isTrackerRequest = event.request.url.endsWith('/matomo.js') + || event.request.url.endsWith('/piwik.js'); + + if (isTrackerRequest) { + if (isOnline) { + syncQueue(); + } + caches.open('matomo').then(function(cache) { + return cache.match(event.request).then(function (response) { + return response || fetch(event.request).then(function(response) { + cache.put(event.request, response.clone()); + return response; + }); + }); + }) + } else if (isTrackingRequest && isOnline) { + syncQueue(); + event.respondWith(fetch(event.request)); + } else if (isTrackingRequest && !isOnline) { + + var headers = {}; + for (const [header, value] of event.request.headers) { + headers[header] = value; + } + + let requestInfo = { + url: event.request.url, + referrer : event.request.referrer, + method : event.request.method, + referrerPolicy : event.request.referrerPolicy, + headers : headers, + created: Date.now() + }; + event.request.text().then(function (postData) { + requestInfo.body = postData; + + getQueue().then(function (queue) { + queue.add(requestInfo); + limitQueueIfNeeded(queue); + + return queue; + }); + }); + + } + }); +} +};
\ No newline at end of file |