1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const stringify = require("json-stringify-safe");
|
4 | const _ = require("lodash");
|
5 | const ApolloGraphClient_1 = require("../graph/ApolloGraphClient");
|
6 | const HandlerResult_1 = require("../HandlerResult");
|
7 | const NodeConfigSecretResolver_1 = require("../internal/env/NodeConfigSecretResolver");
|
8 | const metadata_1 = require("../internal/metadata/metadata");
|
9 | const metadataReading_1 = require("../internal/metadata/metadataReading");
|
10 | const parameterPopulation_1 = require("../internal/parameterPopulation");
|
11 | const logger_1 = require("../internal/util/logger");
|
12 | const string_1 = require("../internal/util/string");
|
13 | const SmartParameters_1 = require("../SmartParameters");
|
14 | const MetadataProcessor_1 = require("../spi/env/MetadataProcessor");
|
15 | const constructionUtils_1 = require("../util/constructionUtils");
|
16 | const AbstractAutomationServer_1 = require("./AbstractAutomationServer");
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | class BuildableAutomationServer extends AbstractAutomationServer_1.AbstractAutomationServer {
|
22 | constructor(opts) {
|
23 | super();
|
24 | this.opts = opts;
|
25 | this.commandHandlers = [];
|
26 | this.eventHandlers = [];
|
27 | this.ingesters = [];
|
28 | this.secretResolver = new NodeConfigSecretResolver_1.NodeConfigSecretResolver();
|
29 | this.metadataProcessor = new MetadataProcessor_1.PassThroughMetadataProcessor();
|
30 | if (opts.secretResolver) {
|
31 | this.secretResolver = opts.secretResolver;
|
32 | }
|
33 | if (opts.metadataProcessor) {
|
34 | this.metadataProcessor = opts.metadataProcessor;
|
35 | }
|
36 | if (opts.endpoints && opts.endpoints.graphql && opts.workspaceIds && opts.workspaceIds.length > 0 && opts.apiKey) {
|
37 | this.graphClient = new ApolloGraphClient_1.ApolloGraphClient(`${opts.endpoints.graphql}/${opts.workspaceIds[0]}`, { Authorization: `Bearer ${opts.apiKey}` });
|
38 | }
|
39 | }
|
40 | registerCommandHandler(chm) {
|
41 | const factory = constructionUtils_1.toFactory(chm);
|
42 | const instanceToInspect = factory();
|
43 | if (instanceToInspect) {
|
44 | const md = metadataReading_1.metadataFromInstance(instanceToInspect);
|
45 | if (!md) {
|
46 | throw new Error(`Cannot get metadata from handler '${stringify(instanceToInspect)}'`);
|
47 | }
|
48 | this.commandHandlers.push({
|
49 | metadata: this.metadataProcessor.process(md, this.opts),
|
50 | invoke: (i, ctx) => {
|
51 | const newHandler = factory();
|
52 | const params = !!newHandler.freshParametersInstance ? newHandler.freshParametersInstance() : newHandler;
|
53 | return this.invokeCommandHandlerWithFreshParametersInstance(newHandler, md, params, i, ctx);
|
54 | },
|
55 | });
|
56 | }
|
57 | return this;
|
58 | }
|
59 | fromCommandHandler(hc) {
|
60 | const md = metadata_1.isCommandHandlerMetadata(hc) ? hc : metadataReading_1.metadataFromInstance(hc);
|
61 | this.commandHandlers.push({
|
62 | metadata: this.metadataProcessor.process(md, this.opts),
|
63 | invoke: (i, ctx) => {
|
64 | const freshParams = !!hc.freshParametersInstance ? hc.freshParametersInstance() : hc;
|
65 | return this.invokeCommandHandlerWithFreshParametersInstance(hc, md, freshParams, i, ctx);
|
66 | },
|
67 | });
|
68 | return this;
|
69 | }
|
70 | registerEventHandler(maker) {
|
71 | const factory = constructionUtils_1.toFactory(maker);
|
72 | const instanceToInspect = factory();
|
73 | if (instanceToInspect) {
|
74 | const md = metadataReading_1.metadataFromInstance(instanceToInspect);
|
75 | if (!md) {
|
76 | throw new Error(`Cannot get metadata from event handler '${stringify(instanceToInspect)}'`);
|
77 | }
|
78 | this.eventHandlers.push({
|
79 | metadata: this.metadataProcessor.process(md, this.opts),
|
80 | invoke: (e, ctx) => this.invokeFreshEventHandlerInstance(factory(), md, e, ctx),
|
81 | });
|
82 | }
|
83 | return this;
|
84 | }
|
85 | registerIngester(ingester) {
|
86 | this.ingesters.push(ingester);
|
87 | return this;
|
88 | }
|
89 | invokeCommandHandler(invocation, metadata, ctx) {
|
90 | const handler = this.commandHandlers.find(a => a.metadata.name === invocation.name);
|
91 | logger_1.logger.info("Invoking command handler '%s'", metadata.name);
|
92 | return handler.invoke(invocation, ctx);
|
93 | }
|
94 | invokeEventHandler(e, metadata, ctx) {
|
95 | const handler = this.eventHandlers.find(a => a.metadata.name === metadata.name);
|
96 | logger_1.logger.info("Invoking event handler '%s'", metadata.name);
|
97 | return handler.invoke(e, ctx);
|
98 | }
|
99 | |
100 |
|
101 |
|
102 | invokeCommandHandlerWithFreshParametersInstance(h, md, params, invocation, ctx) {
|
103 | parameterPopulation_1.populateParameters(params, md, invocation.args);
|
104 | parameterPopulation_1.populateValues(params, md, this.opts);
|
105 | this.populateMappedParameters(params, md, invocation);
|
106 | this.populateSecrets(params, md, invocation.secrets);
|
107 | const bindAndValidate = SmartParameters_1.isSmartParameters(params) ?
|
108 | Promise.resolve(params.bindAndValidate()) :
|
109 | Promise.resolve();
|
110 | return bindAndValidate
|
111 | .then(vr => {
|
112 | if (SmartParameters_1.isValidationError(vr)) {
|
113 | return Promise.reject(`Validation failure invoking command handler '${md.name}': [${vr.message}]`);
|
114 | }
|
115 | const handlerResult = h.handle(this.enrichContext(ctx), params);
|
116 | if (!handlerResult) {
|
117 | return HandlerResult_1.SuccessPromise;
|
118 | }
|
119 | return handlerResult
|
120 | .then(result => {
|
121 | if (result) {
|
122 | return result;
|
123 | }
|
124 | else {
|
125 | return HandlerResult_1.SuccessPromise;
|
126 | }
|
127 | });
|
128 | });
|
129 | }
|
130 | invokeFreshEventHandlerInstance(h, metadata, e, ctx) {
|
131 | this.populateSecrets(h, metadata, e.secrets);
|
132 | parameterPopulation_1.populateValues(h, metadata, this.opts);
|
133 | const handlerResult = h.handle(e, this.enrichContext(ctx), h);
|
134 | if (!handlerResult) {
|
135 | return HandlerResult_1.SuccessPromise;
|
136 | }
|
137 | return handlerResult
|
138 | .then(result => {
|
139 | if (result) {
|
140 | return result;
|
141 | }
|
142 | else {
|
143 | return HandlerResult_1.SuccessPromise;
|
144 | }
|
145 | });
|
146 | }
|
147 | enrichContext(ctx) {
|
148 | ctx.graphClient = ctx.graphClient || this.graphClient;
|
149 | return ctx;
|
150 | }
|
151 | populateMappedParameters(h, metadata, invocation) {
|
152 |
|
153 | class InvocationSecretResolver {
|
154 | constructor(mp) {
|
155 | this.mp = mp;
|
156 | }
|
157 | resolve(key) {
|
158 | const value = this.mp.find(a => a.name === key);
|
159 | if (value) {
|
160 | return String(value.value);
|
161 | }
|
162 | throw new Error(`Cannot resolve mapped parameter '${key}'`);
|
163 | }
|
164 | }
|
165 |
|
166 |
|
167 |
|
168 |
|
169 | const mrResolver = invocation.mappedParameters ?
|
170 | new InvocationSecretResolver(invocation.mappedParameters) :
|
171 | this.secretResolver;
|
172 |
|
173 | const mappedParameters = metadata.mapped_parameters || [];
|
174 | const invMps = invocation.mappedParameters || [];
|
175 | mappedParameters.forEach(mp => {
|
176 | if (invMps.some(im => im.name === mp.name) || mp.required) {
|
177 | _.update(h, mp.name, () => mrResolver.resolve(mp.name));
|
178 | }
|
179 | });
|
180 | }
|
181 | populateSecrets(h, metadata, invocationSecrets) {
|
182 |
|
183 | class InvocationSecretResolver {
|
184 | constructor(sec) {
|
185 | this.sec = sec;
|
186 | }
|
187 | resolve(key) {
|
188 | const value = this.sec.find(a => a.uri === key);
|
189 | if (value) {
|
190 | return String(value.value);
|
191 | }
|
192 | throw new Error(`Cannot resolve secret '${key}'`);
|
193 | }
|
194 | }
|
195 | const secretResolver = invocationSecrets ? new InvocationSecretResolver(invocationSecrets) :
|
196 | this.secretResolver;
|
197 |
|
198 | const secrets = metadata.secrets || [];
|
199 | secrets.forEach(s => {
|
200 | _.update(h, s.name, () => secretResolver.resolve(s.uri));
|
201 | });
|
202 | }
|
203 | get automations() {
|
204 | return {
|
205 | name: this.opts.name,
|
206 | version: this.opts.version,
|
207 | policy: this.opts.policy,
|
208 | team_ids: this.opts.workspaceIds,
|
209 | groups: string_1.toStringArray(this.opts.groups),
|
210 | keywords: this.opts.keywords,
|
211 | commands: this.commandHandlers.map(e => e.metadata),
|
212 | events: this.eventHandlers.map(e => e.metadata),
|
213 | ingesters: this.ingesters,
|
214 | };
|
215 | }
|
216 | }
|
217 | exports.BuildableAutomationServer = BuildableAutomationServer;
|
218 |
|
\ | No newline at end of file |