@theia/core
Version:
Theia is a cloud & desktop IDE framework implemented in TypeScript.
151 lines • 7.8 kB
JavaScript
// *****************************************************************************
// Copyright (C) 2020 Ericsson and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
// *****************************************************************************
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
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;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ElectronWebContentChannel = exports.ElectronMessagingContribution = void 0;
const inversify_1 = require("inversify");
const contribution_provider_1 = require("../../common/contribution-provider");
const messaging_contribution_1 = require("../../node/messaging/messaging-contribution");
const electron_connection_handler_1 = require("../../electron-common/messaging/electron-connection-handler");
const electron_messaging_service_1 = require("./electron-messaging-service");
const channel_1 = require("../../common/message-rpc/channel");
const common_1 = require("../../common");
const uint8_array_message_buffer_1 = require("../../common/message-rpc/uint8-array-message-buffer");
const electron_api_main_1 = require("../electron-api-main");
/**
* This component replicates the role filled by `MessagingContribution` but for Electron.
* Unlike the WebSocket based implementation, we do not expect to receive
* connection events. Instead, we'll create channels based on incoming `open`
* events on the `ipcMain` channel.
* This component allows communication between renderer process (frontend) and electron main process.
*/
let ElectronMessagingContribution = class ElectronMessagingContribution {
constructor() {
this.channelHandlers = new messaging_contribution_1.MessagingContribution.ConnectionHandlers();
/**
* Each electron window has a main channel and its own multiplexer to route multiple client messages the same IPC connection.
*/
this.windowChannelMultiplexer = new Map();
}
init() {
electron_api_main_1.TheiaRendererAPI.onIpcData((sender, data) => this.handleIpcEvent(sender, data));
}
handleIpcEvent(sender, data) {
var _a;
// Get the multiplexer for a given window id
try {
const windowChannelData = (_a = this.windowChannelMultiplexer.get(sender.id)) !== null && _a !== void 0 ? _a : this.createWindowChannelData(sender);
windowChannelData.channel.onMessageEmitter.fire(() => new uint8_array_message_buffer_1.Uint8ArrayReadBuffer(data));
}
catch (error) {
console.error('IPC: Failed to handle message', { error, data });
}
}
// Creates a new multiplexer for a given sender/window
createWindowChannelData(sender) {
const mainChannel = this.createWindowMainChannel(sender);
const multiplexer = new channel_1.ChannelMultiplexer(mainChannel);
multiplexer.onDidOpenChannel(openEvent => {
const { channel, id } = openEvent;
if (this.channelHandlers.route(id, channel)) {
console.debug(`Opening channel for service path '${id}'.`);
channel.onClose(() => console.debug(`Closing channel on service path '${id}'.`));
}
});
sender.once('did-navigate', () => this.disposeMultiplexer(sender.id, multiplexer, 'Window was refreshed')); // When refreshing the browser window.
sender.once('destroyed', () => this.disposeMultiplexer(sender.id, multiplexer, 'Window was closed')); // When closing the browser window.
const data = { channel: mainChannel, multiplexer };
this.windowChannelMultiplexer.set(sender.id, data);
return data;
}
/**
* Creates the main channel to a window.
* @param sender The window that the channel should be established to.
*/
createWindowMainChannel(sender) {
return new ElectronWebContentChannel(sender);
}
disposeMultiplexer(windowId, multiplexer, reason) {
multiplexer.onUnderlyingChannelClose({ reason });
this.windowChannelMultiplexer.delete(windowId);
}
onStart() {
for (const contribution of this.messagingContributions.getContributions()) {
contribution.configure(this);
}
for (const connectionHandler of this.connectionHandlers.getContributions()) {
this.channelHandlers.push(connectionHandler.path, (params, channel) => {
connectionHandler.onConnection(channel);
});
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
ipcChannel(spec, callback) {
this.channelHandlers.push(spec, callback);
}
};
__decorate([
(0, inversify_1.inject)(contribution_provider_1.ContributionProvider),
(0, inversify_1.named)(electron_messaging_service_1.ElectronMessagingService.Contribution),
__metadata("design:type", Object)
], ElectronMessagingContribution.prototype, "messagingContributions", void 0);
__decorate([
(0, inversify_1.inject)(contribution_provider_1.ContributionProvider),
(0, inversify_1.named)(electron_connection_handler_1.ElectronConnectionHandler),
__metadata("design:type", Object)
], ElectronMessagingContribution.prototype, "connectionHandlers", void 0);
__decorate([
(0, inversify_1.postConstruct)(),
__metadata("design:type", Function),
__metadata("design:paramtypes", []),
__metadata("design:returntype", void 0)
], ElectronMessagingContribution.prototype, "init", null);
ElectronMessagingContribution = __decorate([
(0, inversify_1.injectable)()
], ElectronMessagingContribution);
exports.ElectronMessagingContribution = ElectronMessagingContribution;
/**
* Used to establish a connection between the ipcMain and the Electron frontend (window).
* Messages a transferred via electron IPC.
*/
class ElectronWebContentChannel extends channel_1.AbstractChannel {
constructor(sender) {
super();
this.sender = sender;
// Make the message emitter public so that we can easily forward messages received from the ipcMain.
this.onMessageEmitter = new common_1.Emitter();
}
getWriteBuffer() {
const writer = new uint8_array_message_buffer_1.Uint8ArrayWriteBuffer();
writer.onCommit(buffer => {
if (!this.sender.isDestroyed()) {
electron_api_main_1.TheiaRendererAPI.sendData(this.sender, buffer);
}
});
return writer;
}
}
exports.ElectronWebContentChannel = ElectronWebContentChannel;
//# sourceMappingURL=electron-messaging-contribution.js.map
;