chore: cache heartbeats request when they fail or users are offline

This commit is contained in:
Sebastian Velez
2023-01-30 11:39:43 -05:00
parent a4baf7cf86
commit 3d3120ed40
3 changed files with 58 additions and 1 deletions

View File

@@ -37,6 +37,7 @@ module.exports = {
}, },
plugins: ['react', '@typescript-eslint', 'typescript-sort-keys', 'sort-keys-fix'], plugins: ['react', '@typescript-eslint', 'typescript-sort-keys', 'sort-keys-fix'],
rules: { rules: {
'no-await-in-loop': 'off',
'prettier/prettier': 'error', 'prettier/prettier': 'error',
'sort-keys-fix/sort-keys-fix': 'error', 'sort-keys-fix/sort-keys-fix': 'error',
'testing-library/no-debug': 'off', 'testing-library/no-debug': 'off',

View File

@@ -1,11 +1,32 @@
import browser from 'webextension-polyfill'; import browser from 'webextension-polyfill';
import WakaTimeCore from './core/WakaTimeCore'; import WakaTimeCore from './core/WakaTimeCore';
// Add a listener to resolve alarms
browser.alarms.onAlarm.addListener(async (alarm) => {
// |alarm| can be undefined because onAlarm also gets called from
// window.setTimeout on old chrome versions.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (alarm && alarm.name == 'heartbeatAlarm') {
// Checks if the user is online and if there are cached heartbeats requests,
// if so then procedd to send these payload to wakatime api
if (navigator.onLine) {
const { cachedHeartbeats } = await browser.storage.sync.get({
cachedHeartbeats: [],
});
await browser.storage.sync.set({ cachedHeartbeats: [] });
await WakaTimeCore.sendCachedHeartbeatsRequest(cachedHeartbeats as Record<string, unknown>[]);
}
}
});
// Create a new alarm for sending cached heartbeats.
browser.alarms.create('heartbeatAlarm', { periodInMinutes: 2 });
/** /**
* Whenever a active tab is changed it records a heartbeat with that tab url. * Whenever a active tab is changed it records a heartbeat with that tab url.
*/ */
browser.tabs.onActivated.addListener(async () => { browser.tabs.onActivated.addListener(async () => {
console.log('recording a heartbeat - active tab changed'); console.log('recording a heartbeat - active tab changed ');
await WakaTimeCore.recordHeartbeat(); await WakaTimeCore.recordHeartbeat();
}); });

View File

@@ -262,9 +262,44 @@ class WakaTimeCore {
const data = await response.json(); const data = await response.json();
return data; return data;
} catch (err: unknown) { } catch (err: unknown) {
// Stores the payload of the request to be send later
const { cachedHeartbeats } = await browser.storage.sync.get({
cachedHeartbeats: [],
});
cachedHeartbeats.push(payload);
await browser.storage.sync.set({ cachedHeartbeats });
await changeExtensionState('notSignedIn'); await changeExtensionState('notSignedIn');
} }
} }
/**
* Sends cached heartbeats request to wakatime api
* @param requests
*/
async sendCachedHeartbeatsRequest(requests: Record<string, unknown>[]): Promise<void> {
const apiKey = await this.getApiKey();
if (!apiKey) {
return changeExtensionState('notLogging');
}
const chunkSize = 50; // Create batches of max 50 request
for (let i = 0; i < requests.length; i += chunkSize) {
const chunk = requests.slice(i, i + chunkSize);
const requestsPromises: Promise<Response>[] = [];
chunk.forEach((request) =>
requestsPromises.push(
fetch(`${config.heartbeatApiUrl}?api_key=${apiKey}`, {
body: JSON.stringify(request),
method: 'POST',
}),
),
);
try {
await Promise.all(requestsPromises);
} catch (error: unknown) {
console.log('Error sending heartbeats');
}
}
}
} }
export default new WakaTimeCore(); export default new WakaTimeCore();