@@ -3,9 +3,73 @@ 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 ) => {
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 = await getActiveWindowTab ( )
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 ( options . finalizeOnly ) {
56+ return ;
57+ }
58+
59+ console . debug ( '[Background] Sending heartbeat' , data )
60+ await sendHeartbeat (
61+ client ,
62+ bucketId ,
63+ now ,
64+ data ,
65+ config . heartbeat . intervalInSeconds + 20 ,
66+ ) . catch ( ( err : unknown ) => {
67+ console . error ( '[Background] Failed to send heartbeat:' , err ) ;
68+ } )
69+
70+ await setHeartbeatData ( data )
71+ }
72+
973async function heartbeat (
1074 client : AWClient ,
1175 tab : browser . Tabs . Tab | undefined ,
@@ -27,34 +91,23 @@ async function heartbeat(
2791 return
2892 }
2993
30- const now = new Date ( )
3194 const data : IEvent [ 'data' ] = {
3295 url : tab . url ,
3396 title : tab . title ,
3497 audible : tab . audible ?? false ,
3598 incognito : tab . incognito ,
3699 tabCount : tabCount ,
37100 }
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- )
101+
102+ const gmailEnabled = await getGmailEnabled ( ) ;
103+ if ( gmailEnabled && tab . url . includes ( 'mail.google.com' ) ) {
104+ // Sharp cut: finalize the previous activity (e.g. if we came from Google Search)
105+ // but don't start the 'Generic' Gmail event. Gmail.ts will do that with metadata.
106+ await performHeartbeat ( client , data , { finalizeOnly : true } ) ;
107+ return ;
48108 }
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 )
109+
110+ await performHeartbeat ( client , data ) ;
58111}
59112
60113export const sendInitialHeartbeat = async ( client : AWClient ) => {
@@ -76,9 +129,9 @@ export const heartbeatAlarmListener =
76129
77130export const tabActivatedListener =
78131 ( 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- }
132+ async ( activeInfo : browser . Tabs . OnActivatedActiveInfoType ) => {
133+ const tab = await getTab ( activeInfo . tabId )
134+ const tabs = await getTabs ( )
135+ console . debug ( 'Sending heartbeat for tab activation' , tab )
136+ await heartbeat ( client , tab , tabs . length )
137+ }
0 commit comments