resolve-runtime
Version:
This package create server with resolve.
396 lines (333 loc) • 11.8 kB
JavaScript
;
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