aboutsummaryrefslogtreecommitdiffstats
path: root/src/models/Service.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/models/Service.js')
-rw-r--r--src/models/Service.js142
1 files changed, 99 insertions, 43 deletions
diff --git a/src/models/Service.js b/src/models/Service.js
index 4ee054b2b..cc001f98d 100644
--- a/src/models/Service.js
+++ b/src/models/Service.js
@@ -8,7 +8,11 @@ import { todosStore } from '../features/todos';
8import { isValidExternalURL } from '../helpers/url-helpers'; 8import { isValidExternalURL } from '../helpers/url-helpers';
9import UserAgent from './UserAgent'; 9import UserAgent from './UserAgent';
10import { DEFAULT_SERVICE_ORDER } from '../config'; 10import { DEFAULT_SERVICE_ORDER } from '../config';
11import { ifUndefinedString, ifUndefinedBoolean, ifUndefinedNumber } from '../jsUtils'; 11import {
12 ifUndefinedString,
13 ifUndefinedBoolean,
14 ifUndefinedNumber,
15} from '../jsUtils';
12 16
13const debug = require('debug')('Ferdi:Service'); 17const debug = require('debug')('Ferdi:Service');
14 18
@@ -95,11 +99,11 @@ export default class Service {
95 99
96 constructor(data, recipe) { 100 constructor(data, recipe) {
97 if (!data) { 101 if (!data) {
98 throw Error('Service config not valid'); 102 throw new Error('Service config not valid');
99 } 103 }
100 104
101 if (!recipe) { 105 if (!recipe) {
102 throw Error('Service recipe not valid'); 106 throw new Error('Service recipe not valid');
103 } 107 }
104 108
105 this.recipe = recipe; 109 this.recipe = recipe;
@@ -115,22 +119,51 @@ export default class Service {
115 119
116 this.order = ifUndefinedNumber(data.order, this.order); 120 this.order = ifUndefinedNumber(data.order, this.order);
117 this.isEnabled = ifUndefinedBoolean(data.isEnabled, this.isEnabled); 121 this.isEnabled = ifUndefinedBoolean(data.isEnabled, this.isEnabled);
118 this.isNotificationEnabled = ifUndefinedBoolean(data.isNotificationEnabled, this.isNotificationEnabled); 122 this.isNotificationEnabled = ifUndefinedBoolean(
119 this.isBadgeEnabled = ifUndefinedBoolean(data.isBadgeEnabled, this.isBadgeEnabled); 123 data.isNotificationEnabled,
120 this.isIndirectMessageBadgeEnabled = ifUndefinedBoolean(data.isIndirectMessageBadgeEnabled, this.isIndirectMessageBadgeEnabled); 124 this.isNotificationEnabled,
125 );
126 this.isBadgeEnabled = ifUndefinedBoolean(
127 data.isBadgeEnabled,
128 this.isBadgeEnabled,
129 );
130 this.isIndirectMessageBadgeEnabled = ifUndefinedBoolean(
131 data.isIndirectMessageBadgeEnabled,
132 this.isIndirectMessageBadgeEnabled,
133 );
121 this.isMuted = ifUndefinedBoolean(data.isMuted, this.isMuted); 134 this.isMuted = ifUndefinedBoolean(data.isMuted, this.isMuted);
122 this.isDarkModeEnabled = ifUndefinedBoolean(data.isDarkModeEnabled, this.isDarkModeEnabled); 135 this.isDarkModeEnabled = ifUndefinedBoolean(
123 this.darkReaderSettings = ifUndefinedString(data.darkReaderSettings, this.darkReaderSettings); 136 data.isDarkModeEnabled,
124 this.hasCustomUploadedIcon = ifUndefinedBoolean(data.hasCustomIcon, this.hasCustomUploadedIcon); 137 this.isDarkModeEnabled,
138 );
139 this.darkReaderSettings = ifUndefinedString(
140 data.darkReaderSettings,
141 this.darkReaderSettings,
142 );
143 this.hasCustomUploadedIcon = ifUndefinedBoolean(
144 data.hasCustomIcon,
145 this.hasCustomUploadedIcon,
146 );
125 this.proxy = ifUndefinedString(data.proxy, this.proxy); 147 this.proxy = ifUndefinedString(data.proxy, this.proxy);
126 this.spellcheckerLanguage = ifUndefinedString(data.spellcheckerLanguage, this.spellcheckerLanguage); 148 this.spellcheckerLanguage = ifUndefinedString(
127 this.userAgentPref = ifUndefinedString(data.userAgentPref, this.userAgentPref); 149 data.spellcheckerLanguage,
128 this.isHibernationEnabled = ifUndefinedBoolean(data.isHibernationEnabled, this.isHibernationEnabled); 150 this.spellcheckerLanguage,
151 );
152 this.userAgentPref = ifUndefinedString(
153 data.userAgentPref,
154 this.userAgentPref,
155 );
156 this.isHibernationEnabled = ifUndefinedBoolean(
157 data.isHibernationEnabled,
158 this.isHibernationEnabled,
159 );
129 160
130 // Check if "Hibernate on Startup" is enabled and hibernate all services except active one 161 // Check if "Hibernate on Startup" is enabled and hibernate all services except active one
131 const { hibernateOnStartup } = window.ferdi.stores.settings.app; 162 const { hibernateOnStartup } = window.ferdi.stores.settings.app;
132 // The service store is probably not loaded yet so we need to use localStorage data to get active service 163 // The service store is probably not loaded yet so we need to use localStorage data to get active service
133 const isActive = window.localStorage.service && JSON.parse(window.localStorage.service).activeService === this.id; 164 const isActive =
165 window.localStorage.service &&
166 JSON.parse(window.localStorage.service).activeService === this.id;
134 if (hibernateOnStartup && !isActive) { 167 if (hibernateOnStartup && !isActive) {
135 this.isHibernationRequested = true; 168 this.isHibernationRequested = true;
136 } 169 }
@@ -189,9 +222,14 @@ export default class Service {
189 if (this.recipe.hasCustomUrl && this.customUrl) { 222 if (this.recipe.hasCustomUrl && this.customUrl) {
190 let url; 223 let url;
191 try { 224 try {
192 url = normalizeUrl(this.customUrl, { stripWWW: false, removeTrailingSlash: false }); 225 url = normalizeUrl(this.customUrl, {
193 } catch (err) { 226 stripWWW: false,
194 console.error(`Service (${this.recipe.name}): '${this.customUrl}' is not a valid Url.`); 227 removeTrailingSlash: false,
228 });
229 } catch {
230 console.error(
231 `Service (${this.recipe.name}): '${this.customUrl}' is not a valid Url.`,
232 );
195 } 233 }
196 234
197 if (typeof this.recipe.buildUrl === 'function') { 235 if (typeof this.recipe.buildUrl === 'function') {
@@ -241,7 +279,9 @@ export default class Service {
241 } 279 }
242 280
243 initializeWebViewEvents({ handleIPCMessage, openWindow, stores }) { 281 initializeWebViewEvents({ handleIPCMessage, openWindow, stores }) {
244 const webviewWebContents = webContents.fromId(this.webview.getWebContentsId()); 282 const webviewWebContents = webContents.fromId(
283 this.webview.getWebContentsId(),
284 );
245 285
246 this.userAgentModel.setWebviewReference(this.webview); 286 this.userAgentModel.setWebviewReference(this.webview);
247 287
@@ -270,9 +310,15 @@ export default class Service {
270 debug(this.name, 'knownCertificateHosts is not defined in the recipe'); 310 debug(this.name, 'knownCertificateHosts is not defined in the recipe');
271 } 311 }
272 312
273 this.webview.addEventListener('ipc-message', async (e) => { 313 this.webview.addEventListener('ipc-message', async e => {
274 if (e.channel === 'inject-js-unsafe') { 314 if (e.channel === 'inject-js-unsafe') {
275 await Promise.all(e.args.map((script) => this.webview.executeJavaScript(`"use strict"; (() => { ${script} })();`))); 315 await Promise.all(
316 e.args.map(script =>
317 this.webview.executeJavaScript(
318 `"use strict"; (() => { ${script} })();`,
319 ),
320 ),
321 );
276 } else { 322 } else {
277 handleIPCMessage({ 323 handleIPCMessage({
278 serviceId: this.id, 324 serviceId: this.id,
@@ -282,27 +328,33 @@ export default class Service {
282 } 328 }
283 }); 329 });
284 330
285 this.webview.addEventListener('new-window', (event, url, frameName, options) => { 331 this.webview.addEventListener(
286 debug('new-window', event, url, frameName, options); 332 'new-window',
287 if (!isValidExternalURL(event.url)) { 333 (event, url, frameName, options) => {
288 return; 334 debug('new-window', event, url, frameName, options);
289 } 335 if (!isValidExternalURL(event.url)) {
290 if (event.disposition === 'foreground-tab' || event.disposition === 'background-tab') { 336 return;
291 openWindow({ 337 }
292 event, 338 if (
293 url, 339 event.disposition === 'foreground-tab' ||
294 frameName, 340 event.disposition === 'background-tab'
295 options, 341 ) {
296 }); 342 openWindow({
297 } else { 343 event,
298 ipcRenderer.send('open-browser-window', { 344 url,
299 url: event.url, 345 frameName,
300 serviceId: this.id, 346 options,
301 }); 347 });
302 } 348 } else {
303 }); 349 ipcRenderer.send('open-browser-window', {
350 url: event.url,
351 serviceId: this.id,
352 });
353 }
354 },
355 );
304 356
305 this.webview.addEventListener('did-start-loading', (event) => { 357 this.webview.addEventListener('did-start-loading', event => {
306 debug('Did start load', this.name, event); 358 debug('Did start load', this.name, event);
307 359
308 this.hasCrashed = false; 360 this.hasCrashed = false;
@@ -321,9 +373,13 @@ export default class Service {
321 this.webview.addEventListener('did-frame-finish-load', didLoad.bind(this)); 373 this.webview.addEventListener('did-frame-finish-load', didLoad.bind(this));
322 this.webview.addEventListener('did-navigate', didLoad.bind(this)); 374 this.webview.addEventListener('did-navigate', didLoad.bind(this));
323 375
324 this.webview.addEventListener('did-fail-load', (event) => { 376 this.webview.addEventListener('did-fail-load', event => {
325 debug('Service failed to load', this.name, event); 377 debug('Service failed to load', this.name, event);
326 if (event.isMainFrame && event.errorCode !== -21 && event.errorCode !== -3) { 378 if (
379 event.isMainFrame &&
380 event.errorCode !== -21 &&
381 event.errorCode !== -3
382 ) {
327 this.isError = true; 383 this.isError = true;
328 this.errorMessage = event.errorDescription; 384 this.errorMessage = event.errorDescription;
329 this.isLoading = false; 385 this.isLoading = false;
@@ -365,12 +421,12 @@ export default class Service {
365 421
366 initializeWebViewListener() { 422 initializeWebViewListener() {
367 if (this.webview && this.recipe.events) { 423 if (this.webview && this.recipe.events) {
368 Object.keys(this.recipe.events).forEach((eventName) => { 424 for (const eventName of Object.keys(this.recipe.events)) {
369 const eventHandler = this.recipe[this.recipe.events[eventName]]; 425 const eventHandler = this.recipe[this.recipe.events[eventName]];
370 if (typeof eventHandler === 'function') { 426 if (typeof eventHandler === 'function') {
371 this.webview.addEventListener(eventName, eventHandler); 427 this.webview.addEventListener(eventName, eventHandler);
372 } 428 }
373 }); 429 }
374 } 430 }
375 } 431 }
376 432