aboutsummaryrefslogtreecommitdiffstats
path: root/packages/main/src/infrastructure/electron/impl/ElectronServiceView.ts
blob: c4f7e4d4f2ad30559fa7c3182a602aa0d4d54813 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/*
 * Copyright (C)  2022 Kristóf Marussy <kristof@marussy.com>
 *
 * This file is part of Sophie.
 *
 * Sophie is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * SPDX-License-Identifier: AGPL-3.0-only
 */

import type { BrowserViewBounds } from '@sophie/shared';
import { BrowserView } from 'electron';

import type Service from '../../../stores/Service';
import type Resources from '../../resources/Resources';
import type { ServiceView } from '../types';

import ElectronPartition from './ElectronPartition';
import type ElectronViewFactory from './ElectronViewFactory';

export default class ElectronServiceView implements ServiceView {
  readonly id: string;

  readonly partitionId: string;

  readonly browserView: BrowserView;

  constructor(
    service: Service,
    resources: Resources,
    partition: ElectronPartition,
    private readonly parent: ElectronViewFactory,
  ) {
    this.id = service.id;
    this.partitionId = partition.id;
    this.browserView = new BrowserView({
      webPreferences: {
        sandbox: true,
        nodeIntegrationInSubFrames: true,
        preload: resources.getPath('service-preload', 'index.cjs'),
        session: partition.session,
      },
    });

    const { webContents } = this.browserView;

    function setLocation(url: string) {
      service.setLocation({
        url,
        canGoBack: webContents.canGoBack(),
        canGoForward: webContents.canGoForward(),
      });
    }

    webContents.on('did-navigate', (_event, url) => {
      setLocation(url);
    });

    webContents.on('did-navigate-in-page', (_event, url, isMainFrame) => {
      if (isMainFrame) {
        setLocation(url);
      }
    });

    webContents.on('page-title-updated', (_event, title) => {
      service.setTitle(title);
    });

    webContents.on('did-start-loading', () => {
      service.startedLoading();
    });

    webContents.on('did-finish-load', () => {
      service.finishedLoading();
    });

    webContents.on('render-process-gone', () => {
      service.crashed();
    });
  }

  get webContentsId(): number {
    return this.browserView.webContents.id;
  }

  loadURL(url: string): Promise<void> {
    return this.browserView.webContents.loadURL(url);
  }

  goBack(): void {
    this.browserView.webContents.goBack();
  }

  goForward(): void {
    this.browserView.webContents.goForward();
  }

  setBounds(bounds: BrowserViewBounds): void {
    this.browserView.setBounds(bounds);
  }

  dispose(): void {
    this.parent.unregisterServiceView(this.webContentsId);
    setImmediate(() => {
      // Undocumented electron API, see e.g., https://github.com/electron/electron/issues/29626
      (
        this.browserView.webContents as unknown as { destroy(): void }
      ).destroy();
    });
  }
}