2022-01-02 08:44:18 -03:00
|
|
|
package nostr
|
2021-01-31 11:05:09 -03:00
|
|
|
|
|
|
|
import (
|
2021-02-20 17:44:05 -03:00
|
|
|
"crypto/rand"
|
|
|
|
"encoding/hex"
|
2021-01-31 11:05:09 -03:00
|
|
|
"errors"
|
2021-02-07 07:56:55 -03:00
|
|
|
"fmt"
|
2021-01-31 11:05:09 -03:00
|
|
|
|
2022-08-22 08:45:27 -03:00
|
|
|
s "github.com/SaveTheRbtz/generic-sync-map-go"
|
2021-01-31 11:05:09 -03:00
|
|
|
)
|
|
|
|
|
2022-01-02 08:44:18 -03:00
|
|
|
type PublishStatus struct {
|
|
|
|
Relay string
|
2022-05-01 17:51:38 -03:00
|
|
|
Status Status
|
2022-01-02 08:44:18 -03:00
|
|
|
}
|
|
|
|
|
2021-01-31 11:05:09 -03:00
|
|
|
type RelayPool struct {
|
|
|
|
SecretKey *string
|
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
Policies s.MapOf[string, RelayPoolPolicy]
|
|
|
|
Relays s.MapOf[string, *Relay]
|
|
|
|
subscriptions s.MapOf[string, Filters]
|
|
|
|
eventStreams s.MapOf[string, chan EventMessage]
|
2021-01-31 11:05:09 -03:00
|
|
|
|
|
|
|
Notices chan *NoticeMessage
|
|
|
|
}
|
|
|
|
|
2022-01-02 08:50:53 -03:00
|
|
|
type RelayPoolPolicy interface {
|
2022-02-08 16:27:33 -03:00
|
|
|
ShouldRead(Filters) bool
|
2022-01-02 08:50:53 -03:00
|
|
|
ShouldWrite(*Event) bool
|
2021-01-31 11:05:09 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
type SimplePolicy struct {
|
|
|
|
Read bool
|
|
|
|
Write bool
|
|
|
|
}
|
|
|
|
|
2022-02-08 16:27:33 -03:00
|
|
|
func (s SimplePolicy) ShouldRead(_ Filters) bool {
|
2022-01-02 08:50:53 -03:00
|
|
|
return s.Read
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s SimplePolicy) ShouldWrite(_ *Event) bool {
|
|
|
|
return s.Write
|
|
|
|
}
|
|
|
|
|
2021-01-31 11:05:09 -03:00
|
|
|
type NoticeMessage struct {
|
|
|
|
Message string
|
|
|
|
Relay string
|
|
|
|
}
|
|
|
|
|
|
|
|
// New creates a new RelayPool with no relays in it
|
2022-01-02 08:44:18 -03:00
|
|
|
func NewRelayPool() *RelayPool {
|
2021-01-31 11:05:09 -03:00
|
|
|
return &RelayPool{
|
2022-11-06 21:15:42 -03:00
|
|
|
Policies: s.MapOf[string, RelayPoolPolicy]{},
|
|
|
|
Relays: s.MapOf[string, *Relay]{},
|
2021-01-31 11:05:09 -03:00
|
|
|
|
|
|
|
Notices: make(chan *NoticeMessage),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add adds a new relay to the pool, if policy is nil, it will be a simple
|
|
|
|
// read+write policy.
|
2022-01-02 08:50:53 -03:00
|
|
|
func (r *RelayPool) Add(url string, policy RelayPoolPolicy) error {
|
2021-01-31 11:05:09 -03:00
|
|
|
if policy == nil {
|
2022-01-02 08:50:53 -03:00
|
|
|
policy = SimplePolicy{Read: true, Write: true}
|
2021-01-31 11:05:09 -03:00
|
|
|
}
|
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
relay := NewRelay(url)
|
|
|
|
r.Policies.Store(relay.URL, policy)
|
|
|
|
r.Relays.Store(relay.URL, relay)
|
2021-01-31 11:05:09 -03:00
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
r.subscriptions.Range(func(id string, filters Filters) bool {
|
|
|
|
sub := relay.subscribe(id, filters)
|
|
|
|
eventStream, _ := r.eventStreams.Load(id)
|
2022-01-12 10:54:45 -04:00
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
go func(sub *Subscription) {
|
|
|
|
for evt := range sub.Events {
|
|
|
|
eventStream <- EventMessage{Relay: relay.URL, Event: evt}
|
|
|
|
}
|
|
|
|
}(sub)
|
2021-01-31 11:05:09 -03:00
|
|
|
|
2022-08-22 08:45:27 -03:00
|
|
|
return true
|
|
|
|
})
|
2021-02-20 17:44:05 -03:00
|
|
|
|
2021-02-07 07:56:55 -03:00
|
|
|
return nil
|
2021-01-31 11:05:09 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove removes a relay from the pool.
|
|
|
|
func (r *RelayPool) Remove(url string) {
|
2022-01-02 08:44:18 -03:00
|
|
|
nm := NormalizeURL(url)
|
2021-02-20 17:44:05 -03:00
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
r.Relays.Delete(nm)
|
|
|
|
r.Policies.Delete(nm)
|
2022-08-22 08:45:27 -03:00
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
if relay, ok := r.Relays.Load(nm); ok {
|
|
|
|
relay.Close()
|
2021-01-31 11:05:09 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
func (r *RelayPool) Sub(filters Filters) (string, chan EventMessage) {
|
2021-02-20 17:44:05 -03:00
|
|
|
random := make([]byte, 7)
|
|
|
|
rand.Read(random)
|
2022-11-06 21:15:42 -03:00
|
|
|
id := hex.EncodeToString(random)
|
2021-01-31 11:05:09 -03:00
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
r.subscriptions.Store(id, filters)
|
|
|
|
eventStream := make(chan EventMessage)
|
|
|
|
r.eventStreams.Store(id, eventStream)
|
2022-08-22 08:45:27 -03:00
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
r.Relays.Range(func(_ string, relay *Relay) bool {
|
|
|
|
sub := relay.subscribe(id, filters)
|
|
|
|
|
|
|
|
go func(sub *Subscription) {
|
|
|
|
for evt := range sub.Events {
|
|
|
|
eventStream <- EventMessage{Relay: relay.URL, Event: evt}
|
2022-08-22 08:45:27 -03:00
|
|
|
}
|
2022-11-06 21:15:42 -03:00
|
|
|
}(sub)
|
|
|
|
|
2022-08-22 08:45:27 -03:00
|
|
|
return true
|
|
|
|
})
|
2021-01-31 11:05:09 -03:00
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
return id, eventStream
|
2021-01-31 11:05:09 -03:00
|
|
|
}
|
|
|
|
|
2022-01-02 08:44:18 -03:00
|
|
|
func (r *RelayPool) PublishEvent(evt *Event) (*Event, chan PublishStatus, error) {
|
2021-02-20 18:54:34 -03:00
|
|
|
status := make(chan PublishStatus, 1)
|
2021-01-31 11:05:09 -03:00
|
|
|
|
2021-12-16 20:47:53 -03:00
|
|
|
if r.SecretKey == nil && (evt.PubKey == "" || evt.Sig == "") {
|
2021-02-20 17:44:05 -03:00
|
|
|
return nil, status, errors.New("PublishEvent needs either a signed event to publish or to have been configured with a .SecretKey.")
|
2021-01-31 11:05:09 -03:00
|
|
|
}
|
|
|
|
|
2021-12-16 20:47:53 -03:00
|
|
|
if evt.PubKey == "" {
|
2022-05-01 15:10:18 -03:00
|
|
|
sk, err := GetPublicKey(*r.SecretKey)
|
2021-12-16 20:47:53 -03:00
|
|
|
if err != nil {
|
|
|
|
return nil, status, fmt.Errorf("The pool's global SecretKey is invalid: %w", err)
|
|
|
|
}
|
2022-05-01 15:10:18 -03:00
|
|
|
evt.PubKey = sk
|
2021-12-16 20:47:53 -03:00
|
|
|
}
|
|
|
|
|
2021-01-31 11:05:09 -03:00
|
|
|
if evt.Sig == "" {
|
2021-02-07 07:56:55 -03:00
|
|
|
err := evt.Sign(*r.SecretKey)
|
|
|
|
if err != nil {
|
2021-02-20 17:44:05 -03:00
|
|
|
return nil, status, fmt.Errorf("Error signing event: %w", err)
|
2021-02-07 07:56:55 -03:00
|
|
|
}
|
2021-01-31 11:05:09 -03:00
|
|
|
}
|
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
r.Relays.Range(func(url string, relay *Relay) bool {
|
|
|
|
if r, ok := r.Policies.Load(url); !ok || !r.ShouldWrite(evt) {
|
2022-08-22 08:45:27 -03:00
|
|
|
return true
|
2022-01-02 08:50:53 -03:00
|
|
|
}
|
|
|
|
|
2022-11-06 21:15:42 -03:00
|
|
|
go func(relay *Relay) {
|
|
|
|
for resultStatus := range relay.Publish(*evt) {
|
|
|
|
status <- PublishStatus{relay.URL, resultStatus}
|
2021-02-20 18:54:34 -03:00
|
|
|
}
|
2022-11-06 21:15:42 -03:00
|
|
|
}(relay)
|
2022-08-22 08:45:27 -03:00
|
|
|
|
|
|
|
return true
|
|
|
|
})
|
2021-01-31 11:05:09 -03:00
|
|
|
|
2021-02-20 17:44:05 -03:00
|
|
|
return evt, status, nil
|
2021-01-31 11:05:09 -03:00
|
|
|
}
|