UNPKG

resolve-runtime

Version:
396 lines (333 loc) 11.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; require("source-map-support/register"); var _http = require("http"); var _express = _interopRequireDefault(require("express")); var _mqttConnection = _interopRequireDefault(require("mqtt-connection")); var _path = _interopRequireDefault(require("path")); var _resolveApiHandlerExpress = _interopRequireDefault(require("resolve-api-handler-express")); var _resolveCommand = _interopRequireDefault(require("resolve-command")); var _resolveEs = _interopRequireDefault(require("resolve-es")); var _resolveQuery = _interopRequireWildcard(require("resolve-query")); var _socket = _interopRequireDefault(require("socket.io")); var _v = _interopRequireDefault(require("uuid/v4")); var _url = _interopRequireDefault(require("url")); var _websocketStream = _interopRequireDefault(require("websocket-stream")); var _ws = require("ws"); var _create_pubsub_manager = _interopRequireDefault(require("./utils/create_pubsub_manager")); var _get_root_based_url = _interopRequireDefault(require("./utils/get_root_based_url")); var _start_express_server = _interopRequireDefault(require("./utils/start_express_server")); var _saga_runner_express = _interopRequireDefault(require("./utils/saga_runner_express")); var _main_handler = _interopRequireDefault(require("./handlers/main_handler")); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } const initEventStore = async ({ storageAdapter: createStorageAdapter, busAdapter: createBusAdapter }, resolve) => { Object.assign(resolve, { eventStore: (0, _resolveEs.default)({ storage: createStorageAdapter(), bus: createBusAdapter() }) }); }; const initExpress = async resolve => { const app = (0, _express.default)(); const server = new _http.Server(app); Object.defineProperties(resolve, { app: { value: app }, server: { value: server } }); }; const getMqttTopic = (appId, { topicName, topicId }) => { return `${appId}/${topicName === '*' ? '+' : topicName}/${topicId === '*' ? '+' : topicId}`; }; const createServerMqttHandler = (pubsubManager, appId, qos) => ws => { const stream = (0, _websocketStream.default)(ws); const client = new _mqttConnection.default(stream); let messageId = 1; const publisher = (topicName, topicId, event) => new Promise((resolve, reject) => { client.publish({ topic: getMqttTopic(appId, { topicName, topicId }), payload: JSON.stringify(event), messageId: messageId++, qos }, error => error ? reject(error) : resolve()); }); client.on('connect', () => { client.connack({ returnCode: 0 }); }); client.on('pingreq', () => client.pingresp()); client.on('subscribe', packet => { try { for (const subscription of packet.subscriptions) { const [, topicName, topicId] = (subscription.topic || subscription).split('/'); pubsubManager.subscribe({ client: publisher, topicName, topicId }); } client.suback({ granted: [packet.qos], messageId: packet.messageId }); } catch (error) { resolveLog('warn', 'MQTT subscription failed', packet, error); } }); client.on('unsubscribe', packet => { try { for (const unsubscription of packet.unsubscriptions) { const [, topicName, topicId] = (unsubscription.topic || unsubscription).split('/'); pubsubManager.unsubscribe({ client: publisher, topicName, topicId }); } client.unsuback({ granted: [packet.qos], messageId: packet.messageId }); } catch (error) { resolveLog('warn', 'MQTT unsubscription failed', packet, error); } }); const dispose = () => { pubsubManager.unsubscribeClient(publisher); client.destroy(); }; client.on('close', dispose); client.on('error', dispose); client.on('disconnect', dispose); }; const sanitizeWildcardTopic = topic => topic === '*' ? '+' : topic; const createServerSocketIOHandler = pubsubManager => socket => { const publisher = (topicName, topicId, event) => new Promise(resolve => { socket.emit('message', JSON.stringify({ topicName, topicId, payload: event }), resolve); }); socket.on('subscribe', packet => { const subscriptions = JSON.parse(packet); for (const _ref of subscriptions) { const { topicName, topicId } = _ref; pubsubManager.subscribe({ client: publisher, topicName: sanitizeWildcardTopic(topicName), topicId: sanitizeWildcardTopic(topicId) }); } }); socket.on('unsubscribe', packet => { const unsubscriptions = JSON.parse(packet); for (const _ref2 of unsubscriptions) { const { topicName, topicId } = _ref2; pubsubManager.unsubscribe({ client: publisher, topicName: sanitizeWildcardTopic(topicName), topicId: sanitizeWildcardTopic(topicId) }); } }); const dispose = () => { pubsubManager.unsubscribeClient(publisher); }; socket.on('error', dispose); socket.on('disconnect', dispose); }; const initSubscribeAdapter = async resolve => { const pubsubManager = (0, _create_pubsub_manager.default)(); const appId = resolve.applicationName; const qos = 1; try { const handler = createServerSocketIOHandler(pubsubManager); const socketIOServer = (0, _socket.default)(resolve.server, { path: (0, _get_root_based_url.default)(resolve.rootPath, '/api/socket-io/'), serveClient: false, transports: ['polling'] }); socketIOServer.on('connection', handler); } catch (error) { resolveLog('warn', 'Cannot init Socket.IO server socket: ', error); } try { const socketMqttServer = new _ws.Server({ server: resolve.server, path: (0, _get_root_based_url.default)(resolve.rootPath, '/api/mqtt') }); const handler = createServerMqttHandler(pubsubManager, appId, qos); socketMqttServer.on('connection', handler); } catch (error) { resolveLog('warn', 'Cannot init MQTT server socket: ', error); } Object.defineProperties(resolve, { pubsubManager: { value: pubsubManager } }); }; const initHMR = async resolve => { const HMR_ID = (0, _v.default)(); const HMRSocketHandler = socket => { socket.emit('hotModuleReload', HMR_ID); }; const HMRSocketServer = (0, _socket.default)(resolve.server, { path: (0, _get_root_based_url.default)(resolve.rootPath, '/api/hmr/'), serveClient: false }); HMRSocketServer.on('connection', HMRSocketHandler); }; const emptyWorker = async () => { throw new Error('Guard exception: worker should not be invoked on non-cloud environment'); }; const initDomain = async ({ snapshotAdapter: createSnapshotAdapter, readModelAdapters: readModelAdaptersCreators }, resolve) => { const { eventStore, aggregates, readModels, viewModels } = resolve; const snapshotAdapter = createSnapshotAdapter(); const readModelAdapters = {}; for (const _ref3 of readModelAdaptersCreators) { const { name, factory } = _ref3; readModelAdapters[name] = factory(); } const executeCommand = (0, _resolveCommand.default)({ eventStore, aggregates, snapshotAdapter }); const executeQuery = (0, _resolveQuery.default)({ eventStore, viewModels, readModels, readModelAdapters, snapshotAdapter }); Object.assign(resolve, { executeCommand, executeQuery }); Object.defineProperties(resolve, { readModelAdapters: { value: readModelAdapters }, snapshotAdapter: { value: snapshotAdapter } }); }; const initEventLoop = async resolve => { const executors = resolve.executeQuery.getExecutors(_resolveQuery.constants.modelTypes.readModel); const unsubscribe = await resolve.eventStore.loadEvents({ skipStorage: true }, async event => { resolve.pubsubManager.dispatch({ topicName: event.type, topicId: event.aggregateId, event }); const applicationPromises = []; for (const executor of executors) { applicationPromises.push(executor.updateByEvents([event])); } await Promise.all(applicationPromises); }); Object.defineProperty(resolve, 'unsubscribe', { value: unsubscribe }); }; const getSubscribeAdapterOptions = async (resolve, origin, adapterName) => { if (adapterName !== 'mqtt' && adapterName !== 'socket.io') { return null; } const { protocol, hostname, port } = _url.default.parse(origin); const isMqtt = adapterName === 'mqtt'; const isSecure = /^https/.test(protocol); const targetProtocol = ['http', 'https', 'ws', 'wss'][isMqtt * 2 + isSecure]; const targetPath = isMqtt ? '/api/mqtt' : '/api/socket-io/'; const targetPort = port == null ? [80, 443][+isSecure] : port; const url = `${targetProtocol}://${hostname}:${targetPort}${(0, _get_root_based_url.default)(resolve.rootPath, targetPath)}`; return { appId: resolve.applicationName, url }; }; const localEntry = async ({ assemblies, constants, domain, redux, routes }) => { try { const resolve = _objectSpread({ aggregateActions: assemblies.aggregateActions, seedClientEnvs: assemblies.seedClientEnvs }, constants, domain, { redux, routes }); resolve.getSubscribeAdapterOptions = getSubscribeAdapterOptions.bind(null, resolve); await initEventStore(assemblies, resolve); await initExpress(resolve); await initSubscribeAdapter(resolve); await initHMR(resolve); await initDomain(assemblies, resolve); await initEventLoop(resolve); const getCustomParameters = async () => ({ resolve }); const executor = (0, _resolveApiHandlerExpress.default)(_main_handler.default, getCustomParameters); resolve.app.use((0, _get_root_based_url.default)(resolve.rootPath, `/${resolve.staticPath}`), _express.default.static(_path.default.join(process.cwd(), resolve.distDir, './client'))); resolve.app.use(executor); await (0, _saga_runner_express.default)(resolve, assemblies.sagas); await (0, _start_express_server.default)(resolve); resolveLog('debug', 'Local entry point cold start success', resolve); return emptyWorker; } catch (error) { resolveLog('error', 'Local entry point cold start failure', error); } }; var _default = localEntry; exports.default = _default; //# sourceMappingURL=local_entry.js.map