Skip to content

Commit 897c772

Browse files
committed
Address review comments
1 parent b6b3d3e commit 897c772

6 files changed

Lines changed: 83 additions & 46 deletions

File tree

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/code-studio/src/main/AppInit.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,10 @@ function AppInit(props: AppInitProps) {
170170
const coreClient = createCoreClient();
171171
const authType = getAuthType();
172172
log.info(`Login using auth type ${authType}...`);
173-
const loginOptions = await getLoginOptions(authType);
174-
const sessionDetails = await getSessionDetails(authType);
173+
const [loginOptions, sessionDetails] = await Promise.all([
174+
getLoginOptions(authType),
175+
getSessionDetails(authType),
176+
]);
175177
await coreClient.login(loginOptions);
176178

177179
const newPlugins = await loadPlugins();

packages/dashboard-core-plugins/src/panels/ConsolePanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,7 @@ export class ConsolePanel extends PureComponent<
320320
unzip,
321321
} = this.props;
322322
const { consoleSettings, error, objectMap } = this.state;
323-
const { config, session, connection, details } = sessionWrapper;
323+
const { config, session, connection, details = {} } = sessionWrapper;
324324
const { workerName, processInfoId } = details;
325325
const { id: sessionId, type: language } = config;
326326

packages/dashboard-core-plugins/src/redux/actions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export interface SessionWrapper {
2323
session: IdeSession;
2424
connection: IdeConnection;
2525
config: SessionConfig;
26-
details: SessionDetails;
26+
details?: SessionDetails;
2727
}
2828

2929
/**
Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
1-
import { TimeoutError } from '@deephaven/utils';
2-
import { makeMessage, requestParentResponse } from './MessageUtils';
1+
import {
2+
makeMessage,
3+
makeResponse,
4+
Message,
5+
requestParentResponse,
6+
} from './MessageUtils';
37

4-
// describe('Throws exception if called on a window without parent', async () => {
5-
// expect(await requestParentResponse<string>('request', 'response')).toThrow();
6-
// });
7-
8-
jest.useFakeTimers();
8+
it('Throws an exception if called on a window without parent', async () => {
9+
await expect(requestParentResponse('request')).rejects.toThrow(
10+
'window.opener is null, unable to send request.'
11+
);
12+
});
913

1014
describe('requestParentResponse', () => {
11-
const mockPostMessage = jest.fn();
1215
let addListenerSpy: jest.SpyInstance;
1316
let removeListenerSpy: jest.SpyInstance;
1417
let listenerCallback;
18+
let messageId;
19+
const mockPostMessage = jest.fn((data: Message<unknown>) => {
20+
messageId = data.id;
21+
});
1522
const originalWindowOpener = window.opener;
1623
beforeEach(() => {
1724
addListenerSpy = jest
@@ -27,12 +34,13 @@ describe('requestParentResponse', () => {
2734
removeListenerSpy.mockRestore();
2835
mockPostMessage.mockClear();
2936
window.opener = originalWindowOpener;
37+
messageId = undefined;
3038
});
3139

3240
it('Posts message to parent and subscribes to response', async () => {
33-
requestParentResponse<string>('request', 'response');
41+
requestParentResponse('request');
3442
expect(mockPostMessage).toHaveBeenCalledWith(
35-
expect.objectContaining({ message: 'request' }),
43+
expect.objectContaining(makeMessage('request', messageId)),
3644
'*'
3745
);
3846
expect(addListenerSpy).toHaveBeenCalledWith(
@@ -43,31 +51,32 @@ describe('requestParentResponse', () => {
4351

4452
it('Resolves with the payload from the parent window response and unsubscribes', async () => {
4553
const PAYLOAD = 'PAYLOAD';
46-
const promise = requestParentResponse<string>('request', 'response');
54+
const promise = requestParentResponse('request');
4755
listenerCallback({
48-
data: makeMessage<string>('response', PAYLOAD),
56+
data: makeResponse(messageId, PAYLOAD),
4957
});
5058
const result = await promise;
5159
expect(result).toBe(PAYLOAD);
5260
expect(removeListenerSpy).toHaveBeenCalledWith('message', listenerCallback);
5361
});
5462

55-
it('Rejects on time out', async () => {
56-
const promise = requestParentResponse<string>('request', 'response');
57-
expect(removeListenerSpy).not.toHaveBeenCalled();
63+
it('Ignores unrelated response, rejects on timeout', async () => {
64+
jest.useFakeTimers();
65+
const promise = requestParentResponse('request');
66+
listenerCallback({
67+
data: makeMessage('wrong-id'),
68+
});
5869
jest.runOnlyPendingTimers();
59-
expect(removeListenerSpy).toHaveBeenCalled();
60-
await expect(promise).rejects.toThrow(TimeoutError);
70+
await expect(promise).rejects.toThrow('Request timed out');
71+
jest.useRealTimers();
6172
});
6273

63-
// it('Ignores unrelated messages', async () => {
64-
// window.opener = { postMessage: mockPostMessage };
65-
// const PAYLOAD = 'PAYLOAD';
66-
// const promise = requestParentResponse<string>('request', 'response');
67-
// listenerCallback({
68-
// data: makeMessage<string>('response', `TEST_${messageId}`, PAYLOAD),
69-
// });
70-
// const result = await promise;
71-
// expect(result).toBe(PAYLOAD);
72-
// });
74+
it('Times out if no response', async () => {
75+
jest.useFakeTimers();
76+
const promise = requestParentResponse('request');
77+
jest.runOnlyPendingTimers();
78+
expect(removeListenerSpy).toHaveBeenCalled();
79+
await expect(promise).rejects.toThrow('Request timed out');
80+
jest.useRealTimers();
81+
});
7382
});
Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,72 @@
1+
import shortid from 'shortid';
12
import Log from '@deephaven/log';
23
import { TimeoutError } from '@deephaven/utils';
34

45
const log = Log.module('MessageUtils');
56

6-
export const LOGIN_OPTIONS_REQUEST = 'io.deephaven.loginOptions.request';
7-
export const LOGIN_OPTIONS_RESPONSE = 'io.deephaven.loginOptions.response';
7+
export const LOGIN_OPTIONS_REQUEST =
8+
'io.deephaven.message.LoginOptions.request';
89

9-
export const SESSION_DETAILS_REQUEST = 'io.deephaven.sessionDetails.request';
10-
export const SESSION_DETAILS_RESPONSE = 'io.deephaven.sessionDetails.response';
10+
export const SESSION_DETAILS_REQUEST =
11+
'io.deephaven.message.SessionDetails.request';
1112

1213
export interface Message<T> {
1314
message: string;
1415
payload?: T;
15-
id?: string;
16+
id: string;
1617
}
1718

18-
export function makeMessage<T>(message: string, payload?: T): Message<T> {
19-
return { message, payload };
19+
export interface Response<T> {
20+
id: string;
21+
payload: T;
22+
}
23+
24+
/**
25+
* Make message object with optional payload
26+
* @param message Message string
27+
* @param id Unique message id
28+
* @param payload Payload to send
29+
* @returns Message
30+
*/
31+
export function makeMessage<T>(
32+
message: string,
33+
id = shortid(),
34+
payload?: T
35+
): Message<T> {
36+
return { message, id, payload };
37+
}
38+
39+
/**
40+
* Make response object for given message id
41+
* @param messageId Id of the request message to respond to
42+
* @param payload Payload to respond with
43+
* @returns Response
44+
*/
45+
export function makeResponse<T>(messageId: string, payload: T): Response<T> {
46+
return { id: messageId, payload };
2047
}
2148

2249
/**
2350
* Request data from the parent window and wait for response
2451
* @param request Request message to send to the parent window
25-
* @param response Response message to wait for
2652
* @param timeout Timeout in ms
2753
* @returns Payload of the given type, or undefined
2854
*/
2955
export async function requestParentResponse<T>(
3056
request: string,
31-
response: string,
3257
timeout = 30000
33-
): Promise<T | undefined> {
58+
): Promise<T> {
3459
if (window.opener == null) {
3560
throw new Error('window.opener is null, unable to send request.');
3661
}
3762
return new Promise((resolve, reject) => {
3863
let timeoutId: NodeJS.Timeout;
39-
const listener = (event: MessageEvent<Message<T>>) => {
64+
const id = shortid();
65+
const listener = (event: MessageEvent<Response<T>>) => {
4066
const { data } = event;
4167
log.debug('Received message', data);
42-
if (data?.message !== response) {
43-
log.debug('Ignore received message', data);
68+
if (data?.id !== id) {
69+
log.debug("Ignore message, id doesn't match", data);
4470
return;
4571
}
4672
clearTimeout(timeoutId);
@@ -52,6 +78,6 @@ export async function requestParentResponse<T>(
5278
window.removeEventListener('message', listener);
5379
reject(new TimeoutError('Request timed out'));
5480
}, timeout);
55-
window.opener.postMessage(makeMessage(request), '*');
81+
window.opener.postMessage(makeMessage(request, id), '*');
5682
});
5783
}

0 commit comments

Comments
 (0)