Skip to content

Commit 108378b

Browse files
vezworksharon-wang
andauthored
Fix originData favicon path not being stored (#150)
* Fix originData favicon path not being stored This bug was introduced in #141. This PR made it so that favicon fetching did not block storing originData. This resulted in the originData object being updated after it had already been stored, meaning the updated originData object was never stored. Fixing this issue requires introducing a new function `storeOriginFavicon`which fetches the favicon, and once/if the fetch resolves, updates and stores the originData safely using a lock. * Update src/data/storage.js Co-authored-by: Sharon Wang <[email protected]> * Update src/data/storage.js Co-authored-by: Sharon Wang <[email protected]> * Update src/data/storage.js Co-authored-by: Sharon Wang <[email protected]> * Update src/data/storage.js Co-authored-by: Sharon Wang <[email protected]> * Update src/data/storage.js Co-authored-by: Sharon Wang <[email protected]> * Update src/data/storage.js Co-authored-by: Sharon Wang <[email protected]> * Address PR comments * Fix nits Co-authored-by: Sharon Wang <[email protected]>
1 parent 804ac21 commit 108378b

File tree

2 files changed

+64
-31
lines changed

2 files changed

+64
-31
lines changed

src/data/AkitaOriginData.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,11 @@ class AkitaOriginData {
110110
}
111111

112112
/**
113-
* Store the favicon source.
113+
* Set the favicon source.
114114
*
115115
* @param {String} faviconPath The url of the origin's favicon.
116116
*/
117-
storeOriginFavicon(faviconPath) {
117+
setOriginFavicon(faviconPath) {
118118
this.faviconSource = faviconPath;
119119
}
120120

src/data/storage.js

Lines changed: 62 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const AKITA_DATA_TYPE = {
88
'TIME_SPENT': 2,
99
'ORIGIN_FAVICON': 3
1010
};
11+
const VALID_AKITA_DATA_TYPE_VALUES = Object.values(AKITA_DATA_TYPE);
1112

1213
const ORIGIN_NAME_LIST_KEY = 'originList';
1314
const ORIGIN_STATS_KEY = 'originStats';
@@ -83,7 +84,9 @@ async function storeDataIntoAkitaFormatNonMonetized(data, typeOfData) {
8384
* @param {Boolean} isMonetizedData Whether or not the data being stored is for a monetized origin.
8485
*/
8586
async function updateAkitaData(originData, data, typeOfData, isMonetizedData) {
86-
// TODO: ensure typeOfData is one of AKITA_DATA_TYPE
87+
if (!VALID_AKITA_DATA_TYPE_VALUES.includes(typeOfData)) {
88+
throw "invalid typeOfData passed to updateAkitaData";
89+
}
8790

8891
// Get existing originStats or create it if it doesn't already exist
8992
let originStats = await loadOriginStats();
@@ -107,16 +110,48 @@ async function updateAkitaData(originData, data, typeOfData, isMonetizedData) {
107110
updateTimeSpent(originData, originStats, data, isMonetizedData);
108111
break;
109112
case AKITA_DATA_TYPE.ORIGIN_FAVICON: // Only for a monetized origin
110-
updateOriginFavicon(originData, data);
113+
storeOriginFavicon(originData.origin, data);
111114
break;
112-
default:
113-
// console.log("invalid data type provided");
114115
}
115116

116117
// Overwrite or create origin stats in storage
117118
await storeOriginStats(originStats);
118119
}
119120

121+
/**
122+
* Given an origin and an absolute or relative path to a favicon, this function:
123+
* - fetches the favicon to check if it is a valid favicon,
124+
* - if the fetch is successful, the favicon is valid, so the origin's orginData favicon is set
125+
* to the given favicon path,
126+
* - if the fetch is unsuccessful, the origin's originData favicon is set to "",
127+
* - finally, the updated originData is stored.
128+
*
129+
* Note: this function's implementation assumes that the specified origin's data has been created
130+
* and stored prior to the critical section.
131+
*
132+
* @param {String} origin The origin to set a favicon for.
133+
* @param {String} faviconPath The absolute or relative path to the origin's favicon.
134+
*/
135+
async function storeOriginFavicon(origin, faviconPath) {
136+
const absoluteFaviconPath = pathToAbsolutePath(faviconPath, origin);
137+
const isFaviconValid = await isFetchStatusOk(absoluteFaviconPath);
138+
139+
// Once/If the favicon resolves, store the originData with the favicon included
140+
const resolveLock = await acquireStoreLock();
141+
142+
// Get and update existing data for this origin
143+
let originData = await loadOriginData(origin);
144+
if (isFaviconValid) {
145+
originData.setOriginFavicon(absoluteFaviconPath);
146+
} else {
147+
originData.setOriginFavicon("");
148+
}
149+
150+
// Update the data for this origin in storage
151+
await storeOriginData(origin, originData);
152+
resolveLock();
153+
}
154+
120155

121156
/***********************************************************
122157
* Locking Functions
@@ -197,46 +232,44 @@ function updateTimeSpent(originData, originStats, recentTimeSpent, isMonetizedTi
197232
}
198233

199234
/**
200-
* Store the path to the origin's favicon in the origin data. If a relative path
201-
* is provided, construct the absolute path. Attempt to fetch the favicon to check
202-
* if it is a valid path. If fetch response is 200 OK, the path is valid, so store
203-
* the url of the favicon.
235+
* Makes an absolute path from an input path which is either relative or absolute. If the input path
236+
* is absolute, the input path is returned unchanged. If the input path is relative, an absolute
237+
* path on the given origin is made with the input path.
204238
*
205-
* @param {AkitaOriginData} originData The origin data to update.
206-
* @param {String} faviconData The absolute or relative path to the site's favicon.
239+
* @param {String} path A path to convert to an absolute path, or check that it is already an absolute path.
240+
* @param {String} origin If the path is relative, this param is he origin which the path is
241+
* relative to. Not used if the path is absolute.
242+
* @returns {String} The input path as an absolute path.
207243
*/
208-
async function updateOriginFavicon(originData, faviconData) {
209-
let faviconPath = null;
210-
let origin = originData.origin;
211-
244+
function pathToAbsolutePath(path, origin) {
212245
// Regex pattern for the start of the path
213246
const pathStartPattern = /^(https?:\/\/)(www\.)?/i; // i = ignore case (case insensitive)
214247

215-
if (pathStartPattern.test(faviconData)) {
248+
if (pathStartPattern.test(path)) {
216249
// The favicon path is an absolute path
217-
faviconPath = faviconData;
250+
return path;
218251
} else {
219252
// The favicon path is relative to the origin
220253
if ((origin.charAt(origin.length) !== '/')
221-
&& (faviconData.charAt(0) !== '/')
254+
&& (path.charAt(0) !== '/')
222255
) {
223-
faviconPath = origin + "/" + faviconData;
256+
return origin + "/" + path;
224257
} else {
225-
faviconPath = origin + faviconData;
258+
return origin + path;
226259
}
227260
}
261+
}
228262

229-
if (faviconPath) {
230-
let response = await fetch(faviconPath);
263+
/**
264+
* Fetches a url and resolves to true if the response has status 200 OK.
265+
*
266+
* @param {String} url The url to be requested by the browser.
267+
* @returns {Promise<Boolean>} true if the request response has status 200 OK, false otherwise.
268+
*/
269+
async function isFetchStatusOk(url) {
270+
let response = await fetch(url);
231271

232-
if (response) {
233-
if (200 === response.status) {
234-
originData.storeOriginFavicon(faviconPath);
235-
} else {
236-
originData.storeOriginFavicon("");
237-
}
238-
}
239-
}
272+
return (200 === response?.status);
240273
}
241274

242275
/***********************************************************

0 commit comments

Comments
 (0)