resolve-runtime
Version:
This package create server with resolve.
256 lines (213 loc) • 9.03 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
require("source-map-support/register");
var _iotdata = _interopRequireDefault(require("aws-sdk/clients/iotdata"));
var _dynamodb = require("aws-sdk/clients/dynamodb");
var _awsSignatureV = _interopRequireDefault(require("aws-signature-v4"));
var _sts = _interopRequireDefault(require("aws-sdk/clients/sts"));
var _lambda = _interopRequireDefault(require("aws-sdk/clients/lambda"));
var _resolveApiHandlerAwslambda = _interopRequireDefault(require("resolve-api-handler-awslambda"));
var _resolveCommand = _interopRequireDefault(require("resolve-command"));
var _resolveEs = _interopRequireDefault(require("resolve-es"));
var _resolveQuery = _interopRequireWildcard(require("resolve-query"));
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 invokeLambdaSelf = async event => {
const lambda = new _lambda.default({
apiVersion: '2015-03-31'
});
const invokeParams = {
FunctionName: process.env.AWS_LAMBDA_FUNCTION_NAME,
InvocationType: 'Event',
Payload: JSON.stringify(event),
LogType: 'None'
};
return await new Promise((resolve, reject) => lambda.invoke(invokeParams, (err, data) => !err ? resolve(data) : reject(err)));
};
const initResolve = async ({
snapshotAdapter: createSnapshotAdapter,
storageAdapter: createStorageAdapter,
readModelAdapters: readModelAdaptersCreators
}, resolve) => {
const storageAdapter = createStorageAdapter();
const eventStore = (0, _resolveEs.default)({
storage: storageAdapter
});
const {
aggregates,
readModels,
viewModels
} = resolve;
const snapshotAdapter = createSnapshotAdapter();
const readModelAdapters = {};
for (const _ref of readModelAdaptersCreators) {
const {
name,
factory
} = _ref;
readModelAdapters[name] = factory();
}
const executeCommand = (0, _resolveCommand.default)({
eventStore,
aggregates,
snapshotAdapter
});
if (resolve.activeDemandSet == null) {
resolve.__proto__.activeDemandSet = new Set();
}
const doUpdateRequest = async (pool, readModelName, readOptions) => {
const executor = pool.getExecutor(pool, readModelName);
Promise.resolve().then(() => executor.read(readOptions)).catch(error => error).then(() => invokeLambdaSelf({
Records: []
})).catch(error => {
resolveLog('error', 'Update lambda invocation error', error);
});
if (!resolve.activeDemandSet.has(readModelName)) {
// Delay initial read-model on-demand request to enforce awaiting tables creation in common
// cases for better usability, but will be evenntually consistent anyway, even no timeout
await new Promise(resolve => setTimeout(resolve, 2000));
resolve.activeDemandSet.add(readModelName);
}
};
const executeQuery = (0, _resolveQuery.default)({
eventStore,
viewModels,
readModels,
readModelAdapters,
snapshotAdapter,
doUpdateRequest
});
Object.assign(resolve, {
executeCommand,
executeQuery,
eventStore
});
Object.defineProperties(resolve, {
readModelAdapters: {
value: readModelAdapters
},
snapshotAdapter: {
value: snapshotAdapter
},
storageAdapter: {
value: storageAdapter
}
});
};
const disposeResolve = async resolve => {
await resolve.storageAdapter.dispose();
await resolve.snapshotAdapter.dispose();
for (const name of Object.keys(resolve.readModelAdapters)) {
await resolve.readModelAdapters[name].dispose();
}
};
const getSubscribeAdapterOptions = async ({
sts
}) => {
const {
DEPLOYMENT_ID,
IOT_ENDPOINT_HOST,
IOT_ROLE_ARN
} = process.env;
const data = await sts.assumeRole({
RoleArn: IOT_ROLE_ARN,
RoleSessionName: `role-session-${DEPLOYMENT_ID}`,
DurationSeconds: 3600
}).promise();
const url = _awsSignatureV.default.createPresignedURL('GET', IOT_ENDPOINT_HOST, '/mqtt', 'iotdevicegateway', '', {
key: data.Credentials.AccessKeyId,
secret: data.Credentials.SecretAccessKey,
sessionToken: data.Credentials.SessionToken,
protocol: 'wss'
});
return {
appId: DEPLOYMENT_ID,
url
};
};
const lambdaWorker = async (assemblies, resolveBase, lambdaEvent, lambdaContext) => {
resolveLog('debug', 'Lambda handler has received event', lambdaEvent);
lambdaContext.callbackWaitsForEmptyEventLoop = false;
let executorResult = null;
const resolve = Object.create(resolveBase);
try {
await initResolve(assemblies, resolve);
resolveLog('debug', 'Lambda handler has initialized resolve instance', resolve); // API gateway event
if (lambdaEvent.headers != null && lambdaEvent.httpMethod != null) {
resolveLog('debug', 'Lambda handler classified event as API gateway', lambdaEvent.httpMethod, lambdaEvent.headers);
const getCustomParameters = async () => ({
resolve
});
const executor = (0, _resolveApiHandlerAwslambda.default)(_main_handler.default, getCustomParameters);
executorResult = await executor(lambdaEvent, lambdaContext);
} // DynamoDB trigger event
// AWS DynamoDB streams guarantees that changesets from one table partition will
// be delivered strictly into one lambda instance, i.e. following code works in
// single-thread mode for one event storage - see https://amzn.to/2LkKXAV
else if (lambdaEvent.Records != null) {
resolveLog('debug', 'Lambda handler classified event as Dynamo stream', lambdaEvent.Records);
const applicationPromises = [];
const events = lambdaEvent.Records.map(record => _dynamodb.Converter.unmarshall(record.dynamodb.NewImage)); // TODO. Refactoring MQTT publish event
for (const event of events) {
const eventDescriptor = {
topic: `${process.env.DEPLOYMENT_ID}/${event.type}/${event.aggregateId}`,
payload: JSON.stringify(event),
qos: 1
};
applicationPromises.push(resolve.mqtt.publish(eventDescriptor).promise().then(() => {
resolveLog('info', 'Lambda pushed event into MQTT successfully', eventDescriptor);
}).catch(error => {
resolveLog('warn', 'Lambda can not publish event into MQTT', eventDescriptor, error);
}));
}
const executors = resolve.executeQuery.getExecutors(_resolveQuery.constants.modelTypes.readModel);
for (const executor of executors) {
applicationPromises.push(executor.updateByEvents(events));
}
await Promise.all(applicationPromises);
executorResult = true;
}
} finally {
await disposeResolve(resolve);
resolveLog('debug', 'Lambda handler has disposed resolve instance');
}
if (executorResult == null) {
throw new Error(`Lambda cannot be invoked with event: ${lambdaEvent}`);
}
return executorResult;
};
const cloudEntry = async ({
assemblies,
constants,
domain,
redux,
routes
}) => {
try {
const resolve = _objectSpread({
aggregateActions: assemblies.aggregateActions,
seedClientEnvs: assemblies.seedClientEnvs,
sts: new _sts.default(),
mqtt: new _iotdata.default({
endpoint: process.env.IOT_ENDPOINT_HOST
})
}, constants, domain, {
redux,
routes
});
resolve.getSubscribeAdapterOptions = getSubscribeAdapterOptions.bind(null, resolve);
resolveLog('debug', 'Cloud entry point cold start success', resolve);
return lambdaWorker.bind(null, assemblies, resolve);
} catch (error) {
resolveLog('error', 'Cloud entry point cold start failure', error);
}
};
var _default = cloudEntry;
exports.default = _default;
//# sourceMappingURL=cloud_entry.js.map
;