mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-07-04 12:33:04 +02:00
move everything to the same directory.
This commit is contained in:
27
README.md
27
README.md
@ -9,13 +9,13 @@ A set of useful things for [Nostr Protocol](https://github.com/fiatjaf/nostr) im
|
|||||||
### Subscribing to a set of relays
|
### Subscribing to a set of relays
|
||||||
|
|
||||||
```go
|
```go
|
||||||
pool := relaypool.New()
|
pool := nostr.NewRelayPool()
|
||||||
|
|
||||||
pool.Add("wss://relay.nostr.com/", &relaypool.Policy{
|
pool.Add("wss://relay.nostr.com/", &nostr.RelayPoolPolicy{
|
||||||
SimplePolicy: relaypool.SimplePolicy{Read: true, Write: true},
|
SimplePolicy: nostr.SimplePolicy{Read: true, Write: true},
|
||||||
})
|
})
|
||||||
pool.Add("wss://nostrrelay.example.com/", &relaypool.Policy{
|
pool.Add("wss://nostrrelay.example.com/", &nostr.RelayPoolPolicy{
|
||||||
SimplePolicy: relaypool.SimplePolicy{Read: true, Write: true},
|
SimplePolicy: nostr.SimplePolicy{Read: true, Write: true},
|
||||||
})
|
})
|
||||||
|
|
||||||
for notice := range pool.Notices {
|
for notice := range pool.Notices {
|
||||||
@ -26,11 +26,10 @@ for notice := range pool.Notices {
|
|||||||
### Listening for events
|
### Listening for events
|
||||||
|
|
||||||
```go
|
```go
|
||||||
kind1 := event.KindTextNote
|
sub := pool.Sub(nostr.EventFilters{
|
||||||
sub := pool.Sub(filter.EventFilters{
|
|
||||||
{
|
{
|
||||||
Authors: []string{"0ded86bf80c76847320b16f22b7451c08169434837a51ad5fe3b178af6c35f5d"},
|
Authors: []string{"0ded86bf80c76847320b16f22b7451c08169434837a51ad5fe3b178af6c35f5d"},
|
||||||
Kind: &kind1, // or 1
|
Kinds: []string{nostr.KindTextNote}, // or {1}
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -51,10 +50,10 @@ secretKey := "3f06a81e0a0c2ad34ee9df2a30d87a810da9e3c3881f780755ace5e5e64d30a7"
|
|||||||
|
|
||||||
pool.SecretKey = &secretKey
|
pool.SecretKey = &secretKey
|
||||||
|
|
||||||
event, statuses, _ := pool.PublishEvent(&event.Event{
|
event, statuses, _ := pool.PublishEvent(&nostr.Event{
|
||||||
CreatedAt: uint32(time.Now().Unix()),
|
CreatedAt: uint32(time.Now().Unix()),
|
||||||
Kind: 1, // or event.KindTextNote
|
Kind: nostr.KindTextNote,
|
||||||
Tags: make(event.Tags, 0),
|
Tags: make(nostr.Tags, 0),
|
||||||
Content: "hello",
|
Content: "hello",
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -64,11 +63,11 @@ log.Print(event.Sig)
|
|||||||
|
|
||||||
for status := range statuses {
|
for status := range statuses {
|
||||||
switch status.Status {
|
switch status.Status {
|
||||||
case relaypool.PublishStatusSent:
|
case nostr.PublishStatusSent:
|
||||||
fmt.Printf("Sent event %s to '%s'.\n", event.ID, status.Relay)
|
fmt.Printf("Sent event %s to '%s'.\n", event.ID, status.Relay)
|
||||||
case relaypool.PublishStatusFailed:
|
case nostr.PublishStatusFailed:
|
||||||
fmt.Printf("Failed to send event %s to '%s'.\n", event.ID, status.Relay)
|
fmt.Printf("Failed to send event %s to '%s'.\n", event.ID, status.Relay)
|
||||||
case relaypool.PublishStatusSucceeded:
|
case nostr.PublishStatusSucceeded:
|
||||||
fmt.Printf("Event seen %s on '%s'.\n", event.ID, status.Relay)
|
fmt.Printf("Event seen %s on '%s'.\n", event.ID, status.Relay)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package event
|
package nostr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
@ -6,7 +6,6 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/fiatjaf/bip340"
|
"github.com/fiatjaf/bip340"
|
||||||
@ -34,26 +33,6 @@ type Event struct {
|
|||||||
Sig string `json:"sig"`
|
Sig string `json:"sig"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tags []Tag
|
|
||||||
|
|
||||||
func (t *Tags) Scan(src interface{}) error {
|
|
||||||
var jtags []byte = make([]byte, 0)
|
|
||||||
|
|
||||||
switch v := src.(type) {
|
|
||||||
case []byte:
|
|
||||||
jtags = v
|
|
||||||
case string:
|
|
||||||
jtags = []byte(v)
|
|
||||||
default:
|
|
||||||
return errors.New("couldn't scan tags, it's not a json string")
|
|
||||||
}
|
|
||||||
|
|
||||||
json.Unmarshal(jtags, &t)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Tag []interface{}
|
|
||||||
|
|
||||||
// Serialize outputs a byte array that can be hashed/signed to identify/authenticate
|
// Serialize outputs a byte array that can be hashed/signed to identify/authenticate
|
||||||
func (evt *Event) Serialize() []byte {
|
func (evt *Event) Serialize() []byte {
|
||||||
// the serialization process is just putting everything into a JSON array
|
// the serialization process is just putting everything into a JSON array
|
90
filter.go
Normal file
90
filter.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package nostr
|
||||||
|
|
||||||
|
type EventFilters []EventFilter
|
||||||
|
|
||||||
|
type EventFilter struct {
|
||||||
|
IDs StringList `json:"ids,omitempty"`
|
||||||
|
Kinds IntList `json:"kinds,omitempty"`
|
||||||
|
Authors StringList `json:"authors,omitempty"`
|
||||||
|
Since uint32 `json:"since,omitempty"`
|
||||||
|
Until uint32 `json:"until,omitempty"`
|
||||||
|
TagE StringList `json:"#e,omitempty"`
|
||||||
|
TagP StringList `json:"#p,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eff EventFilters) Match(event *Event) bool {
|
||||||
|
for _, filter := range eff {
|
||||||
|
if filter.Matches(event) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ef EventFilter) Matches(event *Event) bool {
|
||||||
|
if event == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ef.IDs != nil && !ef.IDs.Contains(event.ID) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ef.Kinds != nil && !ef.Kinds.Contains(event.Kind) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ef.Authors != nil && !ef.Authors.Contains(event.PubKey) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ef.TagE != nil && !event.Tags.ContainsAny("e", ef.TagE) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ef.TagP != nil && !event.Tags.ContainsAny("p", ef.TagP) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ef.Since != 0 && event.CreatedAt < ef.Since {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ef.Until != 0 && event.CreatedAt >= ef.Until {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func Equal(a EventFilter, b EventFilter) bool {
|
||||||
|
if !a.Kinds.Equals(b.Kinds) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.IDs.Equals(b.IDs) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.Authors.Equals(b.Authors) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.TagE.Equals(b.TagE) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if !a.TagP.Equals(b.TagP) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Since != b.Since {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Until != b.Until {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
@ -1,92 +0,0 @@
|
|||||||
package filter
|
|
||||||
|
|
||||||
import "github.com/fiatjaf/go-nostr/event"
|
|
||||||
|
|
||||||
type EventFilters []EventFilter
|
|
||||||
|
|
||||||
type EventFilter struct {
|
|
||||||
IDs []string `json:"ids,omitempty"`
|
|
||||||
Kinds []int `json:"kinds,omitempty"`
|
|
||||||
Authors []string `json:"authors,omitempty"`
|
|
||||||
Since uint32 `json:"since,omitempty"`
|
|
||||||
Until uint32 `json:"until,omitempty"`
|
|
||||||
TagE []string `json:"#e,omitempty"`
|
|
||||||
TagP []string `json:"#p,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (eff EventFilters) Match(event *event.Event) bool {
|
|
||||||
for _, filter := range eff {
|
|
||||||
if filter.Matches(event) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ef EventFilter) Matches(event *event.Event) bool {
|
|
||||||
if event == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ef.IDs != nil && !stringsContain(ef.IDs, event.ID) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ef.Kinds != nil && !intsContain(ef.Kinds, event.Kind) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ef.Authors != nil && !stringsContain(ef.Authors, event.PubKey) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ef.TagE != nil && !containsAnyTag("e", event.Tags, ef.TagE) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ef.TagP != nil && !containsAnyTag("p", event.Tags, ef.TagP) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ef.Since != 0 && event.CreatedAt < ef.Since {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if ef.Until != 0 && event.CreatedAt >= ef.Until {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func Equal(a EventFilter, b EventFilter) bool {
|
|
||||||
if !intsEqual(a.Kinds, b.Kinds) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !stringsEqual(a.IDs, b.IDs) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !stringsEqual(a.Authors, b.Authors) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !stringsEqual(a.TagE, b.TagE) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !stringsEqual(a.TagP, b.TagP) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Since != b.Since {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if a.Until != b.Until {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
@ -1,8 +1,9 @@
|
|||||||
package filter
|
package nostr
|
||||||
|
|
||||||
import "github.com/fiatjaf/go-nostr/event"
|
type StringList []string
|
||||||
|
type IntList []int
|
||||||
|
|
||||||
func stringsEqual(as, bs []string) bool {
|
func (as StringList) Equals(bs StringList) bool {
|
||||||
if len(as) != len(bs) {
|
if len(as) != len(bs) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -23,7 +24,7 @@ func stringsEqual(as, bs []string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func intsEqual(as, bs []int) bool {
|
func (as IntList) Equals(bs IntList) bool {
|
||||||
if len(as) != len(bs) {
|
if len(as) != len(bs) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -44,7 +45,7 @@ func intsEqual(as, bs []int) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringsContain(haystack []string, needle string) bool {
|
func (haystack StringList) Contains(needle string) bool {
|
||||||
for _, hay := range haystack {
|
for _, hay := range haystack {
|
||||||
if hay == needle {
|
if hay == needle {
|
||||||
return true
|
return true
|
||||||
@ -53,7 +54,7 @@ func stringsContain(haystack []string, needle string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func intsContain(haystack []int, needle int) bool {
|
func (haystack IntList) Contains(needle int) bool {
|
||||||
for _, hay := range haystack {
|
for _, hay := range haystack {
|
||||||
if hay == needle {
|
if hay == needle {
|
||||||
return true
|
return true
|
||||||
@ -61,27 +62,3 @@ func intsContain(haystack []int, needle int) bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func containsAnyTag(tagName string, tags event.Tags, values []string) bool {
|
|
||||||
for _, tag := range tags {
|
|
||||||
if len(tag) < 2 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTagName, ok := tag[0].(string)
|
|
||||||
if !ok || currentTagName != tagName {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
currentTagValue, ok := tag[1].(string)
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if stringsContain(values, currentTagValue) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
package nostrutils
|
package nostr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/url"
|
"net/url"
|
@ -1,4 +1,4 @@
|
|||||||
package relaypool
|
package nostr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@ -10,23 +10,31 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/fiatjaf/bip340"
|
"github.com/fiatjaf/bip340"
|
||||||
"github.com/fiatjaf/go-nostr/event"
|
|
||||||
"github.com/fiatjaf/go-nostr/filter"
|
|
||||||
nostrutils "github.com/fiatjaf/go-nostr/utils"
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PublishStatusSent = 0
|
||||||
|
PublishStatusFailed = -1
|
||||||
|
PublishStatusSucceeded = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
type PublishStatus struct {
|
||||||
|
Relay string
|
||||||
|
Status int
|
||||||
|
}
|
||||||
|
|
||||||
type RelayPool struct {
|
type RelayPool struct {
|
||||||
SecretKey *string
|
SecretKey *string
|
||||||
|
|
||||||
Relays map[string]Policy
|
Relays map[string]RelayPoolPolicy
|
||||||
websockets map[string]*websocket.Conn
|
websockets map[string]*websocket.Conn
|
||||||
subscriptions map[string]*Subscription
|
subscriptions map[string]*Subscription
|
||||||
|
|
||||||
Notices chan *NoticeMessage
|
Notices chan *NoticeMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
type Policy struct {
|
type RelayPoolPolicy struct {
|
||||||
SimplePolicy
|
SimplePolicy
|
||||||
ReadSpecific map[string]SimplePolicy
|
ReadSpecific map[string]SimplePolicy
|
||||||
}
|
}
|
||||||
@ -42,9 +50,9 @@ type NoticeMessage struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new RelayPool with no relays in it
|
// New creates a new RelayPool with no relays in it
|
||||||
func New() *RelayPool {
|
func NewRelayPool() *RelayPool {
|
||||||
return &RelayPool{
|
return &RelayPool{
|
||||||
Relays: make(map[string]Policy),
|
Relays: make(map[string]RelayPoolPolicy),
|
||||||
websockets: make(map[string]*websocket.Conn),
|
websockets: make(map[string]*websocket.Conn),
|
||||||
subscriptions: make(map[string]*Subscription),
|
subscriptions: make(map[string]*Subscription),
|
||||||
|
|
||||||
@ -54,17 +62,17 @@ func New() *RelayPool {
|
|||||||
|
|
||||||
// Add adds a new relay to the pool, if policy is nil, it will be a simple
|
// Add adds a new relay to the pool, if policy is nil, it will be a simple
|
||||||
// read+write policy.
|
// read+write policy.
|
||||||
func (r *RelayPool) Add(url string, policy *Policy) error {
|
func (r *RelayPool) Add(url string, policy *RelayPoolPolicy) error {
|
||||||
if policy == nil {
|
if policy == nil {
|
||||||
policy = &Policy{SimplePolicy: SimplePolicy{Read: true, Write: true}}
|
policy = &RelayPoolPolicy{SimplePolicy: SimplePolicy{Read: true, Write: true}}
|
||||||
}
|
}
|
||||||
|
|
||||||
nm := nostrutils.NormalizeURL(url)
|
nm := NormalizeURL(url)
|
||||||
if nm == "" {
|
if nm == "" {
|
||||||
return fmt.Errorf("invalid relay URL '%s'", url)
|
return fmt.Errorf("invalid relay URL '%s'", url)
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, _, err := websocket.DefaultDialer.Dial(nostrutils.NormalizeURL(url), nil)
|
conn, _, err := websocket.DefaultDialer.Dial(NormalizeURL(url), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error opening websocket to '%s': %w", nm, err)
|
return fmt.Errorf("error opening websocket to '%s': %w", nm, err)
|
||||||
}
|
}
|
||||||
@ -120,7 +128,7 @@ func (r *RelayPool) Add(url string, policy *Policy) error {
|
|||||||
var channel string
|
var channel string
|
||||||
json.Unmarshal(jsonMessage[1], &channel)
|
json.Unmarshal(jsonMessage[1], &channel)
|
||||||
if subscription, ok := r.subscriptions[channel]; ok {
|
if subscription, ok := r.subscriptions[channel]; ok {
|
||||||
var event event.Event
|
var event Event
|
||||||
json.Unmarshal(jsonMessage[2], &event)
|
json.Unmarshal(jsonMessage[2], &event)
|
||||||
|
|
||||||
// check signature of all received events, ignore invalid
|
// check signature of all received events, ignore invalid
|
||||||
@ -148,7 +156,7 @@ func (r *RelayPool) Add(url string, policy *Policy) error {
|
|||||||
|
|
||||||
// Remove removes a relay from the pool.
|
// Remove removes a relay from the pool.
|
||||||
func (r *RelayPool) Remove(url string) {
|
func (r *RelayPool) Remove(url string) {
|
||||||
nm := nostrutils.NormalizeURL(url)
|
nm := NormalizeURL(url)
|
||||||
|
|
||||||
for _, sub := range r.subscriptions {
|
for _, sub := range r.subscriptions {
|
||||||
sub.removeRelay(nm)
|
sub.removeRelay(nm)
|
||||||
@ -161,7 +169,7 @@ func (r *RelayPool) Remove(url string) {
|
|||||||
delete(r.websockets, nm)
|
delete(r.websockets, nm)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RelayPool) Sub(filters filter.EventFilters) *Subscription {
|
func (r *RelayPool) Sub(filters EventFilters) *Subscription {
|
||||||
random := make([]byte, 7)
|
random := make([]byte, 7)
|
||||||
rand.Read(random)
|
rand.Read(random)
|
||||||
|
|
||||||
@ -175,14 +183,14 @@ func (r *RelayPool) Sub(filters filter.EventFilters) *Subscription {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
subscription.Events = make(chan EventMessage)
|
subscription.Events = make(chan EventMessage)
|
||||||
subscription.UniqueEvents = make(chan event.Event)
|
subscription.UniqueEvents = make(chan Event)
|
||||||
r.subscriptions[subscription.channel] = &subscription
|
r.subscriptions[subscription.channel] = &subscription
|
||||||
|
|
||||||
subscription.Sub(filters)
|
subscription.Sub(filters)
|
||||||
return &subscription
|
return &subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RelayPool) PublishEvent(evt *event.Event) (*event.Event, chan PublishStatus, error) {
|
func (r *RelayPool) PublishEvent(evt *Event) (*Event, chan PublishStatus, error) {
|
||||||
status := make(chan PublishStatus, 1)
|
status := make(chan PublishStatus, 1)
|
||||||
|
|
||||||
if r.SecretKey == nil && (evt.PubKey == "" || evt.Sig == "") {
|
if r.SecretKey == nil && (evt.PubKey == "" || evt.Sig == "") {
|
||||||
@ -213,7 +221,7 @@ func (r *RelayPool) PublishEvent(evt *event.Event) (*event.Event, chan PublishSt
|
|||||||
}
|
}
|
||||||
status <- PublishStatus{relay, PublishStatusSent}
|
status <- PublishStatus{relay, PublishStatusSent}
|
||||||
|
|
||||||
subscription := r.Sub(filter.EventFilters{{ID: evt.ID}})
|
subscription := r.Sub(EventFilters{EventFilter{IDs: []string{evt.ID}}})
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case event := <-subscription.UniqueEvents:
|
case event := <-subscription.UniqueEvents:
|
@ -1,12 +0,0 @@
|
|||||||
package relaypool
|
|
||||||
|
|
||||||
const (
|
|
||||||
PublishStatusSent = 0
|
|
||||||
PublishStatusFailed = -1
|
|
||||||
PublishStatusSucceeded = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
type PublishStatus struct {
|
|
||||||
Relay string
|
|
||||||
Status int
|
|
||||||
}
|
|
@ -1,8 +1,6 @@
|
|||||||
package relaypool
|
package nostr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/fiatjaf/go-nostr/event"
|
|
||||||
"github.com/fiatjaf/go-nostr/filter"
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -10,15 +8,15 @@ type Subscription struct {
|
|||||||
channel string
|
channel string
|
||||||
relays map[string]*websocket.Conn
|
relays map[string]*websocket.Conn
|
||||||
|
|
||||||
filters filter.EventFilters
|
filters EventFilters
|
||||||
Events chan EventMessage
|
Events chan EventMessage
|
||||||
|
|
||||||
started bool
|
started bool
|
||||||
UniqueEvents chan event.Event
|
UniqueEvents chan Event
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventMessage struct {
|
type EventMessage struct {
|
||||||
Event event.Event
|
Event Event
|
||||||
Relay string
|
Relay string
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,7 +36,7 @@ func (subscription Subscription) Unsub() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (subscription Subscription) Sub(filters filter.EventFilters) {
|
func (subscription Subscription) Sub(filters EventFilters) {
|
||||||
for _, ws := range subscription.relays {
|
for _, ws := range subscription.relays {
|
||||||
message := []interface{}{
|
message := []interface{}{
|
||||||
"REQ",
|
"REQ",
|
49
tags.go
Normal file
49
tags.go
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package nostr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Tags []Tag
|
||||||
|
type Tag []interface{}
|
||||||
|
|
||||||
|
func (t *Tags) Scan(src interface{}) error {
|
||||||
|
var jtags []byte = make([]byte, 0)
|
||||||
|
|
||||||
|
switch v := src.(type) {
|
||||||
|
case []byte:
|
||||||
|
jtags = v
|
||||||
|
case string:
|
||||||
|
jtags = []byte(v)
|
||||||
|
default:
|
||||||
|
return errors.New("couldn't scan tags, it's not a json string")
|
||||||
|
}
|
||||||
|
|
||||||
|
json.Unmarshal(jtags, &t)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tags Tags) ContainsAny(tagName string, values StringList) bool {
|
||||||
|
for _, tag := range tags {
|
||||||
|
if len(tag) < 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTagName, ok := tag[0].(string)
|
||||||
|
if !ok || currentTagName != tagName {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
currentTagValue, ok := tag[1].(string)
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if values.Contains(currentTagValue) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
Reference in New Issue
Block a user