@@ -49,7 +49,7 @@ function showToast(message: string) {
4949async function processUser ( username : string , tweetElement ?: Element ) {
5050 // skip if already processing this user
5151 if ( inFlightUsers . has ( username ) ) {
52- console . log ( `[xBlockOrigin] Skipping @${ username } - already processing ` )
52+ console . log ( `[xBlockOrigin] Skipping @${ username } - already in queue ` )
5353 return
5454 }
5555 inFlightUsers . add ( username )
@@ -67,7 +67,10 @@ async function processUser(username: string, tweetElement?: Element) {
6767 console . log (
6868 `[xBlockOrigin] Fetching user data for @${ username } (cache miss)`
6969 )
70- const userData = await apiQueue . enqueue ( ( ) => getUserData ( username ) )
70+ const userData = await apiQueue . enqueue (
71+ ( ) => getUserData ( username ) ,
72+ username
73+ )
7174
7275 if ( ! userData ) {
7376 console . error (
@@ -102,7 +105,10 @@ async function processUser(username: string, tweetElement?: Element) {
102105 console . log (
103106 `[xBlockOrigin] Following status cache miss for @${ username } , fetching user data`
104107 )
105- const userData = await apiQueue . enqueue ( ( ) => getUserData ( username ) )
108+ const userData = await apiQueue . enqueue (
109+ ( ) => getUserData ( username ) ,
110+ username
111+ )
106112
107113 if ( ! userData ) {
108114 console . error (
@@ -151,7 +157,7 @@ async function processUser(username: string, tweetElement?: Element) {
151157
152158 // fetch country for new users
153159 console . log ( `[xBlockOrigin] Fetching country for @${ username } ` )
154- country = await apiQueue . enqueue ( ( ) => getCountry ( username ) )
160+ country = await apiQueue . enqueue ( ( ) => getCountry ( username ) , username )
155161
156162 if ( ! country ) {
157163 console . log (
@@ -196,7 +202,7 @@ async function processUser(username: string, tweetElement?: Element) {
196202 console . log (
197203 `[xBlockOrigin] Attempting to mute @${ username } (${ userId } ) from ${ country } ...`
198204 )
199- const success = await apiQueue . enqueue ( ( ) => muteUser ( userId ) )
205+ const success = await apiQueue . enqueue ( ( ) => muteUser ( userId ) , username )
200206
201207 if ( ! success ) {
202208 console . error ( `[xBlockOrigin] Failed to mute @${ username } ` )
@@ -252,64 +258,85 @@ function getCurrentPage(): string {
252258 return 'unknown'
253259}
254260
261+ function waitForNavigation ( currentUrl : string ) : Promise < string > {
262+ // race between popstate event and polling
263+ const popstatePromise = new Promise < string > ( ( resolve ) => {
264+ const handler = ( ) => {
265+ if ( window . location . href !== currentUrl ) {
266+ resolve ( window . location . href )
267+ }
268+ }
269+ window . addEventListener ( 'popstate' , handler , { once : true } )
270+ } )
271+
272+ const pollingPromise = new Promise < string > ( ( resolve ) => {
273+ const checkUrl = ( ) => {
274+ if ( window . location . href !== currentUrl ) {
275+ resolve ( window . location . href )
276+ } else {
277+ setTimeout ( checkUrl , 100 )
278+ }
279+ }
280+ checkUrl ( )
281+ } )
282+
283+ return Promise . race ( [ popstatePromise , pollingPromise ] )
284+ }
285+
255286export function startOrchestrator ( ) {
256287 const cleanupFns : Array < ( ) => void > = [ ]
288+ let running = true
257289
258290 const handleUser = ( username : string , tweetElement ?: Element ) => {
259291 processUser ( username , tweetElement )
260292 }
261293
262- const currentPage = getCurrentPage ( )
263-
264- switch ( currentPage ) {
265- case 'timeline' :
266- cleanupFns . push ( scanTimeline ( handleUser ) )
267- break
268- case 'search' :
269- cleanupFns . push ( scanSearch ( handleUser ) )
270- break
271- case 'notifications' :
272- cleanupFns . push ( scanReplies ( handleUser ) )
273- break
274- case 'status' :
275- cleanupFns . push ( scanStatus ( handleUser ) )
276- break
277- case 'profile' :
278- cleanupFns . push ( scanProfile ( handleUser ) )
279- break
294+ const startScanners = ( page : string ) => {
295+ switch ( page ) {
296+ case 'timeline' :
297+ cleanupFns . push ( scanTimeline ( handleUser ) )
298+ break
299+ case 'search' :
300+ cleanupFns . push ( scanSearch ( handleUser ) )
301+ break
302+ case 'notifications' :
303+ cleanupFns . push ( scanReplies ( handleUser ) )
304+ break
305+ case 'status' :
306+ cleanupFns . push ( scanStatus ( handleUser ) )
307+ break
308+ case 'profile' :
309+ cleanupFns . push ( scanProfile ( handleUser ) )
310+ break
311+ }
280312 }
281313
282- let lastUrl = window . location . href
283- const urlWatcher = setInterval ( ( ) => {
284- if ( window . location . href !== lastUrl ) {
285- lastUrl = window . location . href
314+ const handleNavigation = async ( ) => {
315+ let currentUrl = window . location . href
316+ startScanners ( getCurrentPage ( ) )
317+
318+ while ( running ) {
319+ const newUrl = await waitForNavigation ( currentUrl )
320+ if ( ! running ) break
321+
322+ currentUrl = newUrl
286323
324+ // clear pending API requests on navigation
325+ apiQueue . clear ( )
326+
327+ // cleanup old scanners
287328 cleanupFns . forEach ( ( fn ) => fn ( ) )
288329 cleanupFns . length = 0
289330
290- const newPage = getCurrentPage ( )
291- switch ( newPage ) {
292- case 'timeline' :
293- cleanupFns . push ( scanTimeline ( handleUser ) )
294- break
295- case 'search' :
296- cleanupFns . push ( scanSearch ( handleUser ) )
297- break
298- case 'notifications' :
299- cleanupFns . push ( scanReplies ( handleUser ) )
300- break
301- case 'status' :
302- cleanupFns . push ( scanStatus ( handleUser ) )
303- break
304- case 'profile' :
305- cleanupFns . push ( scanProfile ( handleUser ) )
306- break
307- }
331+ // start new scanners
332+ startScanners ( getCurrentPage ( ) )
308333 }
309- } , 1000 )
334+ }
335+
336+ handleNavigation ( )
310337
311338 return ( ) => {
312- clearInterval ( urlWatcher )
339+ running = false
313340 cleanupFns . forEach ( ( fn ) => fn ( ) )
314341 }
315342}
0 commit comments