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 }