@lightbend/akkaserverless-javascript-sdk
Version:
Akka Serverless JavaScript SDK
140 lines • 6.64 kB
JavaScript
;
/*
* Copyright 2021 Lightbend Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const path = require('path');
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const debug = require('debug')('akkaserverless-view');
// Bind to stdout
debug.log = console.log.bind(console);
const AnySupport = require('./protobuf-any');
const { Metadata } = require('./metadata');
module.exports = class ViewServices {
constructor() {
this.services = {};
}
addService(component, allComponents) {
this.services[component.serviceName] = component;
}
componentType() {
return 'akkaserverless.component.view.Views';
}
register(server) {
// Nothing to register
const includeDirs = [
path.join(__dirname, '..', 'proto'),
path.join(__dirname, '..', 'protoc', 'include'),
path.join(__dirname, '..', '..', 'proto'),
path.join(__dirname, '..', '..', 'protoc', 'include'),
];
const packageDefinition = protoLoader.loadSync(path.join('akkaserverless', 'component', 'view', 'view.proto'), {
includeDirs: includeDirs,
});
const grpcDescriptor = grpc.loadPackageDefinition(packageDefinition);
const viewService = grpcDescriptor.akkaserverless.component.view.Views.service;
server.addService(viewService, {
handle: this.handle.bind(this),
});
}
handle(call) {
const failAndEndCall = function (description) {
// FIXME no failure reporting in protocol and this does not reach the proxy as a failure
/*
call.write({
failure: {
description: description
}
})
*/
call.end();
};
call.on('data', (viewStreamIn) => {
// FIXME: It is currently only implemented to support one request (ReceiveEvent) with one response (Upsert).
// see https://github.com/lightbend/akkaserverless-framework/issues/186
// and https://github.com/lightbend/akkaserverless-framework/issues/187
if (viewStreamIn.receive) {
const receiveEvent = viewStreamIn.receive, service = this.services[receiveEvent.serviceName];
if (service) {
const updateHandler = service.updateHandlers[receiveEvent.commandName];
if (updateHandler) {
try {
const anySupport = new AnySupport(service.root), metadata = new Metadata(receiveEvent.metadata ? receiveEvent.metadata.entries : []), payload = anySupport.deserialize(receiveEvent.payload), existingState = receiveEvent.bySubjectLookupResult
? anySupport.deserialize(receiveEvent.bySubjectLookupResult.value)
: undefined, grpcMethod = service.service.methods[receiveEvent.commandName],
/**
* Context for a view update event.
*
* @interface module:akkaserverless.View.UpdateHandlerContext
* @property {module:akkaserverless.Metadata} metadata for the event
* @property {string} commandName
*/
context = {
viewId: service.viewId,
eventSubject: receiveEvent.metadata['ce-subject'],
metadata: metadata,
commandName: receiveEvent.commandName,
};
const result = updateHandler(payload, existingState, context);
if (result) {
const resultProto = grpcMethod.resolvedResponseType.create(result), resultPayload = AnySupport.serialize(resultProto, false, false);
call.write({
upsert: {
row: {
index: receiveEvent.initialTable,
key: receiveEvent.key,
value: resultPayload,
},
},
});
}
else {
call.write({
upsert: {
row: null,
},
});
}
call.end();
}
catch (err) {
console.error('Error handling event, terminating stream: %o', viewStreamIn);
console.error(err);
failAndEndCall('Fatal error handling event, check user container logs.');
}
}
else {
console.error("No handler defined for commandName: '%s'", receiveEvent.commandName);
failAndEndCall("No handler defined for commandName '" +
receiveEvent.commandName +
"'.");
}
}
else {
console.error("Received event for unknown service: '%s'", viewStreamIn.init.serviceName);
failAndEndCall("Service '" + viewStreamIn.init.serviceName + "' unknown.");
}
}
else {
console.error('Unknown view message received %o', viewStreamIn);
failAndEndCall('Unknown view message received');
}
});
call.on('end', () => {
call.end();
});
}
};
//# sourceMappingURL=view-support.js.map