github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/swarm/network/stream/stream.go (about)

     1  
     2  //此源码被清华学神尹成大魔王专业翻译分析并修改
     3  //尹成QQ77025077
     4  //尹成微信18510341407
     5  //尹成所在QQ群721929980
     6  //尹成邮箱 yinc13@mails.tsinghua.edu.cn
     7  //尹成毕业于清华大学,微软区块链领域全球最有价值专家
     8  //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620
     9  //
    10  //
    11  //
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  
    25  package stream
    26  
    27  import (
    28  	"context"
    29  	"fmt"
    30  	"math"
    31  	"sync"
    32  	"time"
    33  
    34  	"github.com/ethereum/go-ethereum/metrics"
    35  	"github.com/ethereum/go-ethereum/p2p"
    36  	"github.com/ethereum/go-ethereum/p2p/discover"
    37  	"github.com/ethereum/go-ethereum/p2p/protocols"
    38  	"github.com/ethereum/go-ethereum/rpc"
    39  	"github.com/ethereum/go-ethereum/swarm/log"
    40  	"github.com/ethereum/go-ethereum/swarm/network"
    41  	"github.com/ethereum/go-ethereum/swarm/network/stream/intervals"
    42  	"github.com/ethereum/go-ethereum/swarm/pot"
    43  	"github.com/ethereum/go-ethereum/swarm/spancontext"
    44  	"github.com/ethereum/go-ethereum/swarm/state"
    45  	"github.com/ethereum/go-ethereum/swarm/storage"
    46  	opentracing "github.com/opentracing/opentracing-go"
    47  )
    48  
    49  const (
    50  	Low uint8 = iota
    51  	Mid
    52  	High
    53  	Top
    54  PriorityQueue         //
    55  PriorityQueueCap = 32 //
    56  	HashSize         = 32
    57  )
    58  
    59  //
    60  type Registry struct {
    61  	api            *API
    62  	addr           *network.BzzAddr
    63  	skipCheck      bool
    64  	clientMu       sync.RWMutex
    65  	serverMu       sync.RWMutex
    66  	peersMu        sync.RWMutex
    67  	serverFuncs    map[string]func(*Peer, string, bool) (Server, error)
    68  	clientFuncs    map[string]func(*Peer, string, bool) (Client, error)
    69  	peers          map[discover.NodeID]*Peer
    70  	delivery       *Delivery
    71  	intervalsStore state.Store
    72  	doRetrieve     bool
    73  }
    74  
    75  //
    76  type RegistryOptions struct {
    77  	SkipCheck       bool
    78  	DoSync          bool
    79  	DoRetrieve      bool
    80  	SyncUpdateDelay time.Duration
    81  }
    82  
    83  //
    84  func NewRegistry(addr *network.BzzAddr, delivery *Delivery, db *storage.DBAPI, intervalsStore state.Store, options *RegistryOptions) *Registry {
    85  	if options == nil {
    86  		options = &RegistryOptions{}
    87  	}
    88  	if options.SyncUpdateDelay <= 0 {
    89  		options.SyncUpdateDelay = 15 * time.Second
    90  	}
    91  	streamer := &Registry{
    92  		addr:           addr,
    93  		skipCheck:      options.SkipCheck,
    94  		serverFuncs:    make(map[string]func(*Peer, string, bool) (Server, error)),
    95  		clientFuncs:    make(map[string]func(*Peer, string, bool) (Client, error)),
    96  		peers:          make(map[discover.NodeID]*Peer),
    97  		delivery:       delivery,
    98  		intervalsStore: intervalsStore,
    99  		doRetrieve:     options.DoRetrieve,
   100  	}
   101  	streamer.api = NewAPI(streamer)
   102  	delivery.getPeer = streamer.getPeer
   103  	streamer.RegisterServerFunc(swarmChunkServerStreamName, func(_ *Peer, _ string, _ bool) (Server, error) {
   104  		return NewSwarmChunkServer(delivery.db), nil
   105  	})
   106  	streamer.RegisterClientFunc(swarmChunkServerStreamName, func(p *Peer, t string, live bool) (Client, error) {
   107  		return NewSwarmSyncerClient(p, delivery.db, false, NewStream(swarmChunkServerStreamName, t, live))
   108  	})
   109  	RegisterSwarmSyncerServer(streamer, db)
   110  	RegisterSwarmSyncerClient(streamer, db)
   111  
   112  	if options.DoSync {
   113  //
   114  //
   115  //
   116  //
   117  //
   118  //
   119  		latestIntC := func(in <-chan int) <-chan int {
   120  			out := make(chan int, 1)
   121  
   122  			go func() {
   123  				defer close(out)
   124  
   125  				for i := range in {
   126  					select {
   127  					case <-out:
   128  					default:
   129  					}
   130  					out <- i
   131  				}
   132  			}()
   133  
   134  			return out
   135  		}
   136  
   137  		go func() {
   138  //
   139  			time.Sleep(options.SyncUpdateDelay)
   140  
   141  			kad := streamer.delivery.overlay.(*network.Kademlia)
   142  			depthC := latestIntC(kad.NeighbourhoodDepthC())
   143  			addressBookSizeC := latestIntC(kad.AddrCountC())
   144  
   145  //
   146  			streamer.updateSyncing()
   147  
   148  			for depth := range depthC {
   149  				log.Debug("Kademlia neighbourhood depth change", "depth", depth)
   150  
   151  //
   152  //
   153  //
   154  				timer := time.NewTimer(options.SyncUpdateDelay)
   155  //
   156  //
   157  				maxTimer := time.NewTimer(3 * time.Minute)
   158  			loop:
   159  				for {
   160  					select {
   161  					case <-maxTimer.C:
   162  //
   163  						log.Trace("Sync subscriptions update on hard timeout")
   164  //
   165  						streamer.updateSyncing()
   166  						break loop
   167  					case <-timer.C:
   168  //
   169  //
   170  						log.Trace("Sync subscriptions update")
   171  //
   172  						streamer.updateSyncing()
   173  						break loop
   174  					case size := <-addressBookSizeC:
   175  						log.Trace("Kademlia address book size changed on depth change", "size", size)
   176  //
   177  //
   178  						if !timer.Stop() {
   179  							<-timer.C
   180  						}
   181  						timer.Reset(options.SyncUpdateDelay)
   182  					}
   183  				}
   184  				timer.Stop()
   185  				maxTimer.Stop()
   186  			}
   187  		}()
   188  	}
   189  
   190  	return streamer
   191  }
   192  
   193  //
   194  func (r *Registry) RegisterClientFunc(stream string, f func(*Peer, string, bool) (Client, error)) {
   195  	r.clientMu.Lock()
   196  	defer r.clientMu.Unlock()
   197  
   198  	r.clientFuncs[stream] = f
   199  }
   200  
   201  //
   202  func (r *Registry) RegisterServerFunc(stream string, f func(*Peer, string, bool) (Server, error)) {
   203  	r.serverMu.Lock()
   204  	defer r.serverMu.Unlock()
   205  
   206  	r.serverFuncs[stream] = f
   207  }
   208  
   209  //
   210  func (r *Registry) GetClientFunc(stream string) (func(*Peer, string, bool) (Client, error), error) {
   211  	r.clientMu.RLock()
   212  	defer r.clientMu.RUnlock()
   213  
   214  	f := r.clientFuncs[stream]
   215  	if f == nil {
   216  		return nil, fmt.Errorf("stream %v not registered", stream)
   217  	}
   218  	return f, nil
   219  }
   220  
   221  //
   222  func (r *Registry) GetServerFunc(stream string) (func(*Peer, string, bool) (Server, error), error) {
   223  	r.serverMu.RLock()
   224  	defer r.serverMu.RUnlock()
   225  
   226  	f := r.serverFuncs[stream]
   227  	if f == nil {
   228  		return nil, fmt.Errorf("stream %v not registered", stream)
   229  	}
   230  	return f, nil
   231  }
   232  
   233  func (r *Registry) RequestSubscription(peerId discover.NodeID, s Stream, h *Range, prio uint8) error {
   234  //
   235  	if _, err := r.GetServerFunc(s.Name); err != nil {
   236  		return err
   237  	}
   238  
   239  	peer := r.getPeer(peerId)
   240  	if peer == nil {
   241  		return fmt.Errorf("peer not found %v", peerId)
   242  	}
   243  
   244  	if _, err := peer.getServer(s); err != nil {
   245  		if e, ok := err.(*notFoundError); ok && e.t == "server" {
   246  //
   247  			log.Debug("RequestSubscription ", "peer", peerId, "stream", s, "history", h)
   248  			return peer.Send(context.TODO(), &RequestSubscriptionMsg{
   249  				Stream:   s,
   250  				History:  h,
   251  				Priority: prio,
   252  			})
   253  		}
   254  		return err
   255  	}
   256  	log.Trace("RequestSubscription: already subscribed", "peer", peerId, "stream", s, "history", h)
   257  	return nil
   258  }
   259  
   260  //
   261  func (r *Registry) Subscribe(peerId discover.NodeID, s Stream, h *Range, priority uint8) error {
   262  //
   263  	if _, err := r.GetClientFunc(s.Name); err != nil {
   264  		return err
   265  	}
   266  
   267  	peer := r.getPeer(peerId)
   268  	if peer == nil {
   269  		return fmt.Errorf("peer not found %v", peerId)
   270  	}
   271  
   272  	var to uint64
   273  	if !s.Live && h != nil {
   274  		to = h.To
   275  	}
   276  
   277  	err := peer.setClientParams(s, newClientParams(priority, to))
   278  	if err != nil {
   279  		return err
   280  	}
   281  
   282  	if s.Live && h != nil {
   283  		if err := peer.setClientParams(
   284  			getHistoryStream(s),
   285  			newClientParams(getHistoryPriority(priority), h.To),
   286  		); err != nil {
   287  			return err
   288  		}
   289  	}
   290  
   291  	msg := &SubscribeMsg{
   292  		Stream:   s,
   293  		History:  h,
   294  		Priority: priority,
   295  	}
   296  	log.Debug("Subscribe ", "peer", peerId, "stream", s, "history", h)
   297  
   298  	return peer.SendPriority(context.TODO(), msg, priority)
   299  }
   300  
   301  func (r *Registry) Unsubscribe(peerId discover.NodeID, s Stream) error {
   302  	peer := r.getPeer(peerId)
   303  	if peer == nil {
   304  		return fmt.Errorf("peer not found %v", peerId)
   305  	}
   306  
   307  	msg := &UnsubscribeMsg{
   308  		Stream: s,
   309  	}
   310  	log.Debug("Unsubscribe ", "peer", peerId, "stream", s)
   311  
   312  	if err := peer.Send(context.TODO(), msg); err != nil {
   313  		return err
   314  	}
   315  	return peer.removeClient(s)
   316  }
   317  
   318  //
   319  //
   320  func (r *Registry) Quit(peerId discover.NodeID, s Stream) error {
   321  	peer := r.getPeer(peerId)
   322  	if peer == nil {
   323  		log.Debug("stream quit: peer not found", "peer", peerId, "stream", s)
   324  //
   325  		return nil
   326  	}
   327  
   328  	msg := &QuitMsg{
   329  		Stream: s,
   330  	}
   331  	log.Debug("Quit ", "peer", peerId, "stream", s)
   332  
   333  	return peer.Send(context.TODO(), msg)
   334  }
   335  
   336  func (r *Registry) Retrieve(ctx context.Context, chunk *storage.Chunk) error {
   337  	var sp opentracing.Span
   338  	ctx, sp = spancontext.StartSpan(
   339  		ctx,
   340  		"registry.retrieve")
   341  	defer sp.Finish()
   342  
   343  	return r.delivery.RequestFromPeers(ctx, chunk.Addr[:], r.skipCheck)
   344  }
   345  
   346  func (r *Registry) NodeInfo() interface{} {
   347  	return nil
   348  }
   349  
   350  func (r *Registry) PeerInfo(id discover.NodeID) interface{} {
   351  	return nil
   352  }
   353  
   354  func (r *Registry) Close() error {
   355  	return r.intervalsStore.Close()
   356  }
   357  
   358  func (r *Registry) getPeer(peerId discover.NodeID) *Peer {
   359  	r.peersMu.RLock()
   360  	defer r.peersMu.RUnlock()
   361  
   362  	return r.peers[peerId]
   363  }
   364  
   365  func (r *Registry) setPeer(peer *Peer) {
   366  	r.peersMu.Lock()
   367  	r.peers[peer.ID()] = peer
   368  	metrics.GetOrRegisterGauge("registry.peers", nil).Update(int64(len(r.peers)))
   369  	r.peersMu.Unlock()
   370  }
   371  
   372  func (r *Registry) deletePeer(peer *Peer) {
   373  	r.peersMu.Lock()
   374  	delete(r.peers, peer.ID())
   375  	metrics.GetOrRegisterGauge("registry.peers", nil).Update(int64(len(r.peers)))
   376  	r.peersMu.Unlock()
   377  }
   378  
   379  func (r *Registry) peersCount() (c int) {
   380  	r.peersMu.Lock()
   381  	c = len(r.peers)
   382  	r.peersMu.Unlock()
   383  	return
   384  }
   385  
   386  //
   387  func (r *Registry) Run(p *network.BzzPeer) error {
   388  	sp := NewPeer(p.Peer, r)
   389  	r.setPeer(sp)
   390  	defer r.deletePeer(sp)
   391  	defer close(sp.quit)
   392  	defer sp.close()
   393  
   394  	if r.doRetrieve {
   395  		err := r.Subscribe(p.ID(), NewStream(swarmChunkServerStreamName, "", false), nil, Top)
   396  		if err != nil {
   397  			return err
   398  		}
   399  	}
   400  
   401  	return sp.Run(sp.HandleMsg)
   402  }
   403  
   404  //
   405  //
   406  //
   407  //
   408  func (r *Registry) updateSyncing() {
   409  //
   410  	kad := r.delivery.overlay.(*network.Kademlia)
   411  
   412  //
   413  //
   414  //
   415  	subs := make(map[discover.NodeID]map[Stream]struct{})
   416  	r.peersMu.RLock()
   417  	for id, peer := range r.peers {
   418  		peer.serverMu.RLock()
   419  		for stream := range peer.servers {
   420  			if stream.Name == "SYNC" {
   421  				if _, ok := subs[id]; !ok {
   422  					subs[id] = make(map[Stream]struct{})
   423  				}
   424  				subs[id][stream] = struct{}{}
   425  			}
   426  		}
   427  		peer.serverMu.RUnlock()
   428  	}
   429  	r.peersMu.RUnlock()
   430  
   431  //
   432  	kad.EachBin(r.addr.Over(), pot.DefaultPof(256), 0, func(conn network.OverlayConn, bin int) bool {
   433  		p := conn.(network.Peer)
   434  		log.Debug(fmt.Sprintf("Requesting subscription by: registry %s from peer %s for bin: %d", r.addr.ID(), p.ID(), bin))
   435  
   436  //
   437  		stream := NewStream("SYNC", FormatSyncBinKey(uint8(bin)), true)
   438  		if streams, ok := subs[p.ID()]; ok {
   439  //
   440  			delete(streams, stream)
   441  			delete(streams, getHistoryStream(stream))
   442  		}
   443  		err := r.RequestSubscription(p.ID(), stream, NewRange(0, 0), High)
   444  		if err != nil {
   445  			log.Debug("Request subscription", "err", err, "peer", p.ID(), "stream", stream)
   446  			return false
   447  		}
   448  		return true
   449  	})
   450  
   451  //
   452  	for id, streams := range subs {
   453  		if len(streams) == 0 {
   454  			continue
   455  		}
   456  		peer := r.getPeer(id)
   457  		if peer == nil {
   458  			continue
   459  		}
   460  		for stream := range streams {
   461  			log.Debug("Remove sync server", "peer", id, "stream", stream)
   462  			err := r.Quit(peer.ID(), stream)
   463  			if err != nil && err != p2p.ErrShuttingDown {
   464  				log.Error("quit", "err", err, "peer", peer.ID(), "stream", stream)
   465  			}
   466  		}
   467  	}
   468  }
   469  
   470  func (r *Registry) runProtocol(p *p2p.Peer, rw p2p.MsgReadWriter) error {
   471  	peer := protocols.NewPeer(p, rw, Spec)
   472  	bzzPeer := network.NewBzzTestPeer(peer, r.addr)
   473  	r.delivery.overlay.On(bzzPeer)
   474  	defer r.delivery.overlay.Off(bzzPeer)
   475  	return r.Run(bzzPeer)
   476  }
   477  
   478  //
   479  func (p *Peer) HandleMsg(ctx context.Context, msg interface{}) error {
   480  	switch msg := msg.(type) {
   481  
   482  	case *SubscribeMsg:
   483  		return p.handleSubscribeMsg(ctx, msg)
   484  
   485  	case *SubscribeErrorMsg:
   486  		return p.handleSubscribeErrorMsg(msg)
   487  
   488  	case *UnsubscribeMsg:
   489  		return p.handleUnsubscribeMsg(msg)
   490  
   491  	case *OfferedHashesMsg:
   492  		return p.handleOfferedHashesMsg(ctx, msg)
   493  
   494  	case *TakeoverProofMsg:
   495  		return p.handleTakeoverProofMsg(ctx, msg)
   496  
   497  	case *WantedHashesMsg:
   498  		return p.handleWantedHashesMsg(ctx, msg)
   499  
   500  	case *ChunkDeliveryMsg:
   501  		return p.streamer.delivery.handleChunkDeliveryMsg(ctx, p, msg)
   502  
   503  	case *RetrieveRequestMsg:
   504  		return p.streamer.delivery.handleRetrieveRequestMsg(ctx, p, msg)
   505  
   506  	case *RequestSubscriptionMsg:
   507  		return p.handleRequestSubscription(ctx, msg)
   508  
   509  	case *QuitMsg:
   510  		return p.handleQuitMsg(msg)
   511  
   512  	default:
   513  		return fmt.Errorf("unknown message type: %T", msg)
   514  	}
   515  }
   516  
   517  type server struct {
   518  	Server
   519  	stream       Stream
   520  	priority     uint8
   521  	currentBatch []byte
   522  }
   523  
   524  //
   525  type Server interface {
   526  	SetNextBatch(uint64, uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error)
   527  	GetData(context.Context, []byte) ([]byte, error)
   528  	Close()
   529  }
   530  
   531  type client struct {
   532  	Client
   533  	stream    Stream
   534  	priority  uint8
   535  	sessionAt uint64
   536  	to        uint64
   537  	next      chan error
   538  	quit      chan struct{}
   539  
   540  	intervalsKey   string
   541  	intervalsStore state.Store
   542  }
   543  
   544  func peerStreamIntervalsKey(p *Peer, s Stream) string {
   545  	return p.ID().String() + s.String()
   546  }
   547  
   548  func (c client) AddInterval(start, end uint64) (err error) {
   549  	i := &intervals.Intervals{}
   550  	err = c.intervalsStore.Get(c.intervalsKey, i)
   551  	if err != nil {
   552  		return err
   553  	}
   554  	i.Add(start, end)
   555  	return c.intervalsStore.Put(c.intervalsKey, i)
   556  }
   557  
   558  func (c client) NextInterval() (start, end uint64, err error) {
   559  	i := &intervals.Intervals{}
   560  	err = c.intervalsStore.Get(c.intervalsKey, i)
   561  	if err != nil {
   562  		return 0, 0, err
   563  	}
   564  	start, end = i.Next()
   565  	return start, end, nil
   566  }
   567  
   568  //
   569  type Client interface {
   570  	NeedData(context.Context, []byte) func()
   571  	BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error)
   572  	Close()
   573  }
   574  
   575  func (c *client) nextBatch(from uint64) (nextFrom uint64, nextTo uint64) {
   576  	if c.to > 0 && from >= c.to {
   577  		return 0, 0
   578  	}
   579  	if c.stream.Live {
   580  		return from, 0
   581  	} else if from >= c.sessionAt {
   582  		if c.to > 0 {
   583  			return from, c.to
   584  		}
   585  		return from, math.MaxUint64
   586  	}
   587  	nextFrom, nextTo, err := c.NextInterval()
   588  	if err != nil {
   589  		log.Error("next intervals", "stream", c.stream)
   590  		return
   591  	}
   592  	if nextTo > c.to {
   593  		nextTo = c.to
   594  	}
   595  	if nextTo == 0 {
   596  		nextTo = c.sessionAt
   597  	}
   598  	return
   599  }
   600  
   601  func (c *client) batchDone(p *Peer, req *OfferedHashesMsg, hashes []byte) error {
   602  	if tf := c.BatchDone(req.Stream, req.From, hashes, req.Root); tf != nil {
   603  		tp, err := tf()
   604  		if err != nil {
   605  			return err
   606  		}
   607  		if err := p.SendPriority(context.TODO(), tp, c.priority); err != nil {
   608  			return err
   609  		}
   610  		if c.to > 0 && tp.Takeover.End >= c.to {
   611  			return p.streamer.Unsubscribe(p.Peer.ID(), req.Stream)
   612  		}
   613  		return nil
   614  	}
   615  //
   616  	if err := c.AddInterval(req.From, req.To); err != nil {
   617  		return err
   618  	}
   619  	return nil
   620  }
   621  
   622  func (c *client) close() {
   623  	select {
   624  	case <-c.quit:
   625  	default:
   626  		close(c.quit)
   627  	}
   628  	c.Close()
   629  }
   630  
   631  //
   632  //
   633  type clientParams struct {
   634  	priority uint8
   635  	to       uint64
   636  //
   637  	clientCreatedC chan struct{}
   638  }
   639  
   640  func newClientParams(priority uint8, to uint64) *clientParams {
   641  	return &clientParams{
   642  		priority:       priority,
   643  		to:             to,
   644  		clientCreatedC: make(chan struct{}),
   645  	}
   646  }
   647  
   648  func (c *clientParams) waitClient(ctx context.Context) error {
   649  	select {
   650  	case <-ctx.Done():
   651  		return ctx.Err()
   652  	case <-c.clientCreatedC:
   653  		return nil
   654  	}
   655  }
   656  
   657  func (c *clientParams) clientCreated() {
   658  	close(c.clientCreatedC)
   659  }
   660  
   661  //
   662  var Spec = &protocols.Spec{
   663  	Name:       "stream",
   664  	Version:    5,
   665  	MaxMsgSize: 10 * 1024 * 1024,
   666  	Messages: []interface{}{
   667  		UnsubscribeMsg{},
   668  		OfferedHashesMsg{},
   669  		WantedHashesMsg{},
   670  		TakeoverProofMsg{},
   671  		SubscribeMsg{},
   672  		RetrieveRequestMsg{},
   673  		ChunkDeliveryMsg{},
   674  		SubscribeErrorMsg{},
   675  		RequestSubscriptionMsg{},
   676  		QuitMsg{},
   677  	},
   678  }
   679  
   680  func (r *Registry) Protocols() []p2p.Protocol {
   681  	return []p2p.Protocol{
   682  		{
   683  			Name:    Spec.Name,
   684  			Version: Spec.Version,
   685  			Length:  Spec.Length(),
   686  			Run:     r.runProtocol,
   687  //
   688  //
   689  		},
   690  	}
   691  }
   692  
   693  func (r *Registry) APIs() []rpc.API {
   694  	return []rpc.API{
   695  		{
   696  			Namespace: "stream",
   697  			Version:   "3.0",
   698  			Service:   r.api,
   699  			Public:    true,
   700  		},
   701  	}
   702  }
   703  
   704  func (r *Registry) Start(server *p2p.Server) error {
   705  	log.Info("Streamer started")
   706  	return nil
   707  }
   708  
   709  func (r *Registry) Stop() error {
   710  	return nil
   711  }
   712  
   713  type Range struct {
   714  	From, To uint64
   715  }
   716  
   717  func NewRange(from, to uint64) *Range {
   718  	return &Range{
   719  		From: from,
   720  		To:   to,
   721  	}
   722  }
   723  
   724  func (r *Range) String() string {
   725  	return fmt.Sprintf("%v-%v", r.From, r.To)
   726  }
   727  
   728  func getHistoryPriority(priority uint8) uint8 {
   729  	if priority == 0 {
   730  		return 0
   731  	}
   732  	return priority - 1
   733  }
   734  
   735  func getHistoryStream(s Stream) Stream {
   736  	return NewStream(s.Name, s.Key, false)
   737  }
   738  
   739  type API struct {
   740  	streamer *Registry
   741  }
   742  
   743  func NewAPI(r *Registry) *API {
   744  	return &API{
   745  		streamer: r,
   746  	}
   747  }
   748  
   749  func (api *API) SubscribeStream(peerId discover.NodeID, s Stream, history *Range, priority uint8) error {
   750  	return api.streamer.Subscribe(peerId, s, history, priority)
   751  }
   752  
   753  func (api *API) UnsubscribeStream(peerId discover.NodeID, s Stream) error {
   754  	return api.streamer.Unsubscribe(peerId, s)
   755  }