interface.go raw

   1  package nostr
   2  
   3  import (
   4  	"context"
   5  	"errors"
   6  	"slices"
   7  )
   8  
   9  type RelayStore interface {
  10  	Publish(context.Context, Event) error
  11  	QueryEvents(context.Context, Filter) (chan *Event, error)
  12  	QuerySync(context.Context, Filter) ([]*Event, error)
  13  }
  14  
  15  var (
  16  	_ RelayStore = (*Relay)(nil)
  17  	_ RelayStore = (*MultiStore)(nil)
  18  )
  19  
  20  type MultiStore []RelayStore
  21  
  22  func (multi MultiStore) Publish(ctx context.Context, event Event) error {
  23  	errs := make([]error, len(multi))
  24  	for i, s := range multi {
  25  		errs[i] = s.Publish(ctx, event)
  26  	}
  27  	return errors.Join(errs...)
  28  }
  29  
  30  func (multi MultiStore) QueryEvents(ctx context.Context, filter Filter) (chan *Event, error) {
  31  	multich := make(chan *Event)
  32  
  33  	errs := make([]error, len(multi))
  34  	var good bool
  35  	for i, s := range multi {
  36  		ch, err := s.QueryEvents(ctx, filter)
  37  		errs[i] = err
  38  		if err == nil {
  39  			good = true
  40  			go func(ch chan *Event) {
  41  				for evt := range ch {
  42  					multich <- evt
  43  				}
  44  			}(ch)
  45  		}
  46  	}
  47  
  48  	if good {
  49  		return multich, nil
  50  	} else {
  51  		return nil, errors.Join(errs...)
  52  	}
  53  }
  54  
  55  func (multi MultiStore) QuerySync(ctx context.Context, filter Filter) ([]*Event, error) {
  56  	errs := make([]error, len(multi))
  57  	events := make([]*Event, 0, max(filter.Limit, 250))
  58  	for i, s := range multi {
  59  		res, err := s.QuerySync(ctx, filter)
  60  		errs[i] = err
  61  		events = append(events, res...)
  62  	}
  63  	slices.SortFunc(events, func(a, b *Event) int {
  64  		if b.CreatedAt > a.CreatedAt {
  65  			return 1
  66  		} else if b.CreatedAt < a.CreatedAt {
  67  			return -1
  68  		}
  69  		return 0
  70  	})
  71  	return events, errors.Join(errs...)
  72  }
  73