1
+ var matomoAnalytics = { initialize : function ( options ) {
2
+ if ( 'object' !== typeof options ) {
3
+ options = { } ;
4
+ }
5
+
6
+ var maxLimitQueue = options . queueLimit || 50 ;
7
+ var maxTimeLimit = options . timeLimit || ( 60 * 60 * 24 ) ; // in seconds...
8
+ // same as configured in in tracking_requests_require_authentication_when_custom_timestamp_newer_than
9
+
10
+ function getQueue ( )
11
+ {
12
+ return new Promise ( function ( resolve , reject ) {
13
+ // do a thing, possibly async, then...
14
+
15
+ if ( ! indexedDB ) {
16
+ reject ( new Error ( 'No support for IndexedDB' ) ) ;
17
+ return ;
18
+ }
19
+ var request = indexedDB . open ( "matomo" , 1 ) ;
20
+
21
+ request . onerror = function ( ) {
22
+ console . error ( "Error" , request . error ) ;
23
+ reject ( new Error ( request . error ) ) ;
24
+ } ;
25
+ request . onupgradeneeded = function ( event ) {
26
+ console . log ( 'onupgradeneeded' )
27
+ var db = event . target . result ;
28
+
29
+ if ( ! db . objectStoreNames . contains ( 'requests' ) ) {
30
+ db . createObjectStore ( 'requests' , { autoIncrement : true , keyPath : 'id' } ) ;
31
+ }
32
+
33
+ } ;
34
+ request . onsuccess = function ( event ) {
35
+ var db = event . target . result ;
36
+ let transaction = db . transaction ( "requests" , "readwrite" ) ;
37
+ let requests = transaction . objectStore ( "requests" ) ;
38
+ resolve ( requests ) ;
39
+
40
+
41
+ } ;
42
+ } ) ;
43
+ }
44
+
45
+ function syncQueue ( ) {
46
+ // check something in indexdb
47
+ return getQueue ( ) . then ( function ( queue ) {
48
+ queue . openCursor ( ) . onsuccess = function ( event ) {
49
+ var cursor = event . target . result ;
50
+ if ( cursor && navigator . onLine ) {
51
+ cursor . continue ( ) ;
52
+ var queueId = cursor . value . id ;
53
+
54
+ var secondsQueuedAgo = ( ( Date . now ( ) - cursor . value . created ) / 1000 ) ;
55
+ secondsQueuedAgo = parseInt ( secondsQueuedAgo , 10 ) ;
56
+ if ( secondsQueuedAgo > maxTimeLimit ) {
57
+ // too old
58
+ getQueue ( ) . then ( function ( queue ) {
59
+ queue . delete ( queueId ) ;
60
+ } ) ;
61
+ return ;
62
+ }
63
+
64
+ console . log ( "Cursor " + cursor . key ) ;
65
+
66
+ var init = {
67
+ headers : cursor . value . headers ,
68
+ method : cursor . value . method ,
69
+ }
70
+ if ( cursor . value . body ) {
71
+ init . body = cursor . value . body ;
72
+ }
73
+
74
+ if ( cursor . value . url . includes ( '?' ) ) {
75
+ cursor . value . url += '&cdo=' + secondsQueuedAgo ;
76
+ } else if ( init . body ) {
77
+ // todo test if this actually works for bulk requests
78
+ init . body = init . body . replace ( '&idsite=' , '&cdo=' + secondsQueuedAgo + '&idsite=' ) ;
79
+ }
80
+
81
+ fetch ( cursor . value . url , init ) . then ( function ( response ) {
82
+ console . log ( 'server response' , response ) ;
83
+ if ( response . status < 400 ) {
84
+ getQueue ( ) . then ( function ( queue ) {
85
+ queue . delete ( queueId ) ;
86
+ } ) ;
87
+ }
88
+ } ) . catch ( function ( error ) {
89
+ console . error ( 'Send to Server failed:' , error ) ;
90
+ throw error
91
+ } )
92
+ }
93
+ else {
94
+ console . log ( "No more entries!" ) ;
95
+ }
96
+ } ;
97
+ } ) ;
98
+ }
99
+
100
+ function limitQueueIfNeeded ( queue )
101
+ {
102
+ var countRequest = queue . count ( ) ;
103
+ countRequest . onsuccess = function ( event ) {
104
+ if ( event . result > maxLimitQueue ) {
105
+ // we delete only one at a time because of concurrency some other process might delete data too
106
+ queue . openCursor ( ) . onsuccess = function ( event ) {
107
+ var cursor = event . target . result ;
108
+ if ( cursor ) {
109
+ queue . delete ( cursor . value . id ) ;
110
+ limitQueueIfNeeded ( queue ) ;
111
+ }
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ self . addEventListener ( 'sync' , function ( event ) {
118
+ if ( event . tag === 'matomoSync' ) {
119
+ syncQueue ( ) ;
120
+ }
121
+ } ) ;
122
+
123
+ self . addEventListener ( 'fetch' , function ( event ) {
124
+ let isOnline = navigator . onLine ;
125
+
126
+ let isTrackingRequest = ( event . request . url . includes ( '/matomo.php' )
127
+ || event . request . url . includes ( '/piwik.php' ) ) ;
128
+ let isTrackerRequest = event . request . url . endsWith ( '/matomo.js' )
129
+ || event . request . url . endsWith ( '/piwik.js' ) ;
130
+
131
+ if ( isTrackerRequest ) {
132
+ if ( isOnline ) {
133
+ syncQueue ( ) ;
134
+ }
135
+ caches . open ( 'matomo' ) . then ( function ( cache ) {
136
+ return cache . match ( event . request ) . then ( function ( response ) {
137
+ return response || fetch ( event . request ) . then ( function ( response ) {
138
+ cache . put ( event . request , response . clone ( ) ) ;
139
+ return response ;
140
+ } ) ;
141
+ } ) ;
142
+ } )
143
+ } else if ( isTrackingRequest && isOnline ) {
144
+ syncQueue ( ) ;
145
+ event . respondWith ( fetch ( event . request ) ) ;
146
+ } else if ( isTrackingRequest && ! isOnline ) {
147
+
148
+ var headers = { } ;
149
+ for ( const [ header , value ] of event . request . headers ) {
150
+ headers [ header ] = value ;
151
+ }
152
+
153
+ let requestInfo = {
154
+ url : event . request . url ,
155
+ referrer : event . request . referrer ,
156
+ method : event . request . method ,
157
+ referrerPolicy : event . request . referrerPolicy ,
158
+ headers : headers ,
159
+ created : Date . now ( )
160
+ } ;
161
+ event . request . text ( ) . then ( function ( postData ) {
162
+ requestInfo . body = postData ;
163
+
164
+ getQueue ( ) . then ( function ( queue ) {
165
+ queue . add ( requestInfo ) ;
166
+ limitQueueIfNeeded ( queue ) ;
167
+
168
+ return queue ;
169
+ } ) ;
170
+ } ) ;
171
+
172
+ }
173
+ } ) ;
174
+ }
175
+ } ;
0 commit comments