1
1
/**
2
2
* @typedef {import("../../types/new-tab.js").ActivityData } ActivityData
3
3
* @typedef {import("../../types/new-tab.js").ActivityConfig } ActivityConfig
4
+ * @typedef {import("../../types/new-tab.js").UrlInfo } UrlInfo
5
+ * @typedef {import("../../types/new-tab.js").PatchData } PatchData
6
+ * @typedef {import('../../types/new-tab.js').DomainActivity } DomainActivity
7
+ * @typedef {import('../service.js').InvocationSource } InvocationSource
4
8
*/
5
9
import { Service } from '../service.js' ;
6
10
7
- export class ActivityService {
11
+ export class BatchedActivityService {
12
+ INITIAL = 5 ;
13
+ CHUNK_SIZE = 10 ;
14
+ isFetchingNext = false ;
8
15
/**
9
16
* @param {import("../../src/index.js").NewTabPage } ntp - The internal data feed, expected to have a `subscribe` method.
17
+ * @param {boolean } batched
10
18
* @internal
11
19
*/
12
- constructor ( ntp ) {
20
+ constructor ( ntp , batched = false ) {
13
21
this . ntp = ntp ;
22
+ this . batched = batched ;
23
+
24
+ /** @type {Service<import('../../types/new-tab.js').UrlInfo> } */
25
+ this . urlService = new Service ( {
26
+ initial : ( ) => {
27
+ if ( this . batched ) {
28
+ return this . ntp . messaging . request ( 'activity_getUrls' ) ;
29
+ } else {
30
+ /** @type {UrlInfo } */
31
+ const next = {
32
+ urls : [ ] ,
33
+ totalTrackersBlocked : 0 ,
34
+ } ;
35
+ return Promise . resolve ( next ) ;
36
+ }
37
+ } ,
38
+ subscribe : ( cb ) => ntp . messaging . subscribe ( 'activity_onDataPatch' , cb ) ,
39
+ } ) ;
40
+
14
41
/** @type {Service<ActivityData> } */
15
42
this . dataService = new Service ( {
16
- initial : ( ) => ntp . messaging . request ( 'activity_getData' ) ,
43
+ initial : ( params ) => {
44
+ if ( this . batched ) {
45
+ return this . ntp . messaging . request ( 'activity_getDataForUrls' , { urls : params . urls } ) ;
46
+ } else {
47
+ return this . ntp . messaging . request ( 'activity_getData' ) ;
48
+ }
49
+ } ,
17
50
subscribe : ( cb ) => ntp . messaging . subscribe ( 'activity_onDataUpdate' , cb ) ,
51
+ } ) . withUpdater ( ( old , next , source ) => {
52
+ if ( source === 'manual' ) {
53
+ return next ;
54
+ }
55
+ if ( this . batched ) {
56
+ return { activity : old . activity . concat ( next . activity ) } ;
57
+ }
58
+ return next ;
18
59
} ) ;
19
60
20
61
/** @type {Service<ActivityConfig> } */
@@ -29,21 +70,31 @@ export class ActivityService {
29
70
this . burnUnsub = this . ntp . messaging . subscribe ( 'activity_onBurnComplete' , ( ) => {
30
71
this . burns ?. dispatchEvent ( new CustomEvent ( 'activity_onBurnComplete' ) ) ;
31
72
} ) ;
73
+ this . patchesSub = this . onPatchData ( ) ;
32
74
}
33
75
34
76
name ( ) {
35
- return 'ActivityService ' ;
77
+ return 'BatchedActivity ' ;
36
78
}
37
79
38
80
/**
39
- * @returns {Promise<{data: ActivityData; config: ActivityConfig}> }
81
+ * @returns {Promise<{data: ActivityData; config: ActivityConfig }> }
40
82
* @internal
41
83
*/
42
84
async getInitial ( ) {
43
- const p1 = this . configService . fetchInitial ( ) ;
44
- const p2 = this . dataService . fetchInitial ( ) ;
45
- const [ config , data ] = await Promise . all ( [ p1 , p2 ] ) ;
46
- return { config, data } ;
85
+ if ( this . batched ) {
86
+ const configPromise = this . configService . fetchInitial ( ) ;
87
+ const urlsPromise = this . urlService . fetchInitial ( ) ;
88
+ const [ config , urlData ] = await Promise . all ( [ configPromise , urlsPromise ] ) ;
89
+ const data = await this . dataService . fetchInitial ( { urls : urlData . urls . slice ( 0 , this . INITIAL ) } ) ;
90
+ return { config, data } ;
91
+ } else {
92
+ const configPromise = this . configService . fetchInitial ( ) ;
93
+ const dataPromise = this . dataService . fetchInitial ( ) ;
94
+ const urlInfoPromise = this . urlService . fetchInitial ( ) ;
95
+ const [ config , data ] = await Promise . all ( [ configPromise , dataPromise , urlInfoPromise ] ) ;
96
+ return { config, data } ;
97
+ }
47
98
}
48
99
49
100
/**
@@ -53,23 +104,62 @@ export class ActivityService {
53
104
this . configService . destroy ( ) ;
54
105
this . dataService . destroy ( ) ;
55
106
this . burnUnsub ( ) ;
107
+ this . patchesSub ( ) ;
56
108
this . burns = null ;
57
109
}
58
110
59
111
/**
60
- * @param {(evt: {data: ActivityData, source: 'manual' | 'subscription'}) => void } cb
112
+ * @param {string[] } urls
113
+ */
114
+ next ( urls ) {
115
+ if ( ! this . urlService . data ) throw new Error ( 'unreachable' ) ;
116
+ if ( urls . length === 0 ) return ;
117
+ this . isFetchingNext = true ;
118
+ this . dataService . triggerFetch ( { urls } ) ;
119
+ }
120
+
121
+ /**
122
+ * @param {(evt: {data: UrlInfo & PatchData, source: InvocationSource}) => void } cb
123
+ * @internal
124
+ */
125
+ onUrlData ( cb ) {
126
+ return this . urlService . onData ( ( params ) => {
127
+ if ( 'patch' in params . data && params . data . patch !== null ) return console . log ( 'ignoring patch' ) ;
128
+ cb ( params ) ;
129
+ } ) ;
130
+ }
131
+
132
+ /**
133
+ * @internal
134
+ */
135
+ onPatchData ( ) {
136
+ return this . urlService . onData ( ( params ) => {
137
+ if ( ! ( 'patch' in params . data && params . data . patch !== null ) ) return console . log ( 'ignoring none-patch' ) ;
138
+ this . dataService . publish ( { activity : [ /** @type {DomainActivity } */ ( params . data . patch ) ] } ) ;
139
+ } ) ;
140
+ }
141
+
142
+ /**
143
+ * @param {(evt: {data: ActivityData, source: InvocationSource}) => void } cb
61
144
* @internal
62
145
*/
63
146
onData ( cb ) {
64
- return this . dataService . onData ( cb ) ;
147
+ return this . dataService . onData ( ( data ) => {
148
+ this . isFetchingNext = false ;
149
+ cb ( data ) ;
150
+ } ) ;
65
151
}
66
152
67
153
triggerDataFetch ( ) {
68
- return this . dataService . triggerFetch ( ) ;
154
+ if ( this . batched ) {
155
+ this . urlService . triggerFetch ( ) ;
156
+ } else {
157
+ this . dataService . triggerFetch ( ) ;
158
+ }
69
159
}
70
160
71
161
/**
72
- * @param {(evt: {data: ActivityConfig, source: 'manual' | 'subscription' }) => void } cb
162
+ * @param {(evt: {data: ActivityConfig, source: InvocationSource }) => void } cb
73
163
* @internal
74
164
*/
75
165
onConfig ( cb ) {
@@ -138,6 +228,12 @@ export class ActivityService {
138
228
} ) ,
139
229
} ;
140
230
} ) ;
231
+ this . urlService . update ( ( old ) => {
232
+ return {
233
+ ...old ,
234
+ urls : old . urls . filter ( ( x ) => x !== url ) ,
235
+ } ;
236
+ } ) ;
141
237
this . ntp . messaging . notify ( 'activity_removeItem' , { url } ) ;
142
238
}
143
239
/**
0 commit comments