Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion src/background.index.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { getTabInfo } from './background/browser-api/tabs';
import { handleStateChange } from './background/controller';
import { cleanUpLogIndexedDBTable } from './background/services/logs';
import {
handleActiveTabStateChange,
handleAlarm,
handleIdleStateChange,
handleTabUpdate,
handleWindowFocusChange,
} from './background/services/state-service';
import { sendWebActivityAutomatically } from './background/services/stats';
import { cleanUpStatsIndexedDBTable, sendWebActivityAutomatically } from './background/services/stats';
import { logMessage } from './background/tables/logs';
import { Tab } from './shared/browser-api.types';
import { DebugTab } from './shared/db/types';
Expand All @@ -19,6 +20,7 @@ interface Service {
name: string;
intervalInMinutes: number;
handler: () => Promise<void>;
delayInMinutes?: number;
}

const devToolsPorts: { [tabId: number]: Port } = {};
Expand All @@ -30,6 +32,13 @@ const ASYNC_POLL_INTERVAL_MINUTES = 1;
const ASYNC_STATS_INTERVAL_ALARM_NAME = 'send-stats';
const ASYNC_STATS_INTERVAL_MINUTES = 1;

const ASYNC_CLEAN_UP_LOGS_ALARM_NAME = 'cleanup-logs';
const ASYNC_CLEAN_UP_LOGS_MINUTES = 1440; // Daily once
const DEFAULT_LOG_CUTOFF_DAYS = 0; // Daily

const ASYNC_CLEAN_UP_STATS_ALARM_NAME = 'cleanup-stats';
const ASYNC_CLEAN_UP_STATS_MINUTES = 1440; // Daily once

function findDebuggingTabIndexFromId(tabIdOrUrl: number | string | undefined) {
if (tabIdOrUrl !== undefined) {
for (let i = 0; i < debuggingTabs.length; i++) {
Expand Down Expand Up @@ -78,6 +87,14 @@ const asyncPollAlarmHandler = async (): Promise<void> => {
const sendStatsAlarmHandler = async (): Promise<void> =>
await sendWebActivityAutomatically();

const cleanUpLogsAlarmHandler = async (): Promise<void> => {
await cleanUpLogIndexedDBTable(DEFAULT_LOG_CUTOFF_DAYS);
};

const cleanUpStatsAlarmHandler = async (): Promise<void> => {
await cleanUpStatsIndexedDBTable();
};

const ChromeServiceDefinition: Array<Service> = [
{
handler: asyncPollAlarmHandler,
Expand All @@ -89,11 +106,25 @@ const ChromeServiceDefinition: Array<Service> = [
intervalInMinutes: ASYNC_STATS_INTERVAL_MINUTES,
name: ASYNC_STATS_INTERVAL_ALARM_NAME,
},
{
handler: cleanUpLogsAlarmHandler,
intervalInMinutes: ASYNC_CLEAN_UP_LOGS_MINUTES,
name: ASYNC_CLEAN_UP_LOGS_ALARM_NAME,
},
{
delayInMinutes: 0.1,
handler: cleanUpStatsAlarmHandler,
intervalInMinutes: ASYNC_CLEAN_UP_STATS_MINUTES,
name: ASYNC_CLEAN_UP_STATS_ALARM_NAME,
},
];

ChromeServiceDefinition.forEach((service) => {
chrome.alarms.create(service.name, {
periodInMinutes: service.intervalInMinutes,
...(service.delayInMinutes !== undefined && service.delayInMinutes !== null
? { delayInMinutes: service.delayInMinutes }
: {})
});
});

Expand Down
5 changes: 5 additions & 0 deletions src/background/controller/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { getSettings } from '../../shared/preferences';
import { getIsoDate, getMinutesInMs } from '../../shared/utils/dates-helper';
import { isInvalidUrl, isDomainAllowedByUser } from '../../shared/utils/url';
import { logMessage } from '../tables/logs';
import { setActiveTabRecord } from '../tables/state';
import { ActiveTimelineRecordDao, createNewActiveRecord } from './active';
import { updateTimeOnBadge } from './badge';
Expand Down Expand Up @@ -152,6 +153,10 @@ async function commitTabActivity(currentTimelineRecord: TimelineRecord | null, p

const currentIsoDate = getIsoDate(new Date());

const { hostname } = currentTimelineRecord;
const message = `Visited ${hostname} on ${currentIsoDate}`;
await logMessage(message);

await saveTimelineRecord(currentTimelineRecord, currentIsoDate);

// Edge case: If update happens after midnight, we need to update the
Expand Down
72 changes: 72 additions & 0 deletions src/background/services/logs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { connect, TimeTrackerStoreTables } from '../../shared/db/idb';

const getIdsToDelete = async (cutOffDate: Date) => {
console.log(`Cut Off Date: ${cutOffDate.getTime()}`);
const db = await connect();
const logs = await db.getAll(
TimeTrackerStoreTables.Logs,
);
const idsToDelete: number[] = [];

for (const log of logs) {
const recordDate = new Date(log.timestamp).getTime();
if (recordDate < cutOffDate.getTime()) {
const id: number = log.id as number;
// Should be deleted
idsToDelete.push(id);
}
}

return idsToDelete;
};

const deleteRecordsById = async (idsToDelete: number[]) => {
try {

const db = await connect();
const transaction = db.transaction(
TimeTrackerStoreTables.Logs,
'readwrite',
);
const store = transaction.objectStore(TimeTrackerStoreTables.Logs);

for (const id of idsToDelete) {
// Using any as delete function expects string but we store id as number
// this throws lint error
const delId: any = id;
await store.delete(delId);
}

await transaction.done;
console.log('Logs deleted successfully.');
return 'Logs deleted successfully.';
} catch (error) {
console.error('Error deleting IDB records:', error);
return 'Failed to delete records.';
}
};

const cleanUpLogIndexedDBTable = async (cutOff: number) => {
console.log(`handling log table cleanup with cutoff of ${cutOff}`)
if (process.env.NODE_ENV === 'production') {
return;
}

const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - cutOff);

const idsToDelete = await getIdsToDelete(cutoffDate);

console.log(
`Records to Delete: ${JSON.stringify(idsToDelete, null, 2)}`,
);

if (idsToDelete.length > 0) {
return await deleteRecordsById(idsToDelete);
}

return `No logs data available for keeping beyond the ${cutOff} days period.`
};


export { cleanUpLogIndexedDBTable }
41 changes: 40 additions & 1 deletion src/background/services/stats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,4 +178,43 @@ const sendWebActivityAutomatically = async (): Promise<void> => {
});
};

export { sendWebActivityAutomatically };
const deleteRecordsById = async (idsToDelete: string[]) => {
try {

const db = await connect();
const transaction = db.transaction(
TimeTrackerStoreTables.State,
'readwrite',
);
const store = transaction.objectStore(TimeTrackerStoreTables.State);

for (const id of idsToDelete) {
await store.delete(id);
}

await transaction.done;
console.log('Stats deleted successfully.');
return 'Stats deleted successfully.';
} catch (error) {
console.error('Error deleting IDB records:', error);
return 'Failed to delete records.';
}
};

const cleanUpStatsIndexedDBTable = async () => {
console.log(`handling stats table cleanup`)

const keysToDelete = ['active-tab', 'app-state', 'overall-state'];

console.log(
`Records to Delete: ${JSON.stringify(keysToDelete, null, 2)}`,
);

if (keysToDelete.length > 0) {
return await deleteRecordsById(keysToDelete);
}

return `Stats table cleared and ready to be repopulated.`
};

export { sendWebActivityAutomatically, cleanUpStatsIndexedDBTable };
10 changes: 10 additions & 0 deletions src/background/tables/logs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { connect, TimeTrackerStoreTables } from '../../shared/db/idb';
import { LogMessage } from '../../shared/db/types';

export async function logMessage(message: string) {
if (process.env.NODE_ENV === 'production') {
Expand All @@ -8,3 +9,12 @@ export async function logMessage(message: string) {
const db = await connect();
await db.add(TimeTrackerStoreTables.Logs, { message, timestamp: Date.now() });
}

export async function getLogs(): Promise<LogMessage[] | []> {
if (process.env.NODE_ENV === 'production') {
return [];
}

const db = await connect();
return await db.getAll(TimeTrackerStoreTables.Logs);
}
36 changes: 33 additions & 3 deletions src/content/sleep-counter-measures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { getMinutesInMs } from '../shared/utils/dates-helper';
import { ignore } from '../shared/utils/errors';

let messagePollingId = 0;
let backgroundPort: chrome.runtime.Port | null = null;

function tryWakeUpBackground() {
chrome.runtime.sendMessage({ type: WAKE_UP_BACKGROUND }, (response) => {
Expand Down Expand Up @@ -35,17 +36,37 @@ function tryWakeUpBackground() {
}

function connectToExtension() {
chrome.runtime.connect().onDisconnect.addListener(() => {
if (backgroundPort) {
return; // Already connected
}

backgroundPort = chrome.runtime.connect({ name: "codealike-chrome" }); // Use a name for the port

backgroundPort.onDisconnect.addListener(() => {
console.log("Disconnected from background script.");
backgroundPort = null; // Reset the port

try {
throwRuntimeLastError();
throwRuntimeLastError(); // Your error logging function
} catch (error) {
ignore(
isExtensionContextInvalidatedError,
isCouldNotEstablishConnectionError
// You might want to add a check for the back/forward cache error here
)(error);
}
setTimeout(() => connectToExtension(), getMinutesInMs(1));

// Fallback reconnection after a delay
setTimeout(connectToExtension, getMinutesInMs(1));
});

// Optionally, send an initial message upon successful connection
backgroundPort.onMessage.addListener((message) => {
console.log("Received message from background:", message);
// Handle messages
});

console.log("Connected to background script.");
}

export const runManifestV3SleepCounterMeasures = () => {
Expand All @@ -60,3 +81,12 @@ export const runManifestV3SleepCounterMeasures = () => {
}
});
};

// Listen for the 'pageshow' event to attempt immediate reconnection
// when the page is restored from the back/forward cache
window.addEventListener('pageshow', (event) => {
if (event.persisted && !backgroundPort) {
console.log("Page restored from cache, attempting immediate reconnection.");
connectToExtension();
}
});
Loading