UNPKG

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
'use strict'; 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;