Skip to content

Commit

Permalink
feat: add budget warning event, rename app events (#813)
Browse files Browse the repository at this point in the history
  • Loading branch information
rolznz authored Nov 27, 2024
1 parent 3c4d559 commit 0063bf0
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 8 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,9 @@ Internally Alby Hub uses a basic implementation of the pubsub messaging pattern
- `nwc_payment_failed` - failed to make a lightning payment
- `nwc_payment_sent` - successfully made a lightning payment
- `nwc_payment_received` - received a lightning payment
- `nwc_budget_warning` - successfully made a lightning payment, but budget is nearly exceeded
- `nwc_app_created` - a new app connection was created
- `nwc_app_deleted` - a new app connection was deleted
- `nwc_lnclient_*` - underlying LNClient events, consumed only by the transactions service.

### NIP-47 Handlers
Expand Down
4 changes: 2 additions & 2 deletions apps/apps_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ func (svc *appsService) CreateApp(name string, pubkey string, maxAmountSat uint6
}

svc.eventPublisher.Publish(&events.Event{
Event: "app_created",
Event: "nwc_app_created",
Properties: map[string]interface{}{
"name": name,
"id": app.ID,
Expand All @@ -134,7 +134,7 @@ func (svc *appsService) DeleteApp(app *db.App) error {
return err
}
svc.eventPublisher.Publish(&events.Event{
Event: "app_deleted",
Event: "nwc_app_deleted",
Properties: map[string]interface{}{
"name": app.Name,
"id": app.ID,
Expand Down
2 changes: 1 addition & 1 deletion service/create_app_consumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type createAppConsumer struct {

// When a new app is created, subscribe to it on the relay
func (s *createAppConsumer) ConsumeEvent(ctx context.Context, event *events.Event, globalProperties map[string]interface{}) {
if event.Event != "app_created" {
if event.Event != "nwc_app_created" {
return
}

Expand Down
2 changes: 1 addition & 1 deletion service/delete_app_consumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type deleteAppConsumer struct {
// When an app is deleted, unsubscribe from events for that app on the relay
// and publish a deletion event for that app's info event
func (s *deleteAppConsumer) ConsumeEvent(ctx context.Context, event *events.Event, globalProperties map[string]interface{}) {
if event.Event != "app_deleted" {
if event.Event != "nwc_app_deleted" {
return
}
properties, ok := event.Properties.(map[string]interface{})
Expand Down
4 changes: 2 additions & 2 deletions service/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (svc *service) startNostr(ctx context.Context) error {
}).Info("Connected to the relay")
waitToReconnectSeconds = 0

// register a subscriber for events of "app_created" which handles creation of nostr subscription for new app
// register a subscriber for events of "nwc_app_created" which handles creation of nostr subscription for new app
if createAppEventListener != nil {
svc.eventPublisher.RemoveSubscriber(createAppEventListener)
}
Expand Down Expand Up @@ -175,7 +175,7 @@ func (svc *service) startAppWalletSubscription(ctx context.Context, relay *nostr
return err
}

// register a subscriber for "app_deleted" events, which handles nostr subscription cancel and nip47 info event deletion
// register a subscriber for "nwc_app_deleted" events, which handles nostr subscription cancel and nip47 info event deletion
deleteEventSubscriber := deleteAppConsumer{nostrSubscription: sub, walletPubkey: appWalletPubKey, svc: svc, relay: relay}
svc.eventPublisher.RegisterSubscriber(&deleteEventSubscriber)

Expand Down
5 changes: 3 additions & 2 deletions tests/create_app.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package tests

import (
"time"

db "github.com/getAlby/hub/db"
"github.com/getAlby/hub/events"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip04"
"gorm.io/gorm"
"time"
)

func CreateApp(svc *TestService) (app *db.App, ss []byte, err error) {
Expand Down Expand Up @@ -57,7 +58,7 @@ func CreateLegacyApp(svc *TestService, senderPrivkey string) (app *db.App, ss []
}

svc.EventPublisher.Publish(&events.Event{
Event: "app_created",
Event: "nwc_app_created",
Properties: map[string]interface{}{
"name": "test",
"id": app.ID,
Expand Down
40 changes: 40 additions & 0 deletions transactions/transactions_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -978,9 +978,49 @@ func (svc *transactionsService) markTransactionSettled(tx *gorm.DB, dbTransactio
Properties: dbTransaction,
})

if dbTransaction.Type == constants.TRANSACTION_TYPE_OUTGOING && dbTransaction.AppId != nil {
svc.checkBudgetUsage(dbTransaction)
}

return dbTransaction, nil
}

func (svc *transactionsService) checkBudgetUsage(dbTransaction *db.Transaction) {
var app db.App
result := svc.db.Limit(1).Find(&app, &db.App{
ID: *dbTransaction.AppId,
})
if result.RowsAffected == 0 {
logger.Logger.WithField("app_id", dbTransaction.AppId).Error("failed to find app by id")
return
}
if app.Isolated {
return
}

var appPermission db.AppPermission
result = svc.db.Limit(1).Find(&appPermission, &db.AppPermission{
AppId: app.ID,
Scope: constants.PAY_INVOICE_SCOPE,
})
if result.RowsAffected == 0 {
logger.Logger.WithField("app_id", dbTransaction.AppId).Error("failed to find pay_invoice scope")
return
}

budgetUsage := queries.GetBudgetUsageSat(svc.db, &appPermission)
warningUsage := uint64(math.Floor(float64(appPermission.MaxAmountSat) * 0.8))
if budgetUsage >= warningUsage && budgetUsage-dbTransaction.AmountMsat/1000 < warningUsage {
svc.eventPublisher.Publish(&events.Event{
Event: "nwc_budget_warning",
Properties: map[string]interface{}{
"name": app.Name,
"id": app.ID,
},
})
}
}

func (svc *transactionsService) markPaymentFailed(tx *gorm.DB, dbTransaction *db.Transaction, reason string) error {
var existingTransaction db.Transaction
result := tx.Limit(1).Find(&existingTransaction, &db.Transaction{
Expand Down

0 comments on commit 0063bf0

Please sign in to comment.