Add first basic code for external hooks

This commit is contained in:
Jan Oberhauser 2020-05-04 08:56:01 +02:00
parent 582ff76799
commit a380a9a394
7 changed files with 126 additions and 0 deletions

View file

@ -12,6 +12,7 @@ import {
ActiveWorkflowRunner,
CredentialTypes,
Db,
ExternalHooks,
GenericHelpers,
LoadNodesAndCredentials,
NodeTypes,
@ -108,6 +109,12 @@ export class Start extends Command {
const loadNodesAndCredentials = LoadNodesAndCredentials();
await loadNodesAndCredentials.init();
// Load all external hooks
const externalHooks = ExternalHooks();
await externalHooks.init();
// await externalHooks.run('credentials.new');
// Add the found types to an instance other parts of the application can use
const nodeTypes = NodeTypes();
await nodeTypes.init(loadNodesAndCredentials.nodeTypes);

View file

@ -252,6 +252,13 @@ const config = convict({
},
},
externalHookFiles: {
doc: 'Files containing external hooks',
format: String,
default: '',
env: 'EXTERNAL_HOOK_FILES'
},
nodes: {
exclude: {
doc: 'Nodes not to load',

View file

@ -0,0 +1,89 @@
import {
Db,
IDatabaseCollections,
IExternalHooks,
} from "./";
import * as config from '../config';
// import {
// access as fsAccess,
// readdir as fsReaddir,
// readFile as fsReadFile,
// stat as fsStat,
// } from 'fs';
// TODO: Give different name
interface IHookData {
DbCollections: IDatabaseCollections;
}
// export EXTERNAL_HOOK_FILES=/data/packages/cli/dist/src/externalHooksTemp/test-hooks.js
class ExternalHooksClass implements IExternalHooks {
externalHooks: {
[key: string]: Array<() => {}>
} = {};
async init(): Promise<void> {
console.log('ExternalHooks.init');
const externalHookFiles = config.get('externalHookFiles').split(',');
console.log('externalHookFiles');
console.log(externalHookFiles);
for (let hookFilePath of externalHookFiles) {
hookFilePath = hookFilePath.trim();
if (hookFilePath !== '') {
console.log(' --- load: ' + hookFilePath);
const hookFile = require(hookFilePath);
for (const resource of Object.keys(hookFile)) {
// if (this.externalHooks[resource] === undefined) {
// this.externalHooks[resource] = {};
// }
for (const operation of Object.keys(hookFile[resource])) {
const hookString = `${resource}.${operation}`;
if (this.externalHooks[hookString] === undefined) {
this.externalHooks[hookString] = [];
}
this.externalHooks[hookString].push.apply(this.externalHooks[hookString], hookFile[resource][operation]);
}
}
}
}
}
async run(hookName: string): Promise<void> {
console.log('RUN NOW: ' + hookName);
const hookData: IHookData = {
DbCollections: Db.collections,
};
if (this.externalHooks[hookName] === undefined) {
return;
}
for(const externalHookFunction of this.externalHooks[hookName]) {
externalHookFunction.call(hookData);
}
}
}
let externalHooksInstance: ExternalHooksClass | undefined;
export function ExternalHooks(): ExternalHooksClass {
if (externalHooksInstance === undefined) {
externalHooksInstance = new ExternalHooksClass();
}
return externalHooksInstance;
}

View file

@ -188,6 +188,11 @@ export interface IExecutingWorkflowData {
workflowExecution?: PCancelable<IRun>;
}
export interface IExternalHooks {
init(): Promise<void>;
run(hookName: string): Promise<void>;
}
export interface IN8nConfig {
database: IN8nConfigDatabase;
endpoints: IN8nConfigEndpoints;

View file

@ -19,6 +19,7 @@ import {
ActiveWorkflowRunner,
CredentialTypes,
Db,
ExternalHooks,
IActivationError,
ICustomRequest,
ICredentialsDb,
@ -33,6 +34,7 @@ import {
IExecutionsListResponse,
IExecutionsStopData,
IExecutionsSummary,
IExternalHooks,
IN8nUISettings,
IPackageVersions,
IWorkflowBase,
@ -93,6 +95,7 @@ class App {
testWebhooks: TestWebhooks.TestWebhooks;
endpointWebhook: string;
endpointWebhookTest: string;
externalHooks: IExternalHooks;
saveDataErrorExecution: string;
saveDataSuccessExecution: string;
saveManualExecutions: boolean;
@ -124,6 +127,8 @@ class App {
this.protocol = config.get('protocol');
this.sslKey = config.get('ssl_key');
this.sslCert = config.get('ssl_cert');
this.externalHooks = ExternalHooks();
}
@ -689,6 +694,8 @@ class App {
throw new ResponseHelper.ResponseError(`Credentials with the same type and name exist already.`, undefined, 400);
}
await this.externalHooks.run('credentials.new');
// Encrypt the data
const credentials = new Credentials(incomingData.name, incomingData.type, incomingData.nodesAccess);
credentials.setData(incomingData.data, encryptionKey);

View file

@ -0,0 +1,10 @@
export = {
credentials: {
new: [
() => {
// Here any additional code can run or the creation blocked
throw new Error('No additional credentials can be created.');
},
],
},
};

View file

@ -1,4 +1,5 @@
export * from './CredentialTypes';
export * from './ExternalHooks';
export * from './Interfaces';
export * from './LoadNodesAndCredentials';
export * from './NodeTypes';