atriusmaps-node-sdk
Version:
This project provides an API to Atrius Personal Wayfinder maps within a Node environment. See the README.md for more information
226 lines (221 loc) • 7.66 kB
JavaScript
;
var throttleDebounce = require('throttle-debounce');
var geom = require('../../../src/utils/geom.js');
var observable = require('../../../src/utils/observable.js');
var sdkHeadless = require('./sdkHeadless.js');
function _interopNamespaceDefaultOnly (e) { return Object.freeze({ __proto__: null, default: e }); }
let removePreviousListener = null;
function describeMessageRelation(senderOrigin, iframeOrigin) {
if (senderOrigin === "null") {
return "null-origin";
}
return senderOrigin === iframeOrigin ? "same-origin" : "cross-origin";
}
function logBrowserMessageTelemetry(bus, payload) {
bus.send("appInsights/log", {
name: "browserMessageObserved",
properties: {
command: payload.command,
deploymentHost: window.location.host,
iframeOrigin: payload.iframeOrigin,
messageType: payload.messageType,
relation: describeMessageRelation(payload.senderOrigin, payload.iframeOrigin),
senderOrigin: payload.senderOrigin,
wouldRejectCrossOrigin: !isSameOriginBrowserMessage(payload.senderOrigin, payload.iframeOrigin)
}
});
}
function isSameOriginBrowserMessage(senderOrigin, iframeOrigin) {
return senderOrigin === iframeOrigin;
}
function getBrowserCom(app) {
const clean = (value) => JSON.parse(JSON.stringify(value));
const sendResponse = (payload, clientMsgId) => {
const message = { payload, type: "LL-server", clientMsgId };
try {
window.postMessage(message, "*");
} catch {
window.postMessage(clean(message), "*");
}
};
const sendError = (payload, clientMsgId) => {
window.postMessage({ error: true, payload, type: "LL-server", clientMsgId }, "*");
};
const sendEvent = (event, payload) => {
window.postMessage({ event, payload, type: "LL-server" }, "*");
};
const msgHandler = (event) => {
const data = event.data;
if (!data || data.type !== "LL-client") {
return;
}
const iframeOrigin = window.location.origin;
logBrowserMessageTelemetry(app.bus, {
messageType: "LL-client",
senderOrigin: event.origin,
command: data.payload?.command,
iframeOrigin
});
if (!isSameOriginBrowserMessage(event.origin, iframeOrigin)) {
return;
}
app.bus.get("clientAPI/execute", data.payload).then((result) => sendResponse(result, data.msgId)).catch((error) => {
if (app.config.debug) {
console.error(error);
}
sendError(error.message, data.msgId);
});
};
if (removePreviousListener) {
removePreviousListener();
}
window.addEventListener("message", msgHandler);
removePreviousListener = () => window.removeEventListener("message", msgHandler);
return sendEvent;
}
function getNodeCom(app) {
const eventListener = observable();
app.eventListener = eventListener;
const sendEvent = (event, payload) => eventListener.fire(event, payload);
return sendEvent;
}
function registerCustomTypes(app) {
const types = [
{
name: "latLngOrdLocation",
spec: {
type: "object",
props: [
{ name: "lat", type: "float" },
{ name: "lng", type: "float" },
{ name: "ord", type: "integer" }
]
}
},
{
name: "latLngFloorLocation",
spec: {
type: "object",
props: [
{ name: "lat", type: "float" },
{ name: "lng", type: "float" },
{ name: "floorId", type: "string" }
]
}
},
{
name: "poiIdLocation",
spec: { type: "object", props: [{ name: "poiId", type: "integer", min: 0 }] }
},
{
name: "location",
spec: {
type: "multi",
types: [{ type: "poiIdLocation" }, { type: "latLngOrdLocation" }, { type: "latLngFloorLocation" }]
}
},
{
name: "viewSettings",
spec: {
type: "object",
props: [
{ name: "zoom", type: "float", optional: true },
{ name: "pitch", type: "float", optional: true },
{ name: "bearing", type: "float", optional: true }
]
}
}
];
types.forEach((typeDefinition) => {
app.bus.send("clientAPI/registerCustomType", typeDefinition);
});
}
function registerEvents(app, sendEvent) {
const forwardMapMoveEvent = async (eventName, payload) => {
const { lat, lng, floorId, ordinal, structureId } = await app.bus.get("map/getMapCenter");
sendEvent(eventName, { lat, lng, floorId, ord: ordinal, structureId, ...payload });
};
app.bus.monitor(
"map/userMoveStart",
(payload) => void forwardMapMoveEvent("userMoveStart", payload)
);
app.bus.monitor(
"map/userMoving",
throttleDebounce.throttle(
500,
(payload) => void forwardMapMoveEvent("userMoving", payload)
)
);
app.bus.monitor(
"map/moveEnd",
(payload) => void forwardMapMoveEvent("moveEnd", payload)
);
app.bus.monitor(
"map/floorChanged",
({ structure, floor }) => sendEvent("levelChange", {
floorId: floor?.id ?? null,
floorName: floor?.name ?? null,
ord: floor?.ordinal ?? null,
structureId: structure?.id ?? null,
structureName: structure?.name ?? null
})
);
app.bus.monitor("map/poiClicked", ({ poi }) => sendEvent("poiSelected", poi));
app.bus.monitor("poiDetails/showPoi", ({ poi }) => sendEvent("poiShown", poi));
app.bus.monitor("map/click", async ({ lat, lng, ord }) => {
const structures = await app.bus.get("venueData/getStructures");
const mapviewBBox = await app.bus.get("map/getViewBBox");
const { building: structure, floor } = geom.getStructureAndFloorAtPoint(
structures,
lat,
lng,
ord,
mapviewBBox,
true
);
sendEvent("mapClicked", { lat, lng, ord, building: structure, floor });
});
}
async function create(app, config) {
const sendEvent = app.env.isBrowser ? getBrowserCom(app) : getNodeCom(app);
const init = async () => {
registerCustomTypes(app);
sdkHeadless.headlessCommands.forEach(
(commandDefinition) => app.bus.send("clientAPI/registerCommand", commandDefinition)
);
sdkHeadless.handleHeadless(app);
if (!config.headless) {
await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespaceDefaultOnly(require('../../../_virtual/_empty_module_placeholder.js')); }).then((sdkVisual) => {
sdkVisual.visualCommands.forEach(
(commandDefinition) => app.bus.send("clientAPI/registerCommand", commandDefinition)
);
sdkVisual.handleVisual(app, sendEvent);
});
}
const weReady = async () => {
await app.bus.send("system/readywhenyouare");
app.bus.get("clientAPI/execute", { command: "getCommandJSON" }).then((commandJSON) => sendEvent("ready", { commandJSON }));
if (!config.headless && app.config.uiHide?.sidebar && app.env.isDesktop()) {
app.bus.send("map/changePadding", { padding: { left: 55, right: 55, top: 72, bottom: 22 } });
}
};
if (config.headless) {
Promise.all([
new Promise((resolve) => app.bus.monitor("venueData/navGraphLoaded", resolve)),
new Promise((resolve) => app.bus.monitor("venueData/poiDataLoaded", resolve))
]).then(weReady);
} else {
app.bus.on("map/mapReadyToShow", weReady);
}
app.bus.on(
"sdkServer/sendEvent",
({ eventName, ...props }) => sendEvent(eventName, props)
);
};
registerEvents(app, sendEvent);
return { init };
}
exports.create = create;
exports.describeMessageRelation = describeMessageRelation;
exports.isSameOriginBrowserMessage = isSameOriginBrowserMessage;
exports.logBrowserMessageTelemetry = logBrowserMessageTelemetry;