Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions pkg/v1/features/webhooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
package features

import (
"bytes"
"context"
"encoding/json"
"fmt"

"github.com/google/uuid"

"github.com/hatchet-dev/hatchet/pkg/client/rest"
)

type WebhookAuth interface {
toCreateRequest(opts CreateWebhookOpts) (rest.V1CreateWebhookRequest, error)
}

type BasicAuth struct {
Username string
Password string
}

func (a BasicAuth) toCreateRequest(opts CreateWebhookOpts) (rest.V1CreateWebhookRequest, error) {
var req rest.V1CreateWebhookRequest
err := req.FromV1CreateWebhookRequestBasicAuth(rest.V1CreateWebhookRequestBasicAuth{
Name: opts.Name,
SourceName: opts.SourceName,
EventKeyExpression: opts.EventKeyExpression,
AuthType: rest.V1CreateWebhookRequestBasicAuthAuthType("BASIC"),
Auth: rest.V1WebhookBasicAuth{
Username: a.Username,
Password: a.Password,
},
})
return req, err
}

type APIKeyAuth struct {
HeaderName string
APIKey string
}

func (a APIKeyAuth) toCreateRequest(opts CreateWebhookOpts) (rest.V1CreateWebhookRequest, error) {
var req rest.V1CreateWebhookRequest
err := req.FromV1CreateWebhookRequestAPIKey(rest.V1CreateWebhookRequestAPIKey{
Name: opts.Name,
SourceName: opts.SourceName,
EventKeyExpression: opts.EventKeyExpression,
AuthType: rest.V1CreateWebhookRequestAPIKeyAuthType("API_KEY"),
Auth: rest.V1WebhookAPIKeyAuth{
HeaderName: a.HeaderName,
ApiKey: a.APIKey,
},
})
return req, err
}

type HMACAuth struct {
SigningSecret string
SignatureHeaderName string
Algorithm rest.V1WebhookHMACAlgorithm
Encoding rest.V1WebhookHMACEncoding
}

func (a HMACAuth) toCreateRequest(opts CreateWebhookOpts) (rest.V1CreateWebhookRequest, error) {
var req rest.V1CreateWebhookRequest
err := req.FromV1CreateWebhookRequestHMAC(rest.V1CreateWebhookRequestHMAC{
Name: opts.Name,
SourceName: opts.SourceName,
EventKeyExpression: opts.EventKeyExpression,
AuthType: rest.V1CreateWebhookRequestHMACAuthType("HMAC"),
Auth: rest.V1WebhookHMACAuth{
SigningSecret: a.SigningSecret,
SignatureHeaderName: a.SignatureHeaderName,
Algorithm: a.Algorithm,
Encoding: a.Encoding,
},
})
return req, err
}

type CreateWebhookOpts struct {
Name string
SourceName rest.V1WebhookSourceName
EventKeyExpression string
Auth WebhookAuth
}

type UpdateWebhookOpts struct {
EventKeyExpression string
}

type WebhooksClient interface {
List(ctx context.Context, opts *rest.V1WebhookListParams) (*rest.V1WebhookList, error)

Get(ctx context.Context, webhookID string) (*rest.V1Webhook, error)

Create(ctx context.Context, opts CreateWebhookOpts) (*rest.V1Webhook, error)

Update(ctx context.Context, webhookID string, opts UpdateWebhookOpts) (*rest.V1Webhook, error)

Delete(ctx context.Context, webhookID string) (*rest.V1Webhook, error)

Receive(ctx context.Context, webhookID string, payload map[string]interface{}) (*map[string]interface{}, error)
}

type webhooksClientImpl struct {
api *rest.ClientWithResponses
tenantID uuid.UUID
}

func NewWebhooksClient(
api *rest.ClientWithResponses,
tenantID *string,
) WebhooksClient {
return &webhooksClientImpl{
api: api,
tenantID: uuid.MustParse(*tenantID),
}
}

func (c *webhooksClientImpl) List(ctx context.Context, opts *rest.V1WebhookListParams) (*rest.V1WebhookList, error) {
resp, err := c.api.V1WebhookListWithResponse(
ctx,
c.tenantID,
opts,
)

if err != nil {
return nil, err
}

return resp.JSON200, nil
}

func (c *webhooksClientImpl) Get(ctx context.Context, webhookID string) (*rest.V1Webhook, error) {
resp, err := c.api.V1WebhookGetWithResponse(
ctx,
c.tenantID,
webhookID,
)

if err != nil {
return nil, err
}

return resp.JSON200, nil
}

func (c *webhooksClientImpl) Create(ctx context.Context, opts CreateWebhookOpts) (*rest.V1Webhook, error) {
if opts.Auth == nil {
return nil, fmt.Errorf("auth is required")
}

req, err := opts.Auth.toCreateRequest(opts)
if err != nil {
return nil, err
}

resp, err := c.api.V1WebhookCreateWithResponse(
ctx,
c.tenantID,
req,
)

if err != nil {
return nil, err
}

return resp.JSON200, nil
}

func (c *webhooksClientImpl) Update(ctx context.Context, webhookID string, opts UpdateWebhookOpts) (*rest.V1Webhook, error) {
resp, err := c.api.V1WebhookUpdateWithResponse(
ctx,
c.tenantID,
webhookID,
rest.V1UpdateWebhookRequest{
EventKeyExpression: opts.EventKeyExpression,
},
)

if err != nil {
return nil, err
}

return resp.JSON200, nil
}

func (c *webhooksClientImpl) Delete(ctx context.Context, webhookID string) (*rest.V1Webhook, error) {
resp, err := c.api.V1WebhookDeleteWithResponse(
ctx,
c.tenantID,
webhookID,
)

if err != nil {
return nil, err
}

return resp.JSON200, nil
}

func (c *webhooksClientImpl) Receive(ctx context.Context, webhookID string, payload map[string]interface{}) (*map[string]interface{}, error) {
jsonData, err := json.Marshal(payload)
if err != nil {
return nil, err
}

resp, err := c.api.V1WebhookReceiveWithBodyWithResponse(
ctx,
c.tenantID,
webhookID,
"application/json",
bytes.NewReader(jsonData),
)

if err != nil {
return nil, err
}

return resp.JSON200, nil
}
Loading