github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/routing/dht/providers.go (about)

     1  package dht
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess"
     7  	goprocessctx "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/goprocess/context"
     8  	key "github.com/ipfs/go-ipfs/blocks/key"
     9  	peer "github.com/ipfs/go-ipfs/p2p/peer"
    10  
    11  	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
    12  )
    13  
    14  type ProviderManager struct {
    15  	// all non channel fields are meant to be accessed only within
    16  	// the run method
    17  	providers map[key.Key]*providerSet
    18  	local     map[key.Key]struct{}
    19  	lpeer     peer.ID
    20  
    21  	getlocal chan chan []key.Key
    22  	newprovs chan *addProv
    23  	getprovs chan *getProv
    24  	period   time.Duration
    25  	proc     goprocess.Process
    26  }
    27  
    28  type providerSet struct {
    29  	providers []peer.ID
    30  	set       map[peer.ID]time.Time
    31  }
    32  
    33  type addProv struct {
    34  	k   key.Key
    35  	val peer.ID
    36  }
    37  
    38  type getProv struct {
    39  	k    key.Key
    40  	resp chan []peer.ID
    41  }
    42  
    43  func NewProviderManager(ctx context.Context, local peer.ID) *ProviderManager {
    44  	pm := new(ProviderManager)
    45  	pm.getprovs = make(chan *getProv)
    46  	pm.newprovs = make(chan *addProv)
    47  	pm.providers = make(map[key.Key]*providerSet)
    48  	pm.getlocal = make(chan chan []key.Key)
    49  	pm.local = make(map[key.Key]struct{})
    50  	pm.proc = goprocessctx.WithContext(ctx)
    51  	pm.proc.Go(func(p goprocess.Process) { pm.run() })
    52  
    53  	return pm
    54  }
    55  
    56  func (pm *ProviderManager) run() {
    57  	tick := time.NewTicker(time.Hour)
    58  	for {
    59  		select {
    60  		case np := <-pm.newprovs:
    61  			if np.val == pm.lpeer {
    62  				pm.local[np.k] = struct{}{}
    63  			}
    64  			provs, ok := pm.providers[np.k]
    65  			if !ok {
    66  				provs = newProviderSet()
    67  				pm.providers[np.k] = provs
    68  			}
    69  			provs.Add(np.val)
    70  
    71  		case gp := <-pm.getprovs:
    72  			var parr []peer.ID
    73  			provs, ok := pm.providers[gp.k]
    74  			if ok {
    75  				parr = provs.providers
    76  			}
    77  
    78  			gp.resp <- parr
    79  
    80  		case lc := <-pm.getlocal:
    81  			var keys []key.Key
    82  			for k := range pm.local {
    83  				keys = append(keys, k)
    84  			}
    85  			lc <- keys
    86  
    87  		case <-tick.C:
    88  			for _, provs := range pm.providers {
    89  				var filtered []peer.ID
    90  				for p, t := range provs.set {
    91  					if time.Now().Sub(t) > time.Hour*24 {
    92  						delete(provs.set, p)
    93  					} else {
    94  						filtered = append(filtered, p)
    95  					}
    96  				}
    97  				provs.providers = filtered
    98  			}
    99  
   100  		case <-pm.proc.Closing():
   101  			return
   102  		}
   103  	}
   104  }
   105  
   106  func (pm *ProviderManager) AddProvider(ctx context.Context, k key.Key, val peer.ID) {
   107  	prov := &addProv{
   108  		k:   k,
   109  		val: val,
   110  	}
   111  	select {
   112  	case pm.newprovs <- prov:
   113  	case <-ctx.Done():
   114  	}
   115  }
   116  
   117  func (pm *ProviderManager) GetProviders(ctx context.Context, k key.Key) []peer.ID {
   118  	gp := &getProv{
   119  		k:    k,
   120  		resp: make(chan []peer.ID, 1), // buffered to prevent sender from blocking
   121  	}
   122  	select {
   123  	case <-ctx.Done():
   124  		return nil
   125  	case pm.getprovs <- gp:
   126  	}
   127  	select {
   128  	case <-ctx.Done():
   129  		return nil
   130  	case peers := <-gp.resp:
   131  		return peers
   132  	}
   133  }
   134  
   135  func (pm *ProviderManager) GetLocal() []key.Key {
   136  	resp := make(chan []key.Key)
   137  	pm.getlocal <- resp
   138  	return <-resp
   139  }
   140  
   141  func newProviderSet() *providerSet {
   142  	return &providerSet{
   143  		set: make(map[peer.ID]time.Time),
   144  	}
   145  }
   146  
   147  func (ps *providerSet) Add(p peer.ID) {
   148  	_, found := ps.set[p]
   149  	if !found {
   150  		ps.providers = append(ps.providers, p)
   151  	}
   152  
   153  	ps.set[p] = time.Now()
   154  }