2020-08-06 14:03:46 -05:00
|
|
|
import Q from "q";
|
|
|
|
import * as _ from "underscore";
|
2021-03-18 20:41:43 -07:00
|
|
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
2020-09-22 12:19:06 -07:00
|
|
|
import { getDataExplorerWindow } from "../Utils/WindowUtils";
|
2021-03-18 20:41:43 -07:00
|
|
|
import * as Constants from "./Constants";
|
2020-08-06 14:03:46 -05:00
|
|
|
|
|
|
|
export interface CachedDataPromise<T> {
|
|
|
|
deferred: Q.Deferred<T>;
|
|
|
|
startTime: Date;
|
|
|
|
id: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
export const RequestMap: Record<string, CachedDataPromise<any>> = {};
|
|
|
|
|
|
|
|
export function handleCachedDataMessage(message: any): void {
|
|
|
|
const messageContent = message && message.message;
|
|
|
|
if (message == null || messageContent == null || messageContent.id == null || !RequestMap[messageContent.id]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const cachedDataPromise = RequestMap[messageContent.id];
|
|
|
|
if (messageContent.error != null) {
|
|
|
|
cachedDataPromise.deferred.reject(messageContent.error);
|
|
|
|
} else {
|
|
|
|
cachedDataPromise.deferred.resolve(JSON.parse(messageContent.data));
|
|
|
|
}
|
|
|
|
runGarbageCollector();
|
|
|
|
}
|
|
|
|
|
|
|
|
export function sendCachedDataMessage<TResponseDataModel>(
|
|
|
|
messageType: MessageTypes,
|
|
|
|
params: Object[],
|
|
|
|
timeoutInMs?: number
|
|
|
|
): Q.Promise<TResponseDataModel> {
|
|
|
|
let cachedDataPromise: CachedDataPromise<TResponseDataModel> = {
|
|
|
|
deferred: Q.defer<TResponseDataModel>(),
|
|
|
|
startTime: new Date(),
|
2021-01-20 09:15:01 -06:00
|
|
|
id: _.uniqueId(),
|
2020-08-06 14:03:46 -05:00
|
|
|
};
|
|
|
|
RequestMap[cachedDataPromise.id] = cachedDataPromise;
|
|
|
|
sendMessage({ type: messageType, params: params, id: cachedDataPromise.id });
|
|
|
|
|
|
|
|
//TODO: Use telemetry to measure optimal time to resolve/reject promises
|
|
|
|
return cachedDataPromise.deferred.promise.timeout(
|
|
|
|
timeoutInMs || Constants.ClientDefaults.requestTimeoutMs,
|
|
|
|
"Timed out while waiting for response from portal"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function sendMessage(data: any): void {
|
2021-04-09 00:22:41 -07:00
|
|
|
_sendMessage({
|
|
|
|
signature: "pcIframe",
|
|
|
|
data: data,
|
|
|
|
});
|
2020-08-06 14:03:46 -05:00
|
|
|
}
|
|
|
|
|
2021-03-18 20:41:43 -07:00
|
|
|
export function sendReadyMessage(): void {
|
2021-04-09 00:22:41 -07:00
|
|
|
_sendMessage({
|
|
|
|
signature: "pcIframe",
|
|
|
|
kind: "ready",
|
|
|
|
data: "ready",
|
|
|
|
});
|
2021-03-18 20:41:43 -07:00
|
|
|
}
|
|
|
|
|
2020-08-06 14:03:46 -05:00
|
|
|
export function canSendMessage(): boolean {
|
|
|
|
return window.parent !== window;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: This is exported just for testing. It should not be.
|
|
|
|
export function runGarbageCollector() {
|
|
|
|
Object.keys(RequestMap).forEach((key: string) => {
|
|
|
|
const promise: Q.Promise<any> = RequestMap[key].deferred.promise;
|
|
|
|
if (promise.isFulfilled() || promise.isRejected()) {
|
|
|
|
delete RequestMap[key];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2021-04-09 00:22:41 -07:00
|
|
|
|
|
|
|
const _sendMessage = (message: any): void => {
|
|
|
|
if (canSendMessage()) {
|
|
|
|
// Portal window can receive messages from only child windows
|
|
|
|
const portalChildWindow = getDataExplorerWindow(window) || window;
|
|
|
|
if (portalChildWindow === window) {
|
|
|
|
// Current window is a child of portal, send message to portal window
|
|
|
|
portalChildWindow.parent.postMessage(message, portalChildWindow.document.referrer || "*");
|
|
|
|
} else {
|
|
|
|
// Current window is not a child of portal, send message to the child window instead (which is data explorer)
|
|
|
|
portalChildWindow.postMessage(message, portalChildWindow.location.origin || "*");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|