Skip to content

Commit

Permalink
[core] Open local window
Browse files Browse the repository at this point in the history
Add a way for a remote electron window to open a window connected
 to the original backend.

Signed-off-by: Paul Maréchal <paul.marechal@ericsson.com>
  • Loading branch information
paul-marechal committed Jul 19, 2018
1 parent b8b2bc5 commit 0044994
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,17 +114,32 @@ const { join } = require('path');
const { isMaster } = require('cluster');
const { fork } = require('child_process');
const { app, BrowserWindow, ipcMain } = require('electron');
const EventEmitter = require('events');
const fileSchemeTester = /^file:/;
const localUriEvent = new EventEmitter();
let localUri = undefined;
const windows = [];
function setLocalUri(uri) {
localUriEvent.emit('update', localUri = uri);
}
function resolveLocalUriFromPort(port) {
setLocalUri('file://' + join(__dirname, '../../lib/index.html') + '?port=' + port);
}
function createNewWindow(theUrl) {
const config = {
width: 1024,
height: 728,
show: !!theUrl
};
// Converts 'localhost' to the running local backend endpoint
if (localUri && theUrl === 'localhost') {
theUrl = localUri;
}
if (!!theUrl && !fileSchemeTester.test(theUrl)) {
config.webPreferences = {
// nodeIntegration: false,
Expand Down Expand Up @@ -170,25 +185,28 @@ if (isMaster) {
app.on('ready', () => {
// Check whether we are in bundled application or development mode.
const devMode = process.defaultApp || /node_modules[\\/]electron[\\/]/.test(process.execPath);
const mainWindow = createNewWindow();
const loadMainWindow = (port) => {
mainWindow.loadURL('file://' + join(__dirname, '../../lib/index.html') + '?port=' + port);
const loadMainWindow = (uri) => {
// mainWindow.loadURL(\`http://localhost:\${port}\`);
mainWindow.loadURL(uri);
};
localUriEvent.once('update', loadMainWindow);
const mainPath = join(__dirname, '..', 'backend', 'main');
// We need to distinguish between bundled application and development mode when starting the clusters.
// See: https://github.com/electron/electron/issues/6337#issuecomment-230183287
if (devMode) {
require(mainPath).then(address => {
loadMainWindow(address.port);
resolveLocalUriFromPort(address.port)
}).catch((error) => {
console.error(error);
app.exit(1);
});
} else {
const cp = fork(mainPath);
cp.on('message', (message) => {
loadMainWindow(message);
resolveLocalUriFromPort(message);
});
cp.on('error', (error) => {
console.error(error);
Expand Down
6 changes: 4 additions & 2 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,16 @@
"publishConfig": {
"access": "public"
},
"theiaExtensions": [
{
"theiaExtensions": [{
"frontend": "lib/browser/menu/browser-menu-module",
"frontendElectron": "lib/electron-browser/menu/electron-menu-module"
},
{
"frontend": "lib/browser/window/browser-window-module",
"frontendElectron": "lib/electron-browser/window/electron-window-module"
},
{
"frontendElectron": "lib/electron-browser/remote/electron-remote-module"
}
],
"keywords": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import { FrontendApplicationContribution, ContextMenuRenderer, KeybindingContrib
import { ElectronMainMenuFactory } from './electron-main-menu-factory';
import { ElectronContextMenuRenderer } from "./electron-context-menu-renderer";
import { ElectronMenuContribution } from "./electron-menu-contribution";
import { ElectronRemoteContribution } from './electron-remote-contribution';

export default new ContainerModule(bind => {
bind(ElectronMainMenuFactory).toSelf().inSingletonScope();
Expand All @@ -34,9 +33,4 @@ export default new ContainerModule(bind => {
for (const serviceIdentifier of [FrontendApplicationContribution, KeybindingContribution, CommandContribution, MenuContribution]) {
bind(serviceIdentifier).toDynamicValue(ctx => ctx.container.get(ElectronMenuContribution)).inSingletonScope();
}

bind(ElectronRemoteContribution).toSelf().inSingletonScope();
for (const serviceIdentifier of [KeybindingContribution, CommandContribution, MenuContribution]) {
bind(serviceIdentifier).toService(ElectronRemoteContribution);
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/********************************************************************************
* Copyright (C) 2018 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 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable } from 'inversify';

export enum ConnectionType {
Local = 0,
Remote,
}

export const ConnectionStateService = Symbol('ConnectionStateService');
export interface ConnectionStateService {
getState(): string;
isLocal(): boolean;
isRemote(): boolean;
}

@injectable()
export class DefaultConnectionStateService {

protected state: ConnectionType = /^file:/.test(self.location.href) ? ConnectionType.Local : ConnectionType.Remote;

getState(): string {
return ConnectionType[this.state];
}

isLocal(): boolean {
return this.state === ConnectionType.Local;
}

isRemote(): boolean {
return this.state === ConnectionType.Remote;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
import { CommonMenus } from '../../browser';
import { WindowService } from '../../browser/window/window-service';
import { timeout as delay } from '../../common/promise-util';
import { ConnectionStateService } from './connection-state-service';

export namespace ElectronRemoteCommands {
export const CONNECT_TO_REMOTE: Command = {
Expand Down Expand Up @@ -138,6 +139,7 @@ export class CachedRemoteEntry implements RemoteEntry {
@injectable()
export class ElectronRemoteContribution implements QuickOpenModel, CommandContribution, MenuContribution, KeybindingContribution {

@inject(ConnectionStateService) protected readonly connectionState: ConnectionStateService;
@inject(StorageService) protected readonly localStorageService: StorageService;
@inject(QuickOpenService) protected readonly quickOpenService: QuickOpenService;
@inject(WindowService) protected readonly windowService: WindowService;
Expand Down Expand Up @@ -207,12 +209,22 @@ export class ElectronRemoteContribution implements QuickOpenModel, CommandContri
const defaultSchemes = ['http', 'https'];
const inputResponses = [];
const inputEntries = [];
const items = [];
const items: QuickOpenItem[] = [];

// Add a way to open a local electron window
if (this.connectionState.isRemote()) {
items.push(new QuickOpenGroupItem({
label: 'Localhost Application',
groupLabel: 'Electron',
description: 'Electron',
run: this.urlOpener('localhost'),
}));
}

if (lookFor) {
let url = new URI(lookFor);

// Autocompletion (http/https)
// Autocompletion (http/https) if not using http(s) filescheme
if (!/^https?$/.test(url.scheme)) {
const reformated = new URI(`//${lookFor}`);
for (const scheme of defaultSchemes) {
Expand All @@ -231,18 +243,22 @@ export class ElectronRemoteContribution implements QuickOpenModel, CommandContri
inputResponses.push(...await this.accumulateResponses(inputEntries, this.timeout));
}

// Sorting the autocompletion and history based on the status of the responses
const sortedEntries = [...inputResponses, ...await this.historyEntries]
.filter((entry, index, array) => array.findIndex(e => e.url === entry.url) === index) // make unique
.sort((a, b) => { // place OK responses first
if (a.isOk() && b.isOk()) {
// make unique
.filter((entry, index, array) => array.findIndex(e => e.url === entry.url) === index)
// place OK responses first
.sort((a, b) => {
if (a.isOk() === b.isOk()) {
return 0;
} else if (a.isOk()) {
return -1;
} else {
return 1;
}
})
.map((entry, index, array) => { // place a separator between OK and Error responses
// place a separator between OK and Error responses
.map((entry, index, array) => {
const previous = array[index - 1];
const options: QuickOpenGroupItemOptions = {};
if (previous && previous.isOk() && !entry.isOk()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/********************************************************************************
* Copyright (C) 2018 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 WITH Classpath-exception-2.0
********************************************************************************/

import { ContainerModule } from 'inversify';
import { CommandContribution, MenuContribution } from "../../common";
import { KeybindingContribution } from '../../browser';
import { ElectronRemoteContribution } from './electron-remote-contribution';
import { ConnectionStateService, DefaultConnectionStateService } from './connection-state-service';

export default new ContainerModule(bind => {
bind(ConnectionStateService).to(DefaultConnectionStateService).inSingletonScope();

bind(ElectronRemoteContribution).toSelf().inSingletonScope();
for (const serviceIdentifier of [KeybindingContribution, CommandContribution, MenuContribution]) {
bind(serviceIdentifier).toService(ElectronRemoteContribution);
}
});

0 comments on commit 0044994

Please sign in to comment.