Skip to content

Commit

Permalink
Set up listeners for deep links
Browse files Browse the repository at this point in the history
  • Loading branch information
ravicious committed Oct 18, 2023
1 parent 703851a commit 71d4d87
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
67 changes: 67 additions & 0 deletions web/packages/teleterm/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ import {
} from 'teleterm/services/config';
import { createFileStorage } from 'teleterm/services/fileStorage';
import { WindowsManager } from 'teleterm/mainProcess/windowsManager';
import { CONNECT_CUSTOM_PROTOCOL } from 'teleterm/ui/uri';

// Set the app as a default protocol client only if it wasn't started through `electron .`.
if (!process.defaultApp) {
app.setAsDefaultProtocolClient(CONNECT_CUSTOM_PROTOCOL);
}

if (app.requestSingleInstanceLock()) {
initializeApp();
Expand Down Expand Up @@ -128,6 +134,14 @@ function initializeApp(): void {
windowsManager.focusWindow();
});

// Since setUpDeepLinks adds another listener for second-instance, it's important to call it after
// the listener which calls windowsManager.focusWindow. This way the focus will be brought to the
// window before processing the listener for deep links.
//
// The setup must be done synchronously when starting the app, otherwise the listeners won't get
// triggered on macOS if the app is not already running when the user opens a deep link.
setUpDeepLinks(logger, windowsManager, settings);

app.whenReady().then(() => {
if (mainProcess.settings.dev) {
// allow restarts on F6
Expand Down Expand Up @@ -254,3 +268,56 @@ function createFileStorages(userDataDir: string) {
}),
};
}

// Important: Deep links work only with a packaged version of the app.
//
// Technically, Windows could support deep links with a non-packaged version of the app, but for
// simplicity's sake we don't support this.
function setUpDeepLinks(
logger: Logger,
windowsManager: WindowsManager,
settings: types.RuntimeSettings
) {
// The setup is done according to the docs:
// https://www.electronjs.org/docs/latest/tutorial/launch-app-from-url-in-another-app

if (settings.platform === 'darwin') {
// Deep link click on macOS.
app.on('open-url', (event, url) => {
// macOS does bring focus to the _application_ itself. However, if the app has one window and
// the window is minimized, it'll remain so. So we have to focus the window ourselves.
windowsManager.focusWindow();

logger.info(`Deep link launch from open-url, URL: ${url}`);
});
return;
}

// Do not handle deep links if the app was started from `electron .`, as custom protocol URLs
// won't be forwarded to the app on Linux in this case.
if (process.defaultApp) {
return;
}

// Deep link click if the app is already opened (Windows or Linux).
app.on('second-instance', (event, argv) => {
const url = findCustomProtocolUrlInArgv(argv);
if (url) {
logger.info(`Deep link launch from second-instance, URI: ${url}`);
}
});

// Deep link click if the app is not running (Windows or Linux).
const url = findCustomProtocolUrlInArgv(process.argv);

if (!url) {
return;
}
logger.info(`Deep link launch from process.argv, URL: ${url}`);
}

// We don't know the exact position of the URL is in argv. Chromium might inject its own arguments
// into argv. See https://www.electronjs.org/docs/latest/api/app#event-second-instance.
function findCustomProtocolUrlInArgv(argv: string[]) {
return argv.find(arg => arg.startsWith(`${CONNECT_CUSTOM_PROTOCOL}://`));
}
2 changes: 2 additions & 0 deletions web/packages/teleterm/src/ui/uri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ export type DocumentUri = `/docs/${DocumentId}`;
type GatewayId = string;
export type GatewayUri = `/gateways/${GatewayId}`;

export const CONNECT_CUSTOM_PROTOCOL = 'teleport-connect' as const;

export const routing = {
parseClusterUri(uri: string) {
const leafMatch = routing.parseUri(uri, paths.leafCluster);
Expand Down

0 comments on commit 71d4d87

Please sign in to comment.