@@ -3,9 +3,74 @@ import { getActiveWindowTab, getTab, getTabs } from './helpers'
33import config from '../config'
44import { AWClient , IEvent } from 'aw-client'
55import { getBucketId , sendHeartbeat } from './client'
6- import { getEnabled , getHeartbeatData , setHeartbeatData } from '../storage'
6+ import { getEnabled , getHeartbeatData , setHeartbeatData , getGmailEnabled } from '../storage'
77import deepEqual from 'deep-equal'
88
9+ export function setupMessageListener ( client : AWClient ) {
10+ browser . runtime . onMessage . addListener (
11+ async ( message : any , sender : browser . Runtime . MessageSender ) => {
12+ const enabled = await getEnabled ( ) ;
13+ const gmailEnabled = await getGmailEnabled ( ) ;
14+ if ( ! enabled || ! gmailEnabled ) return ;
15+
16+ if ( message . type === 'AW_GMAIL_HEARTBEAT' ) {
17+ const tab = sender . tab ;
18+ if ( ! tab || ! tab . url || ! tab . title ) return ;
19+ if ( ! tab . url . includes ( 'mail.google.com' ) ) return ;
20+ const tabs = await getTabs ( ) ;
21+
22+ const data : IEvent [ 'data' ] = {
23+ url : tab . url ,
24+ title : tab . title ,
25+ audible : tab . audible ?? false ,
26+ incognito : tab . incognito ,
27+ tabCount : tabs . length ,
28+ ...message . data ,
29+ } ;
30+ await performHeartbeat ( client , data ) ;
31+ }
32+ } ,
33+ )
34+ }
35+
36+ async function performHeartbeat (
37+ client : AWClient ,
38+ data : IEvent [ 'data' ] ,
39+ options : { finalizeOnly ?: boolean } = { }
40+ ) {
41+ const bucketId = await getBucketId ( )
42+ const now = new Date ( )
43+ const previousData = await getHeartbeatData ( )
44+ if ( previousData && ! deepEqual ( previousData , data ) ) {
45+ console . debug ( '[Background] Activity changed, finalizing previous session' , previousData )
46+ await sendHeartbeat (
47+ client ,
48+ bucketId ,
49+ new Date ( now . getTime ( ) - 1 ) ,
50+ previousData ,
51+ config . heartbeat . intervalInSeconds + 20 ,
52+ ) . catch ( ( ) => { } )
53+ }
54+
55+ if ( previousData && options . finalizeOnly ) {
56+ await browser . storage . local . remove ( 'heartbeatData' ) ;
57+ return ;
58+ }
59+
60+ console . debug ( '[Background] Sending heartbeat' , data )
61+ await sendHeartbeat (
62+ client ,
63+ bucketId ,
64+ now ,
65+ data ,
66+ config . heartbeat . intervalInSeconds + 20 ,
67+ ) . catch ( ( err : unknown ) => {
68+ console . error ( '[Background] Failed to send heartbeat:' , err ) ;
69+ } )
70+
71+ await setHeartbeatData ( data )
72+ }
73+
974async function heartbeat (
1075 client : AWClient ,
1176 tab : browser . Tabs . Tab | undefined ,
@@ -27,34 +92,23 @@ async function heartbeat(
2792 return
2893 }
2994
30- const now = new Date ( )
3195 const data : IEvent [ 'data' ] = {
3296 url : tab . url ,
3397 title : tab . title ,
3498 audible : tab . audible ?? false ,
3599 incognito : tab . incognito ,
36100 tabCount : tabCount ,
37101 }
38- const previousData = await getHeartbeatData ( )
39- if ( previousData && ! deepEqual ( previousData , data ) ) {
40- console . debug ( 'Sending heartbeat for previous data' , previousData )
41- await sendHeartbeat (
42- client ,
43- await getBucketId ( ) ,
44- new Date ( now . getTime ( ) - 1 ) ,
45- previousData ,
46- config . heartbeat . intervalInSeconds + 20 ,
47- )
102+
103+ const gmailEnabled = await getGmailEnabled ( ) ;
104+ if ( gmailEnabled && tab . url . includes ( 'mail.google.com' ) ) {
105+ // Sharp cut: finalize the previous activity (e.g. if we came from Google Search)
106+ // but don't start the 'Generic' Gmail event. Gmail.ts will do that with metadata.
107+ await performHeartbeat ( client , data , { finalizeOnly : true } ) ;
108+ return ;
48109 }
49- console . debug ( 'Sending heartbeat' , data )
50- await sendHeartbeat (
51- client ,
52- await getBucketId ( ) ,
53- now ,
54- data ,
55- config . heartbeat . intervalInSeconds + 20 ,
56- )
57- await setHeartbeatData ( data )
110+
111+ await performHeartbeat ( client , data ) ;
58112}
59113
60114export const sendInitialHeartbeat = async ( client : AWClient ) => {
@@ -76,9 +130,9 @@ export const heartbeatAlarmListener =
76130
77131export const tabActivatedListener =
78132 ( client : AWClient ) =>
79- async ( activeInfo : browser . Tabs . OnActivatedActiveInfoType ) => {
80- const tab = await getTab ( activeInfo . tabId )
81- const tabs = await getTabs ( )
82- console . debug ( 'Sending heartbeat for tab activation' , tab )
83- await heartbeat ( client , tab , tabs . length )
84- }
133+ async ( activeInfo : browser . Tabs . OnActivatedActiveInfoType ) => {
134+ const tab = await getTab ( activeInfo . tabId )
135+ const tabs = await getTabs ( )
136+ console . debug ( 'Sending heartbeat for tab activation' , tab )
137+ await heartbeat ( client , tab , tabs . length )
138+ }
0 commit comments