Skip to content

Commit 1de68a2

Browse files
authored
Use messaging API (darkreader#277)
- Connect Background and UI via messaging API - This should fix Firefox private mode darkreader#217
1 parent a02b6a0 commit 1de68a2

24 files changed

Lines changed: 448 additions & 304 deletions

File tree

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"malevic": "0.11.6"
2323
},
2424
"devDependencies": {
25-
"@types/chrome": "0.0.59",
25+
"@types/chrome": "0.0.60",
2626
"fancy-log": "1.3.2",
2727
"fs-extra": "5.0.0",
2828
"gulp": "3.9.1",

src/background/extension.ts

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import ConfigManager from './config-manager';
22
import IconManager from './icon-manager';
3+
import Messenger from './messenger';
34
import UserStorage from './user-storage';
4-
import {simpleClone, getFontList, canInjectScript, isUrlInList} from './utils';
5+
import {simpleClone, getFontList, canInjectScript, isUrlInList, getUrlHost} from './utils';
56
import {formatJson} from '../config/utils';
67
import createCSSFilterStylesheet from '../generators/css-filter';
7-
import {FilterConfig, TabInfo} from '../definitions';
8+
import {FilterConfig, TabInfo, ExtensionData} from '../definitions';
89

910
export class Extension {
1011

@@ -14,15 +15,24 @@ export class Extension {
1415
filterConfig: FilterConfig;
1516
fonts: string[];
1617
icon: IconManager;
18+
messenger: Messenger;
1719
user: UserStorage;
1820

1921
constructor() {
20-
21-
this.listeners = new Set();
2222
this.ready = false;
2323

2424
this.icon = new IconManager();
2525
this.config = new ConfigManager();
26+
this.messenger = new Messenger({
27+
collect: () => this.collectData(),
28+
getActiveTabInfo: async () => await this.getActiveTabInfo(),
29+
enable: () => this.enable(),
30+
disable: () => this.disable(),
31+
setConfig: (config) => this.setConfig(config),
32+
toggleSitePattern: (pattern) => this.toggleSitePattern(pattern),
33+
applyDevInversionFixes: (json) => this.applyDevInversionFixes(json),
34+
resetDevInversionFixes: () => this.resetDevInversionFixes(),
35+
});
2636

2737
// Subscribe on keyboard shortcut
2838
chrome.commands.onCommand.addListener((command) => {
@@ -70,7 +80,6 @@ export class Extension {
7080
loadFonts(),
7181
]);
7282

73-
7483
this.user = new UserStorage({defaultFilterConfig: this.config.DEFAULT_FILTER_CONFIG});
7584
const settings = await this.user.loadSettings();
7685
if (settings.enabled) {
@@ -83,87 +92,72 @@ export class Extension {
8392
this.setConfig(settings.config);
8493
}
8594

95+
private collectData(): ExtensionData {
96+
return {
97+
enabled: this.enabled,
98+
filterConfig: this.filterConfig,
99+
ready: this.ready,
100+
fonts: this.fonts,
101+
devInversionFixesText: this.getDevInversionFixesText(),
102+
};
103+
}
104+
86105
enable() {
87106
this.enabled = true;
88107
this.onAppToggle();
89-
this.invokeListeners();
90108
}
91109

92110
disable() {
93111
this.enabled = false;
94112
this.onAppToggle();
95-
this.invokeListeners();
96113
}
97114

98115
setConfig(config: FilterConfig) {
99116
this.filterConfig = {...this.filterConfig, ...config};
100117
this.onConfigPropChanged();
101-
this.invokeListeners();
102118
}
103119

104-
protected listeners: Set<() => void>;
105-
106-
addListener(callback: () => void) {
107-
this.listeners.add(callback);
108-
}
109-
110-
removeListener(callback: () => void) {
111-
this.listeners.delete(callback);
120+
private reportChanges() {
121+
const info = this.collectData();
122+
this.messenger.reportChanges(info);
112123
}
113124

114-
protected invokeListeners() {
115-
this.listeners.forEach((listener) => listener());
116-
}
117-
118-
/**
119-
* Returns info of active tab
120-
* of last focused window.
121-
*/
122-
getActiveTabInfo(callback: (info: TabInfo) => void) {
123-
chrome.tabs.query({
124-
active: true,
125-
lastFocusedWindow: true
126-
}, (tabs) => {
127-
if (tabs.length === 1) {
125+
getActiveTabInfo() {
126+
return new Promise<TabInfo>((resolve) => {
127+
chrome.tabs.query({
128+
active: true,
129+
lastFocusedWindow: true
130+
}, ([tab]) => {
128131
const {DARK_SITES} = this.config;
129-
const tab = tabs[0];
130132
const url = tab.url;
131-
const host = url.match(/^(.*?:\/{2,3})?(.+?)(\/|$)/)[2];
132-
const info: TabInfo = {
133-
url,
134-
host,
133+
resolve({
134+
url: tab.url,
135135
isProtected: !canInjectScript(url),
136136
isInDarkList: isUrlInList(url, DARK_SITES),
137-
};
138-
callback(info);
139-
} else {
140-
if (this.config.DEBUG) {
141-
throw new Error('Unexpected tabs count.');
142-
}
143-
console.error('Unexpected tabs count.');
144-
callback({url: '', host: '', isProtected: false, isInDarkList: false});
145-
}
137+
});
138+
});
146139
});
147140
}
148141

142+
toggleSitePattern(pattern: string) {
143+
const siteList = this.filterConfig.siteList.slice();
144+
const index = siteList.indexOf(pattern);
145+
if (index < 0) {
146+
siteList.push(pattern);
147+
} else {
148+
siteList.splice(index, 1);
149+
}
150+
this.setConfig(Object.assign({}, this.filterConfig, {siteList}));
151+
}
152+
149153
/**
150154
* Adds host name of last focused tab
151155
* into Sites List (or removes).
152156
*/
153-
toggleCurrentSite() {
154-
this.getActiveTabInfo((info) => {
155-
if (info.host) {
156-
const siteList = this.filterConfig.siteList.slice();
157-
const index = siteList.indexOf(info.host);
158-
if (index < 0) {
159-
siteList.push(info.host);
160-
} else {
161-
// Remove site from list
162-
siteList.splice(index, 1);
163-
}
164-
this.setConfig(Object.assign({}, this.filterConfig, {siteList}));
165-
}
166-
});
157+
async toggleCurrentSite() {
158+
const {url} = await this.getActiveTabInfo();
159+
const host = getUrlHost(url);
160+
this.toggleSitePattern(host);
167161
}
168162

169163

@@ -217,6 +211,7 @@ export class Extension {
217211
});
218212
}
219213
this.saveUserSettings();
214+
this.reportChanges();
220215
}
221216

222217
protected onConfigPropChanged() {
@@ -234,6 +229,7 @@ export class Extension {
234229
});
235230
}
236231
this.saveUserSettings();
232+
this.reportChanges();
237233
}
238234

239235

@@ -367,17 +363,17 @@ export class Extension {
367363
this.onConfigPropChanged();
368364
}
369365

370-
applyDevInversionFixes(json: string, callback: (err: Error) => void) {
366+
applyDevInversionFixes(json: string) {
371367
let obj;
372368
try {
373369
obj = JSON.parse(json);
374370
const text = formatJson(obj);
375371
this.saveDevInversionFixes(text);
376372
this.config.handleInversionFixes(obj);
377373
this.onConfigPropChanged();
378-
callback(null);
374+
return null;
379375
} catch (err) {
380-
callback(err);
376+
return err;
381377
}
382378
}
383379
}

src/background/messenger.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import {ExtensionData, ExtensionActions, FilterConfig, TabInfo} from '../definitions';
2+
3+
interface ExtensionAdapter {
4+
collect: () => ExtensionData;
5+
getActiveTabInfo: () => Promise<TabInfo>;
6+
enable: () => void;
7+
disable: () => void;
8+
setConfig: (config: FilterConfig) => void;
9+
toggleSitePattern: (pattern: string) => void;
10+
applyDevInversionFixes: (json: string) => Error;
11+
resetDevInversionFixes: () => void;
12+
}
13+
14+
export default class Messenger {
15+
private reporters: Set<(info: ExtensionData) => void>;
16+
17+
constructor(adapter: ExtensionAdapter) {
18+
this.reporters = new Set();
19+
chrome.runtime.onConnect.addListener((port) => {
20+
port.onMessage.addListener(async ({type, id, data}) => {
21+
switch (type) {
22+
case 'getData': {
23+
const data = adapter.collect();
24+
port.postMessage({id, data});
25+
break;
26+
}
27+
case 'getActiveTabInfo': {
28+
const data = await adapter.getActiveTabInfo();
29+
port.postMessage({id, data});
30+
break;
31+
}
32+
case 'subscribeToChanges': {
33+
const report = (data) => port.postMessage({id, data});
34+
this.reporters.add(report);
35+
port.onDisconnect.addListener(() => this.reporters.delete(report));
36+
break;
37+
}
38+
case 'enable': {
39+
adapter.enable();
40+
break;
41+
}
42+
case 'disable': {
43+
adapter.disable();
44+
break;
45+
}
46+
case 'setConfig': {
47+
adapter.setConfig(data);
48+
break;
49+
}
50+
case 'toggleSitePattern': {
51+
adapter.toggleSitePattern(data);
52+
break;
53+
}
54+
case 'applyDevInversionFixes': {
55+
const error = adapter.applyDevInversionFixes(data);
56+
port.postMessage({id, error: error ? error.message : null});
57+
break;
58+
}
59+
case 'resetDevInversionFixes': {
60+
adapter.resetDevInversionFixes();
61+
break;
62+
}
63+
}
64+
});
65+
});
66+
}
67+
68+
reportChanges(data: ExtensionData) {
69+
this.reporters.forEach((report) => report(data));
70+
}
71+
}

src/background/utils/platform.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import {isUrlInList} from './url';
2+
import {TabInfo} from '../../definitions';
3+
14
export function isFirefox() {
25
return navigator.userAgent.indexOf('Firefox') >= 0;
36
}

src/background/utils/url.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
export function getUrlHost(url: string) {
2+
return url.match(/^(.*?:\/{2,3})?(.+?)(\/|$)/)[2];
3+
}
4+
15
/**
26
* Determines whether URL has a match in URL template list.
37
* @param url Site URL.

src/config/utils.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
function getJsonErrorPosition(err) {
2-
const message = err.message || '';
2+
const message = (err instanceof Error
3+
? err.message
4+
: (err || ''));
35
const m = /position (\d+)/.exec(message);
46
if (m && m[1]) {
57
const i = parseInt(m[1]);

src/definitions.d.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
import {FilterMode} from './generators/css-filter';
22

3-
export interface Extension {
3+
export interface ExtensionData {
44
enabled: boolean;
55
ready: boolean;
66
filterConfig: FilterConfig;
77
fonts: string[];
8+
devInversionFixesText: string;
9+
}
10+
11+
export interface ExtensionActions {
812
enable();
913
disable();
1014
setConfig(config: FilterConfig);
11-
addListener(callback: () => void);
12-
removeListener(callback: () => void);
13-
getActiveTabInfo(callback: (info: TabInfo) => void);
14-
toggleCurrentSite();
15-
getDevInversionFixesText(): string;
15+
toggleSitePattern(pattern: string);
16+
applyDevInversionFixes(json: string): Promise<void>;
17+
resetDevInversionFixes();
18+
}
19+
20+
export interface ExtWrapper {
21+
data: ExtensionData;
22+
actions: ExtensionActions;
1623
}
1724

1825
export interface FilterConfig {
@@ -35,7 +42,6 @@ export interface UserSettings {
3542

3643
export interface TabInfo {
3744
url: string;
38-
host: string;
3945
isProtected: boolean;
4046
isInDarkList: boolean;
4147
}

0 commit comments

Comments
 (0)