2020-08-06 14:03:46 -05:00
|
|
|
import { MessageTypes } from "../Contracts/ExplorerContracts";
|
|
|
|
import Q from "q";
|
|
|
|
import * as _ from "underscore";
|
|
|
|
import * as Constants from "./Constants";
|
2020-09-22 12:19:06 -07:00
|
|
|
import { getDataExplorerWindow } from "../Utils/WindowUtils";
|
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 {
|
|
|
|
if (canSendMessage()) {
|
2020-09-25 14:49:11 -07:00
|
|
|
// We try to find data explorer window first, then fallback to current window
|
|
|
|
const portalChildWindow = getDataExplorerWindow(window) || window;
|
|
|
|
portalChildWindow.parent.postMessage(
|
|
|
|
{
|
|
|
|
signature: "pcIframe",
|
2021-01-20 09:15:01 -06:00
|
|
|
data: data,
|
2020-09-25 14:49:11 -07:00
|
|
|
},
|
|
|
|
portalChildWindow.document.referrer
|
|
|
|
);
|
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];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|