Skip to content

Commit

Permalink
feat: DH-18086: Envoy prefix (#206)
Browse files Browse the repository at this point in the history
feat: DH-18086: Envoy prefix

### Testing
Should be able to connect and run queries against the following:
* Community server
* non-envoy DHE server
* Envoy DHE server
  • Loading branch information
bmingles authored Jan 27, 2025
1 parent a20013a commit bd59aa3
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 23 deletions.
Binary file modified releases/vscode-deephaven-latest.vsix
Binary file not shown.
29 changes: 25 additions & 4 deletions src/controllers/ExtensionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import type {
ICoreClientFactory,
CoreUnauthenticatedClient,
ConnectionState,
WorkerURL,
} from '../types';
import { ServerConnectionTreeDragAndDropController } from './ServerConnectionTreeDragAndDropController';
import { ConnectionController } from './ConnectionController';
Expand Down Expand Up @@ -114,7 +115,8 @@ export class ExtensionController implements Disposable {
'Congratulations, your extension "vscode-deephaven" is now active!'
);

this._outputChannel?.appendLine('Deephaven extension activated');
const version = context.extension.packageJSON.version;
this._outputChannel?.appendLine(`Deephaven extension ${version} activated`);
}

readonly _context: vscode.ExtensionContext;
Expand Down Expand Up @@ -352,12 +354,31 @@ export class ExtensionController implements Disposable {
url: URL
): Promise<CoreUnauthenticatedClient & Disposable> => {
assertDefined(this._coreJsApiCache, 'coreJsApiCache');
const dhc = await this._coreJsApiCache.get(url);

const client = new dhc.CoreClient(url.toString(), {
const workerInfo = await this._serverManager?.getWorkerInfo(
url as WorkerURL
);
const envoyPrefix = workerInfo?.envoyPrefix;
const urlStr = String(workerInfo?.grpcUrl ?? url).replace(/\/$/, '');

const options: DhcType.ConnectOptions = {
debug: false, // Set `debug` to true to see debug logs for gRPC transport
transportFactory: NodeHttp2gRPCTransport.factory,
}) as CoreUnauthenticatedClient;
};

if (envoyPrefix != null) {
options.headers = {
// eslint-disable-next-line @typescript-eslint/naming-convention
'envoy-prefix': envoyPrefix,
};
}

const dhc = await this._coreJsApiCache.get(url);

const client = new dhc.CoreClient(
urlStr,
options
) as CoreUnauthenticatedClient;

// Attach a dispose method so that client caches can dispose of the client
return Object.assign(client, {
Expand Down
12 changes: 7 additions & 5 deletions src/controllers/PanelController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
IServerManager,
NonEmptyArray,
VariableDefintion,
WorkerInfo,
WorkerURL,
} from '../types';
import {
Expand Down Expand Up @@ -292,8 +293,8 @@ export class PanelController extends ControllerBase {
const connection = this._serverManager.getConnection(serverUrl);
assertDefined(connection, 'connection');

const isWorkerUrl = Boolean(
await this._serverManager.getWorkerInfo(serverUrl as WorkerURL)
const workerInfo = await this._serverManager.getWorkerInfo(
serverUrl as WorkerURL
);

for (const variable of variables) {
Expand All @@ -315,7 +316,7 @@ export class PanelController extends ControllerBase {
const iframeUrl = await getEmbedWidgetUrlForConnection(
connection,
title,
isWorkerUrl
workerInfo
);

panel.webview.html = getPanelHtml(iframeUrl, title);
Expand Down Expand Up @@ -347,7 +348,7 @@ export class PanelController extends ControllerBase {
export async function getEmbedWidgetUrlForConnection(
connection: ConnectionState,
title: string,
isWorkerUrl: boolean
workerInfo?: WorkerInfo
): Promise<URL> {
return getEmbedWidgetUrl({
serverUrl: connection.serverUrl,
Expand All @@ -356,7 +357,8 @@ export async function getEmbedWidgetUrlForConnection(
// For Core+ workers in DHE, we use `postMessage` apis for auth where DH
// iframe communicates with parent (the extension) to get login credentials
// from the DHE client. See `getPanelHtml` util for more details.
authProvider: isWorkerUrl ? 'parent' : undefined,
authProvider: workerInfo == null ? undefined : 'parent',
envoyPrefix: workerInfo?.envoyPrefix,
psk:
connection instanceof DhcService ? await connection.getPsk() : undefined,
});
Expand Down
9 changes: 8 additions & 1 deletion src/dh/dhc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,25 @@ export async function getDhc(
* @param title Widget title
* @param themeKey Theme key
* @param authProvider Optional auth provider
* @param envoyPrefix Optional envoy prefix for Core+ workers
* @param psk Optional psk
*/
export function getEmbedWidgetUrl({
serverUrl,
title,
themeKey,
authProvider,
envoyPrefix,
psk,
}: {
serverUrl: URL;
title: string;
themeKey: string;
authProvider?: 'parent';
envoyPrefix?: string | null;
psk?: string | null;
}): URL {
const url = new URL('/iframe/widget', serverUrl);
const url = new URL('iframe/widget/', serverUrl);

url.searchParams.set('name', title);
url.searchParams.set('theme', themeKey);
Expand All @@ -98,6 +101,10 @@ export function getEmbedWidgetUrl({
url.searchParams.set('authProvider', authProvider);
}

if (envoyPrefix) {
url.searchParams.set('envoyPrefix', envoyPrefix);
}

if (psk) {
url.searchParams.set('psk', psk);
}
Expand Down
13 changes: 11 additions & 2 deletions src/dh/dhe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import type { AuthenticatedClient as DheAuthenticatedClient } from '@deephaven-e
import { hasStatusCode, loadModules } from '@deephaven/jsapi-nodejs';
import type {
ConsoleType,
GrpcURL,
IdeURL,
JsapiURL,
QuerySerial,
UniqueID,
WorkerConfig,
Expand Down Expand Up @@ -271,15 +273,22 @@ export async function getWorkerInfoFromQuery(
return;
}

const { grpcUrl, ideUrl, processInfoId, workerName } = queryInfo.designated;
const { envoyPrefix, grpcUrl, ideUrl, jsApiUrl, processInfoId, workerName } =
queryInfo.designated;

const workerUrl = new URL(jsApiUrl) as WorkerURL;
workerUrl.pathname = workerUrl.pathname.replace(/jsapi\/dh-core.js$/, '');

return {
tagId,
serial: querySerial,
grpcUrl: new URL(grpcUrl) as WorkerURL,
envoyPrefix,
grpcUrl: new URL(grpcUrl) as GrpcURL,
ideUrl: new URL(ideUrl) as IdeURL,
jsapiUrl: new URL(jsApiUrl) as JsapiURL,
processInfoId,
workerName,
workerUrl,
};
}

Expand Down
4 changes: 2 additions & 2 deletions src/services/DheService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import * as vscode from 'vscode';
import type { AuthenticatedClient as DheAuthenticatedClient } from '@deephaven-enterprise/auth-nodejs';
import type { EnterpriseDhType as DheType } from '@deephaven-enterprise/jsapi-types';
import {
WorkerURL,
type ConsoleType,
type IAsyncCacheService,
type IConfigService,
Expand All @@ -13,6 +12,7 @@ import {
type UniqueID,
type WorkerConfig,
type WorkerInfo,
type WorkerURL,
} from '../types';
import { URLMap } from './URLMap';
import { Logger } from '../util';
Expand Down Expand Up @@ -231,7 +231,7 @@ export class DheService implements IDheService {
throw new Error('Failed to create worker.');
}

this._workerInfoMap.set(workerInfo.grpcUrl, workerInfo);
this._workerInfoMap.set(workerInfo.workerUrl, workerInfo);

return workerInfo;
};
Expand Down
11 changes: 7 additions & 4 deletions src/services/ServerManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import type {
WorkerInfo,
IDheService,
IAsyncCacheService,
WorkerURL,
UniqueID,
IToastService,
CoreAuthenticatedClient,
ISecretService,
Psk,
WorkerURL,
} from '../types';
import {
getInitialServerStates,
Expand Down Expand Up @@ -211,7 +211,7 @@ export class ServerManager implements IServerManager {
// this indicates that the user cancelled the creation before it was ready.
// In this case, dispose of the worker.
if (!this._connectionMap.has(placeholderUrl)) {
dheService.deleteWorker(workerInfo.grpcUrl);
dheService.deleteWorker(workerInfo.workerUrl);
this._onDidUpdate.fire();
return null;
}
Expand All @@ -228,11 +228,14 @@ export class ServerManager implements IServerManager {

// Map the worker URL to the server URL to make things easier to dispose
// later.
this._workerURLToServerURLMap.set(new URL(workerInfo.grpcUrl), serverUrl);
this._workerURLToServerURLMap.set(
new URL(workerInfo.workerUrl),
serverUrl
);

// Update the server URL to the worker url to be used below with core
// connection creation.
serverUrl = new URL(workerInfo.grpcUrl);
serverUrl = new URL(workerInfo.workerUrl);
}

const connection = this._dhcServiceFactory.create(serverUrl, tagId);
Expand Down
9 changes: 7 additions & 2 deletions src/types/commonTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,17 +90,22 @@ export interface ConnectionState {
readonly tagId?: UniqueID;
}

export type WorkerURL = Brand<'GrpcUrl', URL>;
export type GrpcURL = Brand<'GrpcURL', URL>;
export type IdeURL = Brand<'IdeUrl', URL>;
export type JsapiURL = Brand<'JsapiURL', URL>;
export type QuerySerial = Brand<'QuerySerial', string>;
export type WorkerURL = Brand<'WorkerURL', URL>;

export interface WorkerInfo {
tagId: UniqueID;
grpcUrl: WorkerURL;
envoyPrefix: string | null;
grpcUrl: GrpcURL;
ideUrl: IdeURL;
jsapiUrl: JsapiURL;
processInfoId: string | null;
serial: QuerySerial;
workerName: string | null;
workerUrl: WorkerURL;
}

export interface Disposable {
Expand Down
4 changes: 1 addition & 3 deletions src/types/serviceTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,17 @@ import type {
EventListenerT,
ConnectionState,
ServerState,
UnsubscribeEventListener,
VariableChanges,
VariableDefintion,
VariableID,
WorkerInfo,
WorkerURL,
UniqueID,
UserKeyPairs,
UserLoginPreferences,
CoreUnauthenticatedClient,
Psk,
CoreAuthenticatedClient,
NonEmptyArray,
WorkerURL,
} from '../types/commonTypes';
import type {
AuthenticatedClient as DheAuthenticatedClient,
Expand Down

0 comments on commit bd59aa3

Please sign in to comment.