@@ -33,6 +33,10 @@ const errorCantConnectTo = vAPI.i18n('errorCantConnectTo');
33
33
34
34
const api = { } ;
35
35
36
+ // A hint for various pieces of code to take measures if possible to save
37
+ // bandwidth of remote servers.
38
+ let remoteServerFriendly = false ;
39
+
36
40
/******************************************************************************/
37
41
38
42
const observers = [ ] ;
@@ -157,14 +161,15 @@ api.fetchText = async function(url) {
157
161
// https://github.com/gorhill/uBlock/issues/2592
158
162
// Force browser cache to be bypassed, but only for resources which have
159
163
// been fetched more than one hour ago.
160
- //
161
164
// https://github.com/uBlockOrigin/uBlock-issues/issues/682#issuecomment-515197130
162
165
// Provide filter list authors a way to completely bypass
163
166
// the browser cache.
164
167
// https://github.com/gorhill/uBlock/commit/048bfd251c9b#r37972005
165
168
// Use modulo prime numbers to avoid generating the same token at the
166
169
// same time across different days.
167
- if ( isExternal ) {
170
+ // Do not bypass browser cache if we are asked to be gentle on remote
171
+ // servers.
172
+ if ( isExternal && remoteServerFriendly !== true ) {
168
173
const cacheBypassToken =
169
174
µBlock . hiddenSettings . updateAssetBypassBrowserCache
170
175
? Math . floor ( Date . now ( ) / 1000 ) % 86413
@@ -743,6 +748,19 @@ const getRemote = async function(assetKey) {
743
748
contentURLs = assetDetails . contentURL . slice ( 0 ) ;
744
749
}
745
750
751
+ // If asked to be gentle on remote servers, favour using dedicated CDN
752
+ // servers. If more than one CDN server is present, randomly shuffle the
753
+ // set of servers so as to spread the bandwidth burden.
754
+ if ( remoteServerFriendly && Array . isArray ( assetDetails . cdnURLs ) ) {
755
+ const cdnURLs = assetDetails . cdnURLs . slice ( ) ;
756
+ for ( let i = 0 , n = cdnURLs . length ; i < n ; i ++ ) {
757
+ const j = Math . floor ( Math . random ( ) * n ) ;
758
+ if ( j === i ) { continue ; }
759
+ [ cdnURLs [ j ] , cdnURLs [ i ] ] = [ cdnURLs [ i ] , cdnURLs [ j ] ] ;
760
+ }
761
+ contentURLs . unshift ( ...cdnURLs ) ;
762
+ }
763
+
746
764
for ( const contentURL of contentURLs ) {
747
765
if ( reIsExternalPath . test ( contentURL ) === false ) { continue ; }
748
766
@@ -756,18 +774,17 @@ const getRemote = async function(assetKey) {
756
774
if ( result . statusCode === 0 ) {
757
775
error = 'network error' ;
758
776
}
759
- registerAssetSource (
760
- assetKey ,
761
- { error : { time : Date . now ( ) , error } }
762
- ) ;
777
+ registerAssetSource ( assetKey , {
778
+ error : { time : Date . now ( ) , error }
779
+ } ) ;
763
780
continue ;
764
781
}
765
782
766
783
// Success
767
- assetCacheWrite (
768
- assetKey ,
769
- { content : result . content , url : contentURL }
770
- ) ;
784
+ assetCacheWrite ( assetKey , {
785
+ content : result . content ,
786
+ url : contentURL
787
+ } ) ;
771
788
registerAssetSource ( assetKey , { error : undefined } ) ;
772
789
return reportBack ( result . content ) ;
773
790
}
@@ -835,9 +852,10 @@ const updaterAssetDelayDefault = 120000;
835
852
const updaterUpdated = [ ] ;
836
853
const updaterFetched = new Set ( ) ;
837
854
838
- let updaterStatus ,
839
- updaterTimer ,
840
- updaterAssetDelay = updaterAssetDelayDefault ;
855
+ let updaterStatus ;
856
+ let updaterTimer ;
857
+ let updaterAssetDelay = updaterAssetDelayDefault ;
858
+ let updaterAuto = false ;
841
859
842
860
const updateFirst = function ( ) {
843
861
updaterStatus = 'updating' ;
@@ -861,25 +879,22 @@ const updateNext = async function() {
861
879
if ( updaterFetched . has ( assetKey ) ) { continue ; }
862
880
const cacheEntry = cacheDict [ assetKey ] ;
863
881
if (
864
- cacheEntry &&
882
+ ( cacheEntry instanceof Object ) &&
865
883
( cacheEntry . writeTime + assetEntry . updateAfter * 86400000 ) > now
866
884
) {
867
885
continue ;
868
886
}
869
887
if (
870
- fireNotification (
871
- 'before-asset-updated' ,
872
- { assetKey : assetKey , type : assetEntry . content }
873
- ) === true
888
+ fireNotification ( 'before-asset-updated' , {
889
+ assetKey ,
890
+ type : assetEntry . content
891
+ } ) === true
874
892
) {
875
893
assetKeyToUpdate = assetKey ;
876
894
break ;
877
895
}
878
896
// This will remove a cached asset when it's no longer in use.
879
- if (
880
- cacheEntry &&
881
- cacheEntry . readTime < assetCacheRegistryStartTime
882
- ) {
897
+ if ( cacheEntry && cacheEntry . readTime < assetCacheRegistryStartTime ) {
883
898
assetCacheRemove ( assetKey ) ;
884
899
}
885
900
}
@@ -888,7 +903,13 @@ const updateNext = async function() {
888
903
}
889
904
updaterFetched . add ( assetKeyToUpdate ) ;
890
905
906
+ // In auto-update context, be gentle on remote servers.
907
+ remoteServerFriendly = updaterAuto ;
908
+
891
909
const result = await getRemote ( assetKeyToUpdate ) ;
910
+
911
+ remoteServerFriendly = false ;
912
+
892
913
if ( result . content !== '' ) {
893
914
updaterUpdated . push ( result . assetKey ) ;
894
915
if ( result . assetKey === 'assets.json' ) {
@@ -912,10 +933,11 @@ const updateDone = function() {
912
933
913
934
api . updateStart = function ( details ) {
914
935
const oldUpdateDelay = updaterAssetDelay ;
915
- const newUpdateDelay = typeof details . delay === 'number' ?
916
- details . delay :
917
- updaterAssetDelayDefault ;
936
+ const newUpdateDelay = typeof details . delay === 'number'
937
+ ? details . delay
938
+ : updaterAssetDelayDefault ;
918
939
updaterAssetDelay = Math . min ( oldUpdateDelay , newUpdateDelay ) ;
940
+ updaterAuto = details . auto === true ;
919
941
if ( updaterStatus !== undefined ) {
920
942
if ( newUpdateDelay < oldUpdateDelay ) {
921
943
clearTimeout ( updaterTimer ) ;
0 commit comments