Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(SPV-848) notifications #630

Merged
merged 37 commits into from
Jul 12, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9e73c56
feat(SPV-848): notifiactions & webhook notifier
chris-4chain Jul 9, 2024
05b0218
feat(SVP-848): notifications manager
chris-4chain Jul 9, 2024
45742ea
feat(SPV-848): notifications unit tests
chris-4chain Jul 9, 2024
7ca2dc3
feat(SPV-848): package notification moved to engine
chris-4chain Jul 9, 2024
73973ca
feat(SPV-848): webhook_notifier tests
chris-4chain Jul 9, 2024
d2e0c0a
feat(SPV-848): webhook manager tests
chris-4chain Jul 9, 2024
fe2bd24
feat(SPV-848): fix some tests
chris-4chain Jul 9, 2024
88d0057
feat(SPV-848): call with token & test for ban fcn
chris-4chain Jul 9, 2024
bf3c9ca
feat(SPV-848): webhook subscribtion
chris-4chain Jul 9, 2024
23a4974
feat(SPV-848): fix deadlock
chris-4chain Jul 9, 2024
2be2bab
feat(SPV-848): update webhook info
chris-4chain Jul 9, 2024
a3c6d30
feat(SPV-848): blocking select instead of with-default Sleep
chris-4chain Jul 9, 2024
2fce90a
feat(SPV-848): unsubscribe
chris-4chain Jul 9, 2024
34d5ea8
feat(SPV-848): event type
chris-4chain Jul 9, 2024
281b529
feat(SPV-848): event names by reflect::Name
chris-4chain Jul 9, 2024
492f59f
feat(SPV-848): tidy things
chris-4chain Jul 9, 2024
e108b1e
fix(SPV-848): fix linter errors
chris-4chain Jul 9, 2024
1d1d79a
feat(SPV-848): fix lint errors and a unit test; and a swagger comments
chris-4chain Jul 9, 2024
000e709
feat(SPV-848): regenerate swagger
chris-4chain Jul 9, 2024
1bd7260
feat(SPV-848): fix nil ptr exception
chris-4chain Jul 9, 2024
02db980
feat(SPV-848): fix minor unit tests
chris-4chain Jul 9, 2024
3b89ef9
feat(SPV-848): adjust to self-review
chris-4chain Jul 9, 2024
77ff820
feat(SPV-848): events defined in models package
chris-4chain Jul 9, 2024
11bfd7a
feat(SPV-848): wrong log placement
chris-4chain Jul 9, 2024
d2b4af7
feat(SPV-848): adjust to new ExtendedError approach
chris-4chain Jul 9, 2024
70bce72
feat(SPV-848): adjust to review
chris-4chain Jul 9, 2024
5240db4
feat(SVP-848): typo
chris-4chain Jul 9, 2024
9db25d2
feat(SPV-848): update swagger
chris-4chain Jul 9, 2024
bd5dea7
feat(SPV-848): reimplement webhook model-repository logic
chris-4chain Jul 11, 2024
47a520d
feat(SPV-848): webhooks errors and minor changes
chris-4chain Jul 11, 2024
493de67
feat(SPV-848): lint errors
chris-4chain Jul 11, 2024
4633b0f
Merge branch 'main' into feat-848-notifications
chris-4chain Jul 11, 2024
8c8cea5
feat(SPV-848): update swagger
chris-4chain Jul 11, 2024
52242c1
feat(SPV-848): one empty file removed
chris-4chain Jul 11, 2024
56228d5
feat(SPV-848): adjust to minor comments
chris-4chain Jul 11, 2024
a173968
feat(SPV-848): BanUntil
chris-4chain Jul 11, 2024
5889633
feat(SPV-848): remove mocked notifications
chris-4chain Jul 12, 2024
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
2 changes: 2 additions & 0 deletions actions/admin/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ func NewHandler(appConfig *config.AppConfig, services *config.AppServices) route
adminGroup.POST("/xpub", action.xpubsCreate)
adminGroup.POST("/xpubs/search", action.xpubsSearch)
adminGroup.POST("/xpubs/count", action.xpubsCount)
adminGroup.POST("/webhooks/subscribe", action.subscribeWebhook)
adminGroup.POST("/webhooks/unsubscribe", action.unsubscribeWebhook)
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved
})

return adminEndpoints
Expand Down
61 changes: 61 additions & 0 deletions actions/admin/webhooks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package admin

import (
"net/http"

"github.com/bitcoin-sv/spv-wallet/engine/spverrors"
"github.com/bitcoin-sv/spv-wallet/models"
"github.com/gin-gonic/gin"
)

// subscribeWebhook will subscribe to a webhook to receive notifications
// @Summary Subscribe to a webhook
// @Description Subscribe to a webhook to receive notifications
// @Tags Admin
// @Produce json
// @Param SubscribeRequestBody body models.SubscribeRequestBody false "URL to subscribe to and optional token header and value"
// @Success 200 {boolean} bool "Success response"
// @Failure 500 "Internal server error - Error while subscribing to the webhook"
// @Router /v1/admin/webhooks/subscribe [post]
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved
// @Security x-auth-xpub
func (a *Action) subscribeWebhook(c *gin.Context) {
requestBody := models.SubscribeRequestBody{}
if err := c.Bind(&requestBody); err != nil {
c.JSON(http.StatusBadRequest, err.Error())
return
}

err := a.Services.SpvWalletEngine.SubscribeWebhook(c.Request.Context(), requestBody.URL, requestBody.TokenHeader, requestBody.TokenValue)
if err != nil {
spverrors.ErrorResponse(c, spverrors.ErrWebhookSubscriptionFailed, a.Services.Logger)
return
}

c.JSON(http.StatusOK, true)
}

// unsubscribeWebhook will unsubscribe to a webhook to receive notifications
// @Summary Unsubscribe to a webhook
// @Description Unsubscribe to a webhook to stop receiving notifications
// @Tags Admin
// @Produce json
// @Param UnsubscribeRequestBody body models.UnsubscribeRequestBody false "URL to unsubscribe from"
// @Success 200 {boolean} bool "Success response"
// @Failure 500 "Internal server error - Error while unsubscribing to the webhook"
// @Router /v1/admin/webhooks/unsubscribe [post]
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved
// @Security x-auth-xpub
func (a *Action) unsubscribeWebhook(c *gin.Context) {
wregulski marked this conversation as resolved.
Show resolved Hide resolved
requestModel := models.UnsubscribeRequestBody{}
if err := c.Bind(&requestModel); err != nil {
c.JSON(http.StatusBadRequest, err.Error())
return
}

err := a.Services.SpvWalletEngine.UnsubscribeWebhook(c.Request.Context(), requestModel.URL)
if err != nil {
spverrors.ErrorResponse(c, spverrors.ErrWebhookUnsubscriptionFailed, a.Services.Logger)
return
}

c.JSON(http.StatusOK, true)
}
2 changes: 0 additions & 2 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,6 @@ nodes:
bytes: 1000
notifications:
enabled: false
# url to send notifications
webhook_endpoint: ""
paymail:
beef:
block_headers_service_auth_token: mQZQ6WmxURxWz5ch
Expand Down
2 changes: 0 additions & 2 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,6 @@ type ArcAPI struct {

// NotificationsConfig is the configuration for notifications
type NotificationsConfig struct {
// WebhookEndpoint is the endpoint for webhook registration.
WebhookEndpoint string `json:"webhook_endpoint" mapstructure:"webhook_endpoint"`
// Enabled is the flag that enables notifications service.
Enabled bool `json:"enabled" mapstructure:"enabled"`
}
Expand Down
3 changes: 1 addition & 2 deletions config/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,7 @@ func getNodesDefaults() *NodesConfig {

func getNotificationDefaults() *NotificationsConfig {
return &NotificationsConfig{
Enabled: false,
WebhookEndpoint: "",
Enabled: false,
chris-4chain marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
2 changes: 1 addition & 1 deletion config/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ func (s *AppServices) loadSPVWallet(ctx context.Context, appConfig *AppConfig, t
options = loadTaskManager(appConfig, options)

if appConfig.Notifications != nil && appConfig.Notifications.Enabled {
options = append(options, engine.WithNotifications(appConfig.Notifications.WebhookEndpoint))
options = append(options, engine.WithNotifications())
}

options = loadBroadcastClientArc(appConfig, options, logger)
Expand Down
102 changes: 98 additions & 4 deletions docs/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1079,6 +1079,82 @@ const docTemplate = `{
}
}
},
"/v1/admin/webhooks/subscribe": {
"post": {
"security": [
{
"x-auth-xpub": []
}
],
"description": "Subscribe to a webhook to receive notifications",
"produces": [
"application/json"
],
"tags": [
"Admin"
],
"summary": "Subscribe to a webhook",
"parameters": [
{
"description": "URL to subscribe to and optional token header and value",
"name": "SubscribeRequestBody",
"in": "body",
"schema": {
"$ref": "#/definitions/models.SubscribeRequestBody"
}
}
],
"responses": {
"200": {
"description": "Success response",
"schema": {
"type": "boolean"
}
},
"500": {
"description": "Internal server error - Error while subscribing to the webhook"
}
}
}
},
"/v1/admin/webhooks/unsubscribe": {
"post": {
"security": [
{
"x-auth-xpub": []
}
],
"description": "Unsubscribe to a webhook to stop receiving notifications",
"produces": [
"application/json"
],
"tags": [
"Admin"
],
"summary": "Unsubscribe to a webhook",
"parameters": [
{
"description": "URL to unsubscribe from",
"name": "UnsubscribeRequestBody",
"in": "body",
"schema": {
"$ref": "#/definitions/models.UnsubscribeRequestBody"
}
}
],
"responses": {
"200": {
"description": "Success response",
"schema": {
"type": "boolean"
}
},
"500": {
"description": "Internal server error - Error while unsubscribing to the webhook"
}
}
}
},
"/v1/admin/xpub": {
"post": {
"security": [
Expand Down Expand Up @@ -4005,6 +4081,20 @@ const docTemplate = `{
}
}
},
"models.SubscribeRequestBody": {
"type": "object",
"properties": {
"tokenHeader": {
"type": "string"
},
"tokenValue": {
"type": "string"
},
"url": {
"type": "string"
}
}
},
"models.SyncConfig": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -4390,6 +4480,14 @@ const docTemplate = `{
}
}
},
"models.UnsubscribeRequestBody": {
"type": "object",
"properties": {
"url": {
"type": "string"
}
}
},
"models.Utxo": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -4556,8 +4654,6 @@ const docTemplate = `{
1000000000,
60000000000,
3600000000000,
-9223372036854775808,
9223372036854775807,
1,
1000,
1000000,
Expand All @@ -4574,8 +4670,6 @@ const docTemplate = `{
"Second",
"Minute",
"Hour",
"minDuration",
"maxDuration",
"Nanosecond",
"Microsecond",
"Millisecond",
Expand Down
102 changes: 98 additions & 4 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,82 @@
}
}
},
"/v1/admin/webhooks/subscribe": {
"post": {
"security": [
{
"x-auth-xpub": []
}
],
"description": "Subscribe to a webhook to receive notifications",
"produces": [
"application/json"
],
"tags": [
"Admin"
],
"summary": "Subscribe to a webhook",
"parameters": [
{
"description": "URL to subscribe to and optional token header and value",
"name": "SubscribeRequestBody",
"in": "body",
"schema": {
"$ref": "#/definitions/models.SubscribeRequestBody"
}
}
],
"responses": {
"200": {
"description": "Success response",
"schema": {
"type": "boolean"
}
},
"500": {
"description": "Internal server error - Error while subscribing to the webhook"
}
}
}
},
"/v1/admin/webhooks/unsubscribe": {
"post": {
"security": [
{
"x-auth-xpub": []
}
],
"description": "Unsubscribe to a webhook to stop receiving notifications",
"produces": [
"application/json"
],
"tags": [
"Admin"
],
"summary": "Unsubscribe to a webhook",
"parameters": [
{
"description": "URL to unsubscribe from",
"name": "UnsubscribeRequestBody",
"in": "body",
"schema": {
"$ref": "#/definitions/models.UnsubscribeRequestBody"
}
}
],
"responses": {
"200": {
"description": "Success response",
"schema": {
"type": "boolean"
}
},
"500": {
"description": "Internal server error - Error while unsubscribing to the webhook"
}
}
}
},
"/v1/admin/xpub": {
"post": {
"security": [
Expand Down Expand Up @@ -3996,6 +4072,20 @@
}
}
},
"models.SubscribeRequestBody": {
"type": "object",
"properties": {
"tokenHeader": {
"type": "string"
},
"tokenValue": {
"type": "string"
},
"url": {
"type": "string"
}
}
},
"models.SyncConfig": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -4381,6 +4471,14 @@
}
}
},
"models.UnsubscribeRequestBody": {
"type": "object",
"properties": {
"url": {
"type": "string"
}
}
},
"models.Utxo": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -4547,8 +4645,6 @@
1000000000,
60000000000,
3600000000000,
-9223372036854775808,
9223372036854775807,
1,
1000,
1000000,
Expand All @@ -4565,8 +4661,6 @@
"Second",
"Minute",
"Hour",
"minDuration",
"maxDuration",
"Nanosecond",
"Microsecond",
"Millisecond",
Expand Down
Loading
Loading