Skip to content
This repository was archived by the owner on May 22, 2020. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
df79dc5
RUN-5493: add nativeId to NW info objects
dhamberlin Aug 20, 2019
ec89940
RUN-5493: Differentiate nativeId and uuid
dhamberlin Aug 20, 2019
f0ac310
WIP: uuid enforcement for external windows
dhamberlin Aug 21, 2019
1fc4274
Merge branch 'develop' into RUN-5493-nativeId-refactor
dhamberlin Aug 23, 2019
e0917a5
RUN-5493: Remove uuids for unregistered NWs
dhamberlin Sep 4, 2019
36cadf9
RUN-5493: Fix NWI cleanup
dhamberlin Sep 4, 2019
51715e8
RUN-5493: Include uuid in events and getAllExternalWindows
dhamberlin Sep 11, 2019
b5abd41
RUN-5493: use external process uuid for NWI events when relevant
dhamberlin Sep 12, 2019
d103e35
Resolve merge conflicts
dhamberlin Sep 12, 2019
fabdf72
Merge branch 'develop' into RUN-5493-external-window-id-updates
dhamberlin Sep 16, 2019
11f14fc
remove unwanted changes
dhamberlin Sep 16, 2019
c09baa4
RUN-5493 fix js-adapter version
dhamberlin Sep 16, 2019
97047d0
RUN-5493 alphabetize
dhamberlin Sep 16, 2019
d62fe42
Run-5492: fix NWI eventing
dhamberlin Sep 17, 2019
0ea5335
RUN-5493 get correct window info from getInfo call
dhamberlin Sep 18, 2019
0b4518a
RUN 5493 Release ExtWin ids even if cleanup errors
dhamberlin Oct 8, 2019
1b8ed89
Rename `requestedId` -> `requestedIdentity`
dhamberlin Oct 11, 2019
4c2e3ba
Merge branch 'develop' into RUN-5493-external-window-id-updates
dhamberlin Oct 15, 2019
c451547
Remove unneeded uuid backup
dhamberlin Oct 16, 2019
884685b
Merge branch 'RUN-5493-external-window-id-updates' of github.com:dham…
dhamberlin Oct 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 45 additions & 33 deletions src/browser/api/external_window.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import route from '../../common/route';
import WindowGroups, { GroupChangedEvent, GroupEvent } from '../window_groups';
import ProcessTracker from '../process_tracker';
import SubscriptionManager from '../subscription_manager';
import { releaseUuid, lockUuid } from '../uuid_availability';

electronApp.on('ready', () => {
subToGlobalWinEventHooks();
Expand All @@ -22,6 +23,7 @@ const subscriptionManager = new SubscriptionManager();

// Maps
export const externalWindows = new Map<string, Shapes.ExternalWindow>();
export const nativeIdToUuid = new Map<string, string>();
const disabledUserMovementRequestorCount = new Map<string, number>();
const externalWindowEventAdapters = new Map<string, ExternalWindowEventAdapter>();
const injectionBuses = new Map<string, InjectionBus>();
Expand Down Expand Up @@ -106,9 +108,9 @@ export function getExternalWindowGroup(identity: Identity): Shapes.GroupWindowId
return windowGroup.map(({ name, uuid, isExternalWindow }) => ({ name, uuid, windowName: name, isExternalWindow }));
}

export function getExternalWindowInfo(identity: Identity): Shapes.NativeWindowInfo {
const { uuid } = identity;
const rawNativeWindowInfo = electronApp.getNativeWindowInfoForNativeId(uuid);
export function getExternalWindowInfo(identity: Shapes.NativeWindowIdentity): Shapes.NativeWindowInfo {
const { nativeId } = identity;
const rawNativeWindowInfo = electronApp.getNativeWindowInfoForNativeId(nativeId);
return getNativeWindowInfo(rawNativeWindowInfo);
}

Expand Down Expand Up @@ -257,42 +259,42 @@ function findExistingNativeWindow(identity: Shapes.NativeWindowIdentity): Shapes
? allNativeWindows.find(win => win.process.pid === prelaunchedProcess.process.id)
: allNativeWindows.find(win => {
const liteInfo = getNativeWindowInfoLite(win);
return liteInfo.uuid === uuid || liteInfo.nativeId === nativeId;
return liteInfo.nativeId === nativeId;
});

if (!win) {
return;
}

const liteInfo = getNativeWindowInfoLite(win);
if (prelaunchedProcess) {
// Respect original uuid if present
liteInfo.uuid = prelaunchedProcess.uuid;
}
return liteInfo;
return win && getNativeWindowInfoLite(win);
}

/*
Returns a registered native window or creates a new one if not found.
*/
export function getExternalWindow(identity: Shapes.NativeWindowIdentity): Shapes.ExternalWindow {
const { uuid } = identity;
const nativeId = identity.nativeId;
const uuid = identity.uuid || electronApp.generateGUID();
let externalWindow = externalWindows.get(uuid);

if (externalWindow && nativeId && externalWindow.nativeId !== nativeId) {
throw new Error(`Requested uuid "${uuid}" is already in use for a different window.`);
}

if (!externalWindow) {
if (!lockUuid(uuid)) {
throw new Error(`Failed to wrap, uuid "${uuid}" is already in use.`);
}
const nativeWinObj = findExistingNativeWindow(identity);

if (!nativeWinObj) {
throw new Error(`Attempted to interact with a nonexistent external window using identity ${JSON.stringify(identity)}}`);
}
externalWindow = <Shapes.ExternalWindow>(new ExternalWindow({ hwnd: nativeWinObj.nativeId }));

setAdditionalProperties(externalWindow, identity);
setAdditionalProperties(externalWindow, { uuid, name: identity.name || nativeWinObj.name });
subscribeToInjectionEvents(externalWindow);
subscribeToWinEventHooks(externalWindow);
subscribeToWindowGroupEvents(externalWindow);

externalWindows.set(uuid, externalWindow);
externalWindows.set(externalWindow.uuid, externalWindow);
nativeIdToUuid.set(externalWindow.nativeId, externalWindow.uuid);
}

return externalWindow;
Expand Down Expand Up @@ -450,7 +452,7 @@ function subscribeToWinEventHooks(externalWindow: Shapes.ExternalWindow): void {

// We are subscribing to a process, so we only care about a specific window.
// idChild === '0' indicates that event is from main window, not a subcomponent.
if (nativeWindowInfo.uuid !== nativeId || idChild !== '0') {
if (nativeWindowInfo.nativeId !== nativeId || idChild !== '0') {
return;
}
parser(nativeWindowInfo);
Expand Down Expand Up @@ -532,10 +534,13 @@ function subscribeToWinEventHooks(externalWindow: Shapes.ExternalWindow): void {

// Window grouping stub (makes external windows work with our original disabled frame group tracker)
// Also some of the _options' values are needed in OpenFin Layouts
function setAdditionalProperties(externalWindow: Shapes.ExternalWindow, properIdentity: Shapes.NativeWindowIdentity): Shapes.GroupWindow {
function setAdditionalProperties(
externalWindow: Shapes.ExternalWindow,
requestedIdentity: Shapes.NativeWindowIdentity
): Shapes.GroupWindow {
const { nativeId } = externalWindow;
const uuid = properIdentity.uuid || nativeId;
const name = properIdentity.name || nativeId;
const uuid = requestedIdentity.uuid;
const name = requestedIdentity.name || nativeId;
const identity = { uuid, name, nativeId };

externalWindow._userMovement = true;
Expand Down Expand Up @@ -670,7 +675,7 @@ export function isValidExternalWindow(rawNativeWindowInfo: NativeWindowInfo, ign
*/
function externalWindowCloseCleanup(externalWindow: Shapes.ExternalWindow): void {
const key = getKey(externalWindow);
const { nativeId } = externalWindow;
const { uuid, nativeId } = externalWindow;
const winEventHooks = winEventHooksEmitters.get(key);
const injectionBus = injectionBuses.get(key);
const externalWindowEventAdapter = externalWindowEventAdapters.get(key);
Expand All @@ -679,21 +684,28 @@ function externalWindowCloseCleanup(externalWindow: Shapes.ExternalWindow): void
externalWindow.emit('closing');
disabledUserMovementRequestorCount.delete(key);

winEventHooks.removeAllListeners();
winEventHooksEmitters.delete(key);
try {
winEventHooks.removeAllListeners();
winEventHooksEmitters.delete(key);

injectionBus.removeAllListeners();
injectionBuses.delete(key);

injectionBus.removeAllListeners();
injectionBuses.delete(key);
windowGroupUnSubscription();
windowGroupUnSubscriptions.delete(key);

windowGroupUnSubscription();
windowGroupUnSubscriptions.delete(key);
externalWindowEventAdapter.removeAllListeners();
externalWindowEventAdapters.delete(key);

externalWindowEventAdapter.removeAllListeners();
externalWindowEventAdapters.delete(key);
externalWindow.emit('closed');
externalWindow.removeAllListeners();
} catch (err) {
electronApp.vlog(2, `Error cleaning up ExternalWindow: ${err}`);
}

externalWindow.emit('closed');
externalWindow.removeAllListeners();
externalWindows.delete(nativeId);
externalWindows.delete(uuid);
nativeIdToUuid.delete(nativeId);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should guarantee a few of these things right, if we get an error on a preceding step we should still release the nativeUuid no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rdepena Most of this cleanup seems relatively fail-proof. Wrapped the bits that might fail in a try catch.

releaseUuid(uuid);
}

/*
Expand Down
6 changes: 5 additions & 1 deletion src/browser/api/system.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { fetchReadFile } from '../cached_resource_fetcher';
import { createChromiumSocket, authenticateChromiumSocket } from '../transports/chromium_socket';
import { authenticateFetch, grantAccess } from '../cached_resource_fetcher';
import { getNativeWindowInfoLite } from '../utils';
import { isValidExternalWindow } from './external_window';
import { isValidExternalWindow, nativeIdToUuid } from './external_window';
import { getWindowByUuidName, getBrowserViewByIdentity, getInfoByUuidFrame } from '../core_state';

const defaultProc = {
Expand Down Expand Up @@ -731,6 +731,10 @@ export const System = {

allNativeWindows.forEach(e => {
const externalWindow = getNativeWindowInfoLite(e);
const uuid = nativeIdToUuid.get(externalWindow.nativeId);
if (uuid) {
externalWindow.uuid = uuid;
}
const isValid = isValidExternalWindow(e);

if (isValid) {
Expand Down
31 changes: 28 additions & 3 deletions src/browser/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { basename } from 'path';
import { BrowserWindow as OFBrowserWindow } from '../shapes';
import { BrowserWindow, Rectangle, screen, NativeWindowInfo } from 'electron';
import * as Shapes from '../shapes';
import { nativeIdToUuid } from './api/external_window';
import ProcessTracker from './process_tracker';

/*
This function sets window's bounds to be in a visible area, in case
Expand Down Expand Up @@ -83,23 +85,46 @@ export function getNativeWindowInfoLite(rawNativeWindowInfo: NativeWindowInfo):
name = rawNativeWindowInfo.title;
}

return {
const liteInfo: Shapes.NativeWindowInfoLite = {
name,
nativeId: rawNativeWindowInfo.id,
process: {
injected: rawNativeWindowInfo.process.injected,
pid: rawNativeWindowInfo.process.pid
},
title: rawNativeWindowInfo.title,
uuid: rawNativeWindowInfo.id,
visible: rawNativeWindowInfo.visible
};

const uuid = getNativeWindowUuid(liteInfo);

if (uuid) {
liteInfo.uuid = uuid;
}

return liteInfo;
}

/*
Finds an appropriate uuid for a native window by first checking for its nativeId among
registered ExternalWindows, then checking for its pid among registered external processes
*/
function getNativeWindowUuid(nativeWindowInfo: Shapes.NativeWindowInfoLite): string | void {
let uuid = nativeIdToUuid.get(nativeWindowInfo.nativeId);
if (!uuid) {
const { process: { pid } } = nativeWindowInfo;
const launchedProcess = ProcessTracker.getProcessByPid(pid);
if (launchedProcess) {
uuid = launchedProcess.uuid;
}
}
return uuid;
}

/*
Returns full version of external window info object
*/
export function getNativeWindowInfo(rawNativeWindowInfo: NativeWindowInfo): Shapes.NativeWindowInfo {
export function getNativeWindowInfo(rawNativeWindowInfo: NativeWindowInfo): Shapes.NativeWindowInfo & Shapes.NativeWindowInfoLite {
const liteInfoObject = getNativeWindowInfoLite(rawNativeWindowInfo);

return {
Expand Down
2 changes: 1 addition & 1 deletion src/shapes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ export interface Process extends Omit<ProcessElectron, 'imageName'> {
export interface NativeWindowInfo extends Omit<NativeWindowInfoElectron, 'process'|'id'> {
process: Process;
name: string;
uuid: string;
uuid?: string;
}

export type NativeWindowInfoLite = (Pick<NativeWindowInfo, 'name'|'process'|'title'|'uuid'|'visible'>) & { nativeId: string };
Expand Down