github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/swarm/network/stream/stream.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software MiningReward, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package stream
    18  
    19  import (
    20  	"context"
    21  	"errors"
    22  	"fmt"
    23  	"math"
    24  	"reflect"
    25  	"sync"
    26  	"time"
    27  
    28  	"github.com/insight-chain/inb-go/metrics"
    29  	"github.com/insight-chain/inb-go/p2p"
    30  	"github.com/insight-chain/inb-go/p2p/enode"
    31  	"github.com/insight-chain/inb-go/p2p/protocols"
    32  	"github.com/insight-chain/inb-go/rpc"
    33  	"github.com/insight-chain/inb-go/swarm/log"
    34  	"github.com/insight-chain/inb-go/swarm/network"
    35  	"github.com/insight-chain/inb-go/swarm/network/stream/intervals"
    36  	"github.com/insight-chain/inb-go/swarm/pot"
    37  	"github.com/insight-chain/inb-go/swarm/state"
    38  	"github.com/insight-chain/inb-go/swarm/storage"
    39  )
    40  
    41  const (
    42  	Low uint8 = iota
    43  	Mid
    44  	High
    45  	Top
    46  	PriorityQueue    = 4    // number of priority queues - Low, Mid, High, Top
    47  	PriorityQueueCap = 4096 // queue capacity
    48  	HashSize         = 32
    49  )
    50  
    51  //Enumerate options for syncing and retrieval
    52  type SyncingOption int
    53  type RetrievalOption int
    54  
    55  //Syncing options
    56  const (
    57  	//Syncing disabled
    58  	SyncingDisabled SyncingOption = iota
    59  	//Register the client and the server but not subscribe
    60  	SyncingRegisterOnly
    61  	//Both client and server funcs are registered, subscribe sent automatically
    62  	SyncingAutoSubscribe
    63  )
    64  
    65  const (
    66  	//Retrieval disabled. Used mostly for tests to isolate syncing features (i.e. syncing only)
    67  	RetrievalDisabled RetrievalOption = iota
    68  	//Only the client side of the retrieve request is registered.
    69  	//(light nodes do not serve retrieve requests)
    70  	//once the client is registered, subscription to retrieve request stream is always sent
    71  	RetrievalClientOnly
    72  	//Both client and server funcs are registered, subscribe sent automatically
    73  	RetrievalEnabled
    74  )
    75  
    76  // Registry registry for outgoing and incoming streamer constructors
    77  type Registry struct {
    78  	addr           enode.ID
    79  	api            *API
    80  	skipCheck      bool
    81  	clientMu       sync.RWMutex
    82  	serverMu       sync.RWMutex
    83  	peersMu        sync.RWMutex
    84  	serverFuncs    map[string]func(*Peer, string, bool) (Server, error)
    85  	clientFuncs    map[string]func(*Peer, string, bool) (Client, error)
    86  	peers          map[enode.ID]*Peer
    87  	delivery       *Delivery
    88  	intervalsStore state.Store
    89  	autoRetrieval  bool //automatically subscribe to retrieve request stream
    90  	maxPeerServers int
    91  	spec           *protocols.Spec   //this protocol's spec
    92  	balance        protocols.Balance //implements protocols.Balance, for accounting
    93  	prices         protocols.Prices  //implements protocols.Prices, provides prices to accounting
    94  }
    95  
    96  // RegistryOptions holds optional values for NewRegistry constructor.
    97  type RegistryOptions struct {
    98  	SkipCheck       bool
    99  	Syncing         SyncingOption   //Defines syncing behavior
   100  	Retrieval       RetrievalOption //Defines retrieval behavior
   101  	SyncUpdateDelay time.Duration
   102  	MaxPeerServers  int // The limit of servers for each peer in registry
   103  }
   104  
   105  // NewRegistry is Streamer constructor
   106  func NewRegistry(localID enode.ID, delivery *Delivery, syncChunkStore storage.SyncChunkStore, intervalsStore state.Store, options *RegistryOptions, balance protocols.Balance) *Registry {
   107  	if options == nil {
   108  		options = &RegistryOptions{}
   109  	}
   110  	if options.SyncUpdateDelay <= 0 {
   111  		options.SyncUpdateDelay = 15 * time.Second
   112  	}
   113  	//check if retriaval has been disabled
   114  	retrieval := options.Retrieval != RetrievalDisabled
   115  
   116  	streamer := &Registry{
   117  		addr:           localID,
   118  		skipCheck:      options.SkipCheck,
   119  		serverFuncs:    make(map[string]func(*Peer, string, bool) (Server, error)),
   120  		clientFuncs:    make(map[string]func(*Peer, string, bool) (Client, error)),
   121  		peers:          make(map[enode.ID]*Peer),
   122  		delivery:       delivery,
   123  		intervalsStore: intervalsStore,
   124  		autoRetrieval:  retrieval,
   125  		maxPeerServers: options.MaxPeerServers,
   126  		balance:        balance,
   127  	}
   128  	streamer.setupSpec()
   129  
   130  	streamer.api = NewAPI(streamer)
   131  	delivery.getPeer = streamer.getPeer
   132  
   133  	//if retrieval is enabled, register the server func, so that retrieve requests will be served (non-light nodes only)
   134  	if options.Retrieval == RetrievalEnabled {
   135  		streamer.RegisterServerFunc(swarmChunkServerStreamName, func(_ *Peer, _ string, live bool) (Server, error) {
   136  			if !live {
   137  				return nil, errors.New("only live retrieval requests supported")
   138  			}
   139  			return NewSwarmChunkServer(delivery.chunkStore), nil
   140  		})
   141  	}
   142  
   143  	//if retrieval is not disabled, register the client func (both light nodes and normal nodes can issue retrieve requests)
   144  	if options.Retrieval != RetrievalDisabled {
   145  		streamer.RegisterClientFunc(swarmChunkServerStreamName, func(p *Peer, t string, live bool) (Client, error) {
   146  			return NewSwarmSyncerClient(p, syncChunkStore, NewStream(swarmChunkServerStreamName, t, live))
   147  		})
   148  	}
   149  
   150  	//If syncing is not disabled, the syncing functions are registered (both client and server)
   151  	if options.Syncing != SyncingDisabled {
   152  		RegisterSwarmSyncerServer(streamer, syncChunkStore)
   153  		RegisterSwarmSyncerClient(streamer, syncChunkStore)
   154  	}
   155  
   156  	//if syncing is set to automatically subscribe to the syncing stream, start the subscription process
   157  	if options.Syncing == SyncingAutoSubscribe {
   158  		// latestIntC function ensures that
   159  		//   - receiving from the in chan is not blocked by processing inside the for loop
   160  		// 	 - the latest int value is delivered to the loop after the processing is done
   161  		// In context of NeighbourhoodDepthC:
   162  		// after the syncing is done updating inside the loop, we do not need to update on the intermediate
   163  		// depth changes, only to the latest one
   164  		latestIntC := func(in <-chan int) <-chan int {
   165  			out := make(chan int, 1)
   166  
   167  			go func() {
   168  				defer close(out)
   169  
   170  				for i := range in {
   171  					select {
   172  					case <-out:
   173  					default:
   174  					}
   175  					out <- i
   176  				}
   177  			}()
   178  
   179  			return out
   180  		}
   181  
   182  		go func() {
   183  			// wait for kademlia table to be healthy
   184  			time.Sleep(options.SyncUpdateDelay)
   185  
   186  			kad := streamer.delivery.kad
   187  			depthC := latestIntC(kad.NeighbourhoodDepthC())
   188  			addressBookSizeC := latestIntC(kad.AddrCountC())
   189  
   190  			// initial requests for syncing subscription to peers
   191  			streamer.updateSyncing()
   192  
   193  			for depth := range depthC {
   194  				log.Debug("Kademlia neighbourhood depth change", "depth", depth)
   195  
   196  				// Prevent too early sync subscriptions by waiting until there are no
   197  				// new peers connecting. Sync streams updating will be done after no
   198  				// peers are connected for at least SyncUpdateDelay period.
   199  				timer := time.NewTimer(options.SyncUpdateDelay)
   200  				// Hard limit to sync update delay, preventing long delays
   201  				// on a very dynamic network
   202  				maxTimer := time.NewTimer(3 * time.Minute)
   203  			loop:
   204  				for {
   205  					select {
   206  					case <-maxTimer.C:
   207  						// force syncing update when a hard timeout is reached
   208  						log.Trace("Sync subscriptions update on hard timeout")
   209  						// request for syncing subscription to new peers
   210  						streamer.updateSyncing()
   211  						break loop
   212  					case <-timer.C:
   213  						// start syncing as no new peers has been added to kademlia
   214  						// for some time
   215  						log.Trace("Sync subscriptions update")
   216  						// request for syncing subscription to new peers
   217  						streamer.updateSyncing()
   218  						break loop
   219  					case size := <-addressBookSizeC:
   220  						log.Trace("Kademlia address book size changed on depth change", "size", size)
   221  						// new peers has been added to kademlia,
   222  						// reset the timer to prevent early sync subscriptions
   223  						if !timer.Stop() {
   224  							<-timer.C
   225  						}
   226  						timer.Reset(options.SyncUpdateDelay)
   227  					}
   228  				}
   229  				timer.Stop()
   230  				maxTimer.Stop()
   231  			}
   232  		}()
   233  	}
   234  
   235  	return streamer
   236  }
   237  
   238  //we need to construct a spec instance per node instance
   239  func (r *Registry) setupSpec() {
   240  	//first create the "bare" spec
   241  	r.createSpec()
   242  	//if balance is nil, this node has been started without swap support (swapEnabled flag is false)
   243  	if r.balance != nil && !reflect.ValueOf(r.balance).IsNil() {
   244  		//swap is enabled, so setup the hook
   245  		r.spec.Hook = protocols.NewAccounting(r.balance, r.prices)
   246  	}
   247  }
   248  
   249  // RegisterClient registers an incoming streamer constructor
   250  func (r *Registry) RegisterClientFunc(stream string, f func(*Peer, string, bool) (Client, error)) {
   251  	r.clientMu.Lock()
   252  	defer r.clientMu.Unlock()
   253  
   254  	r.clientFuncs[stream] = f
   255  }
   256  
   257  // RegisterServer registers an outgoing streamer constructor
   258  func (r *Registry) RegisterServerFunc(stream string, f func(*Peer, string, bool) (Server, error)) {
   259  	r.serverMu.Lock()
   260  	defer r.serverMu.Unlock()
   261  
   262  	r.serverFuncs[stream] = f
   263  }
   264  
   265  // GetClient accessor for incoming streamer constructors
   266  func (r *Registry) GetClientFunc(stream string) (func(*Peer, string, bool) (Client, error), error) {
   267  	r.clientMu.RLock()
   268  	defer r.clientMu.RUnlock()
   269  
   270  	f := r.clientFuncs[stream]
   271  	if f == nil {
   272  		return nil, fmt.Errorf("stream %v not registered", stream)
   273  	}
   274  	return f, nil
   275  }
   276  
   277  // GetServer accessor for incoming streamer constructors
   278  func (r *Registry) GetServerFunc(stream string) (func(*Peer, string, bool) (Server, error), error) {
   279  	r.serverMu.RLock()
   280  	defer r.serverMu.RUnlock()
   281  
   282  	f := r.serverFuncs[stream]
   283  	if f == nil {
   284  		return nil, fmt.Errorf("stream %v not registered", stream)
   285  	}
   286  	return f, nil
   287  }
   288  
   289  func (r *Registry) RequestSubscription(peerId enode.ID, s Stream, h *Range, prio uint8) error {
   290  	// check if the stream is registered
   291  	if _, err := r.GetServerFunc(s.Name); err != nil {
   292  		return err
   293  	}
   294  
   295  	peer := r.getPeer(peerId)
   296  	if peer == nil {
   297  		return fmt.Errorf("peer not found %v", peerId)
   298  	}
   299  
   300  	if _, err := peer.getServer(s); err != nil {
   301  		if e, ok := err.(*notFoundError); ok && e.t == "server" {
   302  			// request subscription only if the server for this stream is not created
   303  			log.Debug("RequestSubscription ", "peer", peerId, "stream", s, "history", h)
   304  			return peer.Send(context.TODO(), &RequestSubscriptionMsg{
   305  				Stream:   s,
   306  				History:  h,
   307  				Priority: prio,
   308  			})
   309  		}
   310  		return err
   311  	}
   312  	log.Trace("RequestSubscription: already subscribed", "peer", peerId, "stream", s, "history", h)
   313  	return nil
   314  }
   315  
   316  // Subscribe initiates the streamer
   317  func (r *Registry) Subscribe(peerId enode.ID, s Stream, h *Range, priority uint8) error {
   318  	// check if the stream is registered
   319  	if _, err := r.GetClientFunc(s.Name); err != nil {
   320  		return err
   321  	}
   322  
   323  	peer := r.getPeer(peerId)
   324  	if peer == nil {
   325  		return fmt.Errorf("peer not found %v", peerId)
   326  	}
   327  
   328  	var to uint64
   329  	if !s.Live && h != nil {
   330  		to = h.To
   331  	}
   332  
   333  	err := peer.setClientParams(s, newClientParams(priority, to))
   334  	if err != nil {
   335  		return err
   336  	}
   337  	if s.Live && h != nil {
   338  		if err := peer.setClientParams(
   339  			getHistoryStream(s),
   340  			newClientParams(getHistoryPriority(priority), h.To),
   341  		); err != nil {
   342  			return err
   343  		}
   344  	}
   345  
   346  	msg := &SubscribeMsg{
   347  		Stream:   s,
   348  		History:  h,
   349  		Priority: priority,
   350  	}
   351  	log.Debug("Subscribe ", "peer", peerId, "stream", s, "history", h)
   352  
   353  	return peer.SendPriority(context.TODO(), msg, priority)
   354  }
   355  
   356  func (r *Registry) Unsubscribe(peerId enode.ID, s Stream) error {
   357  	peer := r.getPeer(peerId)
   358  	if peer == nil {
   359  		return fmt.Errorf("peer not found %v", peerId)
   360  	}
   361  
   362  	msg := &UnsubscribeMsg{
   363  		Stream: s,
   364  	}
   365  	log.Debug("Unsubscribe ", "peer", peerId, "stream", s)
   366  
   367  	if err := peer.Send(context.TODO(), msg); err != nil {
   368  		return err
   369  	}
   370  	return peer.removeClient(s)
   371  }
   372  
   373  // Quit sends the QuitMsg to the peer to remove the
   374  // stream peer client and terminate the streaming.
   375  func (r *Registry) Quit(peerId enode.ID, s Stream) error {
   376  	peer := r.getPeer(peerId)
   377  	if peer == nil {
   378  		log.Debug("stream quit: peer not found", "peer", peerId, "stream", s)
   379  		// if the peer is not found, abort the request
   380  		return nil
   381  	}
   382  
   383  	msg := &QuitMsg{
   384  		Stream: s,
   385  	}
   386  	log.Debug("Quit ", "peer", peerId, "stream", s)
   387  
   388  	return peer.Send(context.TODO(), msg)
   389  }
   390  
   391  func (r *Registry) NodeInfo() interface{} {
   392  	return nil
   393  }
   394  
   395  func (r *Registry) PeerInfo(id enode.ID) interface{} {
   396  	return nil
   397  }
   398  
   399  func (r *Registry) Close() error {
   400  	return r.intervalsStore.Close()
   401  }
   402  
   403  func (r *Registry) getPeer(peerId enode.ID) *Peer {
   404  	r.peersMu.RLock()
   405  	defer r.peersMu.RUnlock()
   406  
   407  	return r.peers[peerId]
   408  }
   409  
   410  func (r *Registry) setPeer(peer *Peer) {
   411  	r.peersMu.Lock()
   412  	r.peers[peer.ID()] = peer
   413  	metrics.GetOrRegisterGauge("registry.peers", nil).Update(int64(len(r.peers)))
   414  	r.peersMu.Unlock()
   415  }
   416  
   417  func (r *Registry) deletePeer(peer *Peer) {
   418  	r.peersMu.Lock()
   419  	delete(r.peers, peer.ID())
   420  	metrics.GetOrRegisterGauge("registry.peers", nil).Update(int64(len(r.peers)))
   421  	r.peersMu.Unlock()
   422  }
   423  
   424  func (r *Registry) peersCount() (c int) {
   425  	r.peersMu.Lock()
   426  	c = len(r.peers)
   427  	r.peersMu.Unlock()
   428  	return
   429  }
   430  
   431  // Run protocol run function
   432  func (r *Registry) Run(p *network.BzzPeer) error {
   433  	sp := NewPeer(p.Peer, r)
   434  	r.setPeer(sp)
   435  	defer r.deletePeer(sp)
   436  	defer close(sp.quit)
   437  	defer sp.close()
   438  
   439  	if r.autoRetrieval && !p.LightNode {
   440  		err := r.Subscribe(p.ID(), NewStream(swarmChunkServerStreamName, "", true), nil, Top)
   441  		if err != nil {
   442  			return err
   443  		}
   444  	}
   445  
   446  	return sp.Run(sp.HandleMsg)
   447  }
   448  
   449  // updateSyncing subscribes to SYNC streams by iterating over the
   450  // kademlia connections and bins. If there are existing SYNC streams
   451  // and they are no longer required after iteration, request to Quit
   452  // them will be send to appropriate peers.
   453  func (r *Registry) updateSyncing() {
   454  	kad := r.delivery.kad
   455  	// map of all SYNC streams for all peers
   456  	// used at the and of the function to remove servers
   457  	// that are not needed anymore
   458  	subs := make(map[enode.ID]map[Stream]struct{})
   459  	r.peersMu.RLock()
   460  	for id, peer := range r.peers {
   461  		peer.serverMu.RLock()
   462  		for stream := range peer.servers {
   463  			if stream.Name == "SYNC" {
   464  				if _, ok := subs[id]; !ok {
   465  					subs[id] = make(map[Stream]struct{})
   466  				}
   467  				subs[id][stream] = struct{}{}
   468  			}
   469  		}
   470  		peer.serverMu.RUnlock()
   471  	}
   472  	r.peersMu.RUnlock()
   473  
   474  	// request subscriptions for all nodes and bins
   475  	kad.EachBin(r.addr[:], pot.DefaultPof(256), 0, func(p *network.Peer, bin int) bool {
   476  		log.Debug(fmt.Sprintf("Requesting subscription by: registry %s from peer %s for bin: %d", r.addr, p.ID(), bin))
   477  
   478  		// bin is always less then 256 and it is safe to convert it to type uint8
   479  		stream := NewStream("SYNC", FormatSyncBinKey(uint8(bin)), true)
   480  		if streams, ok := subs[p.ID()]; ok {
   481  			// delete live and history streams from the map, so that it won't be removed with a Quit request
   482  			delete(streams, stream)
   483  			delete(streams, getHistoryStream(stream))
   484  		}
   485  		err := r.RequestSubscription(p.ID(), stream, NewRange(0, 0), High)
   486  		if err != nil {
   487  			log.Debug("Request subscription", "err", err, "peer", p.ID(), "stream", stream)
   488  			return false
   489  		}
   490  		return true
   491  	})
   492  
   493  	// remove SYNC servers that do not need to be subscribed
   494  	for id, streams := range subs {
   495  		if len(streams) == 0 {
   496  			continue
   497  		}
   498  		peer := r.getPeer(id)
   499  		if peer == nil {
   500  			continue
   501  		}
   502  		for stream := range streams {
   503  			log.Debug("Remove sync server", "peer", id, "stream", stream)
   504  			err := r.Quit(peer.ID(), stream)
   505  			if err != nil && err != p2p.ErrShuttingDown {
   506  				log.Error("quit", "err", err, "peer", peer.ID(), "stream", stream)
   507  			}
   508  		}
   509  	}
   510  }
   511  
   512  func (r *Registry) runProtocol(p *p2p.Peer, rw p2p.MsgReadWriter) error {
   513  	peer := protocols.NewPeer(p, rw, r.spec)
   514  	bp := network.NewBzzPeer(peer)
   515  	np := network.NewPeer(bp, r.delivery.kad)
   516  	r.delivery.kad.On(np)
   517  	defer r.delivery.kad.Off(np)
   518  	return r.Run(bp)
   519  }
   520  
   521  // HandleMsg is the message handler that delegates incoming messages
   522  func (p *Peer) HandleMsg(ctx context.Context, msg interface{}) error {
   523  	switch msg := msg.(type) {
   524  
   525  	case *SubscribeMsg:
   526  		return p.handleSubscribeMsg(ctx, msg)
   527  
   528  	case *SubscribeErrorMsg:
   529  		return p.handleSubscribeErrorMsg(msg)
   530  
   531  	case *UnsubscribeMsg:
   532  		return p.handleUnsubscribeMsg(msg)
   533  
   534  	case *OfferedHashesMsg:
   535  		return p.handleOfferedHashesMsg(ctx, msg)
   536  
   537  	case *TakeoverProofMsg:
   538  		return p.handleTakeoverProofMsg(ctx, msg)
   539  
   540  	case *WantedHashesMsg:
   541  		return p.handleWantedHashesMsg(ctx, msg)
   542  
   543  	case *ChunkDeliveryMsgRetrieval:
   544  		//handling chunk delivery is the same for retrieval and syncing, so let's cast the msg
   545  		return p.streamer.delivery.handleChunkDeliveryMsg(ctx, p, ((*ChunkDeliveryMsg)(msg)))
   546  
   547  	case *ChunkDeliveryMsgSyncing:
   548  		//handling chunk delivery is the same for retrieval and syncing, so let's cast the msg
   549  		return p.streamer.delivery.handleChunkDeliveryMsg(ctx, p, ((*ChunkDeliveryMsg)(msg)))
   550  
   551  	case *RetrieveRequestMsg:
   552  		return p.streamer.delivery.handleRetrieveRequestMsg(ctx, p, msg)
   553  
   554  	case *RequestSubscriptionMsg:
   555  		return p.handleRequestSubscription(ctx, msg)
   556  
   557  	case *QuitMsg:
   558  		return p.handleQuitMsg(msg)
   559  
   560  	default:
   561  		return fmt.Errorf("unknown message type: %T", msg)
   562  	}
   563  }
   564  
   565  type server struct {
   566  	Server
   567  	stream       Stream
   568  	priority     uint8
   569  	currentBatch []byte
   570  	sessionIndex uint64
   571  }
   572  
   573  // setNextBatch adjusts passed interval based on session index and whether
   574  // stream is live or history. It calls Server SetNextBatch with adjusted
   575  // interval and returns batch hashes and their interval.
   576  func (s *server) setNextBatch(from, to uint64) ([]byte, uint64, uint64, *HandoverProof, error) {
   577  	if s.stream.Live {
   578  		if from == 0 {
   579  			from = s.sessionIndex
   580  		}
   581  		if to <= from || from >= s.sessionIndex {
   582  			to = math.MaxUint64
   583  		}
   584  	} else {
   585  		if (to < from && to != 0) || from > s.sessionIndex {
   586  			return nil, 0, 0, nil, nil
   587  		}
   588  		if to == 0 || to > s.sessionIndex {
   589  			to = s.sessionIndex
   590  		}
   591  	}
   592  	return s.SetNextBatch(from, to)
   593  }
   594  
   595  // Server interface for outgoing peer Streamer
   596  type Server interface {
   597  	// SessionIndex is called when a server is initialized
   598  	// to get the current cursor state of the stream data.
   599  	// Based on this index, live and history stream intervals
   600  	// will be adjusted before calling SetNextBatch.
   601  	SessionIndex() (uint64, error)
   602  	SetNextBatch(uint64, uint64) (hashes []byte, from uint64, to uint64, proof *HandoverProof, err error)
   603  	GetData(context.Context, []byte) ([]byte, error)
   604  	Close()
   605  }
   606  
   607  type client struct {
   608  	Client
   609  	stream    Stream
   610  	priority  uint8
   611  	sessionAt uint64
   612  	to        uint64
   613  	next      chan error
   614  	quit      chan struct{}
   615  
   616  	intervalsKey   string
   617  	intervalsStore state.Store
   618  }
   619  
   620  func peerStreamIntervalsKey(p *Peer, s Stream) string {
   621  	return p.ID().String() + s.String()
   622  }
   623  
   624  func (c client) AddInterval(start, end uint64) (err error) {
   625  	i := &intervals.Intervals{}
   626  	err = c.intervalsStore.Get(c.intervalsKey, i)
   627  	if err != nil {
   628  		return err
   629  	}
   630  	i.Add(start, end)
   631  	return c.intervalsStore.Put(c.intervalsKey, i)
   632  }
   633  
   634  func (c client) NextInterval() (start, end uint64, err error) {
   635  	i := &intervals.Intervals{}
   636  	err = c.intervalsStore.Get(c.intervalsKey, i)
   637  	if err != nil {
   638  		return 0, 0, err
   639  	}
   640  	start, end = i.Next()
   641  	return start, end, nil
   642  }
   643  
   644  // Client interface for incoming peer Streamer
   645  type Client interface {
   646  	NeedData(context.Context, []byte) func(context.Context) error
   647  	BatchDone(Stream, uint64, []byte, []byte) func() (*TakeoverProof, error)
   648  	Close()
   649  }
   650  
   651  func (c *client) nextBatch(from uint64) (nextFrom uint64, nextTo uint64) {
   652  	if c.to > 0 && from >= c.to {
   653  		return 0, 0
   654  	}
   655  	if c.stream.Live {
   656  		return from, 0
   657  	} else if from >= c.sessionAt {
   658  		if c.to > 0 {
   659  			return from, c.to
   660  		}
   661  		return from, math.MaxUint64
   662  	}
   663  	nextFrom, nextTo, err := c.NextInterval()
   664  	if err != nil {
   665  		log.Error("next intervals", "stream", c.stream)
   666  		return
   667  	}
   668  	if nextTo > c.to {
   669  		nextTo = c.to
   670  	}
   671  	if nextTo == 0 {
   672  		nextTo = c.sessionAt
   673  	}
   674  	return
   675  }
   676  
   677  func (c *client) batchDone(p *Peer, req *OfferedHashesMsg, hashes []byte) error {
   678  	if tf := c.BatchDone(req.Stream, req.From, hashes, req.Root); tf != nil {
   679  		tp, err := tf()
   680  		if err != nil {
   681  			return err
   682  		}
   683  		if err := p.SendPriority(context.TODO(), tp, c.priority); err != nil {
   684  			return err
   685  		}
   686  		if c.to > 0 && tp.Takeover.End >= c.to {
   687  			return p.streamer.Unsubscribe(p.Peer.ID(), req.Stream)
   688  		}
   689  		return nil
   690  	}
   691  	// TODO: make a test case for testing if the interval is added when the batch is done
   692  	if err := c.AddInterval(req.From, req.To); err != nil {
   693  		return err
   694  	}
   695  	return nil
   696  }
   697  
   698  func (c *client) close() {
   699  	select {
   700  	case <-c.quit:
   701  	default:
   702  		close(c.quit)
   703  	}
   704  	c.Close()
   705  }
   706  
   707  // clientParams store parameters for the new client
   708  // between a subscription and initial offered hashes request handling.
   709  type clientParams struct {
   710  	priority uint8
   711  	to       uint64
   712  	// signal when the client is created
   713  	clientCreatedC chan struct{}
   714  }
   715  
   716  func newClientParams(priority uint8, to uint64) *clientParams {
   717  	return &clientParams{
   718  		priority:       priority,
   719  		to:             to,
   720  		clientCreatedC: make(chan struct{}),
   721  	}
   722  }
   723  
   724  func (c *clientParams) waitClient(ctx context.Context) error {
   725  	select {
   726  	case <-ctx.Done():
   727  		return ctx.Err()
   728  	case <-c.clientCreatedC:
   729  		return nil
   730  	}
   731  }
   732  
   733  func (c *clientParams) clientCreated() {
   734  	close(c.clientCreatedC)
   735  }
   736  
   737  //GetSpec returns the streamer spec to callers
   738  //This used to be a global variable but for simulations with
   739  //multiple nodes its fields (notably the Hook) would be overwritten
   740  func (r *Registry) GetSpec() *protocols.Spec {
   741  	return r.spec
   742  }
   743  
   744  func (r *Registry) createSpec() {
   745  	// Spec is the spec of the streamer protocol
   746  	var spec = &protocols.Spec{
   747  		Name:       "stream",
   748  		Version:    8,
   749  		MaxMsgSize: 10 * 1024 * 1024,
   750  		Messages: []interface{}{
   751  			UnsubscribeMsg{},
   752  			OfferedHashesMsg{},
   753  			WantedHashesMsg{},
   754  			TakeoverProofMsg{},
   755  			SubscribeMsg{},
   756  			RetrieveRequestMsg{},
   757  			ChunkDeliveryMsgRetrieval{},
   758  			SubscribeErrorMsg{},
   759  			RequestSubscriptionMsg{},
   760  			QuitMsg{},
   761  			ChunkDeliveryMsgSyncing{},
   762  		},
   763  	}
   764  	r.spec = spec
   765  }
   766  
   767  func (r *Registry) Protocols() []p2p.Protocol {
   768  	return []p2p.Protocol{
   769  		{
   770  			Name:    r.spec.Name,
   771  			Version: r.spec.Version,
   772  			Length:  r.spec.Length(),
   773  			Run:     r.runProtocol,
   774  		},
   775  	}
   776  }
   777  
   778  func (r *Registry) APIs() []rpc.API {
   779  	return []rpc.API{
   780  		{
   781  			Namespace: "stream",
   782  			Version:   "3.0",
   783  			Service:   r.api,
   784  			Public:    true,
   785  		},
   786  	}
   787  }
   788  
   789  func (r *Registry) Start(server *p2p.Server) error {
   790  	log.Info("Streamer started")
   791  	return nil
   792  }
   793  
   794  func (r *Registry) Stop() error {
   795  	return nil
   796  }
   797  
   798  type Range struct {
   799  	From, To uint64
   800  }
   801  
   802  func NewRange(from, to uint64) *Range {
   803  	return &Range{
   804  		From: from,
   805  		To:   to,
   806  	}
   807  }
   808  
   809  func (r *Range) String() string {
   810  	return fmt.Sprintf("%v-%v", r.From, r.To)
   811  }
   812  
   813  func getHistoryPriority(priority uint8) uint8 {
   814  	if priority == 0 {
   815  		return 0
   816  	}
   817  	return priority - 1
   818  }
   819  
   820  func getHistoryStream(s Stream) Stream {
   821  	return NewStream(s.Name, s.Key, false)
   822  }
   823  
   824  type API struct {
   825  	streamer *Registry
   826  }
   827  
   828  func NewAPI(r *Registry) *API {
   829  	return &API{
   830  		streamer: r,
   831  	}
   832  }
   833  
   834  func (api *API) SubscribeStream(peerId enode.ID, s Stream, history *Range, priority uint8) error {
   835  	return api.streamer.Subscribe(peerId, s, history, priority)
   836  }
   837  
   838  func (api *API) UnsubscribeStream(peerId enode.ID, s Stream) error {
   839  	return api.streamer.Unsubscribe(peerId, s)
   840  }