-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdhc.ts
201 lines (172 loc) · 5.5 KB
/
dhc.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
import type { dh as DhType } from '@deephaven/jsapi-types';
import { NoConsoleTypesError } from './errorUtils';
import type {
CoreAuthenticatedClient,
CoreUnauthenticatedClient,
DependencyName,
DependencyVersion,
} from '../types';
import { hasStatusCode, loadModules } from '@deephaven/jsapi-nodejs';
import {
REQUIREMENTS_QUERY_TXT,
REQUIREMENTS_TABLE_NAME,
REQUIREMENTS_TABLE_NAME_COLUMN_NAME,
REQUIREMENTS_TABLE_VERSION_COLUMN_NAME,
} from '../common';
export const AUTH_HANDLER_TYPE_ANONYMOUS =
'io.deephaven.auth.AnonymousAuthenticationHandler';
export const AUTH_HANDLER_TYPE_PSK =
'io.deephaven.authentication.psk.PskAuthenticationHandler';
export const AUTH_HANDLER_TYPE_DHE =
'io.deephaven.enterprise.dnd.authentication.DheAuthenticationHandler';
export type ConnectionAndSession<TConnection, TSession> = {
cn: TConnection;
session: TSession;
};
/**
* Download the DH Core jsapi from a running server and return the `dh` object.
* @param serverUrl URL of the DH Core server to download the api from.
* @param storageDir Directory to store downloaded jsapi files.
* @returns A promise that resolves to the DH Core jsapi.
*/
export async function getDhc(
serverUrl: URL,
storageDir: string
): Promise<typeof DhType> {
// The JS Api needs this whenever we are using Electron fetch api instead of
// the custom gRPC transport.
// @ts-ignore
globalThis.self = globalThis;
// Download jsapi `ESM` files from DH Community server.
const coreModule = await loadModules<typeof DhType>({
serverUrl,
serverPaths: ['jsapi/dh-core.js', 'jsapi/dh-internal.js'],
download: (serverPath, content) => {
if (serverPath === 'jsapi/dh-core.js') {
return content
.replace(
`import {dhinternal} from './dh-internal.js';`,
`const {dhinternal} = require("./dh-internal.js");`
)
.replace(`export default dh;`, `module.exports = dh;`);
}
if (serverPath === 'jsapi/dh-internal.js') {
return content.replace(
`export{__webpack_exports__dhinternal as dhinternal};`,
`module.exports={dhinternal:__webpack_exports__dhinternal};`
);
}
return content;
},
storageDir,
targetModuleType: 'cjs',
});
return coreModule;
}
/**
* Get embed widget url for a widget.
* @param serverUrl Server URL
* @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);
url.searchParams.set('name', title);
url.searchParams.set('theme', themeKey);
if (authProvider) {
url.searchParams.set('authProvider', authProvider);
}
if (envoyPrefix) {
url.searchParams.set('envoyPrefix', envoyPrefix);
}
if (psk) {
url.searchParams.set('psk', psk);
}
return url;
}
/**
* Get a name / version map of python dependencies from a DH session.
* @param session The DH session to use.
* @returns A promise that resolves to a map of python dependencies.
*/
export async function getPythonDependencies(
session: DhType.IdeSession
): Promise<Map<DependencyName, DependencyVersion>> {
await session.runCode(REQUIREMENTS_QUERY_TXT);
const dependencies = new Map<DependencyName, DependencyVersion>();
const table = await session.getTable(REQUIREMENTS_TABLE_NAME);
table.setViewport(0, table.size - 1);
const data = await table.getViewportData();
const nameColumn = table.findColumn(REQUIREMENTS_TABLE_NAME_COLUMN_NAME);
const versionColumn = table.findColumn(
REQUIREMENTS_TABLE_VERSION_COLUMN_NAME
);
for (const row of data.rows) {
const name: DependencyName = row.get(nameColumn);
const version: DependencyVersion = row.get(versionColumn);
dependencies.set(name, version);
}
await session.runCode(`del ${REQUIREMENTS_TABLE_NAME}`);
return dependencies;
}
/**
* Initialize a connection and session to a DHC server.
* @param client The authenticated client to use for the connection.
* @returns A promise that resolves to the connection and session.
*/
export async function initDhcSession(
client: CoreAuthenticatedClient
): Promise<ConnectionAndSession<DhType.IdeConnection, DhType.IdeSession>> {
const cn = await client.getAsIdeConnection();
const [type] = await cn.getConsoleTypes();
if (type == null) {
throw new NoConsoleTypesError();
}
const session = await cn.startSession(type);
return { cn, session };
}
/**
* Check if a given server is running by checking if the `dh-core.js` file is
* accessible.
* @param serverUrl
*/
export async function isDhcServerRunning(serverUrl: URL): Promise<boolean> {
try {
return await hasStatusCode(
new URL('jsapi/dh-core.js', serverUrl.toString()),
[200, 204]
);
} catch {
return false;
}
}
/**
* Login a given unauthenticated client with the given credentials.
* @param client The client to login.
* @param credentials The credentials to use for the login.
* @returns The authenticated client.
*/
export async function loginClient(
client: CoreUnauthenticatedClient,
credentials: DhType.LoginCredentials
): Promise<CoreAuthenticatedClient> {
await client.login(credentials);
return client as unknown as CoreAuthenticatedClient;
}