UNPKG

7.92 kBJavaScriptView Raw
1"use strict";
2// *****************************************************************************
3// Copyright (C) 2020 Ericsson and others.
4//
5// This program and the accompanying materials are made available under the
6// terms of the Eclipse Public License v. 2.0 which is available at
7// http://www.eclipse.org/legal/epl-2.0.
8//
9// This Source Code may also be made available under the following Secondary
10// Licenses when the conditions for such availability set forth in the Eclipse
11// Public License v. 2.0 are satisfied: GNU General Public License, version 2
12// with the GNU Classpath Exception which is available at
13// https://www.gnu.org/software/classpath/license.html.
14//
15// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
16// *****************************************************************************
17var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
18 var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
19 if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
20 else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
21 return c > 3 && r && Object.defineProperty(target, key, r), r;
22};
23var __metadata = (this && this.__metadata) || function (k, v) {
24 if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
25};
26Object.defineProperty(exports, "__esModule", { value: true });
27exports.ElectronWebContentChannel = exports.ElectronMessagingContribution = void 0;
28const electron_1 = require("@theia/electron/shared/electron");
29const inversify_1 = require("inversify");
30const contribution_provider_1 = require("../../common/contribution-provider");
31const messaging_contribution_1 = require("../../node/messaging/messaging-contribution");
32const electron_connection_handler_1 = require("../../electron-common/messaging/electron-connection-handler");
33const electron_messaging_service_1 = require("./electron-messaging-service");
34const channel_1 = require("../../common/message-rpc/channel");
35const common_1 = require("../../common");
36const uint8_array_message_buffer_1 = require("../../common/message-rpc/uint8-array-message-buffer");
37/**
38 * This component replicates the role filled by `MessagingContribution` but for Electron.
39 * Unlike the WebSocket based implementation, we do not expect to receive
40 * connection events. Instead, we'll create channels based on incoming `open`
41 * events on the `ipcMain` channel.
42 * This component allows communication between renderer process (frontend) and electron main process.
43 */
44let ElectronMessagingContribution = class ElectronMessagingContribution {
45 constructor() {
46 this.channelHandlers = new messaging_contribution_1.MessagingContribution.ConnectionHandlers();
47 /**
48 * Each electron window has a main channel and its own multiplexer to route multiple client messages the same IPC connection.
49 */
50 this.windowChannelMultiplexer = new Map();
51 }
52 init() {
53 electron_1.ipcMain.on(electron_connection_handler_1.THEIA_ELECTRON_IPC_CHANNEL_NAME, (event, data) => {
54 this.handleIpcEvent(event, data);
55 });
56 }
57 handleIpcEvent(event, data) {
58 var _a;
59 const sender = event.sender;
60 // Get the multiplexer for a given window id
61 try {
62 const windowChannelData = (_a = this.windowChannelMultiplexer.get(sender.id)) !== null && _a !== void 0 ? _a : this.createWindowChannelData(sender);
63 windowChannelData.channel.onMessageEmitter.fire(() => new uint8_array_message_buffer_1.Uint8ArrayReadBuffer(data));
64 }
65 catch (error) {
66 console.error('IPC: Failed to handle message', { error, data });
67 }
68 }
69 // Creates a new multiplexer for a given sender/window
70 createWindowChannelData(sender) {
71 const mainChannel = this.createWindowMainChannel(sender);
72 const multiplexer = new channel_1.ChannelMultiplexer(mainChannel);
73 multiplexer.onDidOpenChannel(openEvent => {
74 const { channel, id } = openEvent;
75 if (this.channelHandlers.route(id, channel)) {
76 console.debug(`Opening channel for service path '${id}'.`);
77 channel.onClose(() => console.debug(`Closing channel on service path '${id}'.`));
78 }
79 });
80 sender.once('did-navigate', () => this.disposeMultiplexer(sender.id, multiplexer, 'Window was refreshed')); // When refreshing the browser window.
81 sender.once('destroyed', () => this.disposeMultiplexer(sender.id, multiplexer, 'Window was closed')); // When closing the browser window.
82 const data = { channel: mainChannel, multiplexer };
83 this.windowChannelMultiplexer.set(sender.id, data);
84 return data;
85 }
86 /**
87 * Creates the main channel to a window.
88 * @param sender The window that the channel should be established to.
89 */
90 createWindowMainChannel(sender) {
91 return new ElectronWebContentChannel(sender);
92 }
93 disposeMultiplexer(windowId, multiplexer, reason) {
94 multiplexer.onUnderlyingChannelClose({ reason });
95 this.windowChannelMultiplexer.delete(windowId);
96 }
97 onStart() {
98 for (const contribution of this.messagingContributions.getContributions()) {
99 contribution.configure(this);
100 }
101 for (const connectionHandler of this.connectionHandlers.getContributions()) {
102 this.channelHandlers.push(connectionHandler.path, (params, channel) => {
103 connectionHandler.onConnection(channel);
104 });
105 }
106 }
107 // eslint-disable-next-line @typescript-eslint/no-explicit-any
108 ipcChannel(spec, callback) {
109 this.channelHandlers.push(spec, callback);
110 }
111};
112__decorate([
113 (0, inversify_1.inject)(contribution_provider_1.ContributionProvider),
114 (0, inversify_1.named)(electron_messaging_service_1.ElectronMessagingService.Contribution),
115 __metadata("design:type", Object)
116], ElectronMessagingContribution.prototype, "messagingContributions", void 0);
117__decorate([
118 (0, inversify_1.inject)(contribution_provider_1.ContributionProvider),
119 (0, inversify_1.named)(electron_connection_handler_1.ElectronConnectionHandler),
120 __metadata("design:type", Object)
121], ElectronMessagingContribution.prototype, "connectionHandlers", void 0);
122__decorate([
123 (0, inversify_1.postConstruct)(),
124 __metadata("design:type", Function),
125 __metadata("design:paramtypes", []),
126 __metadata("design:returntype", void 0)
127], ElectronMessagingContribution.prototype, "init", null);
128ElectronMessagingContribution = __decorate([
129 (0, inversify_1.injectable)()
130], ElectronMessagingContribution);
131exports.ElectronMessagingContribution = ElectronMessagingContribution;
132/**
133 * Used to establish a connection between the ipcMain and the Electron frontend (window).
134 * Messages a transferred via electron IPC.
135 */
136class ElectronWebContentChannel extends channel_1.AbstractChannel {
137 constructor(sender) {
138 super();
139 this.sender = sender;
140 // Make the message emitter public so that we can easily forward messages received from the ipcMain.
141 this.onMessageEmitter = new common_1.Emitter();
142 }
143 getWriteBuffer() {
144 const writer = new uint8_array_message_buffer_1.Uint8ArrayWriteBuffer();
145 writer.onCommit(buffer => {
146 if (!this.sender.isDestroyed()) {
147 this.sender.send(electron_connection_handler_1.THEIA_ELECTRON_IPC_CHANNEL_NAME, buffer);
148 }
149 });
150 return writer;
151 }
152}
153exports.ElectronWebContentChannel = ElectronWebContentChannel;
154//# sourceMappingURL=electron-messaging-contribution.js.map
\No newline at end of file