github.com/ethersphere/bee/v2@v2.2.0/pkg/topology/kademlia/mock/kademlia.go (about)

     1  // Copyright 2020 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package mock
     6  
     7  import (
     8  	"context"
     9  	"sync"
    10  	"time"
    11  
    12  	"github.com/ethersphere/bee/v2/pkg/p2p"
    13  	"github.com/ethersphere/bee/v2/pkg/swarm"
    14  	"github.com/ethersphere/bee/v2/pkg/topology"
    15  )
    16  
    17  type AddrTuple struct {
    18  	Addr swarm.Address // the peer address
    19  	PO   uint8         // the po
    20  }
    21  
    22  func WithEachPeerRevCalls(addrs ...AddrTuple) Option {
    23  	return optionFunc(func(m *Mock) {
    24  		for _, a := range addrs {
    25  			a := a
    26  			m.eachPeerRev = append(m.eachPeerRev, a)
    27  		}
    28  	})
    29  }
    30  
    31  func WithDepth(d uint8) Option {
    32  	return optionFunc(func(m *Mock) {
    33  		m.depth = d
    34  	})
    35  }
    36  
    37  func WithDepthCalls(d ...uint8) Option {
    38  	return optionFunc(func(m *Mock) {
    39  		m.depthReplies = d
    40  	})
    41  }
    42  
    43  type Mock struct {
    44  	mtx          sync.Mutex
    45  	peers        []swarm.Address
    46  	eachPeerRev  []AddrTuple
    47  	depth        uint8
    48  	depthReplies []uint8
    49  	depthCalls   int
    50  	trigs        []chan struct{}
    51  	trigMtx      sync.Mutex
    52  }
    53  
    54  func NewMockKademlia(o ...Option) *Mock {
    55  	m := &Mock{}
    56  	for _, v := range o {
    57  		v.apply(m)
    58  	}
    59  
    60  	return m
    61  }
    62  
    63  // AddPeers is called when a peers are added to the topology backlog
    64  // for further processing by connectivity strategy.
    65  func (m *Mock) AddPeers(addr ...swarm.Address) {
    66  	panic("not implemented") // TODO: Implement
    67  }
    68  
    69  func (m *Mock) ClosestPeer(addr swarm.Address, _ bool, _ topology.Select, skipPeers ...swarm.Address) (peerAddr swarm.Address, err error) {
    70  	panic("not implemented") // TODO: Implement
    71  }
    72  
    73  func (m *Mock) EachNeighbor(topology.EachPeerFunc) error {
    74  	panic("not implemented") // TODO: Implement
    75  }
    76  
    77  func (m *Mock) EachNeighborRev(topology.EachPeerFunc) error {
    78  	panic("not implemented") // TODO: Implement
    79  }
    80  
    81  func (m *Mock) UpdatePeerHealth(swarm.Address, bool, time.Duration) {
    82  	panic("not implemented") // TODO: Implement
    83  }
    84  
    85  // PeerIterator iterates from closest bin to farthest
    86  func (m *Mock) SetStorageRadius(uint8) {
    87  	panic("not implemented")
    88  }
    89  
    90  func (m *Mock) AddRevPeers(addrs ...AddrTuple) {
    91  	m.mtx.Lock()
    92  	defer m.mtx.Unlock()
    93  	for _, a := range addrs {
    94  		a := a
    95  		m.eachPeerRev = append(m.eachPeerRev, a)
    96  	}
    97  }
    98  
    99  // EachConnectedPeer iterates from closest bin to farthest
   100  func (m *Mock) EachConnectedPeer(f topology.EachPeerFunc, _ topology.Select) error {
   101  	m.mtx.Lock()
   102  	defer m.mtx.Unlock()
   103  
   104  	for i := len(m.peers) - 1; i > 0; i-- {
   105  		stop, _, err := f(m.peers[i], uint8(i))
   106  		if stop {
   107  			return nil
   108  		}
   109  		if err != nil {
   110  			return err
   111  		}
   112  	}
   113  	return nil
   114  }
   115  
   116  // EachPeerRev iterates from farthest bin to closest
   117  func (m *Mock) EachConnectedPeerRev(f topology.EachPeerFunc, _ topology.Select) error {
   118  	m.mtx.Lock()
   119  	defer m.mtx.Unlock()
   120  	for _, v := range m.eachPeerRev {
   121  		stop, _, err := f(v.Addr, v.PO)
   122  		if stop {
   123  			return nil
   124  		}
   125  		if err != nil {
   126  			return err
   127  		}
   128  	}
   129  	return nil
   130  }
   131  
   132  func (m *Mock) IsReachable() bool {
   133  	return true
   134  }
   135  
   136  func (m *Mock) NeighborhoodDepth() uint8 {
   137  	m.mtx.Lock()
   138  	defer m.mtx.Unlock()
   139  
   140  	m.depthCalls++
   141  	if len(m.depthReplies) > 0 {
   142  		return m.depthReplies[m.depthCalls]
   143  	}
   144  	return m.depth
   145  }
   146  
   147  // Connected is called when a peer dials in.
   148  func (m *Mock) Connected(_ context.Context, peer p2p.Peer, _ bool) error {
   149  	m.mtx.Lock()
   150  	m.peers = append(m.peers, peer.Address)
   151  	m.mtx.Unlock()
   152  	m.Trigger()
   153  	return nil
   154  }
   155  
   156  // Disconnected is called when a peer disconnects.
   157  func (m *Mock) Disconnected(peer p2p.Peer) {
   158  	m.mtx.Lock()
   159  	defer m.mtx.Unlock()
   160  
   161  	m.peers = swarm.RemoveAddress(m.peers, peer.Address)
   162  
   163  	m.Trigger()
   164  }
   165  
   166  func (m *Mock) Announce(_ context.Context, _ swarm.Address, _ bool) error {
   167  	return nil
   168  }
   169  
   170  func (m *Mock) AnnounceTo(_ context.Context, _, _ swarm.Address, _ bool) error {
   171  	return nil
   172  }
   173  
   174  func (m *Mock) SubscribeTopologyChange() (c <-chan struct{}, unsubscribe func()) {
   175  	channel := make(chan struct{}, 1)
   176  	var closeOnce sync.Once
   177  
   178  	m.trigMtx.Lock()
   179  	defer m.trigMtx.Unlock()
   180  	m.trigs = append(m.trigs, channel)
   181  
   182  	unsubscribe = func() {
   183  		m.trigMtx.Lock()
   184  		defer m.trigMtx.Unlock()
   185  
   186  		for i, c := range m.trigs {
   187  			if c == channel {
   188  				m.trigs = append(m.trigs[:i], m.trigs[i+1:]...)
   189  				break
   190  			}
   191  		}
   192  
   193  		closeOnce.Do(func() { close(channel) })
   194  	}
   195  
   196  	return channel, unsubscribe
   197  }
   198  
   199  func (m *Mock) Trigger() {
   200  	m.trigMtx.Lock()
   201  	defer m.trigMtx.Unlock()
   202  
   203  	for _, c := range m.trigs {
   204  		select {
   205  		case c <- struct{}{}:
   206  		default:
   207  		}
   208  	}
   209  }
   210  
   211  func (m *Mock) ResetPeers() {
   212  	m.mtx.Lock()
   213  	defer m.mtx.Unlock()
   214  	m.peers = nil
   215  	m.eachPeerRev = nil
   216  }
   217  
   218  func (d *Mock) Halt()        {}
   219  func (m *Mock) Close() error { return nil }
   220  
   221  func (m *Mock) Snapshot() *topology.KadParams {
   222  	panic("not implemented") // TODO: Implement
   223  }
   224  
   225  type Option interface {
   226  	apply(*Mock)
   227  }
   228  type optionFunc func(*Mock)
   229  
   230  func (f optionFunc) apply(r *Mock) { f(r) }