Skip to content

Instantly share code, notes, and snippets.

@fabianmu
Last active August 1, 2023 09:24
Show Gist options
  • Save fabianmu/5281441fbff1c424cf3f766c2db2f01a to your computer and use it in GitHub Desktop.
Save fabianmu/5281441fbff1c424cf3f766c2db2f01a to your computer and use it in GitHub Desktop.
disable webhook for a strapi model
/**
* The event hub is Strapi's event control center.
*/
'use strict';
const debug = require('debug')('strapi:webhook');
const _ = require('lodash');
const fetch = require('node-fetch');
const WorkerQueue = require('./worker-queue');
const defaultConfiguration = {
defaultHeaders: {},
};
class WebhookRunner {
constructor({ eventHub, logger, configuration = {} }) {
debug('Initialized webhook runer');
this.eventHub = eventHub;
this.logger = logger;
this.webhooksMap = new Map();
this.listeners = new Map();
if (typeof configuration !== 'object') {
throw new Error(
'Invalid configuration provided to the webhookRunner.\nCheck your server.json -> webhooks configuration'
);
}
this.config = _.merge(defaultConfiguration, configuration);
this.queue = new WorkerQueue({ logger, concurrency: 5 });
this.queue.subscribe(this.executeListener.bind(this));
}
deleteListener(event) {
debug(`Deleting listener for event '${event}'`);
if (this.listeners.has(event)) {
const fn = this.listeners.get(event);
this.eventHub.off(event, fn);
this.listeners.delete(event);
}
}
createListener(event) {
debug(`Creating listener for event '${event}'`);
if (this.listeners.has(event)) {
this.logger.error(
`The webhook runner is already listening for the event '${event}'. Did you mean to call .register() ?`
);
}
const listen = (info) => {
this.queue.enqueue({ event, info });
};
this.listeners.set(event, listen);
this.eventHub.on(event, listen);
}
async executeListener({ event, info }) {
debug(`Executing webhook for event '${event}'`);
const webhooks = this.webhooksMap.get(event) || [];
const activeWebhooks = webhooks.filter((webhook) => webhook.isEnabled === true);
if (info.model === 'availability' || info.model === 'rate' || info.model === 'rate-plan') {
debug(`skipping '${info.model}'`);
return;
}
for (const webhook of activeWebhooks) {
await this.run(webhook, event, info).catch((error) => {
this.logger.error('Error running webhook');
this.logger.error(error);
});
}
}
run(webhook, event, info = {}) {
const { url, headers } = webhook;
return fetch(url, {
method: 'post',
body: JSON.stringify({
event,
createdAt: new Date(),
...info,
}),
headers: {
...this.config.defaultHeaders,
...headers,
'X-Strapi-Event': event,
'Content-Type': 'application/json',
},
timeout: 10000,
})
.then(async (res) => {
if (res.ok) {
return {
statusCode: res.status,
};
}
return {
statusCode: res.status,
message: await res.text(),
};
})
.catch((err) => {
return {
statusCode: 500,
message: err.message,
};
});
}
add(webhook) {
debug(`Registering webhook '${webhook.id}'`);
const { events } = webhook;
events.forEach((event) => {
if (this.webhooksMap.has(event)) {
this.webhooksMap.get(event).push(webhook);
} else {
this.webhooksMap.set(event, [webhook]);
this.createListener(event);
}
});
}
update(webhook) {
debug(`Refreshing webhook '${webhook.id}'`);
this.remove(webhook);
this.add(webhook);
}
remove(webhook) {
debug(`Unregistering webhook '${webhook.id}'`);
this.webhooksMap.forEach((webhooks, event) => {
const filteredWebhooks = webhooks.filter((value) => value.id !== webhook.id);
// Cleanup hanging listeners
if (filteredWebhooks.length === 0) {
this.webhooksMap.delete(event);
this.deleteListener(event);
} else {
this.webhooksMap.set(event, filteredWebhooks);
}
});
}
}
/**
* Expose a factory function instead of the class
*/
module.exports = function createWebhookRunner(opts) {
return new WebhookRunner(opts);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment