mirror of
https://fast.feibisi.com/https://github.com/parcelvoy/platform.git
synced 2025-09-01 12:26:08 +08:00
feat: add cache key functionality to webhooks
This commit is contained in:
parent
bdeaaaf4c8
commit
dcdffeeb05
8 changed files with 56 additions and 39 deletions
|
@ -3,6 +3,7 @@ export interface Webhook {
|
|||
endpoint: string
|
||||
headers: Record<string, string>
|
||||
body?: Record<string, any>
|
||||
cacheKey?: string
|
||||
}
|
||||
|
||||
export interface WebhookResponse {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import { WebhookTemplate } from '../../render/Template'
|
||||
import Render, { Variables } from '../../render'
|
||||
import { Variables } from '../../render'
|
||||
import { WebhookProvider } from './WebhookProvider'
|
||||
import { WebhookResponse } from './Webhook'
|
||||
import App from '../../app'
|
||||
import { cacheGet, cacheSet } from '../../config/redis'
|
||||
|
||||
export default class WebhookChannel {
|
||||
readonly provider: WebhookProvider
|
||||
|
@ -13,27 +15,22 @@ export default class WebhookChannel {
|
|||
}
|
||||
}
|
||||
|
||||
async send(options: WebhookTemplate, variables: Variables): Promise<WebhookResponse> {
|
||||
const headers = this.compile(options.headers, variables)
|
||||
const endpoint = Render(options.endpoint, variables)
|
||||
const method = options.method
|
||||
const body = method === 'POST' || method === 'PATCH' || method === 'PUT'
|
||||
? this.compile(options.body, variables)
|
||||
: undefined
|
||||
async send(template: WebhookTemplate, variables: Variables): Promise<WebhookResponse> {
|
||||
|
||||
return await this.provider.send({
|
||||
endpoint,
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
})
|
||||
}
|
||||
const message = template.compile(variables)
|
||||
const redis = App.main.redis
|
||||
|
||||
private compile(object: Record<string, string> | undefined, variables: Variables) {
|
||||
if (!object) return {}
|
||||
return Object.keys(object).reduce((body, key) => {
|
||||
body[key] = Render(object[key], variables)
|
||||
return body
|
||||
}, {} as Record<string, any>)
|
||||
// If we have a cache key, check cache first
|
||||
if (message.cacheKey?.length) {
|
||||
const key = `wh:${variables.context.campaign_id}:${message.cacheKey}`
|
||||
const value = await cacheGet<WebhookResponse>(redis, key)
|
||||
if (value) return value
|
||||
const response = await this.provider.send(message)
|
||||
|
||||
await cacheSet(redis, key, response, 3600)
|
||||
return response
|
||||
}
|
||||
|
||||
return await this.provider.send(message)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,6 +208,9 @@ export const truncateWords = function(str: string, count: number, suffix = ''):
|
|||
* Get the base locale from a given locale string
|
||||
* @param locale
|
||||
*/
|
||||
export const baseLocale = (locale: string): string => {
|
||||
return locale.split('-')[0]
|
||||
export const baseLocale = (locale?: string): string | undefined => {
|
||||
if (!locale) return ''
|
||||
const parts = locale.split('-')
|
||||
if (parts.length < 2) return locale
|
||||
return parts[0]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import Render, { Variables, Wrap } from '.'
|
||||
import Render, { RenderObject, Variables, Wrap } from '.'
|
||||
import { Webhook } from '../providers/webhook/Webhook'
|
||||
import { ChannelType } from '../config/channels'
|
||||
import Model, { ModelParams } from '../core/Model'
|
||||
|
@ -183,11 +183,7 @@ export class PushTemplate extends Template {
|
|||
}
|
||||
|
||||
compile(variables: Variables): CompiledPush {
|
||||
const custom = Object.keys(this.custom).reduce((body, key) => {
|
||||
body[key] = Render(this.custom[key], variables)
|
||||
return body
|
||||
}, {} as Record<string, any>)
|
||||
|
||||
const custom = RenderObject(this.custom, variables)
|
||||
const url = this.compileUrl(variables)
|
||||
|
||||
return {
|
||||
|
@ -239,6 +235,7 @@ export class WebhookTemplate extends Template {
|
|||
endpoint!: string
|
||||
body!: Record<string, any>
|
||||
headers: Record<string, string> = {}
|
||||
cacheKey?: string
|
||||
|
||||
parseJson(json: any) {
|
||||
super.parseJson(json)
|
||||
|
@ -247,26 +244,26 @@ export class WebhookTemplate extends Template {
|
|||
this.endpoint = json?.data.endpoint
|
||||
this.body = json?.data.body
|
||||
this.headers = json?.data.headers || {}
|
||||
this.cacheKey = json?.data.cache_key
|
||||
}
|
||||
|
||||
compile(variables: Variables): Webhook {
|
||||
const headers = Object.keys(this.headers ?? {}).reduce((headers, key) => {
|
||||
headers[key] = Render(this.headers[key], variables)
|
||||
return headers
|
||||
}, {} as Record<string, string>)
|
||||
|
||||
const body = Object.keys(this.body ?? {}).reduce((body, key) => {
|
||||
body[key] = Render(this.body[key], variables)
|
||||
return body
|
||||
}, {} as Record<string, any>)
|
||||
const headers = RenderObject(this.headers, variables)
|
||||
const body = ['POST', 'PATCH', 'PUT'].includes(this.method)
|
||||
? RenderObject(this.body, variables)
|
||||
: undefined
|
||||
|
||||
const endpoint = Render(this.endpoint, variables)
|
||||
const cacheKey = this.cacheKey
|
||||
? Render(this.cacheKey, variables)
|
||||
: undefined
|
||||
const method = this.method
|
||||
return {
|
||||
endpoint,
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
cacheKey,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,4 +92,14 @@ export const Render = (template: string, { user, event, journey, context }: Vari
|
|||
})
|
||||
}
|
||||
|
||||
export const RenderObject = (object: Record<string, any> | undefined, variables: Variables) => {
|
||||
if (!object) return {}
|
||||
return Object.keys(object).reduce((body, key) => {
|
||||
body[key] = typeof object[key] === 'object'
|
||||
? RenderObject(object[key], variables)
|
||||
: Render(object[key], variables)
|
||||
return body
|
||||
}, {} as Record<string, any>)
|
||||
}
|
||||
|
||||
export default Render
|
||||
|
|
|
@ -29,8 +29,10 @@
|
|||
"balancer_edit_desc": "Randomly split users across paths. Configure an optional rate limit to limit the number of users that go down a path over a given time period.",
|
||||
"bcc": "BCC",
|
||||
"blast": "Blast",
|
||||
"body": "Body",
|
||||
"body": "Body (JSON)",
|
||||
"bounced": "Bounced",
|
||||
"cache_key": "Cache Key",
|
||||
"cache_key_subtitle": "A unique key to cache the response for this webhook. Only use if you intend to cache the response, leave empty to not cache.",
|
||||
"campaign_alert_pending": "This campaign has not been sent yet! Once the campaign is live or scheduled this tab will show the progress and results.",
|
||||
"campaign_alert_scheduled": "This campaign is pending delivery. It will begin to roll out at",
|
||||
"campaign_delivery_trigger_description": "Delivery for trigger campaigns is activated via API or journey action. An example request of how to trigger a send via API is available below.",
|
||||
|
|
|
@ -453,6 +453,7 @@ export interface WebhookTemplateData {
|
|||
endpoint: string
|
||||
body: Record<string, any>
|
||||
headers: Record<string, string>
|
||||
cache_key?: string
|
||||
}
|
||||
|
||||
export type Template = {
|
||||
|
|
|
@ -133,6 +133,7 @@ const WebhookTable = ({ data }: { data: WebhookTemplateData }) => {
|
|||
[t('endpoint')]: data.endpoint ?? <Tag variant="warn">{t('missing')}</Tag>,
|
||||
[t('headers')]: JSON.stringify(data.headers),
|
||||
[t('body')]: JSON.stringify(data.body),
|
||||
[t('cache_key')]: data.cache_key,
|
||||
}} />
|
||||
}
|
||||
|
||||
|
@ -160,6 +161,11 @@ const WebhookForm = ({ form }: { form: UseFormReturn<TemplateUpdateParams, any>
|
|||
name="data.body"
|
||||
label={t('body')}
|
||||
textarea />
|
||||
<TextInput.Field
|
||||
form={form}
|
||||
name="data.cache_key"
|
||||
label={t('cache_key')}
|
||||
subtitle={t('cache_key_subtitle')} />
|
||||
</>
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue