From f2ab8020a86e8fcf7a8e88eac92e52ca7ab8a891 Mon Sep 17 00:00:00 2001
From: 0x0ff <0x0ff@onsats.org>
Date: Fri, 23 Dec 2022 15:55:52 +0100
Subject: [PATCH] handle event responses as per NIP-20

---
 add-event.go               | 12 +++++++++---
 rss-bridge/main.go         | 12 ++++++++----
 storage/errors.go          |  5 +++++
 storage/postgresql/save.go | 20 ++++++++++++--------
 4 files changed, 34 insertions(+), 15 deletions(-)
 create mode 100644 storage/errors.go

diff --git a/add-event.go b/add-event.go
index 8037e76..3abfa7e 100644
--- a/add-event.go
+++ b/add-event.go
@@ -3,6 +3,7 @@ package relayer
 import (
 	"fmt"
 
+	"github.com/fiatjaf/relayer/storage"
 	"github.com/nbd-wtf/go-nostr"
 )
 
@@ -32,7 +33,7 @@ func AddEvent(relay Relay, evt nostr.Event) (accepted bool, message string) {
 	}
 
 	if !relay.AcceptEvent(&evt) {
-		return false, "blocked"
+		return false, "blocked: event blocked by relay"
 	}
 
 	if 20000 <= evt.Kind && evt.Kind < 30000 {
@@ -42,8 +43,13 @@ func AddEvent(relay Relay, evt nostr.Event) (accepted bool, message string) {
 			advancedSaver.BeforeSave(&evt)
 		}
 
-		if err := store.SaveEvent(&evt); err != nil {
-			return false, fmt.Sprintf("error: failed to save: %s", err.Error())
+		if saveErr := store.SaveEvent(&evt); saveErr != nil {
+			switch saveErr {
+			case storage.ErrDupEvent:
+				return true, saveErr.Error()
+			default:
+				return false, fmt.Sprintf("error: failed to save: %s", saveErr.Error())
+			}
 		}
 
 		if advancedSaver != nil {
diff --git a/rss-bridge/main.go b/rss-bridge/main.go
index 1e9c696..141f055 100644
--- a/rss-bridge/main.go
+++ b/rss-bridge/main.go
@@ -9,9 +9,9 @@ import (
 	"time"
 
 	"github.com/cockroachdb/pebble"
-	"github.com/nbd-wtf/go-nostr"
 	"github.com/fiatjaf/relayer"
 	"github.com/kelseyhightower/envconfig"
+	"github.com/nbd-wtf/go-nostr"
 )
 
 var relay = &Relay{
@@ -101,9 +101,13 @@ type store struct {
 	db *pebble.DB
 }
 
-func (b store) Init() error                    { return nil }
-func (b store) SaveEvent(_ *nostr.Event) error { return errors.New("we don't accept any events") }
-func (b store) DeleteEvent(_, _ string) error  { return errors.New("we can't delete any events") }
+func (b store) Init() error { return nil }
+func (b store) SaveEvent(_ *nostr.Event) error {
+	return errors.New("blocked: we don't accept any events")
+}
+func (b store) DeleteEvent(_, _ string) error {
+	return errors.New("blocked: we can't delete any events")
+}
 
 func (b store) QueryEvents(filter *nostr.Filter) ([]nostr.Event, error) {
 	var evts []nostr.Event
diff --git a/storage/errors.go b/storage/errors.go
new file mode 100644
index 0000000..67f0805
--- /dev/null
+++ b/storage/errors.go
@@ -0,0 +1,5 @@
+package storage
+
+import "errors"
+
+var ErrDupEvent = errors.New("duplicate: event already exists")
diff --git a/storage/postgresql/save.go b/storage/postgresql/save.go
index 225ed55..5280f7d 100644
--- a/storage/postgresql/save.go
+++ b/storage/postgresql/save.go
@@ -2,9 +2,8 @@ package postgresql
 
 import (
 	"encoding/json"
-	"fmt"
-	"strings"
 
+	"github.com/fiatjaf/relayer/storage"
 	"github.com/nbd-wtf/go-nostr"
 )
 
@@ -21,17 +20,22 @@ func (b *PostgresBackend) SaveEvent(evt *nostr.Event) error {
 
 	// insert
 	tagsj, _ := json.Marshal(evt.Tags)
-	_, err := b.DB.Exec(`
+	res, err := b.DB.Exec(`
         INSERT INTO event (id, pubkey, created_at, kind, tags, content, sig)
         VALUES ($1, $2, $3, $4, $5, $6, $7)
+		ON CONFLICT (id) DO NOTHING
     `, evt.ID, evt.PubKey, evt.CreatedAt.Unix(), evt.Kind, tagsj, evt.Content, evt.Sig)
 	if err != nil {
-		if strings.Index(err.Error(), "UNIQUE") != -1 {
-			// already exists
-			return nil
-		}
+		return err
+	}
 
-		return fmt.Errorf("failed to save event %s: %w", evt.ID, err)
+	nr, err := res.RowsAffected()
+	if err != nil {
+		return err
+	}
+
+	if nr == 0 {
+		return storage.ErrDupEvent
 	}
 
 	return nil