2019-06-23 03:35:23 -07:00
|
|
|
import {
|
|
|
|
IWebhookData,
|
|
|
|
WebhookHttpMethod,
|
2020-01-22 15:06:43 -08:00
|
|
|
Workflow,
|
2019-06-23 03:35:23 -07:00
|
|
|
WorkflowExecuteMode,
|
|
|
|
} from 'n8n-workflow';
|
|
|
|
|
|
|
|
import {
|
|
|
|
NodeExecuteFunctions,
|
|
|
|
} from './';
|
|
|
|
|
|
|
|
|
|
|
|
export class ActiveWebhooks {
|
|
|
|
private workflowWebhooks: {
|
|
|
|
[key: string]: IWebhookData[];
|
|
|
|
} = {};
|
|
|
|
|
|
|
|
private webhookUrls: {
|
|
|
|
[key: string]: IWebhookData;
|
|
|
|
} = {};
|
|
|
|
|
|
|
|
testWebhooks = false;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Adds a new webhook
|
|
|
|
*
|
|
|
|
* @param {IWebhookData} webhookData
|
|
|
|
* @param {WorkflowExecuteMode} mode
|
|
|
|
* @returns {Promise<void>}
|
|
|
|
* @memberof ActiveWebhooks
|
|
|
|
*/
|
2020-01-22 15:06:43 -08:00
|
|
|
async add(workflow: Workflow, webhookData: IWebhookData, mode: WorkflowExecuteMode): Promise<void> {
|
|
|
|
if (workflow.id === undefined) {
|
2019-06-23 03:35:23 -07:00
|
|
|
throw new Error('Webhooks can only be added for saved workflows as an id is needed!');
|
|
|
|
}
|
|
|
|
|
2020-05-30 16:03:58 -07:00
|
|
|
const webhookKey = this.getWebhookKey(webhookData.httpMethod, webhookData.path);
|
|
|
|
|
|
|
|
//check that there is not a webhook already registed with that path/method
|
|
|
|
if (this.webhookUrls[webhookKey] !== undefined) {
|
|
|
|
throw new Error('There is test wenhook registered on that path');
|
|
|
|
}
|
|
|
|
|
2020-01-22 15:06:43 -08:00
|
|
|
if (this.workflowWebhooks[webhookData.workflowId] === undefined) {
|
|
|
|
this.workflowWebhooks[webhookData.workflowId] = [];
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make the webhook available directly because sometimes to create it successfully
|
|
|
|
// it gets called
|
2020-05-30 16:03:58 -07:00
|
|
|
this.webhookUrls[webhookKey] = webhookData;
|
2019-06-23 03:35:23 -07:00
|
|
|
|
2020-01-22 15:06:43 -08:00
|
|
|
const webhookExists = await workflow.runWebhookMethod('checkExists', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
2019-06-23 03:35:23 -07:00
|
|
|
if (webhookExists === false) {
|
|
|
|
// If webhook does not exist yet create it
|
2020-01-22 15:06:43 -08:00
|
|
|
await workflow.runWebhookMethod('create', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
2020-01-22 15:06:43 -08:00
|
|
|
this.workflowWebhooks[webhookData.workflowId].push(webhookData);
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns webhookData if a webhook with matches is currently registered
|
|
|
|
*
|
|
|
|
* @param {WebhookHttpMethod} httpMethod
|
|
|
|
* @param {string} path
|
|
|
|
* @returns {(IWebhookData | undefined)}
|
|
|
|
* @memberof ActiveWebhooks
|
|
|
|
*/
|
|
|
|
get(httpMethod: WebhookHttpMethod, path: string): IWebhookData | undefined {
|
|
|
|
const webhookKey = this.getWebhookKey(httpMethod, path);
|
|
|
|
if (this.webhookUrls[webhookKey] === undefined) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
|
|
|
return this.webhookUrls[webhookKey];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-22 15:06:43 -08:00
|
|
|
/**
|
|
|
|
* Returns the ids of all the workflows which have active webhooks
|
|
|
|
*
|
|
|
|
* @returns {string[]}
|
|
|
|
* @memberof ActiveWebhooks
|
|
|
|
*/
|
|
|
|
getWorkflowIds(): string[] {
|
|
|
|
return Object.keys(this.workflowWebhooks);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
/**
|
|
|
|
* Returns key to uniquely identify a webhook
|
|
|
|
*
|
|
|
|
* @param {WebhookHttpMethod} httpMethod
|
|
|
|
* @param {string} path
|
|
|
|
* @returns {string}
|
|
|
|
* @memberof ActiveWebhooks
|
|
|
|
*/
|
|
|
|
getWebhookKey(httpMethod: WebhookHttpMethod, path: string): string {
|
|
|
|
return `${httpMethod}|${path}`;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Removes all webhooks of a workflow
|
|
|
|
*
|
2020-01-22 15:06:43 -08:00
|
|
|
* @param {Workflow} workflow
|
2019-06-23 03:35:23 -07:00
|
|
|
* @returns {boolean}
|
|
|
|
* @memberof ActiveWebhooks
|
|
|
|
*/
|
2020-01-22 15:06:43 -08:00
|
|
|
async removeWorkflow(workflow: Workflow): Promise<boolean> {
|
|
|
|
const workflowId = workflow.id!.toString();
|
|
|
|
|
2019-06-23 03:35:23 -07:00
|
|
|
if (this.workflowWebhooks[workflowId] === undefined) {
|
|
|
|
// If it did not exist then there is nothing to remove
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const webhooks = this.workflowWebhooks[workflowId];
|
|
|
|
|
|
|
|
const mode = 'internal';
|
|
|
|
|
|
|
|
// Go through all the registered webhooks of the workflow and remove them
|
|
|
|
for (const webhookData of webhooks) {
|
2020-01-22 15:06:43 -08:00
|
|
|
await workflow.runWebhookMethod('delete', webhookData, NodeExecuteFunctions, mode, this.testWebhooks);
|
2019-06-23 03:35:23 -07:00
|
|
|
|
|
|
|
delete this.webhookUrls[this.getWebhookKey(webhookData.httpMethod, webhookData.path)];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove also the workflow-webhook entry
|
|
|
|
delete this.workflowWebhooks[workflowId];
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2020-01-22 15:06:43 -08:00
|
|
|
* Removes all the webhooks of the given workflow
|
2019-06-23 03:35:23 -07:00
|
|
|
*/
|
2020-01-22 15:06:43 -08:00
|
|
|
async removeAll(workflows: Workflow[]): Promise<void> {
|
2019-06-23 03:35:23 -07:00
|
|
|
const removePromises = [];
|
2020-01-22 15:06:43 -08:00
|
|
|
for (const workflow of workflows) {
|
|
|
|
removePromises.push(this.removeWorkflow(workflow));
|
2019-06-23 03:35:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
await Promise.all(removePromises);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|