blob: 36370a12b0d57cb84e6b895d3cf86ba9abced655 [file] [log] [blame]
Adrià Vilanova Martínezf7e86852024-05-11 14:16:38 +02001import { Mutex, MutexInterface, withTimeout } from 'async-mutex';
2
3import { getOptions } from './optionsUtils';
4import { OptionCodename, OptionValues } from './optionsPrototype';
5
6export default class OptionsProvider {
7 private optionValues: OptionValues;
8 private isStale = true;
9 private mutex: MutexInterface = withTimeout(new Mutex(), 60 * 1000);
10
11 constructor() {
12 // If the extension settings change, set the current cached value as stale.
13 // We could try only doing this only when we're sure it has changed, but
14 // there are many factors (if the user has changed it manually, if a kill
15 // switch was activated, etc.) so we'll do it every time.
16 chrome.storage.onChanged.addListener((_, areaName) => {
17 if (areaName !== 'sync') return;
18 console.debug('[optionsWatcher] Marking options as stale.');
19 this.isStale = true;
20 });
21 }
22
23 // Returns a promise resolving to the value of option |option|.
24 getOption<O extends OptionCodename>(option: O): Promise<OptionValues[O]> {
25 // When the cached value is marked as stale, it might be possible that there
26 // is a flood of calls to isEnabled(), which in turn causes a flood of calls
27 // to getOptions() because it takes some time for it to be marked as not
28 // stale. Thus, hiding the logic behind a mutex fixes this.
29 return this.mutex.runExclusive(async () => {
30 if (!this.isStale) return Promise.resolve(this.optionValues[option]);
31
32 this.optionValues = await getOptions();
33 this.isStale = false;
34 return this.optionValues[option];
35 });
36 }
37
38 // Returns a promise resolving to whether the |feature| is enabled.
39 async isEnabled(option: OptionCodename) {
40 const value = await this.getOption(option);
41 return value === true;
42 }
43}